diff options
author | Brad King <brad.king@kitware.com> | 2018-07-31 12:07:54 (GMT) |
---|---|---|
committer | Kitware Robot <kwrobot@kitware.com> | 2018-07-31 12:08:05 (GMT) |
commit | c31d9f1c30bddef091517a777936362a403b49b2 (patch) | |
tree | 0ffc9ec8a27f28f01628610559bec1597785bab4 | |
parent | 398ce17faca27b146ebe6c161c435626f6e05674 (diff) | |
parent | 7bb70054e443813dfc21d1b4acc0e719b40f55d8 (diff) | |
download | CMake-c31d9f1c30bddef091517a777936362a403b49b2.zip CMake-c31d9f1c30bddef091517a777936362a403b49b2.tar.gz CMake-c31d9f1c30bddef091517a777936362a403b49b2.tar.bz2 |
Merge topic 'autogen_refactor_initialization'
7bb70054e4 Autogen: Add test for Q_OS_ macros
f345135845 Autogen: For Qt5 pass all implicit include directories to moc
2d6cfe2677 Autogen: Split initializer main method
84bdae8895 Autogen: Compute variables in Init stage instead of Setup stage
8e0d70272d Autogen: Move info file write code into methods
5776639fbf Autogen: Pass absolute include path in info file
2e9199b291 cmLocalGenerator: Respect user requested implicit include directories order
Acked-by: Kitware Robot <kwrobot@kitware.com>
Merge-request: !2230
-rw-r--r-- | Source/cmLocalGenerator.cxx | 15 | ||||
-rw-r--r-- | Source/cmQtAutoGenInitializer.cxx | 1407 | ||||
-rw-r--r-- | Source/cmQtAutoGenInitializer.h | 40 | ||||
-rw-r--r-- | Source/cmQtAutoGeneratorMocUic.cxx | 13 | ||||
-rw-r--r-- | Source/cmQtAutoGeneratorRcc.cxx | 4 | ||||
-rw-r--r-- | Tests/QtAutogen/CommonTests.cmake | 3 | ||||
-rw-r--r-- | Tests/QtAutogen/MocOsMacros/CMakeLists.txt | 16 | ||||
-rw-r--r-- | Tests/QtAutogen/MocOsMacros/TestClass.cpp | 77 | ||||
-rw-r--r-- | Tests/QtAutogen/MocOsMacros/TestClass.hpp | 52 | ||||
-rw-r--r-- | Tests/QtAutogen/MocOsMacros/main.cpp | 32 |
10 files changed, 955 insertions, 704 deletions
diff --git a/Source/cmLocalGenerator.cxx b/Source/cmLocalGenerator.cxx index 647697a..a669477 100644 --- a/Source/cmLocalGenerator.cxx +++ b/Source/cmLocalGenerator.cxx @@ -960,15 +960,14 @@ void cmLocalGenerator::GetIncludeDirectories(std::vector<std::string>& dirs, } if (!stripImplicitDirs) { - if (!appendAllImplicitDirs) { - // Append only those implicit directories that were requested by the user - for (std::string const& i : implicitDirs) { - if (std::find(userDirs.begin(), userDirs.end(), i) != userDirs.end()) { - dirs.push_back(i); - } + // Append only implicit directories that were requested by the user + for (std::string const& i : implicitDirs) { + if (std::find(userDirs.begin(), userDirs.end(), i) != userDirs.end()) { + dirs.push_back(i); } - } else { - // Append all implicit directories + } + // Append remaining implicit directories on demand + if (appendAllImplicitDirs) { for (std::string const& i : implicitDirs) { if (std::find(dirs.begin(), dirs.end(), i) == dirs.end()) { dirs.push_back(i); diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx index fd9829f..7cfdeba 100644 --- a/Source/cmQtAutoGenInitializer.cxx +++ b/Source/cmQtAutoGenInitializer.cxx @@ -195,15 +195,13 @@ bool cmQtAutoGenInitializer::InitCustomTargets() cmGlobalGenerator* globalGen = localGen->GetGlobalGenerator(); // Verbosity - { - this->Verbosity = makefile->GetSafeDefinition("CMAKE_AUTOGEN_VERBOSE"); - if (!this->Verbosity.empty()) { - unsigned long iVerb = 0; - if (!cmSystemTools::StringToULong(this->Verbosity.c_str(), &iVerb)) { - // Non numeric verbosity - this->Verbosity = - cmSystemTools::IsOn(this->Verbosity.c_str()) ? "1" : "0"; - } + this->Verbosity = makefile->GetSafeDefinition("CMAKE_AUTOGEN_VERBOSE"); + if (!this->Verbosity.empty()) { + unsigned long iVerb = 0; + if (!cmSystemTools::StringToULong(this->Verbosity.c_str(), &iVerb)) { + // Non numeric verbosity + this->Verbosity = + cmSystemTools::IsOn(this->Verbosity.c_str()) ? "1" : "0"; } } @@ -214,6 +212,13 @@ bool cmQtAutoGenInitializer::InitCustomTargets() this->ConfigsList.push_back(this->ConfigDefault); } + // Parallel processing + this->Parallel = this->Target->GetSafeProperty("AUTOGEN_PARALLEL"); + if (this->Parallel.empty() || (this->Parallel == "AUTO")) { + // Autodetect number of CPUs + this->Parallel = std::to_string(GetParallelCPUCount()); + } + // Autogen target name this->AutogenTargetName = this->Target->GetName(); this->AutogenTargetName += "_autogen"; @@ -240,19 +245,46 @@ bool cmQtAutoGenInitializer::InitCustomTargets() this->DirBuild += this->AutogenTargetName; } cmSystemTools::ConvertToUnixSlashes(this->DirBuild); + // Remove build directories on cleanup + AddCleanFile(makefile, this->DirBuild); // Working directory this->DirWork = cbd; cmSystemTools::ConvertToUnixSlashes(this->DirWork); + + // Include directory + this->DirInclude = this->DirBuild; + this->DirInclude += "/include"; + if (this->MultiConfig) { + this->DirInclude += "_$<CONFIG>"; + } + if (this->MultiConfig) { + for (std::string const& cfg : this->ConfigsList) { + std::string& dir = this->DirConfigInclude[cfg]; + dir = this->DirBuild; + dir += "/include_"; + dir += cfg; + } + } } - // Autogen files + // Autogen info and settings files { this->AutogenInfoFile = this->DirInfo; this->AutogenInfoFile += "/AutogenInfo.cmake"; this->AutogenSettingsFile = this->DirInfo; this->AutogenSettingsFile += "/AutogenOldSettings.txt"; + + if (this->MultiConfig) { + for (std::string const& cfg : this->ConfigsList) { + std::string& filename = this->AutogenConfigSettingsFile[cfg]; + filename = AppendFilenameSuffix(this->AutogenSettingsFile, "_" + cfg); + AddCleanFile(makefile, filename); + } + } else { + AddCleanFile(makefile, this->AutogenSettingsFile); + } } // Autogen target FOLDER property @@ -272,57 +304,230 @@ bool cmQtAutoGenInitializer::InitCustomTargets() } } - std::set<std::string> autogenDependFiles; - std::set<cmTarget*> autogenDependTargets; - std::vector<std::string> autogenProvides; + if (this->Moc.Enabled || this->Uic.Enabled) { + // Init moc specific settings + if (this->Moc.Enabled && !InitMoc()) { + return false; + } + // Init uic specific settings + if (this->Uic.Enabled && !InitUic()) { + return false; + } - // Remove build directories on cleanup - AddCleanFile(makefile, this->DirBuild); - // Remove old settings on cleanup + // Autogen target: Compute user defined dependencies + { + std::string const deps = + this->Target->GetSafeProperty("AUTOGEN_TARGET_DEPENDS"); + if (!deps.empty()) { + std::vector<std::string> extraDeps; + cmSystemTools::ExpandListArgument(deps, extraDeps); + for (std::string const& depName : extraDeps) { + // Allow target and file dependencies + auto* depTarget = makefile->FindTargetToUse(depName); + if (depTarget != nullptr) { + this->AutogenDependTargets.insert(depTarget); + } else { + this->AutogenDependFiles.insert(depName); + } + } + } + } + } + // Init rcc specific settings + if (this->Rcc.Enabled && !InitRcc()) { + return false; + } + + // Add autogen include directory to the origin target INCLUDE_DIRECTORIES + if (this->Moc.Enabled || this->Uic.Enabled || + (this->Rcc.Enabled && this->MultiConfig)) { + this->Target->AddIncludeDirectory(this->DirInclude, true); + } + + // Scan files + if (!this->InitScanFiles()) { + return false; + } + + // Create autogen target + if ((this->Moc.Enabled || this->Uic.Enabled) && !this->InitAutogenTarget()) { + return false; + } + + // Create rcc targets + if (this->Rcc.Enabled && !this->InitRccTargets()) { + return false; + } + + return true; +} + +bool cmQtAutoGenInitializer::InitMoc() +{ + cmMakefile* makefile = this->Target->Target->GetMakefile(); + cmLocalGenerator* localGen = this->Target->GetLocalGenerator(); + + // Mocs compilation file + this->Moc.MocsCompilation = this->DirBuild; + this->Moc.MocsCompilation += "/mocs_compilation.cpp"; + + // Moc predefs command + if (this->Target->GetPropertyAsBool("AUTOMOC_COMPILER_PREDEFINES") && + this->QtVersionGreaterOrEqual(5, 8)) { + this->Moc.PredefsCmd = + makefile->GetSafeDefinition("CMAKE_CXX_COMPILER_PREDEFINES_COMMAND"); + } + + // Moc includes { - std::string base = this->DirInfo; - base += "/AutogenOldSettings"; + bool const appendImplicit = (this->QtVersionMajor == "5"); + auto GetIncludeDirs = + [this, localGen, appendImplicit](std::string const& cfg) -> 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 + std::vector<std::string> dirs; + localGen->GetIncludeDirectories(dirs, this->Target, "CXX", cfg, false, + appendImplicit); + return cmJoin(dirs, ";"); + }; + + // Default configuration include directories + this->Moc.Includes = GetIncludeDirs(this->ConfigDefault); + // Other configuration settings if (this->MultiConfig) { for (std::string const& cfg : this->ConfigsList) { - std::string filename = base; - filename += '_'; - filename += cfg; - filename += ".cmake"; - AddCleanFile(makefile, filename); + std::string dirs = GetIncludeDirs(cfg); + if (dirs != this->Moc.Includes) { + this->Moc.ConfigIncludes[cfg] = std::move(dirs); + } } - } else { - AddCleanFile(makefile, base.append(".cmake")); } } - // Add moc compilation to generated files list - if (this->Moc.Enabled) { - std::string mocsComp = this->DirBuild + "/mocs_compilation.cpp"; - this->AddGeneratedSource(mocsComp, GeneratorT::MOC); - autogenProvides.push_back(std::move(mocsComp)); - } + // Moc compile definitions + { + auto GetCompileDefinitions = + [this, localGen](std::string const& cfg) -> std::string { + std::set<std::string> defines; + localGen->AddCompileDefinitions(defines, this->Target, cfg, "CXX"); + return cmJoin(defines, ";"); + }; - // Add autogen includes directory to the origin target INCLUDE_DIRECTORIES - if (this->Moc.Enabled || this->Uic.Enabled || - (this->Rcc.Enabled && this->MultiConfig)) { - std::string includeDir = this->DirBuild; - includeDir += "/include"; + // Default configuration defines + this->Moc.Defines = GetCompileDefinitions(this->ConfigDefault); + // Other configuration defines if (this->MultiConfig) { - includeDir += "_$<CONFIG>"; + for (std::string const& cfg : this->ConfigsList) { + std::string defines = GetCompileDefinitions(cfg); + if (defines != this->Moc.Defines) { + this->Moc.ConfigDefines[cfg] = std::move(defines); + } + } } - this->Target->AddIncludeDirectory(includeDir, true); } - // Acquire rcc executable and features - if (this->Rcc.Enabled) { - if (!GetRccExecutable()) { - return false; + // Moc executable + if (!GetMocExecutable()) { + return false; + } + + return true; +} + +bool cmQtAutoGenInitializer::InitUic() +{ + cmMakefile* makefile = this->Target->Target->GetMakefile(); + + // Uic search paths + { + std::string const usp = + this->Target->GetSafeProperty("AUTOUIC_SEARCH_PATHS"); + if (!usp.empty()) { + cmSystemTools::ExpandListArgument(usp, this->Uic.SearchPaths); + std::string const srcDir = makefile->GetCurrentSourceDirectory(); + for (std::string& path : this->Uic.SearchPaths) { + path = cmSystemTools::CollapseFullPath(path, srcDir); + } + } + } + // Uic target options + { + auto UicGetOpts = [this](std::string const& cfg) -> std::string { + std::vector<std::string> opts; + this->Target->GetAutoUicOptions(opts, cfg); + return cmJoin(opts, ";"); + }; + + // Default settings + this->Uic.Options = UicGetOpts(this->ConfigDefault); + + // Configuration specific settings + if (this->MultiConfig) { + for (std::string const& cfg : this->ConfigsList) { + std::string options = UicGetOpts(cfg); + if (options != this->Uic.Options) { + this->Uic.ConfigOptions[cfg] = std::move(options); + } + } } } + // .ui files skip and options + { + std::string const uiExt = "ui"; + std::string pathError; + for (cmSourceFile* sf : makefile->GetSourceFiles()) { + // sf->GetExtension() is only valid after sf->GetFullPath() ... + // 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 const& fPath = sf->GetFullPath(&pathError); + if (!pathError.empty()) { + pathError.clear(); + continue; + } + if (sf->GetExtension() == uiExt) { + std::string const absFile = cmSystemTools::GetRealPath(fPath); + // Check if the .ui file should be skipped + if (sf->GetPropertyAsBool("SKIP_AUTOUIC") || + sf->GetPropertyAsBool("SKIP_AUTOGEN")) { + this->Uic.Skip.insert(absFile); + } + // Check if the .ui file has uic options + std::string const uicOpts = sf->GetSafeProperty("AUTOUIC_OPTIONS"); + if (!uicOpts.empty()) { + // Check if file isn't skipped + if (this->Uic.Skip.count(absFile) == 0) { + this->Uic.FileFiles.push_back(absFile); + std::vector<std::string> optsVec; + cmSystemTools::ExpandListArgument(uicOpts, optsVec); + this->Uic.FileOptions.push_back(std::move(optsVec)); + } + } + } + } + } + + // Uic executable + if (!GetUicExecutable()) { + return false; + } + + return true; +} + +bool cmQtAutoGenInitializer::InitRcc() +{ + if (!GetRccExecutable()) { + return false; + } + return true; +} - // Extract relevant source files - std::vector<std::string> generatedSources; - std::vector<std::string> generatedHeaders; +bool cmQtAutoGenInitializer::InitScanFiles() +{ + cmMakefile* makefile = this->Target->Target->GetMakefile(); + + // Scan through target files { std::string const qrcExt = "qrc"; std::vector<cmSourceFile*> srcFiles; @@ -347,15 +552,15 @@ bool cmQtAutoGenInitializer::InitCustomTargets() const bool generated = sf->GetPropertyAsBool("GENERATED"); if (fileType == cmSystemTools::HEADER_FILE_FORMAT) { if (generated) { - generatedHeaders.push_back(absPath); + this->MocUic.HeadersGenerated.push_back(absPath); } else { - this->Headers.push_back(absPath); + this->MocUic.Headers.push_back(absPath); } } else { if (generated) { - generatedSources.push_back(absPath); + this->MocUic.SourcesGenerated.push_back(absPath); } else { - this->Sources.push_back(absPath); + this->MocUic.Sources.push_back(absPath); } } } @@ -382,125 +587,126 @@ bool cmQtAutoGenInitializer::InitCustomTargets() } } } - // cmGeneratorTarget::GetConfigCommonSourceFiles computes the target's - // 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(); } - // Read skip files from makefile sources + // cmGeneratorTarget::GetConfigCommonSourceFiles computes the target's + // 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(); + if (this->Moc.Enabled || this->Uic.Enabled) { - std::string pathError; - for (cmSourceFile* sf : makefile->GetSourceFiles()) { - // sf->GetExtension() is only valid after sf->GetFullPath() ... - // 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 const& fPath = sf->GetFullPath(&pathError); - if (!pathError.empty()) { - pathError.clear(); - continue; - } - cmSystemTools::FileFormat const fileType = - cmSystemTools::GetFileFormat(sf->GetExtension().c_str()); - if (!(fileType == cmSystemTools::CXX_FILE_FORMAT) && - !(fileType == cmSystemTools::HEADER_FILE_FORMAT)) { - continue; - } - const bool skipAll = sf->GetPropertyAsBool("SKIP_AUTOGEN"); - const bool mocSkip = this->Moc.Enabled && - (skipAll || sf->GetPropertyAsBool("SKIP_AUTOMOC")); - const bool uicSkip = this->Uic.Enabled && - (skipAll || sf->GetPropertyAsBool("SKIP_AUTOUIC")); - if (mocSkip || uicSkip) { - std::string const absFile = cmSystemTools::GetRealPath(fPath); - if (mocSkip) { - this->Moc.Skip.insert(absFile); + // Read skip files from makefile sources + { + std::string pathError; + for (cmSourceFile* sf : makefile->GetSourceFiles()) { + // sf->GetExtension() is only valid after sf->GetFullPath() ... + // 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 const& fPath = sf->GetFullPath(&pathError); + if (!pathError.empty()) { + pathError.clear(); + continue; } - if (uicSkip) { - this->Uic.Skip.insert(absFile); + cmSystemTools::FileFormat const fileType = + cmSystemTools::GetFileFormat(sf->GetExtension().c_str()); + if (!(fileType == cmSystemTools::CXX_FILE_FORMAT) && + !(fileType == cmSystemTools::HEADER_FILE_FORMAT)) { + continue; + } + const bool skipAll = sf->GetPropertyAsBool("SKIP_AUTOGEN"); + const bool mocSkip = this->Moc.Enabled && + (skipAll || sf->GetPropertyAsBool("SKIP_AUTOMOC")); + const bool uicSkip = this->Uic.Enabled && + (skipAll || sf->GetPropertyAsBool("SKIP_AUTOUIC")); + if (mocSkip || uicSkip) { + std::string const absFile = cmSystemTools::GetRealPath(fPath); + if (mocSkip) { + this->Moc.Skip.insert(absFile); + } + if (uicSkip) { + this->Uic.Skip.insert(absFile); + } } } } - } - - // Process GENERATED sources and headers - if (!generatedSources.empty() || !generatedHeaders.empty()) { - // Check status of policy CMP0071 - bool policyAccept = false; - bool policyWarn = false; - cmPolicies::PolicyStatus const CMP0071_status = - makefile->GetPolicyStatus(cmPolicies::CMP0071); - switch (CMP0071_status) { - case cmPolicies::WARN: - policyWarn = true; - CM_FALLTHROUGH; - case cmPolicies::OLD: - // Ignore GENERATED file - break; - case cmPolicies::REQUIRED_IF_USED: - case cmPolicies::REQUIRED_ALWAYS: - case cmPolicies::NEW: - // Process GENERATED file - policyAccept = true; - break; - } - if (policyAccept) { - // Accept GENERATED sources - for (std::string const& absFile : generatedHeaders) { - this->Headers.push_back(absFile); - autogenDependFiles.insert(absFile); - } - for (std::string const& absFile : generatedSources) { - this->Sources.push_back(absFile); - autogenDependFiles.insert(absFile); + // Process GENERATED sources and headers + if (!this->MocUic.SourcesGenerated.empty() || + !this->MocUic.HeadersGenerated.empty()) { + // Check status of policy CMP0071 + bool policyAccept = false; + bool policyWarn = false; + cmPolicies::PolicyStatus const CMP0071_status = + makefile->GetPolicyStatus(cmPolicies::CMP0071); + switch (CMP0071_status) { + case cmPolicies::WARN: + policyWarn = true; + CM_FALLTHROUGH; + case cmPolicies::OLD: + // Ignore GENERATED file + break; + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::REQUIRED_ALWAYS: + case cmPolicies::NEW: + // Process GENERATED file + policyAccept = true; + break; } - } else { - if (policyWarn) { - std::string msg; - msg += cmPolicies::GetPolicyWarning(cmPolicies::CMP0071); - msg += "\n"; - std::string tools; - std::string property; - if (this->Moc.Enabled && this->Uic.Enabled) { - tools = "AUTOMOC and AUTOUIC"; - property = "SKIP_AUTOGEN"; - } else if (this->Moc.Enabled) { - tools = "AUTOMOC"; - property = "SKIP_AUTOMOC"; - } else if (this->Uic.Enabled) { - tools = "AUTOUIC"; - property = "SKIP_AUTOUIC"; + + if (policyAccept) { + // Accept GENERATED sources + for (std::string const& absFile : this->MocUic.HeadersGenerated) { + this->MocUic.Headers.push_back(absFile); + this->AutogenDependFiles.insert(absFile); } - msg += "For compatibility, CMake is excluding the GENERATED source " - "file(s):\n"; - for (const std::string& absFile : generatedHeaders) { - msg.append(" ").append(Quoted(absFile)).append("\n"); + for (std::string const& absFile : this->MocUic.SourcesGenerated) { + this->MocUic.Sources.push_back(absFile); + this->AutogenDependFiles.insert(absFile); } - for (const std::string& absFile : generatedSources) { - msg.append(" ").append(Quoted(absFile)).append("\n"); + } else { + if (policyWarn) { + std::string msg; + msg += cmPolicies::GetPolicyWarning(cmPolicies::CMP0071); + msg += "\n"; + std::string tools; + std::string property; + if (this->Moc.Enabled && this->Uic.Enabled) { + tools = "AUTOMOC and AUTOUIC"; + property = "SKIP_AUTOGEN"; + } else if (this->Moc.Enabled) { + tools = "AUTOMOC"; + property = "SKIP_AUTOMOC"; + } else if (this->Uic.Enabled) { + tools = "AUTOUIC"; + property = "SKIP_AUTOUIC"; + } + msg += "For compatibility, CMake is excluding the GENERATED source " + "file(s):\n"; + for (const std::string& absFile : this->MocUic.HeadersGenerated) { + msg.append(" ").append(Quoted(absFile)).append("\n"); + } + for (const std::string& absFile : this->MocUic.SourcesGenerated) { + msg.append(" ").append(Quoted(absFile)).append("\n"); + } + msg += "from processing by "; + msg += tools; + msg += + ". If any of the files should be processed, set CMP0071 to NEW. " + "If any of the files should not be processed, " + "explicitly exclude them by setting the source file property "; + msg += property; + msg += ":\n set_property(SOURCE file.h PROPERTY "; + msg += property; + msg += " ON)\n"; + makefile->IssueMessage(cmake::AUTHOR_WARNING, msg); } - msg += "from processing by "; - msg += tools; - msg += - ". If any of the files should be processed, set CMP0071 to NEW. " - "If any of the files should not be processed, " - "explicitly exclude them by setting the source file property "; - msg += property; - msg += ":\n set_property(SOURCE file.h PROPERTY "; - msg += property; - msg += " ON)\n"; - makefile->IssueMessage(cmake::AUTHOR_WARNING, msg); } } - // Clear lists - generatedSources.clear(); - generatedHeaders.clear(); - } - // Sort headers and sources - if (this->Moc.Enabled || this->Uic.Enabled) { - std::sort(this->Headers.begin(), this->Headers.end()); - std::sort(this->Sources.begin(), this->Sources.end()); + // Sort headers and sources + if (this->Moc.Enabled || this->Uic.Enabled) { + std::sort(this->MocUic.Headers.begin(), this->MocUic.Headers.end()); + std::sort(this->MocUic.Sources.begin(), this->MocUic.Sources.end()); + } } // Process qrc files @@ -551,6 +757,13 @@ bool cmQtAutoGenInitializer::InitCustomTargets() qrc.SettingsFile = base; qrc.SettingsFile += "Settings.txt"; + + if (this->MultiConfig) { + for (std::string const& cfg : this->ConfigsList) { + qrc.ConfigSettingsFile[cfg] = + AppendFilenameSuffix(qrc.SettingsFile, "_" + cfg); + } + } } } } @@ -576,245 +789,255 @@ bool cmQtAutoGenInitializer::InitCustomTargets() RccMergeOptions(opts, qrc.Options, QtV5); qrc.Options = std::move(opts); } + // RCC resources for (Qrc& qrc : this->Rcc.Qrcs) { - // Register file at target - this->AddGeneratedSource(qrc.RccFile, GeneratorT::RCC); - - std::vector<std::string> ccOutput; - ccOutput.push_back(qrc.RccFile); - - cmCustomCommandLines commandLines; - if (this->MultiConfig) { - // Build for all configurations - for (std::string const& config : this->ConfigsList) { - cmCustomCommandLine currentLine; - currentLine.push_back(cmSystemTools::GetCMakeCommand()); - currentLine.push_back("-E"); - currentLine.push_back("cmake_autorcc"); - currentLine.push_back(qrc.InfoFile); - currentLine.push_back(config); - commandLines.push_back(std::move(currentLine)); + if (!qrc.Generated) { + std::string error; + if (!RccListInputs(qrc.QrcFile, qrc.Resources, error)) { + cmSystemTools::Error(error.c_str()); + return false; } - } else { - cmCustomCommandLine currentLine; - currentLine.push_back(cmSystemTools::GetCMakeCommand()); - currentLine.push_back("-E"); - currentLine.push_back("cmake_autorcc"); - currentLine.push_back(qrc.InfoFile); - currentLine.push_back("$<CONFIG>"); - commandLines.push_back(std::move(currentLine)); } - std::string ccComment = "Automatic RCC for "; - ccComment += FileProjectRelativePath(makefile, qrc.QrcFile); + } + } - if (qrc.Generated) { - // Create custom rcc target - std::string ccName; - { - ccName = this->Target->GetName(); - ccName += "_arcc_"; - ccName += qrc.QrcName; - if (!qrc.Unique) { - ccName += "_"; - ccName += qrc.PathChecksum; - } - std::vector<std::string> ccDepends; - // Add the .qrc and info file to the custom target dependencies - ccDepends.push_back(qrc.QrcFile); - ccDepends.push_back(qrc.InfoFile); - - cmTarget* autoRccTarget = makefile->AddUtilityCommand( - ccName, cmMakefile::TargetOrigin::Generator, true, - this->DirWork.c_str(), ccOutput, ccDepends, commandLines, false, - ccComment.c_str()); - // Create autogen generator target - localGen->AddGeneratorTarget( - new cmGeneratorTarget(autoRccTarget, localGen)); - - // Set FOLDER property in autogen target - if (!this->AutogenFolder.empty()) { - autoRccTarget->SetProperty("FOLDER", this->AutogenFolder.c_str()); - } - } - // Add autogen target to the origin target dependencies - this->Target->Target->AddUtility(ccName, makefile); - } else { - // Create custom rcc command - { - std::vector<std::string> ccByproducts; - std::vector<std::string> ccDepends; - // Add the .qrc and info file to the custom command dependencies - ccDepends.push_back(qrc.QrcFile); - ccDepends.push_back(qrc.InfoFile); + return true; +} - // Add the resource files to the dependencies - { - std::string error; - if (RccListInputs(qrc.QrcFile, qrc.Resources, error)) { - for (std::string const& fileName : qrc.Resources) { - // Add resource file to the custom command dependencies - ccDepends.push_back(fileName); - } - } else { - cmSystemTools::Error(error.c_str()); - return false; - } - } - makefile->AddCustomCommandToOutput(ccOutput, ccByproducts, ccDepends, - /*main_dependency*/ std::string(), - commandLines, ccComment.c_str(), - this->DirWork.c_str()); - } - // Reconfigure when .qrc file changes - makefile->AddCMakeDependFile(qrc.QrcFile); +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->AutogenInfoFile); + + // Files provided by the autogen target + std::vector<std::string> autogenProvides; + if (this->Moc.Enabled) { + this->AddGeneratedSource(this->Moc.MocsCompilation, GeneratorT::MOC); + autogenProvides.push_back(this->Moc.MocsCompilation); + } + + // Compose target comment + std::string autogenComment; + { + std::string tools; + if (this->Moc.Enabled) { + tools += "MOC"; + } + if (this->Uic.Enabled) { + if (!tools.empty()) { + tools += " and "; } + tools += "UIC"; } + autogenComment = "Automatic "; + autogenComment += tools; + autogenComment += " for target "; + autogenComment += this->Target->GetName(); } - // Create _autogen target - if (this->Moc.Enabled || this->Uic.Enabled) { - // Add user defined autogen target dependencies - { - std::string const deps = - this->Target->GetSafeProperty("AUTOGEN_TARGET_DEPENDS"); - if (!deps.empty()) { - std::vector<std::string> extraDeps; - cmSystemTools::ExpandListArgument(deps, extraDeps); - for (std::string const& depName : extraDeps) { - // Allow target and file dependencies - auto* depTarget = makefile->FindTargetToUse(depName); - if (depTarget != nullptr) { - autogenDependTargets.insert(depTarget); - } else { - autogenDependFiles.insert(depName); - } - } - } + // Compose command lines + cmCustomCommandLines commandLines; + { + cmCustomCommandLine currentLine; + currentLine.push_back(cmSystemTools::GetCMakeCommand()); + currentLine.push_back("-E"); + currentLine.push_back("cmake_autogen"); + currentLine.push_back(this->AutogenInfoFile); + currentLine.push_back("$<CONFIGURATION>"); + commandLines.push_back(std::move(currentLine)); + } + + // Use PRE_BUILD on demand + bool usePRE_BUILD = false; + if (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: + // https://connect.microsoft.com/VisualStudio/feedback/details/769495 + usePRE_BUILD = true; + } + // Disable PRE_BUILD in some cases + if (usePRE_BUILD) { + // Cannot use PRE_BUILD with file depends + if (!this->AutogenDependFiles.empty()) { + usePRE_BUILD = false; } + } + // Create the autogen target/command + if (usePRE_BUILD) { + // Add additional autogen target dependencies to origin target + for (cmTarget* depTarget : this->AutogenDependTargets) { + this->Target->Target->AddUtility(depTarget->GetName(), makefile); + } + + // Add the pre-build command directly to bypass the OBJECT_LIBRARY + // rejection in cmMakefile::AddCustomCommandToTarget because we know + // PRE_BUILD will work for an OBJECT_LIBRARY in this specific case. + // + // 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, + commandLines, autogenComment.c_str(), + this->DirWork.c_str()); + cc.SetEscapeOldStyle(false); + cc.SetEscapeAllowMakeVars(true); + this->Target->Target->AddPreBuildCommand(cc); + } else { - // Compose target comment - std::string autogenComment; + // Add link library target dependencies to the autogen target + // dependencies { - std::string tools; - if (this->Moc.Enabled) { - tools += "MOC"; + // add_dependencies/addUtility do not support generator expressions. + // We depend only on the libraries found in all configs therefore. + std::map<cmGeneratorTarget const*, std::size_t> commonTargets; + for (std::string const& config : this->ConfigsList) { + cmLinkImplementationLibraries const* libs = + this->Target->GetLinkImplementationLibraries(config); + if (libs != nullptr) { + for (cmLinkItem const& item : libs->Libraries) { + cmGeneratorTarget const* libTarget = item.Target; + if ((libTarget != nullptr) && + !StaticLibraryCycle(this->Target, libTarget, config)) { + // Increment target config count + commonTargets[libTarget]++; + } + } + } } - if (this->Uic.Enabled) { - if (!tools.empty()) { - tools += " and "; + for (auto const& item : commonTargets) { + if (item.second == this->ConfigsList.size()) { + this->AutogenDependTargets.insert(item.first->Target); } - tools += "UIC"; } - autogenComment = "Automatic "; - autogenComment += tools; - autogenComment += " for target "; - autogenComment += this->Target->GetName(); } - // Compose command lines + // Create autogen target + cmTarget* autogenTarget = makefile->AddUtilityCommand( + this->AutogenTargetName, cmMakefile::TargetOrigin::Generator, true, + this->DirWork.c_str(), /*byproducts=*/autogenProvides, + std::vector<std::string>(this->AutogenDependFiles.begin(), + this->AutogenDependFiles.end()), + commandLines, false, autogenComment.c_str()); + // Create autogen generator target + localGen->AddGeneratorTarget( + new cmGeneratorTarget(autogenTarget, localGen)); + + // Forward origin utilities to autogen target + for (std::string const& depName : this->Target->Target->GetUtilities()) { + autogenTarget->AddUtility(depName, makefile); + } + // Add additional autogen target dependencies to autogen target + for (cmTarget* depTarget : this->AutogenDependTargets) { + autogenTarget->AddUtility(depTarget->GetName(), makefile); + } + + // Set FOLDER property in autogen target + if (!this->AutogenFolder.empty()) { + autogenTarget->SetProperty("FOLDER", this->AutogenFolder.c_str()); + } + + // Add autogen target to the origin target dependencies + this->Target->Target->AddUtility(this->AutogenTargetName, makefile); + } + + return true; +} + +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); + // Register file at target + this->AddGeneratedSource(qrc.RccFile, GeneratorT::RCC); + + std::vector<std::string> ccOutput; + ccOutput.push_back(qrc.RccFile); + cmCustomCommandLines commandLines; - { + if (this->MultiConfig) { + // Build for all configurations + for (std::string const& config : this->ConfigsList) { + cmCustomCommandLine currentLine; + currentLine.push_back(cmSystemTools::GetCMakeCommand()); + currentLine.push_back("-E"); + currentLine.push_back("cmake_autorcc"); + currentLine.push_back(qrc.InfoFile); + currentLine.push_back(config); + commandLines.push_back(std::move(currentLine)); + } + } else { cmCustomCommandLine currentLine; currentLine.push_back(cmSystemTools::GetCMakeCommand()); currentLine.push_back("-E"); - currentLine.push_back("cmake_autogen"); - currentLine.push_back(this->AutogenInfoFile); - currentLine.push_back("$<CONFIGURATION>"); + currentLine.push_back("cmake_autorcc"); + currentLine.push_back(qrc.InfoFile); + currentLine.push_back("$<CONFIG>"); commandLines.push_back(std::move(currentLine)); } + std::string ccComment = "Automatic RCC for "; + ccComment += FileProjectRelativePath(makefile, qrc.QrcFile); - // Use PRE_BUILD on demand - bool usePRE_BUILD = false; - if (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: - // https://connect.microsoft.com/VisualStudio/feedback/details/769495 - usePRE_BUILD = true; - } - // Disable PRE_BUILD in some cases - if (usePRE_BUILD) { - // Cannot use PRE_BUILD with file depends - if (!autogenDependFiles.empty()) { - usePRE_BUILD = false; - } - } - // Create the autogen target/command - if (usePRE_BUILD) { - // Add additional autogen target dependencies to origin target - for (cmTarget* depTarget : autogenDependTargets) { - this->Target->Target->AddUtility(depTarget->GetName(), makefile); - } - - // Add the pre-build command directly to bypass the OBJECT_LIBRARY - // rejection in cmMakefile::AddCustomCommandToTarget because we know - // PRE_BUILD will work for an OBJECT_LIBRARY in this specific case. - // - // 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, - commandLines, autogenComment.c_str(), - this->DirWork.c_str()); - cc.SetEscapeOldStyle(false); - cc.SetEscapeAllowMakeVars(true); - this->Target->Target->AddPreBuildCommand(cc); - } else { - - // Add link library target dependencies to the autogen target - // dependencies + if (qrc.Generated) { + // Create custom rcc target + std::string ccName; { - // add_dependencies/addUtility do not support generator expressions. - // We depend only on the libraries found in all configs therefore. - std::map<cmGeneratorTarget const*, std::size_t> commonTargets; - for (std::string const& config : this->ConfigsList) { - cmLinkImplementationLibraries const* libs = - this->Target->GetLinkImplementationLibraries(config); - if (libs != nullptr) { - for (cmLinkItem const& item : libs->Libraries) { - cmGeneratorTarget const* libTarget = item.Target; - if ((libTarget != nullptr) && - !StaticLibraryCycle(this->Target, libTarget, config)) { - // Increment target config count - commonTargets[libTarget]++; - } - } - } + ccName = this->Target->GetName(); + ccName += "_arcc_"; + ccName += qrc.QrcName; + if (!qrc.Unique) { + ccName += "_"; + ccName += qrc.PathChecksum; } - for (auto const& item : commonTargets) { - if (item.second == this->ConfigsList.size()) { - autogenDependTargets.insert(item.first->Target); - } + std::vector<std::string> ccDepends; + // Add the .qrc and info file to the custom target dependencies + ccDepends.push_back(qrc.QrcFile); + ccDepends.push_back(qrc.InfoFile); + + cmTarget* autoRccTarget = makefile->AddUtilityCommand( + ccName, cmMakefile::TargetOrigin::Generator, true, + this->DirWork.c_str(), ccOutput, ccDepends, commandLines, false, + ccComment.c_str()); + // Create autogen generator target + localGen->AddGeneratorTarget( + new cmGeneratorTarget(autoRccTarget, localGen)); + + // Set FOLDER property in autogen target + if (!this->AutogenFolder.empty()) { + autoRccTarget->SetProperty("FOLDER", this->AutogenFolder.c_str()); } } - - // Create autogen target - cmTarget* autogenTarget = makefile->AddUtilityCommand( - this->AutogenTargetName, cmMakefile::TargetOrigin::Generator, true, - this->DirWork.c_str(), /*byproducts=*/autogenProvides, - std::vector<std::string>(autogenDependFiles.begin(), - autogenDependFiles.end()), - commandLines, false, autogenComment.c_str()); - // Create autogen generator target - localGen->AddGeneratorTarget( - new cmGeneratorTarget(autogenTarget, localGen)); - - // Forward origin utilities to autogen target - for (std::string const& depName : this->Target->Target->GetUtilities()) { - autogenTarget->AddUtility(depName, makefile); - } - // Add additional autogen target dependencies to autogen target - for (cmTarget* depTarget : autogenDependTargets) { - autogenTarget->AddUtility(depTarget->GetName(), makefile); - } - - // Set FOLDER property in autogen target - if (!this->AutogenFolder.empty()) { - autogenTarget->SetProperty("FOLDER", this->AutogenFolder.c_str()); - } - // Add autogen target to the origin target dependencies - this->Target->Target->AddUtility(this->AutogenTargetName, makefile); + this->Target->Target->AddUtility(ccName, makefile); + } else { + // Create custom rcc command + { + std::vector<std::string> ccByproducts; + std::vector<std::string> ccDepends; + // Add the .qrc and info file to the custom command dependencies + ccDepends.push_back(qrc.QrcFile); + ccDepends.push_back(qrc.InfoFile); + + // Add the resource files to the dependencies + for (std::string const& fileName : qrc.Resources) { + // Add resource file to the custom command dependencies + ccDepends.push_back(fileName); + } + makefile->AddCustomCommandToOutput(ccOutput, ccByproducts, ccDepends, + /*main_dependency*/ std::string(), + commandLines, ccComment.c_str(), + this->DirWork.c_str()); + } + // Reconfigure when .qrc file changes + makefile->AddCMakeDependFile(qrc.QrcFile); } } @@ -823,8 +1046,6 @@ bool cmQtAutoGenInitializer::InitCustomTargets() bool cmQtAutoGenInitializer::SetupCustomTargets() { - cmMakefile* makefile = this->Target->Target->GetMakefile(); - // Create info directory on demand if (!cmSystemTools::MakeDirectory(this->DirInfo)) { std::string emsg = ("AutoGen: Could not create directory: "); @@ -833,60 +1054,142 @@ bool cmQtAutoGenInitializer::SetupCustomTargets() return false; } - // Configuration include directories - std::string includeDir = "include"; - std::map<std::string, std::string> includeDirs; - for (std::string const& cfg : this->ConfigsList) { - std::string& dir = includeDirs[cfg]; - dir = "include_"; - dir += cfg; - } - // Generate autogen target info file if (this->Moc.Enabled || this->Uic.Enabled) { + // Write autogen target info files + if (!this->SetupWriteAutogenInfo()) { + return false; + } + } + + // Write AUTORCC info files + if (this->Rcc.Enabled && !this->SetupWriteRccInfo()) { + return false; + } + + return true; +} + +bool cmQtAutoGenInitializer::SetupWriteAutogenInfo() +{ + cmMakefile* makefile = this->Target->Target->GetMakefile(); + + cmGeneratedFileStream ofs; + ofs.SetCopyIfDifferent(true); + ofs.Open(this->AutogenInfoFile.c_str(), false, true); + if (ofs) { + // Utility lambdas + auto CWrite = [&ofs](const char* key, std::string const& value) { + ofs << "set(" << key << " " << cmOutputConverter::EscapeForCMake(value) + << ")\n"; + }; + auto CWriteList = [&CWrite](const char* key, + std::vector<std::string> const& list) { + CWrite(key, cmJoin(list, ";")); + }; + auto CWriteNestedLists = + [&CWrite](const char* key, + std::vector<std::vector<std::string>> const& lists) { + std::vector<std::string> seplist; + for (const std::vector<std::string>& list : lists) { + std::string blist = "{"; + blist += cmJoin(list, ";"); + blist += "}"; + seplist.push_back(std::move(blist)); + } + CWrite(key, cmJoin(seplist, cmQtAutoGen::ListSep)); + }; + auto CWriteSet = [&CWrite](const char* key, + std::set<std::string> const& list) { + CWrite(key, cmJoin(list, ";")); + }; + auto CWriteMap = [&ofs](const char* key, + std::map<std::string, std::string> const& map) { + for (auto const& item : map) { + ofs << "set(" << key << "_" << item.first << " " + << cmOutputConverter::EscapeForCMake(item.second) << ")\n"; + } + }; + auto MfDef = [makefile](const char* key) { + return std::string(makefile->GetSafeDefinition(key)); + }; + + // Write + ofs << "# Meta\n"; + CWrite("AM_MULTI_CONFIG", this->MultiConfig ? "TRUE" : "FALSE"); + CWrite("AM_PARALLEL", this->Parallel); + CWrite("AM_VERBOSITY", this->Verbosity); + + ofs << "# Directories\n"; + CWrite("AM_CMAKE_SOURCE_DIR", MfDef("CMAKE_SOURCE_DIR")); + CWrite("AM_CMAKE_BINARY_DIR", MfDef("CMAKE_BINARY_DIR")); + CWrite("AM_CMAKE_CURRENT_SOURCE_DIR", MfDef("CMAKE_CURRENT_SOURCE_DIR")); + CWrite("AM_CMAKE_CURRENT_BINARY_DIR", MfDef("CMAKE_CURRENT_BINARY_DIR")); + CWrite("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE", + MfDef("CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE")); + CWrite("AM_BUILD_DIR", this->DirBuild); + CWrite("AM_INCLUDE_DIR", this->DirInclude); + CWriteMap("AM_INCLUDE_DIR", this->DirConfigInclude); + + ofs << "# Files\n"; + CWriteList("AM_SOURCES", this->MocUic.Sources); + CWriteList("AM_HEADERS", this->MocUic.Headers); + CWrite("AM_SETTINGS_FILE", this->AutogenSettingsFile); + CWriteMap("AM_SETTINGS_FILE", this->AutogenConfigSettingsFile); + + ofs << "# Qt\n"; + CWrite("AM_QT_VERSION_MAJOR", this->QtVersionMajor); + CWrite("AM_QT_MOC_EXECUTABLE", this->Moc.Executable); + CWrite("AM_QT_UIC_EXECUTABLE", this->Uic.Executable); + if (this->Moc.Enabled) { - this->SetupCustomTargetsMoc(); + ofs << "# MOC settings\n"; + CWriteSet("AM_MOC_SKIP", this->Moc.Skip); + CWrite("AM_MOC_DEFINITIONS", this->Moc.Defines); + CWriteMap("AM_MOC_DEFINITIONS", this->Moc.ConfigDefines); + CWrite("AM_MOC_INCLUDES", this->Moc.Includes); + CWriteMap("AM_MOC_INCLUDES", this->Moc.ConfigIncludes); + CWrite("AM_MOC_OPTIONS", + this->Target->GetSafeProperty("AUTOMOC_MOC_OPTIONS")); + CWrite("AM_MOC_RELAXED_MODE", MfDef("CMAKE_AUTOMOC_RELAXED_MODE")); + CWrite("AM_MOC_MACRO_NAMES", + this->Target->GetSafeProperty("AUTOMOC_MACRO_NAMES")); + CWrite("AM_MOC_DEPEND_FILTERS", + this->Target->GetSafeProperty("AUTOMOC_DEPEND_FILTERS")); + CWrite("AM_MOC_PREDEFS_CMD", this->Moc.PredefsCmd); } + if (this->Uic.Enabled) { - this->SetupCustomTargetsUic(); + ofs << "# UIC settings\n"; + CWriteSet("AM_UIC_SKIP", this->Uic.Skip); + CWrite("AM_UIC_TARGET_OPTIONS", this->Uic.Options); + CWriteMap("AM_UIC_TARGET_OPTIONS", this->Uic.ConfigOptions); + CWriteList("AM_UIC_OPTIONS_FILES", this->Uic.FileFiles); + CWriteNestedLists("AM_UIC_OPTIONS_OPTIONS", this->Uic.FileOptions); + CWriteList("AM_UIC_SEARCH_PATHS", this->Uic.SearchPaths); } + } else { + std::string err = "AutoGen: Could not write file "; + err += this->AutogenInfoFile; + cmSystemTools::Error(err.c_str()); + return false; + } - // Parallel processing - this->Parallel = this->Target->GetSafeProperty("AUTOGEN_PARALLEL"); - if (this->Parallel.empty() || (this->Parallel == "AUTO")) { - // Autodetect number of CPUs - this->Parallel = std::to_string(GetParallelCPUCount()); - } + return true; +} +bool cmQtAutoGenInitializer::SetupWriteRccInfo() +{ + for (Qrc const& qrc : this->Rcc.Qrcs) { cmGeneratedFileStream ofs; ofs.SetCopyIfDifferent(true); - ofs.Open(this->AutogenInfoFile.c_str(), false, true); + ofs.Open(qrc.InfoFile.c_str(), false, true); if (ofs) { // Utility lambdas auto CWrite = [&ofs](const char* key, std::string const& value) { ofs << "set(" << key << " " << cmOutputConverter::EscapeForCMake(value) << ")\n"; }; - auto CWriteList = [&CWrite](const char* key, - std::vector<std::string> const& list) { - CWrite(key, cmJoin(list, ";")); - }; - auto CWriteNestedLists = - [&CWrite](const char* key, - std::vector<std::vector<std::string>> const& lists) { - std::vector<std::string> seplist; - for (const std::vector<std::string>& list : lists) { - std::string blist = "{"; - blist += cmJoin(list, ";"); - blist += "}"; - seplist.push_back(std::move(blist)); - } - CWrite(key, cmJoin(seplist, cmQtAutoGen::ListSep)); - }; - auto CWriteSet = [&CWrite](const char* key, - std::set<std::string> const& list) { - CWrite(key, cmJoin(list, ";")); - }; auto CWriteMap = [&ofs](const char* key, std::map<std::string, std::string> const& map) { for (auto const& item : map) { @@ -894,287 +1197,39 @@ bool cmQtAutoGenInitializer::SetupCustomTargets() << cmOutputConverter::EscapeForCMake(item.second) << ")\n"; } }; - auto MfDef = [makefile](const char* key) { - return std::string(makefile->GetSafeDefinition(key)); - }; // Write - ofs << "# Meta\n"; - CWrite("AM_MULTI_CONFIG", this->MultiConfig ? "TRUE" : "FALSE"); - CWrite("AM_PARALLEL", this->Parallel); - CWrite("AM_VERBOSITY", this->Verbosity); + ofs << "# Configurations\n"; + CWrite("ARCC_MULTI_CONFIG", this->MultiConfig ? "TRUE" : "FALSE"); + CWrite("ARCC_VERBOSITY", this->Verbosity); + ofs << "# Settings file\n"; + CWrite("ARCC_SETTINGS_FILE", qrc.SettingsFile); + CWriteMap("ARCC_SETTINGS_FILE", qrc.ConfigSettingsFile); ofs << "# Directories\n"; - CWrite("AM_CMAKE_SOURCE_DIR", MfDef("CMAKE_SOURCE_DIR")); - CWrite("AM_CMAKE_BINARY_DIR", MfDef("CMAKE_BINARY_DIR")); - CWrite("AM_CMAKE_CURRENT_SOURCE_DIR", MfDef("CMAKE_CURRENT_SOURCE_DIR")); - CWrite("AM_CMAKE_CURRENT_BINARY_DIR", MfDef("CMAKE_CURRENT_BINARY_DIR")); - CWrite("AM_CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE", - MfDef("CMAKE_INCLUDE_DIRECTORIES_PROJECT_BEFORE")); - CWrite("AM_BUILD_DIR", this->DirBuild); - if (this->MultiConfig) { - CWriteMap("AM_INCLUDE_DIR", includeDirs); - } else { - CWrite("AM_INCLUDE_DIR", includeDir); - } - - ofs << "# Files\n"; - CWriteList("AM_SOURCES", this->Sources); - CWriteList("AM_HEADERS", this->Headers); - if (this->MultiConfig) { - std::map<std::string, std::string> settingsFiles; - for (std::string const& cfg : this->ConfigsList) { - settingsFiles[cfg] = - AppendFilenameSuffix(this->AutogenSettingsFile, "_" + cfg); - } - CWriteMap("AM_SETTINGS_FILE", settingsFiles); - } else { - CWrite("AM_SETTINGS_FILE", this->AutogenSettingsFile); - } - - ofs << "# Qt\n"; - CWrite("AM_QT_VERSION_MAJOR", this->QtVersionMajor); - CWrite("AM_QT_MOC_EXECUTABLE", this->Moc.Executable); - CWrite("AM_QT_UIC_EXECUTABLE", this->Uic.Executable); - - if (this->Moc.Enabled) { - ofs << "# MOC settings\n"; - CWriteSet("AM_MOC_SKIP", this->Moc.Skip); - CWrite("AM_MOC_DEFINITIONS", this->Moc.Defines); - CWriteMap("AM_MOC_DEFINITIONS", this->Moc.ConfigDefines); - CWrite("AM_MOC_INCLUDES", this->Moc.Includes); - CWriteMap("AM_MOC_INCLUDES", this->Moc.ConfigIncludes); - CWrite("AM_MOC_OPTIONS", - this->Target->GetSafeProperty("AUTOMOC_MOC_OPTIONS")); - CWrite("AM_MOC_RELAXED_MODE", MfDef("CMAKE_AUTOMOC_RELAXED_MODE")); - CWrite("AM_MOC_MACRO_NAMES", - this->Target->GetSafeProperty("AUTOMOC_MACRO_NAMES")); - CWrite("AM_MOC_DEPEND_FILTERS", - this->Target->GetSafeProperty("AUTOMOC_DEPEND_FILTERS")); - CWrite("AM_MOC_PREDEFS_CMD", this->Moc.PredefsCmd); - } - - if (this->Uic.Enabled) { - ofs << "# UIC settings\n"; - CWriteSet("AM_UIC_SKIP", this->Uic.Skip); - CWrite("AM_UIC_TARGET_OPTIONS", this->Uic.Options); - CWriteMap("AM_UIC_TARGET_OPTIONS", this->Uic.ConfigOptions); - CWriteList("AM_UIC_OPTIONS_FILES", this->Uic.FileFiles); - CWriteNestedLists("AM_UIC_OPTIONS_OPTIONS", this->Uic.FileOptions); - CWriteList("AM_UIC_SEARCH_PATHS", this->Uic.SearchPaths); - } + CWrite("ARCC_BUILD_DIR", this->DirBuild); + CWrite("ARCC_INCLUDE_DIR", this->DirInclude); + CWriteMap("ARCC_INCLUDE_DIR", this->DirConfigInclude); + + ofs << "# Rcc executable\n"; + CWrite("ARCC_RCC_EXECUTABLE", this->Rcc.Executable); + CWrite("ARCC_RCC_LIST_OPTIONS", cmJoin(this->Rcc.ListOptions, ";")); + + ofs << "# Rcc job\n"; + CWrite("ARCC_LOCK_FILE", qrc.LockFile); + CWrite("ARCC_SOURCE", qrc.QrcFile); + CWrite("ARCC_OUTPUT_CHECKSUM", qrc.PathChecksum); + CWrite("ARCC_OUTPUT_NAME", cmSystemTools::GetFilenameName(qrc.RccFile)); + CWrite("ARCC_OPTIONS", cmJoin(qrc.Options, ";")); + CWrite("ARCC_INPUTS", cmJoin(qrc.Resources, ";")); } else { - std::string err = "AutoGen: Could not write file "; - err += this->AutogenInfoFile; + std::string err = "AutoRcc: Could not write file "; + err += qrc.InfoFile; cmSystemTools::Error(err.c_str()); return false; } } - // Generate auto RCC info files - if (this->Rcc.Enabled) { - for (Qrc const& qrc : this->Rcc.Qrcs) { - // Register rcc info file as generated - makefile->AddCMakeOutputFile(qrc.InfoFile); - - cmGeneratedFileStream ofs; - ofs.SetCopyIfDifferent(true); - ofs.Open(qrc.InfoFile.c_str(), false, true); - if (ofs) { - // Utility lambdas - auto CWrite = [&ofs](const char* key, std::string const& value) { - ofs << "set(" << key << " " - << cmOutputConverter::EscapeForCMake(value) << ")\n"; - }; - auto CWriteMap = - [&ofs](const char* key, - std::map<std::string, std::string> const& map) { - for (auto const& item : map) { - ofs << "set(" << key << "_" << item.first << " " - << cmOutputConverter::EscapeForCMake(item.second) << ")\n"; - } - }; - - // Write - ofs << "# Configurations\n"; - CWrite("ARCC_MULTI_CONFIG", this->MultiConfig ? "TRUE" : "FALSE"); - CWrite("ARCC_VERBOSITY", this->Verbosity); - ofs << "# Settings file\n"; - if (this->MultiConfig) { - std::map<std::string, std::string> settingsFiles; - for (std::string const& cfg : this->ConfigsList) { - settingsFiles[cfg] = - AppendFilenameSuffix(qrc.SettingsFile, "_" + cfg); - } - CWriteMap("ARCC_SETTINGS_FILE", settingsFiles); - } else { - CWrite("ARCC_SETTINGS_FILE", qrc.SettingsFile); - } - - ofs << "# Directories\n"; - CWrite("ARCC_BUILD_DIR", this->DirBuild); - if (this->MultiConfig) { - CWriteMap("ARCC_INCLUDE_DIR", includeDirs); - } else { - CWrite("ARCC_INCLUDE_DIR", includeDir); - } - - ofs << "# Rcc executable\n"; - CWrite("ARCC_RCC_EXECUTABLE", this->Rcc.Executable); - CWrite("ARCC_RCC_LIST_OPTIONS", cmJoin(this->Rcc.ListOptions, ";")); - - ofs << "# Rcc job\n"; - CWrite("ARCC_LOCK_FILE", qrc.LockFile); - CWrite("ARCC_SOURCE", qrc.QrcFile); - CWrite("ARCC_OUTPUT_CHECKSUM", qrc.PathChecksum); - CWrite("ARCC_OUTPUT_NAME", - cmSystemTools::GetFilenameName(qrc.RccFile)); - CWrite("ARCC_OPTIONS", cmJoin(qrc.Options, ";")); - CWrite("ARCC_INPUTS", cmJoin(qrc.Resources, ";")); - } else { - std::string err = "AutoRcc: Could not write file "; - err += qrc.InfoFile; - cmSystemTools::Error(err.c_str()); - return false; - } - } - } - - return true; -} - -bool cmQtAutoGenInitializer::SetupCustomTargetsMoc() -{ - cmLocalGenerator* localGen = this->Target->GetLocalGenerator(); - cmMakefile* makefile = this->Target->Target->GetMakefile(); - - // Moc predefs command - if (this->Target->GetPropertyAsBool("AUTOMOC_COMPILER_PREDEFINES") && - this->QtVersionGreaterOrEqual(5, 8)) { - this->Moc.PredefsCmd = - makefile->GetSafeDefinition("CMAKE_CXX_COMPILER_PREDEFINES_COMMAND"); - } - - // Moc includes and compile definitions - { - auto GetIncludeDirs = [this, - localGen](std::string const& cfg) -> 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 - std::vector<std::string> includeDirs; - localGen->GetIncludeDirectories(includeDirs, this->Target, "CXX", cfg, - false); - return cmJoin(includeDirs, ";"); - }; - auto GetCompileDefinitions = - [this, localGen](std::string const& cfg) -> std::string { - std::set<std::string> defines; - localGen->AddCompileDefinitions(defines, this->Target, cfg, "CXX"); - return cmJoin(defines, ";"); - }; - - // Default configuration settings - this->Moc.Includes = GetIncludeDirs(this->ConfigDefault); - this->Moc.Defines = GetCompileDefinitions(this->ConfigDefault); - // Other configuration settings - for (std::string const& cfg : this->ConfigsList) { - { - std::string const configIncludeDirs = GetIncludeDirs(cfg); - if (configIncludeDirs != this->Moc.Includes) { - this->Moc.ConfigIncludes[cfg] = configIncludeDirs; - } - } - { - std::string const configCompileDefs = GetCompileDefinitions(cfg); - if (configCompileDefs != this->Moc.Defines) { - this->Moc.ConfigDefines[cfg] = configCompileDefs; - } - } - } - } - - if (!GetMocExecutable()) { - return false; - } - - return true; -} - -bool cmQtAutoGenInitializer::SetupCustomTargetsUic() -{ - cmMakefile* makefile = this->Target->Target->GetMakefile(); - - // Uic search paths - { - std::string const usp = - this->Target->GetSafeProperty("AUTOUIC_SEARCH_PATHS"); - if (!usp.empty()) { - cmSystemTools::ExpandListArgument(usp, this->Uic.SearchPaths); - std::string const srcDir = makefile->GetCurrentSourceDirectory(); - for (std::string& path : this->Uic.SearchPaths) { - path = cmSystemTools::CollapseFullPath(path, srcDir); - } - } - } - // Uic target options - { - auto UicGetOpts = [this](std::string const& cfg) -> std::string { - std::vector<std::string> opts; - this->Target->GetAutoUicOptions(opts, cfg); - return cmJoin(opts, ";"); - }; - - // Default settings - this->Uic.Options = UicGetOpts(this->ConfigDefault); - - // Configuration specific settings - for (std::string const& cfg : this->ConfigsList) { - std::string const configUicOpts = UicGetOpts(cfg); - if (configUicOpts != this->Uic.Options) { - this->Uic.ConfigOptions[cfg] = configUicOpts; - } - } - } - // .ui files skip and options - { - std::string const uiExt = "ui"; - std::string pathError; - for (cmSourceFile* sf : makefile->GetSourceFiles()) { - // sf->GetExtension() is only valid after sf->GetFullPath() ... - // 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 const& fPath = sf->GetFullPath(&pathError); - if (!pathError.empty()) { - pathError.clear(); - continue; - } - if (sf->GetExtension() == uiExt) { - std::string const absFile = cmSystemTools::GetRealPath(fPath); - // Check if the .ui file should be skipped - if (sf->GetPropertyAsBool("SKIP_AUTOUIC") || - sf->GetPropertyAsBool("SKIP_AUTOGEN")) { - this->Uic.Skip.insert(absFile); - } - // Check if the .ui file has uic options - std::string const uicOpts = sf->GetSafeProperty("AUTOUIC_OPTIONS"); - if (!uicOpts.empty()) { - // Check if file isn't skipped - if (this->Uic.Skip.count(absFile) == 0) { - this->Uic.FileFiles.push_back(absFile); - std::vector<std::string> optsVec; - cmSystemTools::ExpandListArgument(uicOpts, optsVec); - this->Uic.FileOptions.push_back(std::move(optsVec)); - } - } - } - } - } - - if (!GetUicExecutable()) { - return false; - } - return true; } diff --git a/Source/cmQtAutoGenInitializer.h b/Source/cmQtAutoGenInitializer.h index 0999e0f..16f9cdd 100644 --- a/Source/cmQtAutoGenInitializer.h +++ b/Source/cmQtAutoGenInitializer.h @@ -12,6 +12,7 @@ #include <vector> class cmGeneratorTarget; +class cmTarget; /// @brief Initializes the QtAutoGen generators class cmQtAutoGenInitializer : public cmQtAutoGen @@ -38,6 +39,7 @@ public: std::string PathChecksum; std::string InfoFile; std::string SettingsFile; + std::map<std::string, std::string> ConfigSettingsFile; std::string RccFile; bool Generated; bool Unique; @@ -54,8 +56,16 @@ public: bool SetupCustomTargets(); private: - bool SetupCustomTargetsMoc(); - bool SetupCustomTargetsUic(); + bool InitMoc(); + bool InitUic(); + bool InitRcc(); + + bool InitScanFiles(); + bool InitAutogenTarget(); + bool InitRccTargets(); + + bool SetupWriteAutogenInfo(); + bool SetupWriteRccInfo(); void AddGeneratedSource(std::string const& filename, GeneratorT genType); @@ -72,7 +82,7 @@ private: private: cmGeneratorTarget* Target; - bool MultiConfig; + bool MultiConfig = false; // Qt std::string QtVersionMajor; std::string QtVersionMinor; @@ -86,17 +96,28 @@ private: std::string AutogenFolder; std::string AutogenInfoFile; std::string AutogenSettingsFile; + std::map<std::string, std::string> AutogenConfigSettingsFile; + std::set<std::string> AutogenDependFiles; + std::set<cmTarget*> AutogenDependTargets; // Directories std::string DirInfo; std::string DirBuild; std::string DirWork; - // Sources - std::vector<std::string> Headers; - std::vector<std::string> Sources; + std::string DirInclude; + std::map<std::string, std::string> DirConfigInclude; + // Moc and UIC + struct + { + // Sources + std::vector<std::string> Headers; + std::vector<std::string> Sources; + std::vector<std::string> HeadersGenerated; + std::vector<std::string> SourcesGenerated; + } MocUic; // Moc struct { - bool Enabled; + bool Enabled = false; std::string Executable; std::string PredefsCmd; std::set<std::string> Skip; @@ -104,11 +125,12 @@ private: std::map<std::string, std::string> ConfigIncludes; std::string Defines; std::map<std::string, std::string> ConfigDefines; + std::string MocsCompilation; } Moc; // Uic struct { - bool Enabled; + bool Enabled = false; std::string Executable; std::set<std::string> Skip; std::vector<std::string> SearchPaths; @@ -120,7 +142,7 @@ private: // Rcc struct { - bool Enabled; + bool Enabled = false; std::string Executable; std::vector<std::string> ListOptions; std::vector<Qrc> Qrcs; diff --git a/Source/cmQtAutoGeneratorMocUic.cxx b/Source/cmQtAutoGeneratorMocUic.cxx index a6b0247..c364700 100644 --- a/Source/cmQtAutoGeneratorMocUic.cxx +++ b/Source/cmQtAutoGeneratorMocUic.cxx @@ -1247,14 +1247,11 @@ bool cmQtAutoGeneratorMocUic::Init(cmMakefile* makefile) return false; } // include directory - { - std::string dirRel = InfoGetConfig("AM_INCLUDE_DIR"); - if (dirRel.empty()) { - Log().ErrorFile(GeneratorT::GEN, InfoFile(), - "Autogen include directory missing"); - return false; - } - Base_.AutogenIncludeDir = Base_.AbsoluteBuildPath(dirRel); + Base_.AutogenIncludeDir = InfoGetConfig("AM_INCLUDE_DIR"); + if (Base_.AutogenIncludeDir.empty()) { + Log().ErrorFile(GeneratorT::GEN, InfoFile(), + "Autogen include directory missing"); + return false; } // - Files diff --git a/Source/cmQtAutoGeneratorRcc.cxx b/Source/cmQtAutoGeneratorRcc.cxx index e49599f..6caa0d8 100644 --- a/Source/cmQtAutoGeneratorRcc.cxx +++ b/Source/cmQtAutoGeneratorRcc.cxx @@ -141,9 +141,7 @@ bool cmQtAutoGeneratorRcc::Init(cmMakefile* makefile) // Compute rcc output file name if (IsMultiConfig()) { - RccFileOutput_ = AutogenBuildDir_; - RccFileOutput_ += '/'; - RccFileOutput_ += IncludeDir_; + RccFileOutput_ = IncludeDir_; RccFileOutput_ += '/'; RccFileOutput_ += MultiConfigOutput(); } else { diff --git a/Tests/QtAutogen/CommonTests.cmake b/Tests/QtAutogen/CommonTests.cmake index cd05aeb..55d36e6 100644 --- a/Tests/QtAutogen/CommonTests.cmake +++ b/Tests/QtAutogen/CommonTests.cmake @@ -23,6 +23,9 @@ endif() if(QT_TEST_ALLOW_QT_MACROS) ADD_AUTOGEN_TEST(MocCMP0071) endif() +if(NOT QT_TEST_VERSION STREQUAL 4) + ADD_AUTOGEN_TEST(MocOsMacros mocOsMacros) +endif() ADD_AUTOGEN_TEST(UicInclude uicInclude) ADD_AUTOGEN_TEST(UicInterface QtAutoUicInterface) ADD_AUTOGEN_TEST(ObjectLibrary someProgram) diff --git a/Tests/QtAutogen/MocOsMacros/CMakeLists.txt b/Tests/QtAutogen/MocOsMacros/CMakeLists.txt new file mode 100644 index 0000000..51a0ebd --- /dev/null +++ b/Tests/QtAutogen/MocOsMacros/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.11) +project(MocOsMacros) +include("../AutogenTest.cmake") + +# Tests if moc processes the macro Q_OS_MAC + +set(CMAKE_AUTOMOC True) + +add_executable(mocOsMacros + main.cpp + TestClass.cpp + TestClass.hpp +) +target_link_libraries(mocOsMacros PRIVATE ${QT_QTCORE_TARGET}) + +message ( "CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES: ${CMAKE_CXX_IMPLICIT_INCLUDE_DIRECTORIES}" ) diff --git a/Tests/QtAutogen/MocOsMacros/TestClass.cpp b/Tests/QtAutogen/MocOsMacros/TestClass.cpp new file mode 100644 index 0000000..340d130 --- /dev/null +++ b/Tests/QtAutogen/MocOsMacros/TestClass.cpp @@ -0,0 +1,77 @@ +#include "TestClass.hpp" +#include <iostream> + +// -- Mac +#ifndef Q_OS_MAC +void TestClass::MacNotDef() +{ + std::cout << "MacNotDef\n"; +} +#else +void TestClass::MacNotDefElse() +{ + std::cout << "MacNotDefElse\n"; +} +#endif + +#ifdef Q_OS_MAC +void TestClass::MacDef() +{ + std::cout << "MacDef\n"; +} +#else +void TestClass::MacDefElse() +{ + std::cout << "MacDefElse\n"; +} +#endif + +// -- Unix +#ifndef Q_OS_UNIX +void TestClass::UnixNotDef() +{ + std::cout << "UnixNotDef\n"; +} +#else +void TestClass::UnixNotDefElse() +{ + std::cout << "UnixNotDefElse\n"; +} +#endif + +#ifdef Q_OS_UNIX +void TestClass::UnixDef() +{ + std::cout << "UnixDef\n"; +} +#else +void TestClass::UnixDefElse() +{ + std::cout << "UnixDefElse\n"; +} +#endif + +// -- Windows +#ifndef Q_OS_WIN +void TestClass::WindowsNotDef() +{ + std::cout << "WindowsNotDef\n"; +} +#else +void TestClass::WindowsNotDefElse() +{ + std::cout << "WindowsNotDefElse\n"; +} +#endif + +#ifdef Q_OS_WIN +void TestClass::WindowsDef() +{ + std::cout << "WindowsDef\n"; +} +#else +void TestClass::WindowsDefElse() +{ + std::cout << "WindowsDefElse\n"; +} +#endif diff --git a/Tests/QtAutogen/MocOsMacros/TestClass.hpp b/Tests/QtAutogen/MocOsMacros/TestClass.hpp new file mode 100644 index 0000000..53000aa --- /dev/null +++ b/Tests/QtAutogen/MocOsMacros/TestClass.hpp @@ -0,0 +1,52 @@ +#ifndef TestClass_hpp +#define TestClass_hpp + +#include <QObject> +#include <QtGlobal> + +class TestClass : public QObject +{ + Q_OBJECT +public Q_SLOTS: + +// -- Mac +#ifndef Q_OS_MAC + void MacNotDef(); +#else + void MacNotDefElse(); +#endif + +#ifdef Q_OS_MAC + void MacDef(); +#else + void MacDefElse(); +#endif + +// -- Unix +#ifndef Q_OS_UNIX + void UnixNotDef(); +#else + void UnixNotDefElse(); +#endif + +#ifdef Q_OS_UNIX + void UnixDef(); +#else + void UnixDefElse(); +#endif + +// -- Windows +#ifndef Q_OS_WIN + void WindowsNotDef(); +#else + void WindowsNotDefElse(); +#endif + +#ifdef Q_OS_WIN + void WindowsDef(); +#else + void WindowsDefElse(); +#endif +}; + +#endif /* TestClass_hpp */ diff --git a/Tests/QtAutogen/MocOsMacros/main.cpp b/Tests/QtAutogen/MocOsMacros/main.cpp new file mode 100644 index 0000000..f8eec3c --- /dev/null +++ b/Tests/QtAutogen/MocOsMacros/main.cpp @@ -0,0 +1,32 @@ +#include "TestClass.hpp" +#include <QtGlobal> + +int main() +{ + TestClass a; +#ifdef Q_OS_MAC + a.MacNotDefElse(); + a.MacDef(); +#else + a.MacNotDef(); + a.MacDefElse(); +#endif + +#ifdef Q_OS_UNIX + a.UnixNotDefElse(); + a.UnixDef(); +#else + a.UnixNotDef(); + a.UnixDefElse(); +#endif + +#ifdef Q_OS_WIN + a.WindowsNotDefElse(); + a.WindowsDef(); +#else + a.WindowsNotDef(); + a.WindowsDefElse(); +#endif + + return 0; +} |