diff options
author | Brad King <brad.king@kitware.com> | 2019-09-19 15:19:34 (GMT) |
---|---|---|
committer | Kitware Robot <kwrobot@kitware.com> | 2019-09-19 15:19:52 (GMT) |
commit | 9c31d83aa2a3d3f5921f4a5a559e126e285b96c5 (patch) | |
tree | 9506b2dbacaa62370c1d978965bbf2750a6b7a04 /Source | |
parent | e199294673665e01b1cba48625ec1b18c960c90e (diff) | |
parent | cc0900d9cd5fe1fa224d48738965b2928c09f6e7 (diff) | |
download | CMake-9c31d83aa2a3d3f5921f4a5a559e126e285b96c5.zip CMake-9c31d83aa2a3d3f5921f4a5a559e126e285b96c5.tar.gz CMake-9c31d83aa2a3d3f5921f4a5a559e126e285b96c5.tar.bz2 |
Merge topic 'autogen_path_prefix'
cc0900d9cd Help: Add release notes for AUTOMOC_PATH_PREFIX
692d8e3492 Help: Add documentation for AUTOMOC_PATH_PREFIX
1933ade9f1 Tests: At QtAutogen.MocIncludeSymlink test
706d9738a6 Tests: Merge QtAutogen.MocIncludeStrict and MocIncludeRelaxed
d018d27c10 Autogen: Add moc path prefix generation (AUTOMOC_PATH_PREFIX)
77983c8147 Autogen: Add IsHeader flag to SourceFileT class
f9e5441eb4 Autogen: Abbreviate file paths in messages
51676cf655 Autogen: Split JobEvalCacheT job into separate moc and uic jobs
...
Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !3818
Diffstat (limited to 'Source')
-rw-r--r-- | Source/cmQtAutoGen.cxx | 9 | ||||
-rw-r--r-- | Source/cmQtAutoGen.h | 3 | ||||
-rw-r--r-- | Source/cmQtAutoGenInitializer.cxx | 366 | ||||
-rw-r--r-- | Source/cmQtAutoGenInitializer.h | 18 | ||||
-rw-r--r-- | Source/cmQtAutoGenerator.cxx | 31 | ||||
-rw-r--r-- | Source/cmQtAutoGenerator.h | 24 | ||||
-rw-r--r-- | Source/cmQtAutoMocUic.cxx | 1129 | ||||
-rw-r--r-- | Source/cmQtAutoMocUic.h | 231 | ||||
-rw-r--r-- | Source/cmQtAutoRcc.cxx | 118 | ||||
-rw-r--r-- | Source/cmTarget.cxx | 1 |
10 files changed, 1047 insertions, 883 deletions
diff --git a/Source/cmQtAutoGen.cxx b/Source/cmQtAutoGen.cxx index f3c78d3..57c8825 100644 --- a/Source/cmQtAutoGen.cxx +++ b/Source/cmQtAutoGen.cxx @@ -162,6 +162,15 @@ std::string cmQtAutoGen::QuotedCommand(std::vector<std::string> const& command) return res; } +std::string cmQtAutoGen::ParentDir(cm::string_view filename) +{ + auto slashPos = filename.rfind('/'); + if (slashPos == cm::string_view::npos) { + return std::string(); + } + return std::string(filename.substr(0, slashPos)); +} + std::string cmQtAutoGen::SubDirPrefix(cm::string_view filename) { auto slashPos = filename.rfind('/'); diff --git a/Source/cmQtAutoGen.h b/Source/cmQtAutoGen.h index fb15586..71969ee 100644 --- a/Source/cmQtAutoGen.h +++ b/Source/cmQtAutoGen.h @@ -80,6 +80,9 @@ public: static std::string QuotedCommand(std::vector<std::string> const& command); + /// @brief Returns the parent directory of the file (thread safe) + static std::string ParentDir(cm::string_view filename); + /// @brief Returns the parent directory of the file with a "/" suffix static std::string SubDirPrefix(cm::string_view filename); diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx index 355141e..ad4e4d5 100644 --- a/Source/cmQtAutoGenInitializer.cxx +++ b/Source/cmQtAutoGenInitializer.cxx @@ -1,9 +1,11 @@ /* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmQtAutoGenInitializer.h" + #include "cmQtAutoGen.h" #include "cmQtAutoGenGlobalInitializer.h" +#include "cmAlgorithms.h" #include "cmCustomCommand.h" #include "cmCustomCommandLines.h" #include "cmFilePathChecksum.h" @@ -41,7 +43,9 @@ #include "cm_memory.hxx" -static std::size_t GetParallelCPUCount() +namespace { + +std::size_t GetParallelCPUCount() { static std::size_t count = 0; // Detect only on the first call @@ -55,8 +59,8 @@ static std::size_t GetParallelCPUCount() return count; } -static std::string FileProjectRelativePath(cmMakefile* makefile, - std::string const& fileName) +std::string FileProjectRelativePath(cmMakefile* makefile, + std::string const& fileName) { std::string res; { @@ -80,9 +84,9 @@ static std::string FileProjectRelativePath(cmMakefile* makefile, * recursive STATIC_LIBRARY dependencies depends on targetOrigin * (STATIC_LIBRARY cycle). */ -static bool StaticLibraryCycle(cmGeneratorTarget const* targetOrigin, - cmGeneratorTarget const* targetDepend, - std::string const& config) +bool StaticLibraryCycle(cmGeneratorTarget const* targetOrigin, + cmGeneratorTarget const* targetDepend, + std::string const& config) { bool cycle = false; if ((targetOrigin->GetType() == cmStateEnums::STATIC_LIBRARY) && @@ -120,6 +124,42 @@ static bool StaticLibraryCycle(cmGeneratorTarget const* targetOrigin, return cycle; } +/** Sanitizes file search paths */ +class SearchPathSanitizer +{ +public: + SearchPathSanitizer(cmMakefile* makefile) + : SourcePath_(makefile->GetCurrentSourceDirectory()) + { + } + std::vector<std::string> operator()( + std::vector<std::string> const& paths) const; + +private: + std::string SourcePath_; +}; + +std::vector<std::string> SearchPathSanitizer::operator()( + std::vector<std::string> const& paths) const +{ + std::vector<std::string> res; + res.reserve(paths.size()); + for (std::string const& srcPath : paths) { + // Collapse relative paths + std::string path = cmSystemTools::CollapseFullPath(srcPath, SourcePath_); + // Remove suffix slashes + while (cmHasSuffix(path, '/')) { + path.pop_back(); + } + // Accept only non empty paths + if (!path.empty()) { + res.emplace_back(std::move(path)); + } + } + return res; +} +} // End of unnamed namespace + cmQtAutoGenInitializer::InfoWriter::InfoWriter(std::string const& filename) { Ofs_.SetCopyIfDifferent(true); @@ -213,11 +253,15 @@ void cmQtAutoGenInitializer::InfoWriter::WriteNestedLists( }; cmQtAutoGenInitializer::cmQtAutoGenInitializer( - cmQtAutoGenGlobalInitializer* globalInitializer, cmGeneratorTarget* target, - IntegerVersion const& qtVersion, bool mocEnabled, bool uicEnabled, - bool rccEnabled, bool globalAutogenTarget, bool globalAutoRccTarget) + cmQtAutoGenGlobalInitializer* globalInitializer, + cmGeneratorTarget* genTarget, IntegerVersion const& qtVersion, + bool mocEnabled, bool uicEnabled, bool rccEnabled, bool globalAutogenTarget, + bool globalAutoRccTarget) : GlobalInitializer(globalInitializer) - , Target(target) + , GenTarget(genTarget) + , GlobalGen(genTarget->GetGlobalGenerator()) + , LocalGen(genTarget->GetLocalGenerator()) + , Makefile(genTarget->Makefile) , QtVersion(qtVersion) { AutogenTarget.GlobalTarget = globalAutogenTarget; @@ -229,19 +273,15 @@ cmQtAutoGenInitializer::cmQtAutoGenInitializer( bool cmQtAutoGenInitializer::InitCustomTargets() { - cmMakefile* makefile = this->Target->Target->GetMakefile(); - cmLocalGenerator* localGen = this->Target->GetLocalGenerator(); - cmGlobalGenerator* globalGen = localGen->GetGlobalGenerator(); - // Configurations - this->MultiConfig = globalGen->IsMultiConfig(); - this->ConfigDefault = makefile->GetConfigurations(this->ConfigsList); + this->MultiConfig = this->GlobalGen->IsMultiConfig(); + this->ConfigDefault = this->Makefile->GetConfigurations(this->ConfigsList); if (this->ConfigsList.empty()) { this->ConfigsList.push_back(this->ConfigDefault); } // Verbosity - this->Verbosity = makefile->GetSafeDefinition("CMAKE_AUTOGEN_VERBOSE"); + this->Verbosity = this->Makefile->GetSafeDefinition("CMAKE_AUTOGEN_VERBOSE"); if (!this->Verbosity.empty()) { unsigned long iVerb = 0; if (!cmStrToULong(this->Verbosity, &iVerb)) { @@ -253,14 +293,14 @@ bool cmQtAutoGenInitializer::InitCustomTargets() // Targets FOLDER { const char* folder = - makefile->GetState()->GetGlobalProperty("AUTOMOC_TARGETS_FOLDER"); + this->Makefile->GetState()->GetGlobalProperty("AUTOMOC_TARGETS_FOLDER"); if (folder == nullptr) { - folder = - makefile->GetState()->GetGlobalProperty("AUTOGEN_TARGETS_FOLDER"); + folder = this->Makefile->GetState()->GetGlobalProperty( + "AUTOGEN_TARGETS_FOLDER"); } // Inherit FOLDER property from target (#13688) if (folder == nullptr) { - folder = this->Target->GetProperty("FOLDER"); + folder = this->GenTarget->GetProperty("FOLDER"); } if (folder != nullptr) { this->TargetsFolder = folder; @@ -270,7 +310,7 @@ bool cmQtAutoGenInitializer::InitCustomTargets() // Check status of policy CMP0071 { cmPolicies::PolicyStatus const CMP0071_status = - makefile->GetPolicyStatus(cmPolicies::CMP0071); + this->Makefile->GetPolicyStatus(cmPolicies::CMP0071); switch (CMP0071_status) { case cmPolicies::WARN: this->CMP0071Warn = true; @@ -291,18 +331,18 @@ bool cmQtAutoGenInitializer::InitCustomTargets() { // Collapsed current binary directory std::string const cbd = cmSystemTools::CollapseFullPath( - std::string(), makefile->GetCurrentBinaryDirectory()); + std::string(), this->Makefile->GetCurrentBinaryDirectory()); // Info directory - this->Dir.Info = - cmStrCat(cbd, "/CMakeFiles/", this->Target->GetName(), "_autogen.dir"); + this->Dir.Info = cmStrCat(cbd, "/CMakeFiles/", this->GenTarget->GetName(), + "_autogen.dir"); cmSystemTools::ConvertToUnixSlashes(this->Dir.Info); // Build directory - this->Dir.Build = this->Target->GetSafeProperty("AUTOGEN_BUILD_DIR"); + this->Dir.Build = this->GenTarget->GetSafeProperty("AUTOGEN_BUILD_DIR"); if (this->Dir.Build.empty()) { this->Dir.Build = - cmStrCat(cbd, '/', this->Target->GetName(), "_autogen"); + cmStrCat(cbd, '/', this->GenTarget->GetName(), "_autogen"); } cmSystemTools::ConvertToUnixSlashes(this->Dir.Build); // Cleanup build directory @@ -339,11 +379,12 @@ bool cmQtAutoGenInitializer::InitCustomTargets() } // Autogen target name - this->AutogenTarget.Name = cmStrCat(this->Target->GetName(), "_autogen"); + this->AutogenTarget.Name = + cmStrCat(this->GenTarget->GetName(), "_autogen"); // Autogen target parallel processing this->AutogenTarget.Parallel = - this->Target->GetSafeProperty("AUTOGEN_PARALLEL"); + this->GenTarget->GetSafeProperty("AUTOGEN_PARALLEL"); if (this->AutogenTarget.Parallel.empty() || (this->AutogenTarget.Parallel == "AUTO")) { // Autodetect number of CPUs @@ -377,15 +418,14 @@ bool cmQtAutoGenInitializer::InitCustomTargets() // Autogen target: Compute user defined dependencies { this->AutogenTarget.DependOrigin = - this->Target->GetPropertyAsBool("AUTOGEN_ORIGIN_DEPENDS"); + this->GenTarget->GetPropertyAsBool("AUTOGEN_ORIGIN_DEPENDS"); std::string const deps = - this->Target->GetSafeProperty("AUTOGEN_TARGET_DEPENDS"); + this->GenTarget->GetSafeProperty("AUTOGEN_TARGET_DEPENDS"); if (!deps.empty()) { - std::vector<std::string> extraDeps = cmExpandedList(deps); - for (std::string const& depName : extraDeps) { + for (std::string const& depName : cmExpandedList(deps)) { // Allow target and file dependencies - auto* depTarget = makefile->FindTargetToUse(depName); + auto* depTarget = this->Makefile->FindTargetToUse(depName); if (depTarget != nullptr) { this->AutogenTarget.DependTargets.insert(depTarget); } else { @@ -397,13 +437,13 @@ bool cmQtAutoGenInitializer::InitCustomTargets() // CMAKE_AUTOMOC_RELAXED_MODE deprecation warning if (this->Moc.Enabled) { - if (makefile->IsOn("CMAKE_AUTOMOC_RELAXED_MODE")) { - makefile->IssueMessage( + if (this->Makefile->IsOn("CMAKE_AUTOMOC_RELAXED_MODE")) { + this->Makefile->IssueMessage( MessageType::AUTHOR_WARNING, cmStrCat("AUTOMOC: CMAKE_AUTOMOC_RELAXED_MODE is " "deprecated an will be removed in the future. Consider " "disabling it and converting the target ", - this->Target->GetName(), " to regular mode.")); + this->GenTarget->GetName(), " to regular mode.")); } } } @@ -415,7 +455,7 @@ bool cmQtAutoGenInitializer::InitCustomTargets() // Add autogen include directory to the origin target INCLUDE_DIRECTORIES if (this->MocOrUicEnabled() || (this->Rcc.Enabled && this->MultiConfig)) { - this->Target->AddIncludeDirectory(this->Dir.Include, true); + this->GenTarget->AddIncludeDirectory(this->Dir.Include, true); } // Scan files @@ -438,33 +478,29 @@ bool cmQtAutoGenInitializer::InitCustomTargets() bool cmQtAutoGenInitializer::InitMoc() { - cmMakefile* makefile = this->Target->Target->GetMakefile(); - cmLocalGenerator* localGen = this->Target->GetLocalGenerator(); - // Mocs compilation file this->Moc.MocsCompilation = cmStrCat(this->Dir.Build, "/mocs_compilation.cpp"); // Moc predefs command - if (this->Target->GetPropertyAsBool("AUTOMOC_COMPILER_PREDEFINES") && + if (this->GenTarget->GetPropertyAsBool("AUTOMOC_COMPILER_PREDEFINES") && (this->QtVersion >= IntegerVersion(5, 8))) { - this->Moc.PredefsCmd = - makefile->GetSafeDefinition("CMAKE_CXX_COMPILER_PREDEFINES_COMMAND"); + this->Moc.PredefsCmd = this->Makefile->GetSafeDefinition( + "CMAKE_CXX_COMPILER_PREDEFINES_COMMAND"); } // Moc includes { - bool const appendImplicit = (this->QtVersion.Major >= 5); + SearchPathSanitizer sanitizer(this->Makefile); auto GetIncludeDirs = - [this, localGen, - appendImplicit](std::string const& cfg) -> std::vector<std::string> { + [this, &sanitizer](std::string const& cfg) -> std::vector<std::string> { // Get the include dirs for this target, without stripping the implicit - // include dirs off, see - // https://gitlab.kitware.com/cmake/cmake/issues/13667 + // include dirs off, see issue #13667. std::vector<std::string> dirs; - localGen->GetIncludeDirectoriesImplicit(dirs, this->Target, "CXX", cfg, - false, appendImplicit); - return dirs; + bool const appendImplicit = (this->QtVersion.Major >= 5); + this->LocalGen->GetIncludeDirectoriesImplicit( + dirs, this->GenTarget, "CXX", cfg, false, appendImplicit); + return sanitizer(dirs); }; // Default configuration include directories @@ -483,9 +519,9 @@ bool cmQtAutoGenInitializer::InitMoc() // Moc compile definitions { auto GetCompileDefinitions = - [this, localGen](std::string const& cfg) -> std::set<std::string> { + [this](std::string const& cfg) -> std::set<std::string> { std::set<std::string> defines; - localGen->GetTargetDefines(this->Target, cfg, "CXX", defines); + this->LocalGen->GetTargetDefines(this->GenTarget, cfg, "CXX", defines); #ifdef _WIN32 if (this->Moc.PredefsCmd.empty()) { // Add WIN32 definition if we don't have a moc_predefs.h @@ -525,18 +561,13 @@ bool cmQtAutoGenInitializer::InitMoc() bool cmQtAutoGenInitializer::InitUic() { - cmMakefile* makefile = this->Target->Target->GetMakefile(); - // Uic search paths { std::string const usp = - this->Target->GetSafeProperty("AUTOUIC_SEARCH_PATHS"); + this->GenTarget->GetSafeProperty("AUTOUIC_SEARCH_PATHS"); if (!usp.empty()) { - cmExpandList(usp, this->Uic.SearchPaths); - std::string const& srcDir = makefile->GetCurrentSourceDirectory(); - for (std::string& path : this->Uic.SearchPaths) { - path = cmSystemTools::CollapseFullPath(path, srcDir); - } + this->Uic.SearchPaths = + SearchPathSanitizer(this->Makefile)(cmExpandedList(usp)); } } // Uic target options @@ -544,7 +575,7 @@ bool cmQtAutoGenInitializer::InitUic() auto UicGetOpts = [this](std::string const& cfg) -> std::vector<std::string> { std::vector<std::string> opts; - this->Target->GetAutoUicOptions(opts, cfg); + this->GenTarget->GetAutoUicOptions(opts, cfg); return opts; }; @@ -605,14 +636,13 @@ bool cmQtAutoGenInitializer::InitRcc() bool cmQtAutoGenInitializer::InitScanFiles() { - cmMakefile* makefile = this->Target->Target->GetMakefile(); - cmake const* cm = makefile->GetCMakeInstance(); + cmake const* cm = this->Makefile->GetCMakeInstance(); auto const& kw = this->GlobalInitializer->kw(); auto makeMUFile = [this, &kw](cmSourceFile* sf, std::string const& fullPath, bool muIt) -> MUFileHandle { MUFileHandle muf = cm::make_unique<MUFile>(); - muf->RealPath = cmSystemTools::GetRealPath(fullPath); + muf->FullPath = fullPath; muf->SF = sf; muf->Generated = sf->GetIsGenerated(); bool const skipAutogen = sf->GetPropertyAsBool(kw.SKIP_AUTOGEN); @@ -642,9 +672,9 @@ bool cmQtAutoGenInitializer::InitScanFiles() { // Scan through target files std::vector<cmSourceFile*> srcFiles; - this->Target->GetConfigCommonSourceFiles(srcFiles); + this->GenTarget->GetConfigCommonSourceFiles(srcFiles); for (cmSourceFile* sf : srcFiles) { - // sf->GetExtension() is only valid after sf->GetFullPath() ... + // sf->GetExtension() is only valid after sf->ResolveFullPath() ... // Since we're iterating over source files that might be not in the // target we need to check for path errors (not existing files). std::string pathError; @@ -670,7 +700,7 @@ bool cmQtAutoGenInitializer::InitScanFiles() !sf->GetPropertyAsBool(kw.SKIP_AUTORCC)) { // Register qrc file Qrc qrc; - qrc.QrcFile = cmSystemTools::GetRealPath(fullPath); + qrc.QrcFile = fullPath; qrc.QrcName = cmSystemTools::GetFilenameWithoutLastExtension(qrc.QrcFile); qrc.Generated = sf->GetIsGenerated(); @@ -690,7 +720,7 @@ bool cmQtAutoGenInitializer::InitScanFiles() // sources meta data cache. Clear it so that OBJECT library targets that // are AUTOGEN initialized after this target get their added // mocs_compilation.cpp source acknowledged by this target. - this->Target->ClearSourcesCache(); + this->GenTarget->ClearSourcesCache(); // For source files find additional headers and private headers if (this->MocOrUicEnabled()) { @@ -704,21 +734,21 @@ bool cmQtAutoGenInitializer::InitScanFiles() MUFile const& muf = *pair.second; if (muf.MocIt || muf.UicIt) { // Search for the default header file and a private header - std::string const& srcPath = muf.SF->ResolveFullPath(); - std::string basePath = - cmStrCat(cmQtAutoGen::SubDirPrefix(srcPath), - cmSystemTools::GetFilenameWithoutLastExtension(srcPath)); + std::string const& srcFullPath = muf.SF->ResolveFullPath(); + std::string basePath = cmStrCat( + cmQtAutoGen::SubDirPrefix(srcFullPath), + cmSystemTools::GetFilenameWithoutLastExtension(srcFullPath)); for (auto const& suffix : suffixes) { std::string const suffixedPath = cmStrCat(basePath, suffix); for (auto const& ext : exts) { std::string fullPath = cmStrCat(suffixedPath, '.', ext); auto constexpr locationKind = cmSourceFileLocationKind::Known; - cmSourceFile* sf = makefile->GetSource(fullPath, locationKind); + cmSourceFile* sf = + this->Makefile->GetSource(fullPath, locationKind); if (sf != nullptr) { // Check if we know about this header already - if (this->AutogenTarget.Headers.find(sf) != - this->AutogenTarget.Headers.end()) { + if (cmContains(this->AutogenTarget.Headers, sf)) { continue; } // We only accept not-GENERATED files that do exist. @@ -728,7 +758,7 @@ bool cmQtAutoGenInitializer::InitScanFiles() } } else if (cmSystemTools::FileExists(fullPath)) { // Create a new source file for the existing file - sf = makefile->CreateSource(fullPath, false, locationKind); + sf = this->Makefile->CreateSource(fullPath, false, locationKind); } if (sf != nullptr) { @@ -757,8 +787,8 @@ bool cmQtAutoGenInitializer::InitScanFiles() // The reason is that their file names might be discovered from source files // at generation time. if (this->MocOrUicEnabled()) { - for (cmSourceFile* sf : makefile->GetSourceFiles()) { - // sf->GetExtension() is only valid after sf->GetFullPath() ... + for (cmSourceFile* sf : this->Makefile->GetSourceFiles()) { + // sf->GetExtension() is only valid after sf->ResolveFullPath() ... // Since we're iterating over source files that might be not in the // target we need to check for path errors (not existing files). std::string pathError; @@ -770,16 +800,14 @@ bool cmQtAutoGenInitializer::InitScanFiles() cmSystemTools::LowerCase(sf->GetExtension()); if (cm->IsHeaderExtension(extLower)) { - if (this->AutogenTarget.Headers.find(sf) == - this->AutogenTarget.Headers.end()) { + if (!cmContains(this->AutogenTarget.Headers, sf)) { auto muf = makeMUFile(sf, fullPath, false); if (muf->SkipMoc || muf->SkipUic) { this->AutogenTarget.Headers.emplace(sf, std::move(muf)); } } } else if (cm->IsSourceExtension(extLower)) { - if (this->AutogenTarget.Sources.find(sf) == - this->AutogenTarget.Sources.end()) { + if (!cmContains(this->AutogenTarget.Headers, sf)) { auto muf = makeMUFile(sf, fullPath, false); if (muf->SkipMoc || muf->SkipUic) { this->AutogenTarget.Sources.emplace(sf, std::move(muf)); @@ -787,7 +815,6 @@ bool cmQtAutoGenInitializer::InitScanFiles() } } else if (this->Uic.Enabled && (extLower == kw.ui)) { // .ui file - std::string realPath = cmSystemTools::GetRealPath(fullPath); bool const skipAutogen = sf->GetPropertyAsBool(kw.SKIP_AUTOGEN); bool const skipUic = (skipAutogen || sf->GetPropertyAsBool(kw.SKIP_AUTOUIC)); @@ -795,13 +822,12 @@ bool cmQtAutoGenInitializer::InitScanFiles() // Check if the .ui file has uic options std::string const uicOpts = sf->GetSafeProperty(kw.AUTOUIC_OPTIONS); if (!uicOpts.empty()) { - this->Uic.FileFiles.push_back(std::move(realPath)); - std::vector<std::string> optsVec = cmExpandedList(uicOpts); - this->Uic.FileOptions.push_back(std::move(optsVec)); + this->Uic.FileFiles.push_back(fullPath); + this->Uic.FileOptions.push_back(cmExpandedList(uicOpts)); } } else { // Register skipped .ui file - this->Uic.SkipUi.insert(std::move(realPath)); + this->Uic.SkipUi.insert(fullPath); } } } @@ -812,7 +838,7 @@ bool cmQtAutoGenInitializer::InitScanFiles() if (this->CMP0071Accept) { // Let the autogen target depend on the GENERATED files for (MUFile* muf : this->AutogenTarget.FilesGenerated) { - this->AutogenTarget.DependFiles.insert(muf->RealPath); + this->AutogenTarget.DependFiles.insert(muf->FullPath); } } else if (this->CMP0071Warn) { cm::string_view property; @@ -825,9 +851,9 @@ bool cmQtAutoGenInitializer::InitScanFiles() } std::string files; for (MUFile* muf : this->AutogenTarget.FilesGenerated) { - files += cmStrCat(" ", Quoted(muf->RealPath), '\n'); + files += cmStrCat(" ", Quoted(muf->FullPath), '\n'); } - makefile->IssueMessage( + this->Makefile->IssueMessage( MessageType::AUTHOR_WARNING, cmStrCat( cmPolicies::GetPolicyWarning(cmPolicies::CMP0071), '\n', @@ -848,7 +874,7 @@ bool cmQtAutoGenInitializer::InitScanFiles() const bool modernQt = (this->QtVersion.Major >= 5); // Target rcc options std::vector<std::string> optionsTarget = - cmExpandedList(this->Target->GetSafeProperty(kw.AUTORCC_OPTIONS)); + cmExpandedList(this->GenTarget->GetSafeProperty(kw.AUTORCC_OPTIONS)); // Check if file name is unique for (Qrc& qrc : this->Rcc.Qrcs) { @@ -862,7 +888,7 @@ bool cmQtAutoGenInitializer::InitScanFiles() } // Path checksum and file names { - cmFilePathChecksum const fpathCheckSum(makefile); + cmFilePathChecksum const fpathCheckSum(this->Makefile); for (Qrc& qrc : this->Rcc.Qrcs) { qrc.PathChecksum = fpathCheckSum.getPart(qrc.QrcFile); // RCC output file name @@ -925,12 +951,8 @@ bool cmQtAutoGenInitializer::InitScanFiles() bool cmQtAutoGenInitializer::InitAutogenTarget() { - cmMakefile* makefile = this->Target->Target->GetMakefile(); - cmLocalGenerator* localGen = this->Target->GetLocalGenerator(); - cmGlobalGenerator* globalGen = localGen->GetGlobalGenerator(); - // Register info file as generated by CMake - makefile->AddCMakeOutputFile(this->AutogenTarget.InfoFile); + this->Makefile->AddCMakeOutputFile(this->AutogenTarget.InfoFile); // Files provided by the autogen target std::vector<std::string> autogenProvides; @@ -952,8 +974,8 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() } tools += "UIC"; } - autogenComment = - cmStrCat("Automatic ", tools, " for target ", this->Target->GetName()); + autogenComment = cmStrCat("Automatic ", tools, " for target ", + this->GenTarget->GetName()); } // Compose command lines @@ -963,7 +985,7 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() // Use PRE_BUILD on demand bool usePRE_BUILD = false; - if (globalGen->GetName().find("Visual Studio") != std::string::npos) { + if (this->GlobalGen->GetName().find("Visual Studio") != std::string::npos) { // Under VS use a PRE_BUILD event instead of a separate target to // reduce the number of targets loaded into the IDE. // This also works around a VS 11 bug that may skip updating the target: @@ -985,7 +1007,8 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() if (usePRE_BUILD) { // Add additional autogen target dependencies to origin target for (cmTarget* depTarget : this->AutogenTarget.DependTargets) { - this->Target->Target->AddUtility(depTarget->GetName(), makefile); + this->GenTarget->Target->AddUtility(depTarget->GetName(), + this->Makefile); } // Add the pre-build command directly to bypass the OBJECT_LIBRARY @@ -995,12 +1018,12 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() // PRE_BUILD does not support file dependencies! const std::vector<std::string> no_output; const std::vector<std::string> no_deps; - cmCustomCommand cc(makefile, no_output, autogenProvides, no_deps, + cmCustomCommand cc(this->Makefile, no_output, autogenProvides, no_deps, commandLines, autogenComment.c_str(), this->Dir.Work.c_str()); cc.SetEscapeOldStyle(false); cc.SetEscapeAllowMakeVars(true); - this->Target->Target->AddPreBuildCommand(cc); + this->GenTarget->Target->AddPreBuildCommand(cc); } else { // Add link library target dependencies to the autogen target @@ -1011,12 +1034,12 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() std::map<cmGeneratorTarget const*, std::size_t> commonTargets; for (std::string const& config : this->ConfigsList) { cmLinkImplementationLibraries const* libs = - this->Target->GetLinkImplementationLibraries(config); + this->GenTarget->GetLinkImplementationLibraries(config); if (libs != nullptr) { for (cmLinkItem const& item : libs->Libraries) { cmGeneratorTarget const* libTarget = item.Target; if ((libTarget != nullptr) && - !StaticLibraryCycle(this->Target, libTarget, config)) { + !StaticLibraryCycle(this->GenTarget, libTarget, config)) { // Increment target config count commonTargets[libTarget]++; } @@ -1031,25 +1054,25 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() } // Create autogen target - cmTarget* autogenTarget = makefile->AddUtilityCommand( + cmTarget* autogenTarget = this->Makefile->AddUtilityCommand( this->AutogenTarget.Name, cmMakefile::TargetOrigin::Generator, true, this->Dir.Work.c_str(), /*byproducts=*/autogenProvides, std::vector<std::string>(this->AutogenTarget.DependFiles.begin(), this->AutogenTarget.DependFiles.end()), commandLines, false, autogenComment.c_str()); // Create autogen generator target - localGen->AddGeneratorTarget( - new cmGeneratorTarget(autogenTarget, localGen)); + this->LocalGen->AddGeneratorTarget( + new cmGeneratorTarget(autogenTarget, this->LocalGen)); // Forward origin utilities to autogen target if (this->AutogenTarget.DependOrigin) { - for (BT<std::string> const& depName : this->Target->GetUtilities()) { - autogenTarget->AddUtility(depName.Value, makefile); + for (BT<std::string> const& depName : this->GenTarget->GetUtilities()) { + autogenTarget->AddUtility(depName.Value, this->Makefile); } } // Add additional autogen target dependencies to autogen target for (cmTarget* depTarget : this->AutogenTarget.DependTargets) { - autogenTarget->AddUtility(depTarget->GetName(), makefile); + autogenTarget->AddUtility(depTarget->GetName(), this->Makefile); } // Set FOLDER property in autogen target @@ -1058,11 +1081,12 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() } // Add autogen target to the origin target dependencies - this->Target->Target->AddUtility(this->AutogenTarget.Name, makefile); + this->GenTarget->Target->AddUtility(this->AutogenTarget.Name, + this->Makefile); // Add autogen target to the global autogen target dependencies if (this->AutogenTarget.GlobalTarget) { - this->GlobalInitializer->AddToGlobalAutoGen(localGen, + this->GlobalInitializer->AddToGlobalAutoGen(this->LocalGen, this->AutogenTarget.Name); } } @@ -1072,12 +1096,9 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() bool cmQtAutoGenInitializer::InitRccTargets() { - cmMakefile* makefile = this->Target->Target->GetMakefile(); - cmLocalGenerator* localGen = this->Target->GetLocalGenerator(); - for (Qrc const& qrc : this->Rcc.Qrcs) { // Register info file as generated by CMake - makefile->AddCMakeOutputFile(qrc.InfoFile); + this->Makefile->AddCMakeOutputFile(qrc.InfoFile); // Register file at target this->AddGeneratedSource(qrc.RccFile, this->Rcc); @@ -1102,41 +1123,43 @@ bool cmQtAutoGenInitializer::InitRccTargets() cmMakeCommandLine({ cmSystemTools::GetCMakeCommand(), "-E", "cmake_autorcc", qrc.InfoFile, "$<CONFIG>" })); } - std::string ccComment = cmStrCat( - "Automatic RCC for ", FileProjectRelativePath(makefile, qrc.QrcFile)); + std::string ccComment = + cmStrCat("Automatic RCC for ", + FileProjectRelativePath(this->Makefile, qrc.QrcFile)); if (qrc.Generated || this->Rcc.GlobalTarget) { // Create custom rcc target std::string ccName; { - ccName = cmStrCat(this->Target->GetName(), "_arcc_", qrc.QrcName); + ccName = cmStrCat(this->GenTarget->GetName(), "_arcc_", qrc.QrcName); if (!qrc.Unique) { ccName += cmStrCat('_', qrc.PathChecksum); } - cmTarget* autoRccTarget = makefile->AddUtilityCommand( + cmTarget* autoRccTarget = this->Makefile->AddUtilityCommand( ccName, cmMakefile::TargetOrigin::Generator, true, this->Dir.Work.c_str(), ccOutput, ccDepends, commandLines, false, ccComment.c_str()); // Create autogen generator target - localGen->AddGeneratorTarget( - new cmGeneratorTarget(autoRccTarget, localGen)); + this->LocalGen->AddGeneratorTarget( + new cmGeneratorTarget(autoRccTarget, this->LocalGen)); // Set FOLDER property in autogen target if (!this->TargetsFolder.empty()) { autoRccTarget->SetProperty("FOLDER", this->TargetsFolder.c_str()); } if (!this->Rcc.ExecutableTargetName.empty()) { - autoRccTarget->AddUtility(this->Rcc.ExecutableTargetName, makefile); + autoRccTarget->AddUtility(this->Rcc.ExecutableTargetName, + this->Makefile); } } // Add autogen target to the origin target dependencies - this->Target->Target->AddUtility(ccName, makefile); + this->GenTarget->Target->AddUtility(ccName, this->Makefile); // Add autogen target to the global autogen target dependencies if (this->Rcc.GlobalTarget) { - this->GlobalInitializer->AddToGlobalAutoRcc(localGen, ccName); + this->GlobalInitializer->AddToGlobalAutoRcc(this->LocalGen, ccName); } } else { // Create custom rcc command @@ -1153,13 +1176,13 @@ bool cmQtAutoGenInitializer::InitRccTargets() } std::string no_main_dependency; cmImplicitDependsList no_implicit_depends; - makefile->AddCustomCommandToOutput( + this->Makefile->AddCustomCommandToOutput( ccOutput, ccByproducts, ccDepends, no_main_dependency, no_implicit_depends, commandLines, ccComment.c_str(), this->Dir.Work.c_str()); } // Reconfigure when .qrc file changes - makefile->AddCMakeDependFile(qrc.QrcFile); + this->Makefile->AddCMakeDependFile(qrc.QrcFile); } } @@ -1192,9 +1215,8 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo() InfoWriter ofs(this->AutogenTarget.InfoFile); if (ofs) { // Utility lambdas - cmMakefile* makefile = this->Target->Target->GetMakefile(); - auto MfDef = [makefile](const char* key) { - return makefile->GetSafeDefinition(key); + auto MfDef = [this](const char* key) { + return this->Makefile->GetSafeDefinition(key); }; // Write common settings @@ -1210,8 +1232,6 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo() MfDef("CMAKE_CURRENT_SOURCE_DIR")); ofs.Write("AM_CMAKE_CURRENT_BINARY_DIR", MfDef("CMAKE_CURRENT_BINARY_DIR")); - ofs.Write("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE", - MfDef("CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE")); ofs.Write("AM_BUILD_DIR", this->Dir.Build); ofs.Write("AM_INCLUDE_DIR", this->Dir.Include); ofs.WriteConfig("AM_INCLUDE_DIR", this->Dir.ConfigInclude); @@ -1238,7 +1258,7 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo() } std::sort(sortedHeaders.begin(), sortedHeaders.end(), [](MUFile const* a, MUFile const* b) { - return (a->RealPath < b->RealPath); + return (a->FullPath < b->FullPath); }); } @@ -1247,13 +1267,13 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo() continue; } if (muf->SkipMoc) { - moc_skip.insert(muf->RealPath); + moc_skip.insert(muf->FullPath); } if (muf->SkipUic) { - uic_skip.insert(muf->RealPath); + uic_skip.insert(muf->FullPath); } if (muf->MocIt || muf->UicIt) { - headers.emplace_back(muf->RealPath); + headers.emplace_back(muf->FullPath); headersFlags.emplace_back( cmStrCat(muf->MocIt ? 'M' : 'm', muf->UicIt ? 'U' : 'u')); } @@ -1261,7 +1281,7 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo() } // Header build paths { - cmFilePathChecksum const fpathCheckSum(makefile); + cmFilePathChecksum const fpathCheckSum(this->Makefile); std::unordered_set<std::string> emitted; for (std::string const& hdr : headers) { std::string const basePath = @@ -1292,7 +1312,7 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo() } std::sort(sorted.begin(), sorted.end(), [](MUFile const* a, MUFile const* b) { - return (a->RealPath < b->RealPath); + return (a->FullPath < b->FullPath); }); for (MUFile const* const muf : sorted) { @@ -1300,13 +1320,13 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo() continue; } if (muf->SkipMoc) { - moc_skip.insert(muf->RealPath); + moc_skip.insert(muf->FullPath); } if (muf->SkipUic) { - uic_skip.insert(muf->RealPath); + uic_skip.insert(muf->FullPath); } if (muf->MocIt || muf->UicIt) { - sources.emplace_back(muf->RealPath); + sources.emplace_back(muf->FullPath); sourcesFlags.emplace_back( cmStrCat(muf->MocIt ? 'M' : 'm', muf->UicIt ? 'U' : 'u')); } @@ -1339,12 +1359,14 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo() ofs.WriteStrings("AM_MOC_INCLUDES", this->Moc.Includes); ofs.WriteConfigStrings("AM_MOC_INCLUDES", this->Moc.ConfigIncludes); ofs.Write("AM_MOC_OPTIONS", - this->Target->GetSafeProperty("AUTOMOC_MOC_OPTIONS")); + this->GenTarget->GetSafeProperty("AUTOMOC_MOC_OPTIONS")); ofs.Write("AM_MOC_RELAXED_MODE", MfDef("CMAKE_AUTOMOC_RELAXED_MODE")); + ofs.Write("AM_MOC_PATH_PREFIX", + this->GenTarget->GetSafeProperty("AUTOMOC_PATH_PREFIX")); ofs.Write("AM_MOC_MACRO_NAMES", - this->Target->GetSafeProperty("AUTOMOC_MACRO_NAMES")); + this->GenTarget->GetSafeProperty("AUTOMOC_MACRO_NAMES")); ofs.Write("AM_MOC_DEPEND_FILTERS", - this->Target->GetSafeProperty("AUTOMOC_DEPEND_FILTERS")); + this->GenTarget->GetSafeProperty("AUTOMOC_DEPEND_FILTERS")); ofs.Write("AM_MOC_PREDEFS_CMD", this->Moc.PredefsCmd); } @@ -1375,6 +1397,11 @@ bool cmQtAutoGenInitializer::SetupWriteRccInfo() for (Qrc const& qrc : this->Rcc.Qrcs) { InfoWriter ofs(qrc.InfoFile); if (ofs) { + // Utility lambdas + auto MfDef = [this](const char* key) { + return this->Makefile->GetSafeDefinition(key); + }; + // Write ofs.Write("# Configurations\n"); ofs.Write("ARCC_MULTI_CONFIG", this->MultiConfig ? "TRUE" : "FALSE"); @@ -1384,6 +1411,8 @@ bool cmQtAutoGenInitializer::SetupWriteRccInfo() ofs.WriteConfig("ARCC_SETTINGS_FILE", qrc.ConfigSettingsFile); ofs.Write("# Directories\n"); + ofs.Write("ARCC_CMAKE_SOURCE_DIR", MfDef("CMAKE_SOURCE_DIR")); + ofs.Write("ARCC_CMAKE_BINARY_DIR", MfDef("CMAKE_BINARY_DIR")); ofs.Write("ARCC_BUILD_DIR", this->Dir.Build); ofs.Write("ARCC_INCLUDE_DIR", this->Dir.Include); ofs.WriteConfig("ARCC_INCLUDE_DIR", this->Dir.ConfigInclude); @@ -1414,8 +1443,7 @@ bool cmQtAutoGenInitializer::SetupWriteRccInfo() void cmQtAutoGenInitializer::RegisterGeneratedSource( std::string const& filename) { - cmMakefile* makefile = this->Target->Target->GetMakefile(); - cmSourceFile* gFile = makefile->GetOrCreateSource(filename, true); + cmSourceFile* gFile = this->Makefile->GetOrCreateSource(filename, true); gFile->SetProperty("GENERATED", "1"); gFile->SetProperty("SKIP_AUTOGEN", "1"); } @@ -1427,7 +1455,7 @@ bool cmQtAutoGenInitializer::AddGeneratedSource(std::string const& filename, // Register source at makefile this->RegisterGeneratedSource(filename); // Add source file to target - this->Target->AddSource(filename, prepend); + this->GenTarget->AddSource(filename, prepend); // Add source file to source group return this->AddToSourceGroup(filename, genVars.GenNameUpper); } @@ -1435,7 +1463,6 @@ bool cmQtAutoGenInitializer::AddGeneratedSource(std::string const& filename, bool cmQtAutoGenInitializer::AddToSourceGroup(std::string const& fileName, cm::string_view genNameUpper) { - cmMakefile* makefile = this->Target->Target->GetMakefile(); cmSourceGroup* sourceGroup = nullptr; // Acquire source group { @@ -1447,7 +1474,8 @@ bool cmQtAutoGenInitializer::AddToSourceGroup(std::string const& fileName, cmStrCat(genNameUpper, "_SOURCE_GROUP"), "AUTOGEN_SOURCE_GROUP" }; for (std::string const& prop : props) { - const char* propName = makefile->GetState()->GetGlobalProperty(prop); + const char* propName = + this->Makefile->GetState()->GetGlobalProperty(prop); if ((propName != nullptr) && (*propName != '\0')) { groupName = propName; property = prop; @@ -1457,7 +1485,7 @@ bool cmQtAutoGenInitializer::AddToSourceGroup(std::string const& fileName, } // Generate a source group on demand if (!groupName.empty()) { - sourceGroup = makefile->GetOrCreateSourceGroup(groupName); + sourceGroup = this->Makefile->GetOrCreateSourceGroup(groupName); if (sourceGroup == nullptr) { cmSystemTools::Error( cmStrCat(genNameUpper, " error in ", property, @@ -1475,8 +1503,8 @@ bool cmQtAutoGenInitializer::AddToSourceGroup(std::string const& fileName, void cmQtAutoGenInitializer::AddCleanFile(std::string const& fileName) { - Target->Target->AppendProperty("ADDITIONAL_CLEAN_FILES", fileName.c_str(), - false); + this->GenTarget->Target->AppendProperty("ADDITIONAL_CLEAN_FILES", + fileName.c_str(), false); } static unsigned int CharPtrToUInt(const char* const input) @@ -1489,7 +1517,7 @@ static unsigned int CharPtrToUInt(const char* const input) } static std::vector<cmQtAutoGen::IntegerVersion> GetKnownQtVersions( - cmGeneratorTarget const* target) + cmGeneratorTarget const* genTarget) { // Qt version variable prefixes static std::initializer_list< @@ -1511,7 +1539,7 @@ static std::vector<cmQtAutoGen::IntegerVersion> GetKnownQtVersions( } }; - cmMakefile* makefile = target->Target->GetMakefile(); + cmMakefile* makefile = genTarget->Makefile; // Read versions from variables for (auto const& keyPair : keys) { @@ -1561,22 +1589,20 @@ bool cmQtAutoGenInitializer::GetQtExecutable(GenVarsT& genVars, { auto print_err = [this, &genVars](std::string const& err) { cmSystemTools::Error(cmStrCat(genVars.GenNameUpper, " for target ", - this->Target->GetName(), ": ", err)); + this->GenTarget->GetName(), ": ", err)); }; // Custom executable { std::string const prop = cmStrCat(genVars.GenNameUpper, "_EXECUTABLE"); - std::string const val = this->Target->Target->GetSafeProperty(prop); + std::string const val = this->GenTarget->Target->GetSafeProperty(prop); if (!val.empty()) { // Evaluate generator expression { - cmListFileBacktrace lfbt = - this->Target->Target->GetMakefile()->GetBacktrace(); + cmListFileBacktrace lfbt = this->Makefile->GetBacktrace(); cmGeneratorExpression ge(lfbt); std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(val); - genVars.Executable = - cge->Evaluate(this->Target->GetLocalGenerator(), ""); + genVars.Executable = cge->Evaluate(this->LocalGen, ""); } if (genVars.Executable.empty() && !ignoreMissingTarget) { print_err(prop + " evaluates to an empty value"); @@ -1604,15 +1630,15 @@ bool cmQtAutoGenInitializer::GetQtExecutable(GenVarsT& genVars, std::string const targetName = cmStrCat(prefix, executable); // Find target - cmLocalGenerator* localGen = this->Target->GetLocalGenerator(); - cmGeneratorTarget* target = localGen->FindGeneratorTargetToUse(targetName); - if (target != nullptr) { + cmGeneratorTarget* genTarget = + this->LocalGen->FindGeneratorTargetToUse(targetName); + if (genTarget != nullptr) { genVars.ExecutableTargetName = targetName; - genVars.ExecutableTarget = target; - if (target->IsImported()) { - genVars.Executable = target->ImportedGetLocation(""); + genVars.ExecutableTarget = genTarget; + if (genTarget->IsImported()) { + genVars.Executable = genTarget->ImportedGetLocation(""); } else { - genVars.Executable = target->GetLocation(""); + genVars.Executable = genTarget->GetLocation(""); } } else { if (ignoreMissingTarget) { diff --git a/Source/cmQtAutoGenInitializer.h b/Source/cmQtAutoGenInitializer.h index 84a27e4..bedda30 100644 --- a/Source/cmQtAutoGenInitializer.h +++ b/Source/cmQtAutoGenInitializer.h @@ -18,9 +18,12 @@ #include <vector> class cmGeneratorTarget; -class cmTarget; +class cmGlobalGenerator; +class cmLocalGenerator; +class cmMakefile; class cmQtAutoGenGlobalInitializer; class cmSourceFile; +class cmTarget; /// @brief Initializes the QtAutoGen generators class cmQtAutoGenInitializer : public cmQtAutoGen @@ -47,7 +50,7 @@ public: /// @brief Moc/Uic file struct MUFile { - std::string RealPath; + std::string FullPath; cmSourceFile* SF = nullptr; bool Generated = false; bool SkipMoc = false; @@ -112,10 +115,10 @@ public: public: /// @return The detected Qt version and the required Qt major version static std::pair<IntegerVersion, unsigned int> GetQtVersion( - cmGeneratorTarget const* target); + cmGeneratorTarget const* genTarget); cmQtAutoGenInitializer(cmQtAutoGenGlobalInitializer* globalInitializer, - cmGeneratorTarget* target, + cmGeneratorTarget* genTarget, IntegerVersion const& qtVersion, bool mocEnabled, bool uicEnabled, bool rccEnabled, bool globalAutogenTarget, bool globalAutoRccTarget); @@ -152,8 +155,11 @@ private: bool ignoreMissingTarget) const; private: - cmQtAutoGenGlobalInitializer* GlobalInitializer; - cmGeneratorTarget* Target; + cmQtAutoGenGlobalInitializer* GlobalInitializer = nullptr; + cmGeneratorTarget* GenTarget = nullptr; + cmGlobalGenerator* GlobalGen = nullptr; + cmLocalGenerator* LocalGen = nullptr; + cmMakefile* Makefile = nullptr; // Configuration IntegerVersion QtVersion; diff --git a/Source/cmQtAutoGenerator.cxx b/Source/cmQtAutoGenerator.cxx index 80b8741..086b68c 100644 --- a/Source/cmQtAutoGenerator.cxx +++ b/Source/cmQtAutoGenerator.cxx @@ -93,32 +93,18 @@ void cmQtAutoGenerator::Logger::Warning(GenT genType, } } -void cmQtAutoGenerator::Logger::WarningFile(GenT genType, - cm::string_view filename, - cm::string_view message) const -{ - Warning(genType, cmStrCat(" ", Quoted(filename), '\n', message)); -} - void cmQtAutoGenerator::Logger::Error(GenT genType, cm::string_view message) const { std::string msg = - cmStrCat(HeadLine(cmStrCat(GeneratorName(genType), " error")), message, - cmHasSuffix(message, '\n') ? "\n" : "\n\n"); + cmStrCat('\n', HeadLine(cmStrCat(GeneratorName(genType), " error")), + message, cmHasSuffix(message, '\n') ? "\n" : "\n\n"); { std::lock_guard<std::mutex> lock(Mutex_); cmSystemTools::Stderr(msg); } } -void cmQtAutoGenerator::Logger::ErrorFile(GenT genType, - cm::string_view filename, - cm::string_view message) const -{ - Error(genType, cmStrCat(" ", Quoted(filename), '\n', message)); -} - void cmQtAutoGenerator::Logger::ErrorCommand( GenT genType, cm::string_view message, std::vector<std::string> const& command, std::string const& output) const @@ -286,3 +272,16 @@ std::string cmQtAutoGenerator::SettingsFind(std::string const& content, } return std::string(); } + +std::string cmQtAutoGenerator::MessagePath(cm::string_view path) const +{ + std::string res; + if (cmHasPrefix(path, ProjectDirs().Source)) { + res = cmStrCat("SRC:", path.substr(ProjectDirs().Source.size())); + } else if (cmHasPrefix(path, ProjectDirs().Binary)) { + res = cmStrCat("BIN:", path.substr(ProjectDirs().Binary.size())); + } else { + res = std::string(path); + } + return cmQtAutoGen::Quoted(res); +} diff --git a/Source/cmQtAutoGenerator.h b/Source/cmQtAutoGenerator.h index 4b8b0b7..371b25c 100644 --- a/Source/cmQtAutoGenerator.h +++ b/Source/cmQtAutoGenerator.h @@ -23,9 +23,7 @@ class cmQtAutoGenerator : public cmQtAutoGen public: // -- Types - /** - * Thread safe logger - */ + /** Thread safe logger. */ class Logger { public: @@ -45,12 +43,8 @@ public: void Info(GenT genType, cm::string_view message) const; // -- Log warning void Warning(GenT genType, cm::string_view message) const; - void WarningFile(GenT genType, cm::string_view filename, - cm::string_view message) const; // -- Log error void Error(GenT genType, cm::string_view message) const; - void ErrorFile(GenT genType, cm::string_view filename, - cm::string_view message) const; void ErrorCommand(GenT genType, cm::string_view message, std::vector<std::string> const& command, std::string const& output) const; @@ -64,6 +58,15 @@ public: bool ColorOutput_ = false; }; + /** Project directories. */ + struct ProjectDirsT + { + std::string Source; + std::string Binary; + std::string CurrentSource; + std::string CurrentBinary; + }; + // -- File system methods static bool MakeParentDirectory(std::string const& filename); static bool FileRead(std::string& content, std::string const& filename, @@ -91,13 +94,18 @@ public: std::string const& InfoDir() const { return InfoDir_; } std::string const& InfoConfig() const { return InfoConfig_; } + // -- Directories + ProjectDirsT const& ProjectDirs() const { return ProjectDirs_; } + // -- Utility static std::string SettingsFind(std::string const& content, const char* key); + std::string MessagePath(cm::string_view path) const; protected: // -- Abstract processing interface virtual bool Init(cmMakefile* makefile) = 0; virtual bool Process() = 0; + ProjectDirsT& ProjectDirsRef() { return ProjectDirs_; } private: // -- Info settings @@ -105,6 +113,8 @@ private: cmFileTime InfoFileTime_; std::string InfoDir_; std::string InfoConfig_; + // -- Directories + ProjectDirsT ProjectDirs_; }; #endif diff --git a/Source/cmQtAutoMocUic.cxx b/Source/cmQtAutoMocUic.cxx index 40ebdde..4e4875e 100644 --- a/Source/cmQtAutoMocUic.cxx +++ b/Source/cmQtAutoMocUic.cxx @@ -2,14 +2,6 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmQtAutoMocUic.h" -#include <algorithm> -#include <initializer_list> -#include <list> -#include <set> -#include <utility> - -#include "cm_memory.hxx" - #include "cmAlgorithms.h" #include "cmCryptoHash.h" #include "cmGeneratedFileStream.h" @@ -17,9 +9,13 @@ #include "cmQtAutoGen.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" +#include "cm_memory.hxx" #include "cmake.h" #include "cmsys/FStream.hxx" +#include <algorithm> +#include <set> +#include <utility> #if defined(__APPLE__) # include <unistd.h> #endif @@ -238,13 +234,6 @@ void cmQtAutoMocUic::JobT::LogError(GenT genType, Gen()->Log().Error(genType, message); } -void cmQtAutoMocUic::JobT::LogFileError(GenT genType, cm::string_view filename, - cm::string_view message) const -{ - Gen()->AbortError(); - Gen()->Log().ErrorFile(genType, filename, message); -} - void cmQtAutoMocUic::JobT::LogCommandError( GenT genType, cm::string_view message, std::vector<std::string> const& command, std::string const& output) const @@ -269,6 +258,7 @@ bool cmQtAutoMocUic::JobT::RunProcess(GenT genType, info.empty() || cmHasSuffix(info, '\n') ? "" : "\n", QuotedCommand(command), '\n')); } + // Run command return cmWorkerPool::JobT::RunProcess(result, command, BaseConst().AutogenBuildDir); } @@ -283,24 +273,21 @@ void cmQtAutoMocUic::JobMocPredefsT::Process() if (!Update(reason.get())) { return; } - std::string const& predefsFileRel = MocConst().PredefsFileRel; std::string const& predefsFileAbs = MocConst().PredefsFileAbs; { cmWorkerPool::ProcessResultT result; { // Compose command std::vector<std::string> cmd = MocConst().PredefsCmd; - // Add includes - cmAppend(cmd, MocConst().Includes); // Add definitions - for (std::string const& def : MocConst().Definitions) { - cmd.emplace_back("-D" + def); - } + cmAppend(cmd, MocConst().OptionsDefinitions); + // Add includes + cmAppend(cmd, MocConst().OptionsIncludes); // Execute command if (!RunProcess(GenT::MOC, result, cmd, reason.get())) { LogCommandError(GenT::MOC, cmStrCat("The content generation command for ", - Quoted(predefsFileRel), " failed.\n", + MessagePath(predefsFileAbs), " failed.\n", result.ErrorMessage), cmd, result.StdOut); return; @@ -310,19 +297,20 @@ void cmQtAutoMocUic::JobMocPredefsT::Process() // (Re)write predefs file only on demand if (cmQtAutoGenerator::FileDiffers(predefsFileAbs, result.StdOut)) { if (!cmQtAutoGenerator::FileWrite(predefsFileAbs, result.StdOut)) { - LogFileError(GenT::MOC, predefsFileAbs, - cmStrCat("Writing ", Quoted(predefsFileRel), " failed.")); + LogError( + GenT::MOC, + cmStrCat("Writing ", MessagePath(predefsFileAbs), " failed.")); return; } } else { // Touch to update the time stamp if (Log().Verbose()) { - Log().Info(GenT::MOC, "Touching " + Quoted(predefsFileRel)); + Log().Info(GenT::MOC, "Touching " + MessagePath(predefsFileAbs)); } if (!cmSystemTools::Touch(predefsFileAbs, false)) { - LogFileError( - GenT::MOC, predefsFileAbs, - cmStrCat("Touching ", Quoted(predefsFileAbs), " failed.")); + LogError( + GenT::MOC, + cmStrCat("Touching ", MessagePath(predefsFileAbs), " failed.")); return; } } @@ -330,7 +318,9 @@ void cmQtAutoMocUic::JobMocPredefsT::Process() // Read file time afterwards if (!MocEval().PredefsTime.Load(predefsFileAbs)) { - LogFileError(GenT::MOC, predefsFileAbs, "File time reading failed."); + LogError(GenT::MOC, + cmStrCat("Reading the file time of ", MessagePath(predefsFileAbs), + " failed.")); return; } } @@ -340,7 +330,7 @@ bool cmQtAutoMocUic::JobMocPredefsT::Update(std::string* reason) const // Test if the file exists if (!MocEval().PredefsTime.Load(MocConst().PredefsFileAbs)) { if (reason != nullptr) { - *reason = cmStrCat("Generating ", Quoted(MocConst().PredefsFileRel), + *reason = cmStrCat("Generating ", MessagePath(MocConst().PredefsFileAbs), ", because it doesn't exist."); } return true; @@ -349,7 +339,7 @@ bool cmQtAutoMocUic::JobMocPredefsT::Update(std::string* reason) const // Test if the settings changed if (MocConst().SettingsChanged) { if (reason != nullptr) { - *reason = cmStrCat("Generating ", Quoted(MocConst().PredefsFileRel), + *reason = cmStrCat("Generating ", MessagePath(MocConst().PredefsFileAbs), ", because the moc settings changed."); } return true; @@ -362,8 +352,9 @@ bool cmQtAutoMocUic::JobMocPredefsT::Update(std::string* reason) const if (execTime.Load(exec)) { if (MocEval().PredefsTime.Older(execTime)) { if (reason != nullptr) { - *reason = cmStrCat("Generating ", Quoted(MocConst().PredefsFileRel), - " because it is older than ", Quoted(exec), '.'); + *reason = + cmStrCat("Generating ", MessagePath(MocConst().PredefsFileAbs), + " because it is older than ", MessagePath(exec), '.'); } return true; } @@ -380,19 +371,21 @@ bool cmQtAutoMocUic::JobParseT::ReadFile() std::string const& fileName = FileHandle->FileName; // Write info if (Log().Verbose()) { - Log().Info(GenT::GEN, "Parsing " + Quoted(fileName)); + Log().Info(GenT::GEN, cmStrCat("Parsing ", MessagePath(fileName))); } // Read file content { std::string error; if (!cmQtAutoGenerator::FileRead(Content, fileName, &error)) { - LogFileError(GenT::GEN, fileName, "Could not read the file: " + error); + LogError( + GenT::GEN, + cmStrCat("Could not read ", MessagePath(fileName), ".\n", error)); return false; } } // Warn if empty if (Content.empty()) { - Log().WarningFile(GenT::GEN, fileName, "The file is empty."); + Log().Warning(GenT::GEN, cmStrCat(MessagePath(fileName), " is empty.")); return false; } return true; @@ -555,37 +548,35 @@ void cmQtAutoMocUic::JobParseSourceT::Process() } } -void cmQtAutoMocUic::JobEvaluateT::Process() +std::string cmQtAutoMocUic::JobEvalCacheT::MessageSearchLocations() const { - // Evaluate for moc - if (MocConst().Enabled) { - // Evaluate headers - for (auto const& pair : BaseEval().Headers) { - if (!MocEvalHeader(pair.second)) { - return; - } - } - // Evaluate sources - for (auto const& pair : BaseEval().Sources) { - if (!MocEvalSource(pair.second)) { - return; - } + std::string res; + res.reserve(512); + for (std::string const& path : SearchLocations) { + res += " "; + res += MessagePath(path); + res += '\n'; + } + return res; +} + +void cmQtAutoMocUic::JobEvalCacheMocT::Process() +{ + // Evaluate headers + for (auto const& pair : BaseEval().Headers) { + if (!EvalHeader(pair.second)) { + return; } } - // Evaluate for uic - if (UicConst().Enabled) { - if (!UicEval(BaseEval().Headers) || !UicEval(BaseEval().Sources)) { + // Evaluate sources + for (auto const& pair : BaseEval().Sources) { + if (!EvalSource(pair.second)) { return; } } - - // Add discovered header parse jobs - Gen()->CreateParseJobs<JobParseHeaderT>(MocEval().HeadersDiscovered); - // Add generate job after - Gen()->WorkerPool().EmplaceJob<JobGenerateT>(); } -bool cmQtAutoMocUic::JobEvaluateT::MocEvalHeader(SourceFileHandleT source) +bool cmQtAutoMocUic::JobEvalCacheMocT::EvalHeader(SourceFileHandleT source) { SourceFileT const& sourceFile = *source; auto const& parseData = sourceFile.ParseData->Moc; @@ -606,13 +597,13 @@ bool cmQtAutoMocUic::JobEvaluateT::MocEvalHeader(SourceFileHandleT source) } // Register mapping in headers map - MocRegisterMapping(handle, true); + RegisterMapping(handle); } return true; } -bool cmQtAutoMocUic::JobEvaluateT::MocEvalSource( +bool cmQtAutoMocUic::JobEvalCacheMocT::EvalSource( SourceFileHandleT const& source) { SourceFileT const& sourceFile = *source; @@ -623,7 +614,7 @@ bool cmQtAutoMocUic::JobEvaluateT::MocEvalSource( return true; } - std::string const sourceDir = SubDirPrefix(sourceFile.FileName); + std::string const sourceDirPrefix = SubDirPrefix(sourceFile.FileName); std::string const sourceBase = cmSystemTools::GetFilenameWithoutLastExtension(sourceFile.FileName); @@ -650,27 +641,30 @@ bool cmQtAutoMocUic::JobEvaluateT::MocEvalSource( // Check if this source needs to be moc processed but doesn't. if (!sourceIncludesDotMoc && !parseData.Macro.empty() && !(relaxedMode && sourceIncludesMocUnderscore)) { - LogFileError(GenT::MOC, sourceFile.FileName, - cmStrCat("The file contains a ", Quoted(parseData.Macro), - " macro, but does not include ", - Quoted(sourceBase + ".moc"), - "!\nConsider to\n - add #include \"", sourceBase, - ".moc\"\n - enable SKIP_AUTOMOC for this file")); + LogError(GenT::MOC, + cmStrCat(MessagePath(sourceFile.FileName), "\ncontains a ", + Quoted(parseData.Macro), " macro, but does not include ", + MessagePath(sourceBase + ".moc"), + "!\nConsider to\n - add #include \"", sourceBase, + ".moc\"\n - enable SKIP_AUTOMOC for this file")); return false; } // Evaluate "moc_" includes for (IncludeKeyT const& incKey : parseData.Include.Underscore) { - std::string const headerBase = incKey.Dir + incKey.Base; - SourceFileHandleT header = MocFindIncludedHeader(sourceDir, headerBase); - if (!header) { - LogFileError(GenT::MOC, sourceFile.FileName, - cmStrCat("The file includes the moc file ", - Quoted(incKey.Key), - ",\nbut the header could not be found " - "in the following locations\n", - MocMessageTestHeaders(headerBase))); - return false; + SourceFileHandleT headerHandle; + { + std::string const headerBase = cmStrCat(incKey.Dir, incKey.Base); + if (!FindIncludedHeader(headerHandle, sourceDirPrefix, headerBase)) { + LogError(GenT::MOC, + cmStrCat(MessagePath(sourceFile.FileName), + "\nincludes the moc file ", MessagePath(incKey.Key), + ",\nbut a header ", MessageHeader(headerBase), + "\ncould not be found " + "in the following directories\n", + MessageSearchLocations())); + return false; + } } // The include might be handled differently in relaxed mode if (relaxedMode && !sourceIncludesDotMoc && !parseData.Macro.empty() && @@ -682,30 +676,30 @@ bool cmQtAutoMocUic::JobEvaluateT::MocEvalSource( // used. This is for KDE4 compatibility. // Issue a warning - Log().WarningFile( - GenT::MOC, sourceFile.FileName, - cmStrCat("The file contains a ", Quoted(parseData.Macro), - " macro, but does not include ", Quoted(sourceBase + ".moc"), - ".\nInstead it includes ", Quoted(incKey.Key), - ".\nRunning moc on the source\n ", - Quoted(sourceFile.FileName), "!\nBetter include ", - Quoted(sourceBase + ".moc"), + Log().Warning( + GenT::MOC, + cmStrCat(MessagePath(sourceFile.FileName), "\ncontains a ", + Quoted(parseData.Macro), " macro, but does not include ", + MessagePath(sourceBase + ".moc"), ".\nInstead it includes ", + MessagePath(incKey.Key), ".\nRunning moc on the source\n ", + MessagePath(sourceFile.FileName), "!\nBetter include ", + MessagePath(sourceBase + ".moc"), " for compatibility with regular mode.\n", "This is a CMAKE_AUTOMOC_RELAXED_MODE warning.\n")); // Create mapping - if (!MocRegisterIncluded(incKey.Key, source, source, false)) { + if (!RegisterIncluded(incKey.Key, source, source)) { return false; } continue; } // Check if header is skipped - if (MocConst().skipped(header->FileName)) { + if (MocConst().skipped(headerHandle->FileName)) { continue; } // Create mapping - if (!MocRegisterIncluded(incKey.Key, source, std::move(header), true)) { + if (!RegisterIncluded(incKey.Key, source, std::move(headerHandle))) { return false; } } @@ -718,53 +712,60 @@ bool cmQtAutoMocUic::JobEvaluateT::MocEvalSource( bool const ownMoc = (incKey.Base == sourceBase); if (ownMoc && !parseData.Macro.empty()) { // Create mapping for the regular use case - if (!MocRegisterIncluded(incKey.Key, source, source, false)) { + if (!RegisterIncluded(incKey.Key, source, source)) { return false; } continue; } // Try to find a header instead but issue a warning. // This is for KDE4 compatibility. - std::string const headerBase = incKey.Dir + incKey.Base; - SourceFileHandleT header = MocFindIncludedHeader(sourceDir, headerBase); - if (!header) { - LogFileError( - GenT::MOC, sourceFile.FileName, - cmStrCat("The file includes the moc file ", Quoted(incKey.Key), - ",\nwhich seems to be the moc file from a different source " - "file.\nCMAKE_AUTOMOC_RELAXED_MODE: Also a matching header" - "could not be found in the following locations\n", - MocMessageTestHeaders(headerBase))); - return false; + SourceFileHandleT headerHandle; + { + std::string const headerBase = cmStrCat(incKey.Dir, incKey.Base); + if (!FindIncludedHeader(headerHandle, sourceDirPrefix, headerBase)) { + LogError( + GenT::MOC, + cmStrCat( + MessagePath(sourceFile.FileName), "\nincludes the moc file ", + MessagePath(incKey.Key), + ",\nwhich seems to be the moc file from a different source " + "file.\nCMAKE_AUTOMOC_RELAXED_MODE:\nAlso a matching header ", + MessageHeader(headerBase), + "\ncould not be found in the following directories\n", + MessageSearchLocations())); + return false; + } } // Check if header is skipped - if (MocConst().skipped(header->FileName)) { + if (MocConst().skipped(headerHandle->FileName)) { continue; } // Issue a warning if (ownMoc && parseData.Macro.empty()) { - Log().WarningFile( - GenT::MOC, sourceFile.FileName, - cmStrCat("The file includes the moc file ", Quoted(incKey.Key), + Log().Warning( + GenT::MOC, + cmStrCat(MessagePath(sourceFile.FileName), + "\nincludes the moc file ", MessagePath(incKey.Key), ", but does not contain a\n", MocConst().MacrosString(), " macro.\nRunning moc on the header\n ", - Quoted(header->FileName), "!\nBetter include ", - Quoted("moc_" + incKey.Base + ".cpp"), + MessagePath(headerHandle->FileName), "!\nBetter include ", + MessagePath("moc_" + incKey.Base + ".cpp"), " for a compatibility with regular mode.\n", "This is a CMAKE_AUTOMOC_RELAXED_MODE warning.\n")); } else { - Log().WarningFile( - GenT::MOC, sourceFile.FileName, - cmStrCat("The file includes the moc file ", Quoted(incKey.Key), - " instead of ", Quoted("moc_" + incKey.Base + ".cpp"), + Log().Warning( + GenT::MOC, + cmStrCat(MessagePath(sourceFile.FileName), + "\nincludes the moc file ", MessagePath(incKey.Key), + " instead of ", MessagePath("moc_" + incKey.Base + ".cpp"), ".\nRunning moc on the header\n ", - Quoted(header->FileName), "!\nBetter include ", - Quoted("moc_" + incKey.Base + ".cpp"), + MessagePath(headerHandle->FileName), "!\nBetter include ", + MessagePath("moc_" + incKey.Base + ".cpp"), " for compatibility with regular mode.\n", "This is a CMAKE_AUTOMOC_RELAXED_MODE warning.\n")); } // Create mapping - if (!MocRegisterIncluded(incKey.Key, source, std::move(header), true)) { + if (!RegisterIncluded(incKey.Key, source, std::move(headerHandle))) { return false; } } @@ -775,25 +776,26 @@ bool cmQtAutoMocUic::JobEvaluateT::MocEvalSource( bool const ownMoc = (incKey.Base == sourceBase); if (!ownMoc) { // Don't allow <BASE>.moc include other than own in regular mode - LogFileError( - GenT::MOC, sourceFile.FileName, - cmStrCat("The file includes the moc file ", Quoted(incKey.Key), - ",\nwhich seems to be the moc file from a different " - "source file.\nThis is not supported. Include ", - Quoted(sourceBase + ".moc"), - " to run moc on this source file.")); + LogError(GenT::MOC, + cmStrCat(MessagePath(sourceFile.FileName), + "\nincludes the moc file ", MessagePath(incKey.Key), + ",\nwhich seems to be the moc file from a different " + "source file.\nThis is not supported. Include ", + MessagePath(sourceBase + ".moc"), + " to run moc on this source file.")); return false; } // Accept but issue a warning if moc isn't required if (parseData.Macro.empty()) { - Log().WarningFile(GenT::MOC, sourceFile.FileName, - cmStrCat("The file includes the moc file ", - Quoted(incKey.Key), - ", but does not contain a ", - MocConst().MacrosString(), " macro.")); + Log().Warning(GenT::MOC, + cmStrCat(MessagePath(sourceFile.FileName), + "\nincludes the moc file ", + MessagePath(incKey.Key), + ", but does not contain a ", + MocConst().MacrosString(), " macro.")); } // Create mapping - if (!MocRegisterIncluded(incKey.Key, source, source, false)) { + if (!RegisterIncluded(incKey.Key, source, source)) { return false; } } @@ -802,80 +804,74 @@ bool cmQtAutoMocUic::JobEvaluateT::MocEvalSource( return true; } -cmQtAutoMocUic::SourceFileHandleT -cmQtAutoMocUic::JobEvaluateT::MocFindIncludedHeader( - std::string const& includerDir, std::string const& includeBase) const +bool cmQtAutoMocUic::JobEvalCacheMocT::FindIncludedHeader( + SourceFileHandleT& headerHandle, cm::string_view includerDir, + cm::string_view includeBase) { - // Search in vicinity of the source - { - SourceFileHandleT res = MocFindHeader(includerDir + includeBase); - if (res) { - return res; - } - } - // Search in include directories - for (std::string const& path : MocConst().IncludePaths) { - std::string testPath = cmStrCat(path, '/', includeBase); - SourceFileHandleT res = MocFindHeader(testPath); - if (res) { - return res; - } - } - // Return without success - return SourceFileHandleT(); -} + // Clear search locations + SearchLocations.clear(); + + auto findHeader = [this, + &headerHandle](std::string const& basePath) -> bool { + bool found = false; + std::string const baseCollapsed = + this->Gen()->CollapseFullPathTS(cmStrCat(basePath, '.')); + for (std::string const& ext : this->BaseConst().HeaderExtensions) { + std::string const testPath = cmStrCat(baseCollapsed, ext); + cmFileTime fileTime; + if (!fileTime.Load(testPath)) { + // File not found + continue; + } -cmQtAutoMocUic::SourceFileHandleT cmQtAutoMocUic::JobEvaluateT::MocFindHeader( - std::string const& basePath) const -{ - std::string testPath; - testPath.reserve(basePath.size() + 8); - for (std::string const& ext : BaseConst().HeaderExtensions) { - testPath.clear(); - testPath += basePath; - testPath += '.'; - testPath += ext; - cmFileTime fileTime; - if (fileTime.Load(testPath)) { - // Compute real path of the file - testPath = cmSystemTools::GetRealPath(testPath); // Return a known file if it exists already { auto it = BaseEval().Headers.find(testPath); if (it != BaseEval().Headers.end()) { - return it->second; + headerHandle = it->second; + found = true; + break; } } + // Created and return discovered file entry - SourceFileHandleT& res = MocEval().HeadersDiscovered[testPath]; - if (!res) { - res = std::make_shared<SourceFileT>(testPath); - res->FileTime = fileTime; - res->Moc = true; + { + SourceFileHandleT& handle = MocEval().HeadersDiscovered[testPath]; + if (!handle) { + handle = std::make_shared<SourceFileT>(testPath); + handle->FileTime = fileTime; + handle->IsHeader = true; + handle->Moc = true; + } + headerHandle = handle; + found = true; + break; } - return res; } - } - // Return without success - return SourceFileHandleT(); -} + if (!found) { + this->SearchLocations.emplace_back( + cmQtAutoGen::ParentDir(baseCollapsed)); + } + return found; + }; -std::string cmQtAutoMocUic::JobEvaluateT::MocMessageTestHeaders( - cm::string_view fileBase) const -{ - std::string const exts = - cmStrCat(".{", cmJoin(BaseConst().HeaderExtensions, ","), '}'); - // Compose result string - std::string res = cmStrCat(" ", fileBase, exts, '\n'); + // Search in vicinity of the source + if (findHeader(cmStrCat(includerDir, includeBase))) { + return true; + } + // Search in include directories for (std::string const& path : MocConst().IncludePaths) { - res += cmStrCat(" ", path, '/', fileBase, exts, '\n'); + if (findHeader(cmStrCat(path, '/', includeBase))) { + return true; + } } - return res; + // Return without success + return false; } -bool cmQtAutoMocUic::JobEvaluateT::MocRegisterIncluded( +bool cmQtAutoMocUic::JobEvalCacheMocT::RegisterIncluded( std::string const& includeString, SourceFileHandleT includerFileHandle, - SourceFileHandleT sourceFileHandle, bool sourceIsHeader) const + SourceFileHandleT sourceFileHandle) const { // Check if this file is already included MappingHandleT& handle = MocEval().Includes[includeString]; @@ -883,18 +879,19 @@ bool cmQtAutoMocUic::JobEvaluateT::MocRegisterIncluded( // Check if the output file would be generated from different source files if (handle->SourceFile != sourceFileHandle) { std::string files = - cmStrCat(" ", Quoted(includerFileHandle->FileName), '\n'); + cmStrCat(" ", MessagePath(includerFileHandle->FileName), '\n'); for (auto const& item : handle->IncluderFiles) { - files += cmStrCat(" ", Quoted(item->FileName), '\n'); + files += cmStrCat(" ", MessagePath(item->FileName), '\n'); } LogError( GenT::MOC, cmStrCat("The source files\n", files, - "contain the same include string ", Quoted(includeString), + "contain the same include string ", + MessagePath(includeString), ", but\nthe moc file would be generated from different " "source files\n ", - Quoted(sourceFileHandle->FileName), " and\n ", - Quoted(handle->SourceFile->FileName), + MessagePath(sourceFileHandle->FileName), " and\n ", + MessagePath(handle->SourceFile->FileName), ".\nConsider to\n" " - not include the \"moc_<NAME>.cpp\" file\n" " - add a directory prefix to a \"<NAME>.moc\" include " @@ -916,15 +913,16 @@ bool cmQtAutoMocUic::JobEvaluateT::MocRegisterIncluded( handle->OutputFile = Gen()->AbsoluteIncludePath(includeString); // Register mapping in sources/headers map - MocRegisterMapping(handle, sourceIsHeader); + RegisterMapping(handle); return true; } -void cmQtAutoMocUic::JobEvaluateT::MocRegisterMapping( - MappingHandleT mappingHandle, bool sourceIsHeader) const +void cmQtAutoMocUic::JobEvalCacheMocT::RegisterMapping( + MappingHandleT mappingHandle) const { - auto& regMap = - sourceIsHeader ? MocEval().HeaderMappings : MocEval().SourceMappings; + auto& regMap = mappingHandle->SourceFile->IsHeader + ? MocEval().HeaderMappings + : MocEval().SourceMappings; // Check if source file already gets mapped auto& regHandle = regMap[mappingHandle->SourceFile->FileName]; if (!regHandle) { @@ -938,17 +936,33 @@ void cmQtAutoMocUic::JobEvaluateT::MocRegisterMapping( } } -bool cmQtAutoMocUic::JobEvaluateT::UicEval(SourceFileMapT const& fileMap) +std::string cmQtAutoMocUic::JobEvalCacheMocT::MessageHeader( + cm::string_view headerBase) const { - for (auto const& pair : fileMap) { - if (!UicEvalFile(pair.second)) { - return false; + return MessagePath(cmStrCat( + headerBase, ".{", cmJoin(this->BaseConst().HeaderExtensions, ","), '}')); +} + +void cmQtAutoMocUic::JobEvalCacheUicT::Process() +{ + // Prepare buffers + SearchLocations.reserve((UicConst().SearchPaths.size() + 1) * 2); + + // Evaluate headers + for (auto const& pair : BaseEval().Headers) { + if (!EvalFile(pair.second)) { + return; + } + } + // Evaluate sources + for (auto const& pair : BaseEval().Sources) { + if (!EvalFile(pair.second)) { + return; } } - return true; } -bool cmQtAutoMocUic::JobEvaluateT::UicEvalFile( +bool cmQtAutoMocUic::JobEvalCacheUicT::EvalFile( SourceFileHandleT const& sourceFileHandle) { SourceFileT const& sourceFile = *sourceFileHandle; @@ -957,17 +971,25 @@ bool cmQtAutoMocUic::JobEvaluateT::UicEvalFile( return true; } - std::string const sourceDir = SubDirPrefix(sourceFile.FileName); + std::string const sourceDirPrefix = SubDirPrefix(sourceFile.FileName); for (IncludeKeyT const& incKey : Include) { - // Find .ui file name - SourceFileHandleT uiFileHandle = - UicFindIncludedUi(sourceFile.FileName, sourceDir, incKey); - if (!uiFileHandle || UicConst().skipped(uiFileHandle->FileName)) { + // Find .ui file + UiName = cmStrCat(incKey.Base, ".ui"); + if (!FindIncludedUi(sourceDirPrefix, incKey.Dir)) { + LogError(GenT::UIC, + cmStrCat(MessagePath(sourceFile.FileName), + "\nincludes the uic file ", MessagePath(incKey.Key), + ",\nbut the user interface file ", MessagePath(UiName), + "\ncould not be found in the following directories\n", + MessageSearchLocations())); + return false; + } + // Check if the file is skipped + if (UicConst().skipped(UiFileHandle->FileName)) { continue; } // Register mapping - if (!UicRegisterMapping(incKey.Key, std::move(uiFileHandle), - sourceFileHandle)) { + if (!RegisterMapping(incKey.Key, sourceFileHandle)) { return false; } } @@ -975,20 +997,73 @@ bool cmQtAutoMocUic::JobEvaluateT::UicEvalFile( return true; } -bool cmQtAutoMocUic::JobEvaluateT::UicRegisterMapping( - std::string const& includeString, SourceFileHandleT uiFileHandle, - SourceFileHandleT includerFileHandle) +bool cmQtAutoMocUic::JobEvalCacheUicT::FindIncludedUi( + cm::string_view sourceDirPrefix, cm::string_view includePrefix) +{ + // Clear locations buffer + SearchLocations.clear(); + + auto findUi = [this](std::string const& testPath) -> bool { + std::string const fullPath = this->Gen()->CollapseFullPathTS(testPath); + cmFileTime fileTime; + if (!fileTime.Load(fullPath)) { + this->SearchLocations.emplace_back(cmQtAutoGen::ParentDir(fullPath)); + return false; + } + // .ui file found in files system! + // Get or create .ui file handle + SourceFileHandleT& handle = this->UicEval().UiFiles[fullPath]; + if (!handle) { + // The file wasn't registered, yet + handle = std::make_shared<SourceFileT>(fullPath); + handle->FileTime = fileTime; + } + this->UiFileHandle = handle; + return true; + }; + + // Vicinity of the source + if (findUi(cmStrCat(sourceDirPrefix, UiName))) { + return true; + } + if (!includePrefix.empty()) { + if (findUi(cmStrCat(sourceDirPrefix, includePrefix, UiName))) { + return true; + } + } + // Additional AUTOUIC search paths + auto const& searchPaths = UicConst().SearchPaths; + if (!searchPaths.empty()) { + for (std::string const& sPath : searchPaths) { + if (findUi(cmStrCat(sPath, '/', UiName))) { + return true; + } + } + if (!includePrefix.empty()) { + for (std::string const& sPath : searchPaths) { + if (findUi(cmStrCat(sPath, '/', includePrefix, UiName))) { + return true; + } + } + } + } + + return false; +} + +bool cmQtAutoMocUic::JobEvalCacheUicT::RegisterMapping( + std::string const& includeString, SourceFileHandleT includerFileHandle) { auto& Includes = Gen()->UicEval().Includes; auto it = Includes.find(includeString); if (it != Includes.end()) { MappingHandleT const& handle = it->second; - if (handle->SourceFile != uiFileHandle) { + if (handle->SourceFile != UiFileHandle) { // The output file already gets generated - from a different .ui file! std::string files = - cmStrCat(" ", Quoted(includerFileHandle->FileName), '\n'); + cmStrCat(" ", MessagePath(includerFileHandle->FileName), '\n'); for (auto const& item : handle->IncluderFiles) { - files += cmStrCat(" ", Quoted(item->FileName), '\n'); + files += cmStrCat(" ", MessagePath(item->FileName), '\n'); } LogError( GenT::UIC, @@ -997,8 +1072,8 @@ bool cmQtAutoMocUic::JobEvaluateT::UicRegisterMapping( Quoted(includeString), ", but\nthe uic file would be generated from different " "user interface files\n ", - Quoted(uiFileHandle->FileName), " and\n ", - Quoted(handle->SourceFile->FileName), + MessagePath(UiFileHandle->FileName), " and\n ", + MessagePath(handle->SourceFile->FileName), ".\nConsider to\n" " - add a directory prefix to a \"ui_<NAME>.h\" include " "(e.g \"sub/ui_<NAME>.h\")\n" @@ -1013,7 +1088,7 @@ bool cmQtAutoMocUic::JobEvaluateT::UicRegisterMapping( MappingHandleT handle = std::make_shared<MappingT>(); handle->IncludeString = includeString; handle->IncluderFiles.emplace_back(std::move(includerFileHandle)); - handle->SourceFile = std::move(uiFileHandle); + handle->SourceFile = UiFileHandle; handle->OutputFile = Gen()->AbsoluteIncludePath(includeString); // Register mapping Includes.emplace(includeString, std::move(handle)); @@ -1021,123 +1096,60 @@ bool cmQtAutoMocUic::JobEvaluateT::UicRegisterMapping( return true; } -cmQtAutoMocUic::SourceFileHandleT -cmQtAutoMocUic::JobEvaluateT::UicFindIncludedUi( - std::string const& sourceFile, std::string const& sourceDir, - IncludeKeyT const& incKey) const +void cmQtAutoMocUic::JobEvalCacheFinishT::Process() { - std::string searchFileName = cmStrCat(incKey.Base, ".ui"); - // Collect search paths list - std::vector<std::string> testFiles; - { - auto& searchPaths = UicConst().SearchPaths; - testFiles.reserve((searchPaths.size() + 1) * 2); - - // Vicinity of the source - testFiles.emplace_back(sourceDir + searchFileName); - if (!incKey.Dir.empty()) { - testFiles.emplace_back(cmStrCat(sourceDir, incKey.Dir, searchFileName)); - } - // AUTOUIC search paths - if (!searchPaths.empty()) { - for (std::string const& sPath : searchPaths) { - testFiles.emplace_back(cmStrCat(sPath, '/', searchFileName)); - } - if (!incKey.Dir.empty()) { - for (std::string const& sPath : searchPaths) { - testFiles.emplace_back( - cmStrCat(sPath, '/', incKey.Dir, searchFileName)); - } - } - } - } - - // Search for the .ui file! - for (std::string const& testFile : testFiles) { - cmFileTime fileTime; - if (fileTime.Load(testFile)) { - // .ui file found in files system! - std::string realPath = cmSystemTools::GetRealPath(testFile); - // Get or create .ui file handle - SourceFileHandleT& handle = Gen()->UicEval().UiFiles[realPath]; - if (!handle) { - // The file wasn't registered, yet - handle = std::make_shared<SourceFileT>(realPath); - handle->FileTime = fileTime; - } - return handle; - } - } + // Add discovered header parse jobs + Gen()->CreateParseJobs<JobParseHeaderT>(MocEval().HeadersDiscovered); - // Log error + // Add dependency probing jobs { - std::string files; - for (std::string const& testFile : testFiles) { - files += cmStrCat(" ", Quoted(testFile), '\n'); + // Add fence job to ensure all parsing has finished + Gen()->WorkerPool().EmplaceJob<JobFenceT>(); + if (MocConst().Enabled) { + Gen()->WorkerPool().EmplaceJob<JobProbeDepsMocT>(); } - LogFileError( - GenT::UIC, sourceFile, - cmStrCat("The file includes the uic file ", Quoted(incKey.Key), - ",\nbut the user interface file ", Quoted(searchFileName), - "\ncould not be found in the following locations\n", files)); + if (UicConst().Enabled) { + Gen()->WorkerPool().EmplaceJob<JobProbeDepsUicT>(); + } + // Add probe finish job + Gen()->WorkerPool().EmplaceJob<JobProbeDepsFinishT>(); } - - return SourceFileHandleT(); } -void cmQtAutoMocUic::JobGenerateT::Process() +void cmQtAutoMocUic::JobProbeDepsMocT::Process() { - // Add moc compile jobs - if (MocConst().Enabled) { - for (auto const& pair : MocEval().HeaderMappings) { - // Register if this mapping is a candidate for mocs_compilation.cpp - bool const compFile = pair.second->IncludeString.empty(); - if (compFile) { - MocEval().CompFiles.emplace_back(pair.second->SourceFile->BuildPath); - } - if (!MocGenerate(pair.second, compFile)) { - return; - } + // Create moc header jobs + for (auto const& pair : MocEval().HeaderMappings) { + // Register if this mapping is a candidate for mocs_compilation.cpp + bool const compFile = pair.second->IncludeString.empty(); + if (compFile) { + MocEval().CompFiles.emplace_back(pair.second->SourceFile->BuildPath); } - for (auto const& pair : MocEval().SourceMappings) { - if (!MocGenerate(pair.second, false)) { - return; - } + if (!Generate(pair.second, compFile)) { + return; } - - // Add mocs compilations job on demand - Gen()->WorkerPool().EmplaceJob<JobMocsCompilationT>(); } - // Add uic compile jobs - if (UicConst().Enabled) { - for (auto const& pair : Gen()->UicEval().Includes) { - if (!UicGenerate(pair.second)) { - return; - } + // Create moc source jobs + for (auto const& pair : MocEval().SourceMappings) { + if (!Generate(pair.second, false)) { + return; } } - - // Add finish job - Gen()->WorkerPool().EmplaceJob<JobFinishT>(); } -bool cmQtAutoMocUic::JobGenerateT::MocGenerate(MappingHandleT const& mapping, - bool compFile) const +bool cmQtAutoMocUic::JobProbeDepsMocT::Generate(MappingHandleT const& mapping, + bool compFile) const { std::unique_ptr<std::string> reason; if (Log().Verbose()) { reason = cm::make_unique<std::string>(); } - if (MocUpdate(*mapping, reason.get())) { - // Create the parent directory - if (!MakeParentDirectory(mapping->OutputFile)) { - LogFileError(GenT::MOC, mapping->OutputFile, - "Could not create parent directory."); - return false; - } + if (Probe(*mapping, reason.get())) { + // Register the parent directory for creation + MocEval().OutputDirs.emplace(cmQtAutoGen::ParentDir(mapping->OutputFile)); // Add moc job - Gen()->WorkerPool().EmplaceJob<JobMocT>(mapping, std::move(reason)); + Gen()->WorkerPool().EmplaceJob<JobCompileMocT>(mapping, std::move(reason)); // Check if a moc job for a mocs_compilation.cpp entry was generated if (compFile) { MocEval().CompUpdated = true; @@ -1146,7 +1158,7 @@ bool cmQtAutoMocUic::JobGenerateT::MocGenerate(MappingHandleT const& mapping, return true; } -bool cmQtAutoMocUic::JobGenerateT::MocUpdate(MappingT const& mapping, +bool cmQtAutoMocUic::JobProbeDepsMocT::Probe(MappingT const& mapping, std::string* reason) const { std::string const& sourceFile = mapping.SourceFile->FileName; @@ -1157,8 +1169,8 @@ bool cmQtAutoMocUic::JobGenerateT::MocUpdate(MappingT const& mapping, if (!outputFileTime.Load(outputFile)) { if (reason != nullptr) { *reason = - cmStrCat("Generating ", Quoted(outputFile), - ", because it doesn't exist, from ", Quoted(sourceFile)); + cmStrCat("Generating ", MessagePath(outputFile), + ", because it doesn't exist, from ", MessagePath(sourceFile)); } return true; } @@ -1166,9 +1178,9 @@ bool cmQtAutoMocUic::JobGenerateT::MocUpdate(MappingT const& mapping, // Test if any setting changed if (MocConst().SettingsChanged) { if (reason != nullptr) { - *reason = cmStrCat("Generating ", Quoted(outputFile), + *reason = cmStrCat("Generating ", MessagePath(outputFile), ", because the uic settings changed, from ", - Quoted(sourceFile)); + MessagePath(sourceFile)); } return true; } @@ -1176,9 +1188,9 @@ bool cmQtAutoMocUic::JobGenerateT::MocUpdate(MappingT const& mapping, // Test if the source file is newer if (outputFileTime.Older(mapping.SourceFile->FileTime)) { if (reason != nullptr) { - *reason = cmStrCat("Generating ", Quoted(outputFile), + *reason = cmStrCat("Generating ", MessagePath(outputFile), ", because it's older than its source file, from ", - Quoted(sourceFile)); + MessagePath(sourceFile)); } return true; } @@ -1187,9 +1199,10 @@ bool cmQtAutoMocUic::JobGenerateT::MocUpdate(MappingT const& mapping, if (!MocConst().PredefsFileAbs.empty()) { if (outputFileTime.Older(MocEval().PredefsTime)) { if (reason != nullptr) { - *reason = cmStrCat( - "Generating ", Quoted(outputFile), ", because it's older than ", - Quoted(MocConst().PredefsFileAbs), ", from ", Quoted(sourceFile)); + *reason = cmStrCat("Generating ", MessagePath(outputFile), + ", because it's older than ", + MessagePath(MocConst().PredefsFileAbs), ", from ", + MessagePath(sourceFile)); } return true; } @@ -1198,9 +1211,9 @@ bool cmQtAutoMocUic::JobGenerateT::MocUpdate(MappingT const& mapping, // Test if the moc executable is newer if (outputFileTime.Older(MocConst().ExecutableTime)) { if (reason != nullptr) { - *reason = cmStrCat("Generating ", Quoted(outputFile), + *reason = cmStrCat("Generating ", MessagePath(outputFile), ", because it's older than the moc executable, from ", - Quoted(sourceFile)); + MessagePath(sourceFile)); } return true; } @@ -1211,19 +1224,21 @@ bool cmQtAutoMocUic::JobGenerateT::MocUpdate(MappingT const& mapping, std::string const sourceDir = SubDirPrefix(sourceFile); for (std::string const& dep : mapping.SourceFile->ParseData->Moc.Depends) { // Find dependency file - auto const depMatch = MocFindDependency(sourceDir, dep); + auto const depMatch = FindDependency(sourceDir, dep); if (depMatch.first.empty()) { - Log().WarningFile(GenT::MOC, sourceFile, - "Could not find dependency file " + Quoted(dep)); + Log().Warning(GenT::MOC, + cmStrCat(MessagePath(sourceFile), " depends on ", + MessagePath(dep), + " but the file does not exist.")); continue; } // Test if dependency file is older if (outputFileTime.Older(depMatch.second)) { if (reason != nullptr) { - *reason = - cmStrCat("Generating ", Quoted(outputFile), - ", because it's older than its dependency file ", - Quoted(depMatch.first), ", from ", Quoted(sourceFile)); + *reason = cmStrCat("Generating ", MessagePath(outputFile), + ", because it's older than its dependency file ", + MessagePath(depMatch.first), ", from ", + MessagePath(sourceFile)); } return true; } @@ -1234,7 +1249,7 @@ bool cmQtAutoMocUic::JobGenerateT::MocUpdate(MappingT const& mapping, } std::pair<std::string, cmFileTime> -cmQtAutoMocUic::JobGenerateT::MocFindDependency( +cmQtAutoMocUic::JobProbeDepsMocT::FindDependency( std::string const& sourceDir, std::string const& includeString) const { using ResPair = std::pair<std::string, cmFileTime>; @@ -1256,27 +1271,26 @@ cmQtAutoMocUic::JobGenerateT::MocFindDependency( return ResPair(); } -bool cmQtAutoMocUic::JobGenerateT::UicGenerate( - MappingHandleT const& mapping) const +void cmQtAutoMocUic::JobProbeDepsUicT::Process() { - std::unique_ptr<std::string> reason; - if (Log().Verbose()) { - reason = cm::make_unique<std::string>(); - } - if (UicUpdate(*mapping, reason.get())) { - // Create the parent directory - if (!MakeParentDirectory(mapping->OutputFile)) { - LogFileError(GenT::UIC, mapping->OutputFile, - "Could not create parent directory."); - return false; + for (auto const& pair : Gen()->UicEval().Includes) { + MappingHandleT const& mapping = pair.second; + std::unique_ptr<std::string> reason; + if (Log().Verbose()) { + reason = cm::make_unique<std::string>(); } + if (!Probe(*mapping, reason.get())) { + continue; + } + + // Register the parent directory for creation + UicEval().OutputDirs.emplace(cmQtAutoGen::ParentDir(mapping->OutputFile)); // Add uic job - Gen()->WorkerPool().EmplaceJob<JobUicT>(mapping, std::move(reason)); + Gen()->WorkerPool().EmplaceJob<JobCompileUicT>(mapping, std::move(reason)); } - return true; } -bool cmQtAutoMocUic::JobGenerateT::UicUpdate(MappingT const& mapping, +bool cmQtAutoMocUic::JobProbeDepsUicT::Probe(MappingT const& mapping, std::string* reason) const { std::string const& sourceFile = mapping.SourceFile->FileName; @@ -1287,8 +1301,8 @@ bool cmQtAutoMocUic::JobGenerateT::UicUpdate(MappingT const& mapping, if (!outputFileTime.Load(outputFile)) { if (reason != nullptr) { *reason = - cmStrCat("Generating ", Quoted(outputFile), - ", because it doesn't exist, from ", Quoted(sourceFile)); + cmStrCat("Generating ", MessagePath(outputFile), + ", because it doesn't exist, from ", MessagePath(sourceFile)); } return true; } @@ -1296,9 +1310,9 @@ bool cmQtAutoMocUic::JobGenerateT::UicUpdate(MappingT const& mapping, // Test if the uic settings changed if (UicConst().SettingsChanged) { if (reason != nullptr) { - *reason = cmStrCat("Generating ", Quoted(outputFile), + *reason = cmStrCat("Generating ", MessagePath(outputFile), ", because the uic settings changed, from ", - Quoted(sourceFile)); + MessagePath(sourceFile)); } return true; } @@ -1306,9 +1320,9 @@ bool cmQtAutoMocUic::JobGenerateT::UicUpdate(MappingT const& mapping, // Test if the source file is newer if (outputFileTime.Older(mapping.SourceFile->FileTime)) { if (reason != nullptr) { - *reason = cmStrCat("Generating ", Quoted(outputFile), + *reason = cmStrCat("Generating ", MessagePath(outputFile), " because it's older than the source file ", - Quoted(sourceFile)); + MessagePath(sourceFile)); } return true; } @@ -1316,9 +1330,9 @@ bool cmQtAutoMocUic::JobGenerateT::UicUpdate(MappingT const& mapping, // Test if the uic executable is newer if (outputFileTime.Older(UicConst().ExecutableTime)) { if (reason != nullptr) { - *reason = cmStrCat("Generating ", Quoted(outputFile), + *reason = cmStrCat("Generating ", MessagePath(outputFile), ", because it's older than the uic executable, from ", - Quoted(sourceFile)); + MessagePath(sourceFile)); } return true; } @@ -1326,24 +1340,93 @@ bool cmQtAutoMocUic::JobGenerateT::UicUpdate(MappingT const& mapping, return false; } -void cmQtAutoMocUic::JobMocT::Process() +void cmQtAutoMocUic::JobProbeDepsFinishT::Process() +{ + // Create output directories + { + using StringSet = std::unordered_set<std::string>; + auto createDirs = [this](GenT genType, StringSet const& dirSet) { + for (std::string const& dirName : dirSet) { + if (!cmSystemTools::MakeDirectory(dirName)) { + this->LogError( + genType, + cmStrCat("Creating directory ", MessagePath(dirName), " failed.")); + return; + } + } + }; + if (MocConst().Enabled && UicConst().Enabled) { + StringSet outputDirs = MocEval().OutputDirs; + outputDirs.insert(UicEval().OutputDirs.begin(), + UicEval().OutputDirs.end()); + createDirs(GenT::GEN, outputDirs); + } else if (MocConst().Enabled) { + createDirs(GenT::MOC, MocEval().OutputDirs); + } else if (UicConst().Enabled) { + createDirs(GenT::UIC, UicEval().OutputDirs); + } + } + + if (MocConst().Enabled) { + // Add mocs compilations job + Gen()->WorkerPool().EmplaceJob<JobMocsCompilationT>(); + } + + // Add finish job + Gen()->WorkerPool().EmplaceJob<JobFinishT>(); +} + +void cmQtAutoMocUic::JobCompileMocT::Process() { std::string const& sourceFile = Mapping->SourceFile->FileName; std::string const& outputFile = Mapping->OutputFile; // Compose moc command std::vector<std::string> cmd; - cmd.push_back(MocConst().Executable); - // Add options - cmAppend(cmd, MocConst().AllOptions); - // Add predefs include - if (!MocConst().PredefsFileAbs.empty()) { - cmd.emplace_back("--include"); - cmd.push_back(MocConst().PredefsFileAbs); + { + // Reserve large enough + cmd.reserve(MocConst().OptionsDefinitions.size() + + MocConst().OptionsIncludes.size() + + MocConst().OptionsExtra.size() + 16); + cmd.push_back(MocConst().Executable); + // Add definitions + cmAppend(cmd, MocConst().OptionsDefinitions); + // Add includes + cmAppend(cmd, MocConst().OptionsIncludes); + // Add predefs include + if (!MocConst().PredefsFileAbs.empty()) { + cmd.emplace_back("--include"); + cmd.push_back(MocConst().PredefsFileAbs); + } + // Add path prefix on demand + if (MocConst().PathPrefix && Mapping->SourceFile->IsHeader) { + for (std::string const& dir : MocConst().IncludePaths) { + cm::string_view prefix = sourceFile; + if (cmHasPrefix(prefix, dir)) { + prefix.remove_prefix(dir.size()); + if (cmHasPrefix(prefix, '/')) { + prefix.remove_prefix(1); + auto slashPos = prefix.rfind('/'); + if (slashPos != cm::string_view::npos) { + cmd.emplace_back("-p"); + cmd.emplace_back(prefix.substr(0, slashPos)); + } else { + cmd.emplace_back("-p"); + cmd.emplace_back("./"); + } + break; + } + } + } + } + // Add extra options + cmAppend(cmd, MocConst().OptionsExtra); + // Add output file + cmd.emplace_back("-o"); + cmd.push_back(outputFile); + // Add source file + cmd.push_back(sourceFile); } - cmd.emplace_back("-o"); - cmd.push_back(outputFile); - cmd.push_back(sourceFile); // Execute moc command cmWorkerPool::ProcessResultT result; @@ -1358,19 +1441,19 @@ void cmQtAutoMocUic::JobMocT::Process() if (!Mapping->IncluderFiles.empty()) { includers = "included by\n"; for (auto const& item : Mapping->IncluderFiles) { - includers += cmStrCat(" ", Quoted(item->FileName), '\n'); + includers += cmStrCat(" ", MessagePath(item->FileName), '\n'); } } LogCommandError(GenT::MOC, cmStrCat("The moc process failed to compile\n ", - Quoted(sourceFile), "\ninto\n ", - Quoted(outputFile), '\n', includers, + MessagePath(sourceFile), "\ninto\n ", + MessagePath(outputFile), '\n', includers, result.ErrorMessage), cmd, result.StdOut); } } -void cmQtAutoMocUic::JobUicT::Process() +void cmQtAutoMocUic::JobCompileUicT::Process() { std::string const& sourceFile = Mapping->SourceFile->FileName; std::string const& outputFile = Mapping->OutputFile; @@ -1402,13 +1485,13 @@ void cmQtAutoMocUic::JobUicT::Process() // Uic command failed std::string includers; for (auto const& item : Mapping->IncluderFiles) { - includers += cmStrCat(" ", Quoted(item->FileName), '\n'); + includers += cmStrCat(" ", MessagePath(item->FileName), '\n'); } LogCommandError(GenT::UIC, cmStrCat("The uic process failed to compile\n ", - Quoted(sourceFile), "\ninto\n ", - Quoted(outputFile), "\nincluded by\n", includers, - result.ErrorMessage), + MessagePath(sourceFile), "\ninto\n ", + MessagePath(outputFile), "\nincluded by\n", + includers, result.ErrorMessage), cmd, result.StdOut); } } @@ -1436,20 +1519,24 @@ void cmQtAutoMocUic::JobMocsCompilationT::Process() if (cmQtAutoGenerator::FileDiffers(compAbs, content)) { // Actually write mocs compilation file if (Log().Verbose()) { - Log().Info(GenT::MOC, "Generating MOC compilation " + compAbs); + Log().Info(GenT::MOC, + "Generating MOC compilation " + MessagePath(compAbs)); } if (!FileWrite(compAbs, content)) { - LogFileError(GenT::MOC, compAbs, - "mocs compilation file writing failed."); + LogError(GenT::MOC, + cmStrCat("Writing MOC compilation ", MessagePath(compAbs), + " failed.")); } } else if (MocEval().CompUpdated) { // Only touch mocs compilation file if (Log().Verbose()) { - Log().Info(GenT::MOC, "Touching mocs compilation " + compAbs); + Log().Info(GenT::MOC, + "Touching MOC compilation " + MessagePath(compAbs)); } if (!cmSystemTools::Touch(compAbs, false)) { - LogFileError(GenT::MOC, compAbs, - "mocs compilation file touching failed."); + LogError(GenT::MOC, + cmStrCat("Touching MOC compilation ", MessagePath(compAbs), + " failed.")); } } } @@ -1543,12 +1630,10 @@ bool cmQtAutoMocUic::Init(cmMakefile* makefile) makefile->GetCMakeInstance()->GetHeaderExtensions(); // - Files and directories - BaseConst_.IncludeProjectDirsBefore = - InfoGetBool("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE"); - BaseConst_.ProjectSourceDir = InfoGet("AM_CMAKE_SOURCE_DIR"); - BaseConst_.ProjectBinaryDir = InfoGet("AM_CMAKE_BINARY_DIR"); - BaseConst_.CurrentSourceDir = InfoGet("AM_CMAKE_CURRENT_SOURCE_DIR"); - BaseConst_.CurrentBinaryDir = InfoGet("AM_CMAKE_CURRENT_BINARY_DIR"); + ProjectDirsRef().Source = InfoGet("AM_CMAKE_SOURCE_DIR"); + ProjectDirsRef().Binary = InfoGet("AM_CMAKE_BINARY_DIR"); + ProjectDirsRef().CurrentSource = InfoGet("AM_CMAKE_CURRENT_SOURCE_DIR"); + ProjectDirsRef().CurrentBinary = InfoGet("AM_CMAKE_CURRENT_BINARY_DIR"); BaseConst_.AutogenBuildDir = InfoGet("AM_BUILD_DIR"); if (BaseConst_.AutogenBuildDir.empty()) { return LogInfoError("Autogen build directory missing."); @@ -1563,7 +1648,7 @@ bool cmQtAutoMocUic::Init(cmMakefile* makefile) } if (!BaseConst_.CMakeExecutableTime.Load(BaseConst_.CMakeExecutable)) { return LogInfoError(cmStrCat("The CMake executable ", - Quoted(BaseConst_.CMakeExecutable), + MessagePath(BaseConst_.CMakeExecutable), " does not exist.")); } BaseConst_.ParseCacheFile = InfoGetConfig("AM_PARSE_CACHE_FILE"); @@ -1592,7 +1677,7 @@ bool cmQtAutoMocUic::Init(cmMakefile* makefile) // Load the executable file time if (!MocConst_.ExecutableTime.Load(MocConst_.Executable)) { return LogInfoError(cmStrCat("The moc executable ", - Quoted(MocConst_.Executable), + MessagePath(MocConst_.Executable), " does not exist.")); } for (std::string& sfl : InfoGetList("AM_MOC_SKIP")) { @@ -1600,8 +1685,11 @@ bool cmQtAutoMocUic::Init(cmMakefile* makefile) } MocConst_.Definitions = InfoGetConfigList("AM_MOC_DEFINITIONS"); MocConst_.IncludePaths = InfoGetConfigList("AM_MOC_INCLUDES"); - MocConst_.Options = InfoGetList("AM_MOC_OPTIONS"); + MocConst_.OptionsExtra = InfoGetList("AM_MOC_OPTIONS"); + MocConst_.RelaxedMode = InfoGetBool("AM_MOC_RELAXED_MODE"); + MocConst_.PathPrefix = InfoGetBool("AM_MOC_PATH_PREFIX"); + for (std::string const& item : InfoGetList("AM_MOC_MACRO_NAMES")) { MocConst_.MacroFilters.emplace_back( item, ("[\n][ \t]*{?[ \t]*" + item).append("[^a-zA-Z0-9_]")); @@ -1658,7 +1746,7 @@ bool cmQtAutoMocUic::Init(cmMakefile* makefile) // Load the executable file time if (!UicConst_.ExecutableTime.Load(UicConst_.Executable)) { return LogInfoError(cmStrCat("The uic executable ", - Quoted(UicConst_.Executable), + MessagePath(UicConst_.Executable), " does not exist.")); } for (std::string& sfl : InfoGetList("AM_UIC_SKIP")) { @@ -1685,83 +1773,89 @@ bool cmQtAutoMocUic::Init(cmMakefile* makefile) } } - // - Headers and sources + // Headers { - auto makeSource = - [&LogInfoError](std::string const& fileName, - std::string const& fileFlags) -> SourceFileHandleT { + // Get file lists + cm::string_view const keyFiles = "AM_HEADERS"; + cm::string_view const keyFlags = "AM_HEADERS_FLAGS"; + std::vector<std::string> files = InfoGetList(keyFiles); + std::vector<std::string> flags = InfoGetList(keyFlags); + std::vector<std::string> builds; + if (!MatchSizes(keyFiles, keyFlags, files.size(), flags.size())) { + return false; + } + if (MocConst().Enabled) { + cm::string_view const keyPaths = "AM_HEADERS_BUILD_PATHS"; + builds = InfoGetList(keyPaths); + if (!MatchSizes(keyFiles, keyPaths, files.size(), builds.size())) { + return false; + } + } + + // Process file lists + for (std::size_t ii = 0; ii != files.size(); ++ii) { + std::string& fileName(files[ii]); + std::string const& fileFlags(flags[ii]); if (fileFlags.size() != 2) { - LogInfoError("Invalid file flags string size"); - return SourceFileHandleT(); + LogInfoError(cmStrCat("Invalid flags string size ", fileFlags.size(), + "in ", keyFlags)); + return false; } cmFileTime fileTime; if (!fileTime.Load(fileName)) { - LogInfoError("The source file " + cmQtAutoGen::Quoted(fileName) + - " does not exist."); - return SourceFileHandleT(); - } - SourceFileHandleT sfh = std::make_shared<SourceFileT>(fileName); - sfh->FileTime = fileTime; - sfh->Moc = (fileFlags[0] == 'M'); - sfh->Uic = (fileFlags[1] == 'U'); - return sfh; - }; - - // Headers - { - // Get file lists - cm::string_view const keyFiles = "AM_HEADERS"; - cm::string_view const keyFlags = "AM_HEADERS_FLAGS"; - std::vector<std::string> files = InfoGetList(keyFiles); - std::vector<std::string> flags = InfoGetList(keyFlags); - std::vector<std::string> builds; - if (!MatchSizes(keyFiles, keyFlags, files.size(), flags.size())) { + LogInfoError(cmStrCat("The header file ", this->MessagePath(fileName), + " does not exist.")); return false; } - if (MocConst().Enabled) { - cm::string_view const keyPaths = "AM_HEADERS_BUILD_PATHS"; - builds = InfoGetList(keyPaths); - if (!MatchSizes(keyFiles, keyPaths, files.size(), builds.size())) { - return false; - } - } - // Process file lists - for (std::size_t ii = 0; ii != files.size(); ++ii) { - std::string& fileName(files[ii]); - SourceFileHandleT sfh = makeSource(fileName, flags[ii]); - if (!sfh) { - return false; - } - if (MocConst().Enabled) { - sfh->BuildPath = std::move(builds[ii]); - if (sfh->BuildPath.empty()) { - Log().ErrorFile(GenT::GEN, this->InfoFile(), - "Header file build path is empty"); - return false; - } + + SourceFileHandleT sourceHandle = std::make_shared<SourceFileT>(fileName); + sourceHandle->FileTime = fileTime; + sourceHandle->IsHeader = true; + sourceHandle->Moc = (fileFlags[0] == 'M'); + sourceHandle->Uic = (fileFlags[1] == 'U'); + + if (sourceHandle->Moc && MocConst().Enabled) { + sourceHandle->BuildPath = std::move(builds[ii]); + if (sourceHandle->BuildPath.empty()) { + return LogInfoError("Header file build path is empty"); } - BaseEval().Headers.emplace(std::move(fileName), std::move(sfh)); } + BaseEval().Headers.emplace(std::move(fileName), std::move(sourceHandle)); } + } - // Sources - { - cm::string_view const keyFiles = "AM_SOURCES"; - cm::string_view const keyFlags = "AM_SOURCES_FLAGS"; - std::vector<std::string> files = InfoGetList(keyFiles); - std::vector<std::string> flags = InfoGetList(keyFlags); - if (!MatchSizes(keyFiles, keyFlags, files.size(), flags.size())) { + // Sources + { + cm::string_view const keyFiles = "AM_SOURCES"; + cm::string_view const keyFlags = "AM_SOURCES_FLAGS"; + std::vector<std::string> files = InfoGetList(keyFiles); + std::vector<std::string> flags = InfoGetList(keyFlags); + if (!MatchSizes(keyFiles, keyFlags, files.size(), flags.size())) { + return false; + } + + // Process file lists + for (std::size_t ii = 0; ii != files.size(); ++ii) { + std::string& fileName(files[ii]); + std::string const& fileFlags(flags[ii]); + if (fileFlags.size() != 2) { + LogInfoError(cmStrCat("Invalid flags string size ", fileFlags.size(), + "in ", keyFlags)); return false; } - // Process file lists - for (std::size_t ii = 0; ii != files.size(); ++ii) { - std::string& fileName(files[ii]); - SourceFileHandleT sfh = makeSource(fileName, flags[ii]); - if (!sfh) { - return false; - } - BaseEval().Sources.emplace(std::move(fileName), std::move(sfh)); + cmFileTime fileTime; + if (!fileTime.Load(fileName)) { + LogInfoError(cmStrCat("The source file ", this->MessagePath(fileName), + " does not exist.")); + return false; } + + SourceFileHandleT sourceHandle = std::make_shared<SourceFileT>(fileName); + sourceHandle->FileTime = fileTime; + sourceHandle->IsHeader = false; + sourceHandle->Moc = (fileFlags[0] == 'M'); + sourceHandle->Uic = (fileFlags[1] == 'U'); + BaseEval().Sources.emplace(std::move(fileName), std::move(sourceHandle)); } } @@ -1775,49 +1869,20 @@ bool cmQtAutoMocUic::Init(cmMakefile* makefile) // Moc predefs file if (!MocConst_.PredefsCmd.empty()) { + std::string pathRel; if (BaseConst_.MultiConfig) { - MocConst_.PredefsFileRel = - cmStrCat("moc_predefs_", InfoConfig(), ".h"); + pathRel = cmStrCat("moc_predefs_", InfoConfig(), ".h"); } else { - MocConst_.PredefsFileRel = "moc_predefs.h"; + pathRel = "moc_predefs.h"; } - MocConst_.PredefsFileAbs = AbsoluteBuildPath(MocConst().PredefsFileRel); + MocConst_.PredefsFileAbs = AbsoluteBuildPath(pathRel); } - // Sort include directories on demand - if (BaseConst().IncludeProjectDirsBefore) { - // Move strings to temporary list - std::list<std::string> includes(MocConst().IncludePaths.begin(), - MocConst().IncludePaths.end()); - MocConst_.IncludePaths.clear(); - MocConst_.IncludePaths.reserve(includes.size()); - // Append project directories only - { - std::initializer_list<cm::string_view> const movePaths = { - BaseConst().ProjectBinaryDir, BaseConst().ProjectSourceDir - }; - for (cm::string_view const& ppath : movePaths) { - auto it = includes.begin(); - while (it != includes.end()) { - std::string const& path = *it; - if (cmHasPrefix(path, ppath)) { - MocConst_.IncludePaths.push_back(path); - it = includes.erase(it); - } else { - ++it; - } - } - } - } - // Append remaining directories - MocConst_.IncludePaths.insert(MocConst_.IncludePaths.end(), - includes.begin(), includes.end()); - } // Compose moc includes list { + // Compute framework paths std::set<std::string> frameworkPaths; for (std::string const& path : MocConst().IncludePaths) { - MocConst_.Includes.push_back("-I" + path); // Extract framework path if (cmHasLiteralSuffix(path, ".framework/Headers")) { // Go up twice to get to the framework root @@ -1827,26 +1892,26 @@ bool cmQtAutoMocUic::Init(cmMakefile* makefile) pathComponents.begin(), pathComponents.end() - 2)); } } + // Reserve options + MocConst_.OptionsIncludes.reserve(MocConst().IncludePaths.size() + + frameworkPaths.size() * 2); + // Append includes + for (std::string const& path : MocConst().IncludePaths) { + MocConst_.OptionsIncludes.emplace_back("-I" + path); + } // Append framework includes for (std::string const& path : frameworkPaths) { - MocConst_.Includes.emplace_back("-F"); - MocConst_.Includes.push_back(path); + MocConst_.OptionsIncludes.emplace_back("-F"); + MocConst_.OptionsIncludes.push_back(path); } } - // Setup single list with all options + + // Compose moc definitions list { - // Add includes - MocConst_.AllOptions.insert(MocConst_.AllOptions.end(), - MocConst().Includes.begin(), - MocConst().Includes.end()); - // Add definitions + MocConst_.OptionsDefinitions.reserve(MocConst().Definitions.size()); for (std::string const& def : MocConst().Definitions) { - MocConst_.AllOptions.push_back("-D" + def); + MocConst_.OptionsDefinitions.emplace_back("-D" + def); } - // Add options - MocConst_.AllOptions.insert(MocConst_.AllOptions.end(), - MocConst().Options.begin(), - MocConst().Options.end()); } } @@ -1870,18 +1935,38 @@ void cmQtAutoMocUic::CreateParseJobs(SourceFileMapT const& sourceMap) } } +/** Concurrently callable implementation of cmSystemTools::CollapseFullPath */ +std::string cmQtAutoMocUic::CollapseFullPathTS(std::string const& path) const +{ + std::lock_guard<std::mutex> guard(CMakeLibMutex_); + return cmSystemTools::CollapseFullPath(path, ProjectDirs().CurrentSource); +} + void cmQtAutoMocUic::InitJobs() { // Add moc_predefs.h job if (MocConst().Enabled && !MocConst().PredefsCmd.empty()) { WorkerPool().EmplaceJob<JobMocPredefsT>(); } + // Add header parse jobs CreateParseJobs<JobParseHeaderT>(BaseEval().Headers); // Add source parse jobs CreateParseJobs<JobParseSourceT>(BaseEval().Sources); - // Add evaluate job - WorkerPool().EmplaceJob<JobEvaluateT>(); + + // Add parse cache evaluations jobs + { + // Add a fence job to ensure all parsing has finished + WorkerPool().EmplaceJob<JobFenceT>(); + if (MocConst().Enabled) { + WorkerPool().EmplaceJob<JobEvalCacheMocT>(); + } + if (UicConst().Enabled) { + WorkerPool().EmplaceJob<JobEvalCacheUicT>(); + } + // Add evaluate job + WorkerPool().EmplaceJob<JobEvalCacheFinishT>(); + } } bool cmQtAutoMocUic::Process() @@ -1920,11 +2005,18 @@ void cmQtAutoMocUic::SettingsFileRead() if (MocConst_.Enabled) { cryptoHash.Initialize(); cha(MocConst().Executable); - std::for_each(MocConst().AllOptions.begin(), MocConst().AllOptions.end(), - cha); - cha(BaseConst().IncludeProjectDirsBefore ? "TRUE" : "FALSE"); - std::for_each(MocConst().PredefsCmd.begin(), MocConst().PredefsCmd.end(), - cha); + for (auto const& item : MocConst().OptionsDefinitions) { + cha(item); + } + for (auto const& item : MocConst().OptionsIncludes) { + cha(item); + } + for (auto const& item : MocConst().OptionsExtra) { + cha(item); + } + for (auto const& item : MocConst().PredefsCmd) { + cha(item); + } for (auto const& filter : MocConst().DependFilters) { cha(filter.Key); } @@ -1984,7 +2076,9 @@ bool cmQtAutoMocUic::SettingsFileWrite() // Only write if any setting changed if (MocConst().SettingsChanged || UicConst().SettingsChanged) { if (Log().Verbose()) { - Log().Info(GenT::GEN, "Writing settings file " + Quoted(SettingsFile_)); + Log().Info( + GenT::GEN, + cmStrCat("Writing settings file ", MessagePath(SettingsFile_))); } // Compose settings file content std::string content; @@ -2001,8 +2095,9 @@ bool cmQtAutoMocUic::SettingsFileWrite() // Write settings file std::string error; if (!cmQtAutoGenerator::FileWrite(SettingsFile_, content, &error)) { - Log().ErrorFile(GenT::GEN, SettingsFile_, - "Settings file writing failed. " + error); + Log().Error(GenT::GEN, + cmStrCat("Writing the settings file ", + MessagePath(SettingsFile_), " failed.\n", error)); // Remove old settings file to trigger a full rebuild on the next run cmSystemTools::RemoveFile(SettingsFile_); return false; @@ -2042,12 +2137,14 @@ bool cmQtAutoMocUic::ParseCacheWrite() if (BaseEval().ParseCacheChanged) { if (Log().Verbose()) { Log().Info(GenT::GEN, - "Writing parse cache file " + - Quoted(BaseConst().ParseCacheFile)); + cmStrCat("Writing the parse cache file ", + MessagePath(BaseConst().ParseCacheFile))); } if (!BaseEval().ParseCache.WriteToFile(BaseConst().ParseCacheFile)) { - Log().ErrorFile(GenT::GEN, BaseConst().ParseCacheFile, - "Parse cache file writing failed."); + Log().Error(GenT::GEN, + cmStrCat("Writing the parse cache file ", + MessagePath(BaseConst().ParseCacheFile), + " failed.")); return false; } } @@ -2058,8 +2155,10 @@ bool cmQtAutoMocUic::CreateDirectories() { // Create AUTOGEN include directory if (!cmSystemTools::MakeDirectory(BaseConst().AutogenIncludeDir)) { - Log().ErrorFile(GenT::GEN, BaseConst().AutogenIncludeDir, - "Could not create directory."); + Log().Error(GenT::GEN, + cmStrCat("Creating the AUTOGEN include directory ", + MessagePath(BaseConst().AutogenIncludeDir), + " failed.")); return false; } return true; diff --git a/Source/cmQtAutoMocUic.h b/Source/cmQtAutoMocUic.h index 549b088..43123f2 100644 --- a/Source/cmQtAutoMocUic.h +++ b/Source/cmQtAutoMocUic.h @@ -16,6 +16,7 @@ #include <cstddef> #include <map> #include <memory> +#include <mutex> #include <set> #include <string> #include <unordered_map> @@ -40,9 +41,7 @@ public: public: // -- Types - /** - * Search key plus regular expression pair - */ + /** Search key plus regular expression pair. */ struct KeyExpT { KeyExpT() = default; @@ -63,9 +62,7 @@ public: cmsys::RegularExpression Exp; }; - /** - * Include string with sub parts - */ + /** Include string with sub parts. */ struct IncludeKeyT { IncludeKeyT(std::string const& key, std::size_t basePrefixLength); @@ -75,9 +72,7 @@ public: std::string Base; // Base part of the include file name }; - /** - * Source file parsing cache - */ + /** Source file parsing cache. */ class ParseCacheT { public: @@ -127,9 +122,7 @@ public: std::unordered_map<std::string, FileHandleT> Map_; }; - /** - * Source file data - */ + /** Source file data. */ class SourceFileT { public: @@ -143,15 +136,14 @@ public: cmFileTime FileTime; ParseCacheT::FileHandleT ParseData; std::string BuildPath; + bool IsHeader = false; bool Moc = false; bool Uic = false; }; using SourceFileHandleT = std::shared_ptr<SourceFileT>; using SourceFileMapT = std::map<std::string, SourceFileHandleT>; - /** - * Meta compiler file mapping information - */ + /** Meta compiler file mapping information. */ struct MappingT { SourceFileHandleT SourceFile; @@ -162,9 +154,7 @@ public: using MappingHandleT = std::shared_ptr<MappingT>; using MappingMapT = std::map<std::string, MappingHandleT>; - /** - * Common settings - */ + /** Common settings. */ class BaseSettingsT { public: @@ -178,13 +168,8 @@ public: // -- Attributes // - Config bool MultiConfig = false; - bool IncludeProjectDirsBefore = false; unsigned int QtVersionMajor = 4; // - Directories - std::string ProjectSourceDir; - std::string ProjectBinaryDir; - std::string CurrentSourceDir; - std::string CurrentBinaryDir; std::string AutogenBuildDir; std::string AutogenIncludeDir; // - Files @@ -194,9 +179,7 @@ public: std::vector<std::string> HeaderExtensions; }; - /** - * Shared common variables - */ + /** Shared common variables. */ class BaseEvalT { public: @@ -210,9 +193,7 @@ public: SourceFileMapT Sources; }; - /** - * Moc settings - */ + /** Moc settings. */ class MocSettingsT { public: @@ -231,26 +212,24 @@ public: bool Enabled = false; bool SettingsChanged = false; bool RelaxedMode = false; + bool PathPrefix = false; cmFileTime ExecutableTime; std::string Executable; std::string CompFileAbs; - std::string PredefsFileRel; std::string PredefsFileAbs; std::unordered_set<std::string> SkipList; std::vector<std::string> IncludePaths; - std::vector<std::string> Includes; std::vector<std::string> Definitions; - std::vector<std::string> Options; - std::vector<std::string> AllOptions; + std::vector<std::string> OptionsIncludes; + std::vector<std::string> OptionsDefinitions; + std::vector<std::string> OptionsExtra; std::vector<std::string> PredefsCmd; std::vector<KeyExpT> DependFilters; std::vector<KeyExpT> MacroFilters; cmsys::RegularExpression RegExpInclude; }; - /** - * Moc shared variables - */ + /** Moc shared variables. */ class MocEvalT { public: @@ -262,14 +241,14 @@ public: MappingMapT Includes; // -- Discovered files SourceFileMapT HeadersDiscovered; + // -- Output directories + std::unordered_set<std::string> OutputDirs; // -- Mocs compilation bool CompUpdated = false; std::vector<std::string> CompFiles; }; - /** - * Uic settings - */ + /** Uic settings. */ class UicSettingsT { public: @@ -294,25 +273,23 @@ public: cmsys::RegularExpression RegExpInclude; }; - /** - * Uic shared variables - */ + /** Uic shared variables. */ class UicEvalT { public: + // -- Discovered files SourceFileMapT UiFiles; + // -- Mappings MappingMapT Includes; + // -- Output directories + std::unordered_set<std::string> OutputDirs; }; - /** - * Abstract job class for concurrent job processing - */ + /** Abstract job class for concurrent job processing. */ class JobT : public cmWorkerPool::JobT { protected: - /** - * @brief Protected default constructor - */ + /** Protected default constructor. */ JobT(bool fence = false) : cmWorkerPool::JobT(fence) { @@ -333,25 +310,24 @@ public: UicSettingsT const& UicConst() const { return Gen()->UicConst(); } UicEvalT& UicEval() const { return Gen()->UicEval(); } - // -- Error logging with automatic abort + // -- Logging + std::string MessagePath(cm::string_view path) const + { + return Gen()->MessagePath(path); + } + // - Error logging with automatic abort void LogError(GenT genType, cm::string_view message) const; - void LogFileError(GenT genType, cm::string_view filename, - cm::string_view message) const; void LogCommandError(GenT genType, cm::string_view message, std::vector<std::string> const& command, std::string const& output) const; - /** - * @brief Run an external process. Use only during Process() call! - */ + /** @brief Run an external process. Use only during Process() call! */ bool RunProcess(GenT genType, cmWorkerPool::ProcessResultT& result, std::vector<std::string> const& command, std::string* infoMessage = nullptr); }; - /** - * Fence job utility class - */ + /** Fence job utility class. */ class JobFenceT : public JobT { public: @@ -362,18 +338,14 @@ public: void Process() override{}; }; - /** - * Generate moc_predefs.h - */ + /** Generate moc_predefs.h. */ class JobMocPredefsT : public JobFenceT { void Process() override; bool Update(std::string* reason) const; }; - /** - * File parse job base class - */ + /** File parse job base class. */ class JobParseT : public JobT { public: @@ -397,9 +369,7 @@ public: std::string Content; }; - /** - * Header file parse job - */ + /** Header file parse job. */ class JobParseHeaderT : public JobParseT { public: @@ -407,9 +377,7 @@ public: void Process() override; }; - /** - * Source file parse job - */ + /** Source file parse job. */ class JobParseSourceT : public JobParseT { public: @@ -417,57 +385,79 @@ public: void Process() override; }; - /** - * Evaluate parsed files - */ - class JobEvaluateT : public JobFenceT + /** Evaluate cached file parse data - moc. */ + class JobEvalCacheT : public JobT + { + protected: + std::string MessageSearchLocations() const; + std::vector<std::string> SearchLocations; + }; + + /** Evaluate cached file parse data - moc. */ + class JobEvalCacheMocT : public JobEvalCacheT + { + void Process() override; + bool EvalHeader(SourceFileHandleT source); + bool EvalSource(SourceFileHandleT const& source); + bool FindIncludedHeader(SourceFileHandleT& headerHandle, + cm::string_view includerDir, + cm::string_view includeBase); + bool RegisterIncluded(std::string const& includeString, + SourceFileHandleT includerFileHandle, + SourceFileHandleT sourceFileHandle) const; + void RegisterMapping(MappingHandleT mappingHandle) const; + std::string MessageHeader(cm::string_view headerBase) const; + }; + + /** Evaluate cached file parse data - uic. */ + class JobEvalCacheUicT : public JobEvalCacheT + { + void Process() override; + bool EvalFile(SourceFileHandleT const& sourceFileHandle); + bool FindIncludedUi(cm::string_view sourceDirPrefix, + cm::string_view includePrefix); + bool RegisterMapping(std::string const& includeString, + SourceFileHandleT includerFileHandle); + + std::string UiName; + SourceFileHandleT UiFileHandle; + }; + + /** Evaluate cached file parse data - finish */ + class JobEvalCacheFinishT : public JobFenceT { void Process() override; + }; - // -- Moc - bool MocEvalHeader(SourceFileHandleT source); - bool MocEvalSource(SourceFileHandleT const& source); - SourceFileHandleT MocFindIncludedHeader( - std::string const& includerDir, std::string const& includeBase) const; - SourceFileHandleT MocFindHeader(std::string const& basePath) const; - std::string MocMessageTestHeaders(cm::string_view fileBase) const; - bool MocRegisterIncluded(std::string const& includeString, - SourceFileHandleT includerFileHandle, - SourceFileHandleT sourceFileHandle, - bool sourceIsHeader) const; - void MocRegisterMapping(MappingHandleT mappingHandle, - bool sourceIsHeader) const; - - // -- Uic - bool UicEval(SourceFileMapT const& fileMap); - bool UicEvalFile(SourceFileHandleT const& sourceFileHandle); - SourceFileHandleT UicFindIncludedUi(std::string const& sourceFile, - std::string const& sourceDir, - IncludeKeyT const& incKey) const; - bool UicRegisterMapping(std::string const& includeString, - SourceFileHandleT uiFileHandle, - SourceFileHandleT includerFileHandle); + /** Dependency probing base job. */ + class JobProbeDepsT : public JobT + { }; - /** - * Generates moc/uic jobs - */ - class JobGenerateT : public JobFenceT + /** Probes file dependencies and generates moc compile jobs. */ + class JobProbeDepsMocT : public JobProbeDepsT { void Process() override; - // -- Moc - bool MocGenerate(MappingHandleT const& mapping, bool compFile) const; - bool MocUpdate(MappingT const& mapping, std::string* reason) const; - std::pair<std::string, cmFileTime> MocFindDependency( + bool Generate(MappingHandleT const& mapping, bool compFile) const; + bool Probe(MappingT const& mapping, std::string* reason) const; + std::pair<std::string, cmFileTime> FindDependency( std::string const& sourceDir, std::string const& includeString) const; - // -- Uic - bool UicGenerate(MappingHandleT const& mapping) const; - bool UicUpdate(MappingT const& mapping, std::string* reason) const; }; - /** - * File compiling base job - */ + /** Probes file dependencies and generates uic compile jobs. */ + class JobProbeDepsUicT : public JobProbeDepsT + { + void Process() override; + bool Probe(MappingT const& mapping, std::string* reason) const; + }; + + /** Dependency probing finish job. */ + class JobProbeDepsFinishT : public JobFenceT + { + void Process() override; + }; + + /** Meta compiler base job. */ class JobCompileT : public JobT { public: @@ -482,36 +472,30 @@ public: std::unique_ptr<std::string> Reason; }; - /** - * moc compiles a file - */ - class JobMocT : public JobCompileT + /** moc compiles a file. */ + class JobCompileMocT : public JobCompileT { public: using JobCompileT::JobCompileT; void Process() override; }; - /** - * uic compiles a file - */ - class JobUicT : public JobCompileT + /** uic compiles a file. */ + class JobCompileUicT : public JobCompileT { public: using JobCompileT::JobCompileT; void Process() override; }; - /// @brief Generate mocs_compilation.cpp - /// + /** Generate mocs_compilation.cpp. */ class JobMocsCompilationT : public JobFenceT { private: void Process() override; }; - /// @brief The last job - /// + /** @brief The last job. */ class JobFinishT : public JobFenceT { private: @@ -536,6 +520,7 @@ public: std::string AbsoluteIncludePath(cm::string_view relativePath) const; template <class JOBTYPE> void CreateParseJobs(SourceFileMapT const& sourceMap); + std::string CollapseFullPathTS(std::string const& path) const; private: // -- Utility accessors @@ -572,6 +557,8 @@ private: // -- Worker thread pool std::atomic<bool> JobError_ = ATOMIC_VAR_INIT(false); cmWorkerPool WorkerPool_; + // -- Concurrent processing + mutable std::mutex CMakeLibMutex_; }; #endif diff --git a/Source/cmQtAutoRcc.cxx b/Source/cmQtAutoRcc.cxx index e931346..cd3e034 100644 --- a/Source/cmQtAutoRcc.cxx +++ b/Source/cmQtAutoRcc.cxx @@ -16,7 +16,6 @@ #include <algorithm> cmQtAutoRcc::cmQtAutoRcc() = default; - cmQtAutoRcc::~cmQtAutoRcc() = default; bool cmQtAutoRcc::Init(cmMakefile* makefile) @@ -41,8 +40,8 @@ bool cmQtAutoRcc::Init(cmMakefile* makefile) return cmExpandedList(InfoGetConfig(key)); }; auto LogInfoError = [this](cm::string_view msg) -> bool { - this->Log().Error(GenT::RCC, - cmStrCat("In ", Quoted(this->InfoFile()), ":\n", msg)); + this->Log().Error( + GenT::RCC, cmStrCat("In ", MessagePath(this->InfoFile()), ":\n", msg)); return false; }; @@ -56,6 +55,8 @@ bool cmQtAutoRcc::Init(cmMakefile* makefile) MultiConfig_ = makefile->IsOn("ARCC_MULTI_CONFIG"); // - Directories + ProjectDirsRef().Source = InfoGet("ARCC_CMAKE_SOURCE_DIR"); + ProjectDirsRef().Binary = InfoGet("ARCC_CMAKE_BINARY_DIR"); AutogenBuildDir_ = InfoGet("ARCC_BUILD_DIR"); if (AutogenBuildDir_.empty()) { return LogInfoError("Build directory empty."); @@ -69,8 +70,8 @@ bool cmQtAutoRcc::Init(cmMakefile* makefile) // - Rcc executable RccExecutable_ = InfoGet("ARCC_RCC_EXECUTABLE"); if (!RccExecutableTime_.Load(RccExecutable_)) { - return LogInfoError(cmStrCat("The rcc executable ", Quoted(RccExecutable_), - " does not exist.")); + return LogInfoError(cmStrCat( + "The rcc executable ", MessagePath(RccExecutable_), " does not exist.")); } RccListOptions_ = InfoGetList("ARCC_RCC_LIST_OPTIONS"); @@ -185,8 +186,9 @@ bool cmQtAutoRcc::SettingsFileRead() if (!cmSystemTools::FileExists(SettingsFile_, true)) { // Touch the settings file to make sure it exists if (!cmSystemTools::Touch(SettingsFile_, true)) { - Log().ErrorFile(GenT::RCC, SettingsFile_, - "Settings file creation failed."); + Log().Error(GenT::RCC, + cmStrCat("Touching the settings file ", + MessagePath(SettingsFile_), " failed.")); return false; } } @@ -196,7 +198,9 @@ bool cmQtAutoRcc::SettingsFileRead() // Make sure the lock file exists if (!cmSystemTools::FileExists(LockFile_, true)) { if (!cmSystemTools::Touch(LockFile_, true)) { - Log().ErrorFile(GenT::RCC, LockFile_, "Lock file creation failed."); + Log().Error(GenT::RCC, + cmStrCat("Touching the lock file ", MessagePath(LockFile_), + " failed.")); return false; } } @@ -204,8 +208,9 @@ bool cmQtAutoRcc::SettingsFileRead() cmFileLockResult lockResult = LockFileLock_.Lock(LockFile_, static_cast<unsigned long>(-1)); if (!lockResult.IsOk()) { - Log().ErrorFile(GenT::RCC, LockFile_, - "File lock failed: " + lockResult.GetOutputMessage()); + Log().Error(GenT::RCC, + cmStrCat("Locking of the lock file ", MessagePath(LockFile_), + " failed.\n", lockResult.GetOutputMessage())); return false; } } @@ -221,8 +226,10 @@ bool cmQtAutoRcc::SettingsFileRead() if (SettingsChanged_) { std::string error; if (!FileWrite(SettingsFile_, "", &error)) { - Log().ErrorFile(GenT::RCC, SettingsFile_, - "Settings file clearing failed. " + error); + Log().Error(GenT::RCC, + cmStrCat("Clearing of the settings file ", + MessagePath(SettingsFile_), " failed.\n", + error)); return false; } } @@ -239,14 +246,16 @@ bool cmQtAutoRcc::SettingsFileWrite() // Only write if any setting changed if (SettingsChanged_) { if (Log().Verbose()) { - Log().Info(GenT::RCC, "Writing settings file " + Quoted(SettingsFile_)); + Log().Info(GenT::RCC, + "Writing settings file " + MessagePath(SettingsFile_)); } // Write settings file std::string content = cmStrCat("rcc:", SettingsString_, '\n'); std::string error; if (!FileWrite(SettingsFile_, content, &error)) { - Log().ErrorFile(GenT::RCC, SettingsFile_, - "Settings file writing failed. " + error); + Log().Error(GenT::RCC, + cmStrCat("Writing of the settings file ", + MessagePath(SettingsFile_), " failed.\n", error)); // Remove old settings file to trigger a full rebuild on the next run cmSystemTools::RemoveFile(SettingsFile_); return false; @@ -263,17 +272,18 @@ bool cmQtAutoRcc::TestQrcRccFiles(bool& generate) { // Test if the rcc input file exists if (!QrcFileTime_.Load(QrcFile_)) { - Log().ErrorFile( - GenT::RCC, QrcFile_, - cmStrCat("The resources file ", Quoted(QrcFile_), " does not exist")); + Log().Error(GenT::RCC, + cmStrCat("The resources file ", MessagePath(QrcFile_), + " does not exist")); return false; } // Test if the rcc output file exists if (!RccFileTime_.Load(RccFileOutput_)) { if (Log().Verbose()) { - Reason = cmStrCat("Generating ", Quoted(RccFileOutput_), - ", because it doesn't exist, from ", Quoted(QrcFile_)); + Reason = + cmStrCat("Generating ", MessagePath(RccFileOutput_), + ", because it doesn't exist, from ", MessagePath(QrcFile_)); } generate = true; return true; @@ -282,9 +292,9 @@ bool cmQtAutoRcc::TestQrcRccFiles(bool& generate) // Test if the settings changed if (SettingsChanged_) { if (Log().Verbose()) { - Reason = cmStrCat("Generating ", Quoted(RccFileOutput_), + Reason = cmStrCat("Generating ", MessagePath(RccFileOutput_), ", because the rcc settings changed, from ", - Quoted(QrcFile_)); + MessagePath(QrcFile_)); } generate = true; return true; @@ -293,9 +303,9 @@ bool cmQtAutoRcc::TestQrcRccFiles(bool& generate) // Test if the rcc output file is older than the .qrc file if (RccFileTime_.Older(QrcFileTime_)) { if (Log().Verbose()) { - Reason = cmStrCat("Generating ", Quoted(RccFileOutput_), - ", because it is older than ", Quoted(QrcFile_), - ", from ", Quoted(QrcFile_)); + Reason = cmStrCat("Generating ", MessagePath(RccFileOutput_), + ", because it is older than ", MessagePath(QrcFile_), + ", from ", MessagePath(QrcFile_)); } generate = true; return true; @@ -304,9 +314,9 @@ bool cmQtAutoRcc::TestQrcRccFiles(bool& generate) // Test if the rcc output file is older than the rcc executable if (RccFileTime_.Older(RccExecutableTime_)) { if (Log().Verbose()) { - Reason = cmStrCat("Generating ", Quoted(RccFileOutput_), + Reason = cmStrCat("Generating ", MessagePath(RccFileOutput_), ", because it is older than the rcc executable, from ", - Quoted(QrcFile_)); + MessagePath(QrcFile_)); } generate = true; return true; @@ -322,7 +332,9 @@ bool cmQtAutoRcc::TestResources(bool& generate) std::string error; RccLister const lister(RccExecutable_, RccListOptions_); if (!lister.list(QrcFile_, Inputs_, error, Log().Verbose())) { - Log().ErrorFile(GenT::RCC, QrcFile_, error); + Log().Error( + GenT::RCC, + cmStrCat("Listing of ", MessagePath(QrcFile_), " failed.\n", error)); return false; } } @@ -332,17 +344,18 @@ bool cmQtAutoRcc::TestResources(bool& generate) // Check if the resource file exists cmFileTime fileTime; if (!fileTime.Load(resFile)) { - Log().ErrorFile(GenT::RCC, QrcFile_, - cmStrCat("Could not find the resource file\n ", - Quoted(resFile), '\n')); + Log().Error(GenT::RCC, + cmStrCat("The resource file ", MessagePath(resFile), + " listed in ", MessagePath(QrcFile_), + " does not exist.")); return false; } // Check if the resource file is newer than the rcc output file if (RccFileTime_.Older(fileTime)) { if (Log().Verbose()) { - Reason = cmStrCat("Generating ", Quoted(RccFileOutput_), - ", because it is older than ", Quoted(resFile), - ", from ", Quoted(QrcFile_)); + Reason = cmStrCat("Generating ", MessagePath(RccFileOutput_), + ", because it is older than ", MessagePath(resFile), + ", from ", MessagePath(QrcFile_)); } generate = true; break; @@ -357,12 +370,15 @@ bool cmQtAutoRcc::TestInfoFile() if (RccFileTime_.Older(InfoFileTime())) { if (Log().Verbose()) { Log().Info(GenT::RCC, - cmStrCat("Touching ", Quoted(RccFileOutput_), - " because it is older than ", Quoted(InfoFile()))); + cmStrCat("Touching ", MessagePath(RccFileOutput_), + " because it is older than ", + MessagePath(InfoFile()))); } // Touch build file if (!cmSystemTools::Touch(RccFileOutput_, false)) { - Log().ErrorFile(GenT::RCC, RccFileOutput_, "Build file touch failed"); + Log().Error( + GenT::RCC, + cmStrCat("Touching ", MessagePath(RccFileOutput_), " failed.")); return false; } BuildFileChanged_ = true; @@ -375,8 +391,9 @@ bool cmQtAutoRcc::GenerateRcc() { // Make parent directory if (!MakeParentDirectory(RccFileOutput_)) { - Log().ErrorFile(GenT::RCC, RccFileOutput_, - "Could not create parent directory"); + Log().Error(GenT::RCC, + cmStrCat("Could not create parent directory of ", + MessagePath(RccFileOutput_))); return false; } @@ -405,8 +422,8 @@ bool cmQtAutoRcc::GenerateRcc() // rcc process failed Log().ErrorCommand(GenT::RCC, cmStrCat("The rcc process failed to compile\n ", - Quoted(QrcFile_), "\ninto\n ", - Quoted(RccFileOutput_)), + MessagePath(QrcFile_), "\ninto\n ", + MessagePath(RccFileOutput_)), cmd, rccStdOut + rccStdErr); cmSystemTools::RemoveFile(RccFileOutput_); return false; @@ -443,22 +460,29 @@ bool cmQtAutoRcc::GenerateWrapper() if (fileDiffers) { // Write new wrapper file if (Log().Verbose()) { - Log().Info(GenT::RCC, "Generating RCC wrapper file " + RccFilePublic_); + Log().Info(GenT::RCC, + cmStrCat("Generating RCC wrapper file ", + MessagePath(RccFilePublic_))); } std::string error; if (!FileWrite(RccFilePublic_, content, &error)) { - Log().ErrorFile(GenT::RCC, RccFilePublic_, - "RCC wrapper file writing failed. " + error); + Log().Error(GenT::RCC, + cmStrCat("Generating RCC wrapper file ", + MessagePath(RccFilePublic_), " failed.\n", + error)); return false; } } else if (BuildFileChanged_) { // Just touch the wrapper file if (Log().Verbose()) { - Log().Info(GenT::RCC, "Touching RCC wrapper file " + RccFilePublic_); + Log().Info( + GenT::RCC, + cmStrCat("Touching RCC wrapper file ", MessagePath(RccFilePublic_))); } if (!cmSystemTools::Touch(RccFilePublic_, false)) { - Log().ErrorFile(GenT::RCC, RccFilePublic_, - "RCC wrapper file touch failed."); + Log().Error(GenT::RCC, + cmStrCat("Touching RCC wrapper file ", + MessagePath(RccFilePublic_), " failed.")); return false; } } diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index e65fb25..8900ebf 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -312,6 +312,7 @@ cmTarget::cmTarget(std::string const& name, cmStateEnums::TargetType type, initProp("AUTOMOC_MACRO_NAMES"); initProp("AUTOMOC_MOC_OPTIONS"); initProp("AUTOUIC_OPTIONS"); + initProp("AUTOMOC_PATH_PREFIX"); initProp("AUTOUIC_SEARCH_PATHS"); initProp("AUTORCC_OPTIONS"); initProp("LINK_DEPENDS_NO_SHARED"); |