diff options
Diffstat (limited to 'Source')
42 files changed, 652 insertions, 245 deletions
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 9202d03..d77680c 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,7 +1,7 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) set(CMake_VERSION_MINOR 28) -set(CMake_VERSION_PATCH 20240116) +set(CMake_VERSION_PATCH 20240124) #set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) diff --git a/Source/CTest/cmCTestGIT.cxx b/Source/CTest/cmCTestGIT.cxx index 984c837..99c5a2b 100644 --- a/Source/CTest/cmCTestGIT.cxx +++ b/Source/CTest/cmCTestGIT.cxx @@ -2,7 +2,6 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmCTestGIT.h" -#include <cctype> #include <cstdio> #include <cstdlib> #include <ctime> @@ -414,14 +413,14 @@ protected: const char* ConsumeSpace(const char* c) { - while (*c && isspace(*c)) { + while (*c && cmIsSpace(*c)) { ++c; } return c; } const char* ConsumeField(const char* c) { - while (*c && !isspace(*c)) { + while (*c && !cmIsSpace(*c)) { ++c; } return c; @@ -481,7 +480,7 @@ private: { // Person Name <person@domain.com> 1234567890 +0000 const char* c = str; - while (*c && isspace(*c)) { + while (*c && cmIsSpace(*c)) { ++c; } @@ -490,7 +489,7 @@ private: ++c; } const char* name_last = c; - while (name_last != name_first && isspace(*(name_last - 1))) { + while (name_last != name_first && cmIsSpace(*(name_last - 1))) { --name_last; } person.Name.assign(name_first, name_last - name_first); diff --git a/Source/cmCMakeHostSystemInformationCommand.cxx b/Source/cmCMakeHostSystemInformationCommand.cxx index 699e23b..e4160a1 100644 --- a/Source/cmCMakeHostSystemInformationCommand.cxx +++ b/Source/cmCMakeHostSystemInformationCommand.cxx @@ -178,7 +178,7 @@ cm::optional<std::pair<std::string, std::string>> ParseOSReleaseLine( if (std::isalpha(ch) || ch == '_') { key += ch; state = PARSE_KEY; - } else if (!std::isspace(ch)) { + } else if (!cmIsSpace(ch)) { state = IGNORE_REST; } break; @@ -238,7 +238,7 @@ cm::optional<std::pair<std::string, std::string>> ParseOSReleaseLine( break; case PARSE_VALUE: - if (ch == '#' || std::isspace(ch)) { + if (ch == '#' || cmIsSpace(ch)) { state = IGNORE_REST; } else { value += ch; diff --git a/Source/cmCMakeLanguageCommand.cxx b/Source/cmCMakeLanguageCommand.cxx index 329427c..9ffc363 100644 --- a/Source/cmCMakeLanguageCommand.cxx +++ b/Source/cmCMakeLanguageCommand.cxx @@ -398,6 +398,32 @@ bool cmCMakeLanguageCommand(std::vector<cmListFileArgument> const& args, if (!moreArgs()) { return FatalError(status, "called with incorrect number of arguments"); } + if (expArgs[expArg] == "EXIT"_s) { + ++expArg; // consume "EXIT". + + if (!moreArgs()) { + return FatalError(status, "EXIT requires one argument"); + } + + auto workingMode = + status.GetMakefile().GetCMakeInstance()->GetWorkingMode(); + if (workingMode != cmake::SCRIPT_MODE) { + return FatalError(status, "EXIT can be used only in SCRIPT mode"); + } + + long retCode = 0; + + if (!cmStrToLong(expArgs[expArg], &retCode)) { + return FatalError(status, + cmStrCat("EXIT requires one integral argument, got \"", + expArgs[expArg], '\"')); + } + + if (workingMode == cmake::SCRIPT_MODE) { + status.SetExitCode(static_cast<int>(retCode)); + } + return true; + } if (expArgs[expArg] == "SET_DEPENDENCY_PROVIDER"_s) { finishArgs(); diff --git a/Source/cmComputeLinkInformation.cxx b/Source/cmComputeLinkInformation.cxx index 40eb902..c985767 100644 --- a/Source/cmComputeLinkInformation.cxx +++ b/Source/cmComputeLinkInformation.cxx @@ -553,7 +553,8 @@ bool cmComputeLinkInformation::Compute() this->Target->GetType() == cmStateEnums::MODULE_LIBRARY || this->Target->GetType() == cmStateEnums::STATIC_LIBRARY || (this->Target->CanCompileSources() && - (this->Target->HaveCxx20ModuleSources() || + (this->Target->HaveCxxModuleSupport(this->Config) == + cmGeneratorTarget::Cxx20SupportLevel::Supported || this->Target->HaveFortranSources())))) { return false; } diff --git a/Source/cmConfigure.cmake.h.in b/Source/cmConfigure.cmake.h.in index de74716..23e4846 100644 --- a/Source/cmConfigure.cmake.h.in +++ b/Source/cmConfigure.cmake.h.in @@ -14,8 +14,13 @@ #pragma warning(disable : 1572) /* floating-point equality test */ #endif -#if defined(__LCC__) && defined(__EDG__) && (__LCC__ == 123) +#if defined(__LCC__) && defined(__EDG__) +#if __LCC__ == 123 #pragma diag_suppress 2910 /* excess -Wunused-function in 1.23.x */ +#elif __LCC__ == 121 +#pragma diag_suppress 2727 /* excess -Wunused-function in 1.21.x */ +#include <limits.h> /* ..._MIN, ..._MAX constants */ +#endif #endif #cmakedefine HAVE_ENVIRON_NOT_REQUIRE_PROTOTYPE diff --git a/Source/cmDebuggerExceptionManager.cxx b/Source/cmDebuggerExceptionManager.cxx index a27426c..470e44c 100644 --- a/Source/cmDebuggerExceptionManager.cxx +++ b/Source/cmDebuggerExceptionManager.cxx @@ -78,7 +78,7 @@ cmDebuggerExceptionManager::HandleExceptionInfoRequest() response.exceptionId = TheException->Id; response.breakMode = "always"; response.description = TheException->Description; - TheException = {}; + TheException = cm::nullopt; } return response; } diff --git a/Source/cmExecuteProcessCommand.cxx b/Source/cmExecuteProcessCommand.cxx index 483a601..da6def9 100644 --- a/Source/cmExecuteProcessCommand.cxx +++ b/Source/cmExecuteProcessCommand.cxx @@ -2,7 +2,6 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmExecuteProcessCommand.h" -#include <cctype> /* isspace */ #include <cstdint> #include <cstdio> #include <iostream> @@ -35,11 +34,7 @@ namespace { bool cmExecuteProcessCommandIsWhitespace(char c) { - // isspace takes 'int' but documents that the value must be representable - // by 'unsigned char', or EOF. Cast to 'unsigned char' to avoid sign - // extension while casting to 'int'. - return (isspace(static_cast<int>(static_cast<unsigned char>(c))) || - c == '\n' || c == '\r'); + return (cmIsSpace(c) || c == '\n' || c == '\r'); } void cmExecuteProcessCommandFixText(std::vector<char>& output, diff --git a/Source/cmExecutionStatus.h b/Source/cmExecutionStatus.h index ced3548..e023971 100644 --- a/Source/cmExecutionStatus.h +++ b/Source/cmExecutionStatus.h @@ -7,6 +7,8 @@ #include <string> #include <vector> +#include <cm/optional> + class cmMakefile; /** \class cmExecutionStatus @@ -53,6 +55,11 @@ public: void SetNestedError() { this->NestedError = true; } bool GetNestedError() const { return this->NestedError; } + void SetExitCode(int code) noexcept { this->ExitCode = code; } + bool HasExitCode() const noexcept { return this->ExitCode.has_value(); } + void CleanExitCode() noexcept { this->ExitCode.reset(); } + int GetExitCode() const noexcept { return this->ExitCode.value_or(-1); } + private: cmMakefile& Makefile; std::string Error; @@ -60,5 +67,6 @@ private: bool BreakInvoked = false; bool ContinueInvoked = false; bool NestedError = false; + cm::optional<int> ExitCode; std::vector<std::string> Variables; }; diff --git a/Source/cmExportBuildFileGenerator.cxx b/Source/cmExportBuildFileGenerator.cxx index 8ba8d97..81e3d54 100644 --- a/Source/cmExportBuildFileGenerator.cxx +++ b/Source/cmExportBuildFileGenerator.cxx @@ -3,6 +3,7 @@ #include "cmExportBuildFileGenerator.h" #include <algorithm> +#include <cstddef> #include <map> #include <memory> #include <set> @@ -12,6 +13,7 @@ #include <cm/string_view> #include <cmext/string_view> +#include "cmCryptoHash.h" #include "cmExportSet.h" #include "cmFileSet.h" #include "cmGeneratedFileStream.h" @@ -156,7 +158,19 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) this->GenerateTargetFileSets(gte, os); } - this->GenerateCxxModuleInformation(os); + std::string cxx_modules_name; + if (this->ExportSet) { + cxx_modules_name = this->ExportSet->GetName(); + } else { + cmCryptoHash hasher(cmCryptoHash::AlgoSHA3_512); + constexpr std::size_t HASH_TRUNCATION = 12; + for (auto const& target : this->Targets) { + hasher.Append(target.Name); + } + cxx_modules_name = hasher.FinalizeHex().substr(0, HASH_TRUNCATION); + } + + this->GenerateCxxModuleInformation(cxx_modules_name, os); // Generate import file content for each configuration. for (std::string const& c : this->Configurations) { @@ -165,7 +179,7 @@ bool cmExportBuildFileGenerator::GenerateMainFile(std::ostream& os) // Generate import file content for each configuration. for (std::string const& c : this->Configurations) { - this->GenerateImportCxxModuleConfigTargetInclusion(c); + this->GenerateImportCxxModuleConfigTargetInclusion(cxx_modules_name, c); } this->GenerateMissingTargetsCheckCode(os); @@ -526,7 +540,7 @@ std::string cmExportBuildFileGenerator::GetCxxModulesDirectory() const } void cmExportBuildFileGenerator::GenerateCxxModuleConfigInformation( - std::ostream& os) const + std::string const& name, std::ostream& os) const { const char* opt = ""; if (this->Configurations.size() > 1) { @@ -539,13 +553,13 @@ void cmExportBuildFileGenerator::GenerateCxxModuleConfigInformation( if (c.empty()) { c = "noconfig"; } - os << "include(\"${CMAKE_CURRENT_LIST_DIR}/cxx-modules-" << c << ".cmake\"" - << opt << ")\n"; + os << "include(\"${CMAKE_CURRENT_LIST_DIR}/cxx-modules-" << name << '-' + << c << ".cmake\"" << opt << ")\n"; } } bool cmExportBuildFileGenerator::GenerateImportCxxModuleConfigTargetInclusion( - std::string config) const + std::string const& name, std::string config) const { auto cxx_modules_dirname = this->GetCxxModulesDirectory(); if (cxx_modules_dirname.empty()) { @@ -556,8 +570,9 @@ bool cmExportBuildFileGenerator::GenerateImportCxxModuleConfigTargetInclusion( config = "noconfig"; } - std::string fileName = cmStrCat(this->FileDir, '/', cxx_modules_dirname, - "/cxx-modules-", config, ".cmake"); + std::string fileName = + cmStrCat(this->FileDir, '/', cxx_modules_dirname, "/cxx-modules-", name, + '-', config, ".cmake"); cmGeneratedFileStream os(fileName, true); if (!os) { diff --git a/Source/cmExportBuildFileGenerator.h b/Source/cmExportBuildFileGenerator.h index 9f11d13..ee4779f 100644 --- a/Source/cmExportBuildFileGenerator.h +++ b/Source/cmExportBuildFileGenerator.h @@ -105,8 +105,10 @@ protected: cmExportSet* GetExportSet() const override { return this->ExportSet; } std::string GetCxxModulesDirectory() const override; - void GenerateCxxModuleConfigInformation(std::ostream&) const override; - bool GenerateImportCxxModuleConfigTargetInclusion(std::string) const; + void GenerateCxxModuleConfigInformation(std::string const&, + std::ostream&) const override; + bool GenerateImportCxxModuleConfigTargetInclusion(std::string const&, + std::string) const; std::pair<std::vector<std::string>, std::string> FindBuildExportInfo( cmGlobalGenerator* gg, const std::string& name); diff --git a/Source/cmExportFileGenerator.cxx b/Source/cmExportFileGenerator.cxx index e2c3edd..f332007 100644 --- a/Source/cmExportFileGenerator.cxx +++ b/Source/cmExportFileGenerator.cxx @@ -1587,7 +1587,8 @@ void cmExportFileGenerator::GenerateTargetFileSets(cmGeneratorTarget* gte, } } -void cmExportFileGenerator::GenerateCxxModuleInformation(std::ostream& os) +void cmExportFileGenerator::GenerateCxxModuleInformation( + std::string const& name, std::ostream& os) { auto const cxx_module_dirname = this->GetCxxModulesDirectory(); if (cxx_module_dirname.empty()) { @@ -1597,19 +1598,19 @@ void cmExportFileGenerator::GenerateCxxModuleInformation(std::ostream& os) // Write the include. os << "# Include C++ module properties\n" << "include(\"${CMAKE_CURRENT_LIST_DIR}/" << cxx_module_dirname - << "/cxx-modules.cmake\")\n\n"; + << "/cxx-modules-" << name << ".cmake\")\n\n"; // Get the path to the file we're going to write. std::string path = this->MainImportFile; path = cmSystemTools::GetFilenamePath(path); auto trampoline_path = - cmStrCat(path, '/', cxx_module_dirname, "/cxx-modules.cmake"); + cmStrCat(path, '/', cxx_module_dirname, "/cxx-modules-", name, ".cmake"); // Include all configuration-specific include files. cmGeneratedFileStream ap(trampoline_path, true); ap.SetCopyIfDifferent(true); - this->GenerateCxxModuleConfigInformation(ap); + this->GenerateCxxModuleConfigInformation(name, ap); } void cmExportFileGenerator::SetRequiredCMakeVersion(unsigned int major, diff --git a/Source/cmExportFileGenerator.h b/Source/cmExportFileGenerator.h index 554dd4a..f619576 100644 --- a/Source/cmExportFileGenerator.h +++ b/Source/cmExportFileGenerator.h @@ -192,7 +192,7 @@ protected: void GenerateTargetFileSets(cmGeneratorTarget* gte, std::ostream& os, cmTargetExport* te = nullptr); - void GenerateCxxModuleInformation(std::ostream& os); + void GenerateCxxModuleInformation(std::string const& name, std::ostream& os); virtual std::string GetFileSetDirectories(cmGeneratorTarget* gte, cmFileSet* fileSet, @@ -253,5 +253,6 @@ private: const std::string& config) = 0; virtual std::string GetCxxModulesDirectory() const = 0; - virtual void GenerateCxxModuleConfigInformation(std::ostream& os) const = 0; + virtual void GenerateCxxModuleConfigInformation(std::string const&, + std::ostream& os) const = 0; }; diff --git a/Source/cmExportInstallFileGenerator.cxx b/Source/cmExportInstallFileGenerator.cxx index 64e694c..c5b9dc9 100644 --- a/Source/cmExportInstallFileGenerator.cxx +++ b/Source/cmExportInstallFileGenerator.cxx @@ -170,10 +170,12 @@ bool cmExportInstallFileGenerator::GenerateMainFile(std::ostream& os) bool result = true; - this->GenerateCxxModuleInformation(os); + std::string cxx_modules_name = this->IEGen->GetExportSet()->GetName(); + this->GenerateCxxModuleInformation(cxx_modules_name, os); if (requiresConfigFiles) { for (std::string const& c : this->Configurations) { - if (!this->GenerateImportCxxModuleConfigTargetInclusion(c)) { + if (!this->GenerateImportCxxModuleConfigTargetInclusion(cxx_modules_name, + c)) { result = false; } } @@ -724,12 +726,12 @@ std::string cmExportInstallFileGenerator::GetCxxModulesDirectory() const } void cmExportInstallFileGenerator::GenerateCxxModuleConfigInformation( - std::ostream& os) const + std::string const& name, std::ostream& os) const { // Now load per-configuration properties for them. /* clang-format off */ os << "# Load information for each installed configuration.\n" - "file(GLOB _cmake_cxx_module_includes \"${CMAKE_CURRENT_LIST_DIR}/cxx-modules-*.cmake\")\n" + "file(GLOB _cmake_cxx_module_includes \"${CMAKE_CURRENT_LIST_DIR}/cxx-modules-" << name << "-*.cmake\")\n" "foreach(_cmake_cxx_module_include IN LISTS _cmake_cxx_module_includes)\n" " include(\"${_cmake_cxx_module_include}\")\n" "endforeach()\n" @@ -739,7 +741,8 @@ void cmExportInstallFileGenerator::GenerateCxxModuleConfigInformation( } bool cmExportInstallFileGenerator:: - GenerateImportCxxModuleConfigTargetInclusion(std::string const& config) + GenerateImportCxxModuleConfigTargetInclusion(std::string const& name, + std::string const& config) { auto cxx_modules_dirname = this->GetCxxModulesDirectory(); if (cxx_modules_dirname.empty()) { @@ -754,7 +757,7 @@ bool cmExportInstallFileGenerator:: std::string const dest = cmStrCat(this->FileDir, '/', cxx_modules_dirname, '/'); std::string fileName = - cmStrCat(dest, "cxx-modules-", filename_config, ".cmake"); + cmStrCat(dest, "cxx-modules-", name, '-', filename_config, ".cmake"); cmGeneratedFileStream os(fileName, true); if (!os) { diff --git a/Source/cmExportInstallFileGenerator.h b/Source/cmExportInstallFileGenerator.h index 9de0c8e..7a72584 100644 --- a/Source/cmExportInstallFileGenerator.h +++ b/Source/cmExportInstallFileGenerator.h @@ -119,8 +119,10 @@ protected: cmTargetExport* te) override; std::string GetCxxModulesDirectory() const override; - void GenerateCxxModuleConfigInformation(std::ostream&) const override; - bool GenerateImportCxxModuleConfigTargetInclusion(std::string const&); + void GenerateCxxModuleConfigInformation(std::string const&, + std::ostream&) const override; + bool GenerateImportCxxModuleConfigTargetInclusion(std::string const&, + std::string const&); cmExportSet* GetExportSet() const override { diff --git a/Source/cmExportTryCompileFileGenerator.h b/Source/cmExportTryCompileFileGenerator.h index 5c34fad..4c7d287 100644 --- a/Source/cmExportTryCompileFileGenerator.h +++ b/Source/cmExportTryCompileFileGenerator.h @@ -56,7 +56,10 @@ protected: cmTargetExport* te) override; std::string GetCxxModulesDirectory() const override { return {}; } - void GenerateCxxModuleConfigInformation(std::ostream&) const override {} + void GenerateCxxModuleConfigInformation(std::string const&, + std::ostream&) const override + { + } private: std::string FindTargets(const std::string& prop, diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 11253db..ac8bc67 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -3578,7 +3578,7 @@ void cmGeneratorTarget::AddCUDAArchitectureFlagsImpl(cmBuildStep compileOrLink, flags += "]\""; } - } else if (compiler == "Clang") { + } else if (compiler == "Clang" && compileOrLink == cmBuildStep::Compile) { for (CudaArchitecture& architecture : architectures) { flags += " --cuda-gpu-arch=sm_" + architecture.name; @@ -8417,14 +8417,14 @@ bool cmGeneratorTarget::DiscoverSyntheticTargets(cmSyntheticTargetCache& cache, } if (gt->HaveCxx20ModuleSources()) { - auto hasher = cmCryptoHash::New("SHA3_512"); + cmCryptoHash hasher(cmCryptoHash::AlgoSHA3_512); constexpr size_t HASH_TRUNCATION = 12; - auto dirhash = hasher->HashString( + auto dirhash = hasher.HashString( gt->GetLocalGenerator()->GetCurrentBinaryDirectory()); std::string safeName = gt->GetName(); cmSystemTools::ReplaceString(safeName, ":", "_"); auto targetIdent = - hasher->HashString(cmStrCat("@d_", dirhash, "@u_", usage.GetHash())); + hasher.HashString(cmStrCat("@d_", dirhash, "@u_", usage.GetHash())); std::string targetName = cmStrCat(safeName, "@synth_", targetIdent.substr(0, HASH_TRUNCATION)); diff --git a/Source/cmImportedCxxModuleInfo.cxx b/Source/cmImportedCxxModuleInfo.cxx index 9e3ac9a..c54b265 100644 --- a/Source/cmImportedCxxModuleInfo.cxx +++ b/Source/cmImportedCxxModuleInfo.cxx @@ -4,7 +4,6 @@ #include "cmImportedCxxModuleInfo.h" #include <cstddef> -#include <memory> #include <string> #include <utility> #include <vector> @@ -60,13 +59,13 @@ std::string ImportedCxxModuleLookup::BmiNameForSource(std::string const& path) auto importit = this->ImportedInfo.find(path); std::string bmiName; - auto hasher = cmCryptoHash::New("SHA3_512"); + cmCryptoHash hasher(cmCryptoHash::AlgoSHA3_512); constexpr size_t HASH_TRUNCATION = 12; if (importit != this->ImportedInfo.end()) { - auto safename = hasher->HashString(importit->second.Name); + auto safename = hasher.HashString(importit->second.Name); bmiName = cmStrCat(safename.substr(0, HASH_TRUNCATION), ".bmi"); } else { - auto dirhash = hasher->HashString(path); + auto dirhash = hasher.HashString(path); bmiName = cmStrCat(dirhash.substr(0, HASH_TRUNCATION), ".bmi"); } diff --git a/Source/cmInstallExportGenerator.cxx b/Source/cmInstallExportGenerator.cxx index 72f0ac7..2f3da3e 100644 --- a/Source/cmInstallExportGenerator.cxx +++ b/Source/cmInstallExportGenerator.cxx @@ -160,10 +160,11 @@ void cmInstallExportGenerator::GenerateScriptConfigs(std::ostream& os, // Remove old per-configuration export files if the main changes. std::string installedDir = cmStrCat( "$ENV{DESTDIR}", ConvertToAbsoluteDestination(cxx_module_dest), '/'); - std::string installedFile = cmStrCat(installedDir, "/cxx-modules.cmake"); + std::string installedFile = cmStrCat(installedDir, "/cxx-modules-", + this->ExportSet->GetName(), ".cmake"); std::string toInstallFile = cmStrCat(cmSystemTools::GetFilenamePath(config_file_example), - "/cxx-modules.cmake"); + "/cxx-modules-", this->ExportSet->GetName(), ".cmake"); os << indent << "if(EXISTS \"" << installedFile << "\")\n"; Indent indentN = indent.Next(); Indent indentNN = indentN.Next(); diff --git a/Source/cmMakefile.cxx b/Source/cmMakefile.cxx index 936b282..2687afa 100644 --- a/Source/cmMakefile.cxx +++ b/Source/cmMakefile.cxx @@ -529,6 +529,12 @@ bool cmMakefile::ExecuteCommand(const cmListFileFunction& lff, cmSystemTools::SetFatalErrorOccurred(); } } + if (this->GetCMakeInstance()->HasScriptModeExitCode() && + this->GetCMakeInstance()->GetWorkingMode() == cmake::SCRIPT_MODE) { + // pass-through the exit code from inner cmake_language(EXIT) , + // possibly from include() or similar command... + status.SetExitCode(this->GetCMakeInstance()->GetScriptModeExitCode()); + } } } else { if (!cmSystemTools::GetFatalErrorOccurred()) { @@ -898,6 +904,11 @@ void cmMakefile::RunListFile(cmListFile const& listFile, if (cmSystemTools::GetFatalErrorOccurred()) { break; } + if (status.HasExitCode()) { + // cmake_language EXIT was requested, early break. + this->GetCMakeInstance()->SetScriptModeExitCode(status.GetExitCode()); + break; + } if (status.GetReturnInvoked()) { this->RaiseScope(status.GetReturnVariables()); // Exit early due to return command. @@ -1427,8 +1438,8 @@ static void s_RemoveDefineFlag(std::string const& flag, std::string& dflags) for (std::string::size_type lpos = dflags.find(flag, 0); lpos != std::string::npos; lpos = dflags.find(flag, lpos)) { std::string::size_type rpos = lpos + len; - if ((lpos <= 0 || isspace(dflags[lpos - 1])) && - (rpos >= dflags.size() || isspace(dflags[rpos]))) { + if ((lpos <= 0 || cmIsSpace(dflags[lpos - 1])) && + (rpos >= dflags.size() || cmIsSpace(dflags[rpos]))) { dflags.erase(lpos, len); } else { ++lpos; diff --git a/Source/cmQtAutoGen.h b/Source/cmQtAutoGen.h index 5a23ae9..b302403 100644 --- a/Source/cmQtAutoGen.h +++ b/Source/cmQtAutoGen.h @@ -6,6 +6,7 @@ #include <memory> #include <string> +#include <unordered_map> #include <vector> #include <cm/string_view> @@ -16,6 +17,22 @@ class cmQtAutoGen { public: + /** String value with per configuration variants. */ + class ConfigString + { + public: + std::string Default; + std::unordered_map<std::string, std::string> Config; + }; + + /** String values with per configuration variants. */ + template <typename C> + class ConfigStrings + { + public: + C Default; + std::unordered_map<std::string, C> Config; + }; /** Integer version. */ struct IntegerVersion { diff --git a/Source/cmQtAutoGenGlobalInitializer.cxx b/Source/cmQtAutoGenGlobalInitializer.cxx index 1da8847..5e2f99f 100644 --- a/Source/cmQtAutoGenGlobalInitializer.cxx +++ b/Source/cmQtAutoGenGlobalInitializer.cxx @@ -213,24 +213,81 @@ void cmQtAutoGenGlobalInitializer::AddToGlobalAutoRcc( } } -cmQtAutoGen::CompilerFeaturesHandle +cmQtAutoGen::ConfigStrings<cmQtAutoGen::CompilerFeaturesHandle> cmQtAutoGenGlobalInitializer::GetCompilerFeatures( - std::string const& generator, std::string const& executable, - std::string& error) + std::string const& generator, cmQtAutoGen::ConfigString const& executable, + std::string& error, bool const isMultiConfig, bool UseBetterGraph) { + cmQtAutoGen::ConfigStrings<cmQtAutoGen::CompilerFeaturesHandle> res; + if (isMultiConfig && UseBetterGraph) { + for (auto const& config : executable.Config) { + auto const exe = config.second; + // Check if we have cached features + { + auto it = this->CompilerFeatures_.Config[config.first].find(exe); + if (it != this->CompilerFeatures_.Config[config.first].end()) { + res.Config[config.first] = it->second; + continue; + } + } + + // Check if the executable exists + if (!cmSystemTools::FileExists(exe, true)) { + error = cmStrCat("The \"", generator, "\" executable ", + cmQtAutoGen::Quoted(exe), " does not exist."); + res.Config[config.first] = {}; + continue; + } + + // Test the executable + std::string stdOut; + { + std::string stdErr; + std::vector<std::string> command; + command.emplace_back(exe); + command.emplace_back("-h"); + int retVal = 0; + const bool runResult = cmSystemTools::RunSingleCommand( + command, &stdOut, &stdErr, &retVal, nullptr, + cmSystemTools::OUTPUT_NONE, cmDuration::zero(), + cmProcessOutput::Auto); + if (!runResult) { + error = cmStrCat("Test run of \"", generator, "\" executable ", + cmQtAutoGen::Quoted(exe), " failed.\n", + cmQtAutoGen::QuotedCommand(command), '\n', stdOut, + '\n', stdErr); + res.Config[config.first] = {}; + continue; + } + } + + // Create valid handle + res.Config[config.first] = + std::make_shared<cmQtAutoGen::CompilerFeatures>(); + res.Config[config.first]->HelpOutput = std::move(stdOut); + + // Register compiler features + this->CompilerFeatures_.Config[config.first].emplace( + exe, res.Config[config.first]); + } + return res; + } + // Check if we have cached features { - auto it = this->CompilerFeatures_.find(executable); - if (it != this->CompilerFeatures_.end()) { - return it->second; + auto it = this->CompilerFeatures_.Default.find(executable.Default); + if (it != this->CompilerFeatures_.Default.end()) { + res.Default = it->second; + return res; } } // Check if the executable exists - if (!cmSystemTools::FileExists(executable, true)) { - error = cmStrCat("The \"", generator, "\" executable ", - cmQtAutoGen::Quoted(executable), " does not exist."); - return cmQtAutoGen::CompilerFeaturesHandle(); + if (!cmSystemTools::FileExists(executable.Default, true)) { + error = + cmStrCat("The \"", generator, "\" executable ", + cmQtAutoGen::Quoted(executable.Default), " does not exist."); + return cmQtAutoGen::ConfigStrings<cmQtAutoGen::CompilerFeaturesHandle>(); } // Test the executable @@ -238,7 +295,7 @@ cmQtAutoGenGlobalInitializer::GetCompilerFeatures( { std::string stdErr; std::vector<std::string> command; - command.emplace_back(executable); + command.emplace_back(executable.Default); command.emplace_back("-h"); int retVal = 0; const bool runResult = cmSystemTools::RunSingleCommand( @@ -246,20 +303,18 @@ cmQtAutoGenGlobalInitializer::GetCompilerFeatures( cmDuration::zero(), cmProcessOutput::Auto); if (!runResult) { error = cmStrCat("Test run of \"", generator, "\" executable ", - cmQtAutoGen::Quoted(executable), " failed.\n", + cmQtAutoGen::Quoted(executable.Default), " failed.\n", cmQtAutoGen::QuotedCommand(command), '\n', stdOut, '\n', stdErr); - return cmQtAutoGen::CompilerFeaturesHandle(); + return cmQtAutoGen::ConfigStrings<cmQtAutoGen::CompilerFeaturesHandle>(); } } - // Create valid handle - cmQtAutoGen::CompilerFeaturesHandle res = - std::make_shared<cmQtAutoGen::CompilerFeatures>(); - res->HelpOutput = std::move(stdOut); + res.Default = std::make_shared<cmQtAutoGen::CompilerFeatures>(); + res.Default->HelpOutput = std::move(stdOut); // Register compiler features - this->CompilerFeatures_.emplace(executable, res); + this->CompilerFeatures_.Default.emplace(executable.Default, res.Default); return res; } diff --git a/Source/cmQtAutoGenGlobalInitializer.h b/Source/cmQtAutoGenGlobalInitializer.h index e8569a5..c1c4758 100644 --- a/Source/cmQtAutoGenGlobalInitializer.h +++ b/Source/cmQtAutoGenGlobalInitializer.h @@ -66,14 +66,17 @@ private: void AddToGlobalAutoRcc(cmLocalGenerator* localGen, std::string const& targetName); - cmQtAutoGen::CompilerFeaturesHandle GetCompilerFeatures( - std::string const& generator, std::string const& executable, - std::string& error); + cmQtAutoGen::ConfigStrings<cmQtAutoGen::CompilerFeaturesHandle> + GetCompilerFeatures(std::string const& generator, + cmQtAutoGen::ConfigString const& executable, + std::string& error, bool isMultiConfig, + bool UseBetterGraph); std::vector<std::unique_ptr<cmQtAutoGenInitializer>> Initializers_; std::map<cmLocalGenerator*, std::string> GlobalAutoGenTargets_; std::map<cmLocalGenerator*, std::string> GlobalAutoRccTargets_; - std::unordered_map<std::string, cmQtAutoGen::CompilerFeaturesHandle> + cmQtAutoGen::ConfigStrings< + std::unordered_map<std::string, cmQtAutoGen::CompilerFeaturesHandle>> CompilerFeatures_; Keywords const Keywords_; }; diff --git a/Source/cmQtAutoGenInitializer.cxx b/Source/cmQtAutoGenInitializer.cxx index 8213274..ff6be2a 100644 --- a/Source/cmQtAutoGenInitializer.cxx +++ b/Source/cmQtAutoGenInitializer.cxx @@ -2,6 +2,7 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmQtAutoGenInitializer.h" +#include <array> #include <cstddef> #include <deque> #include <initializer_list> @@ -17,6 +18,7 @@ #include <cm/algorithm> #include <cm/iterator> #include <cm/memory> +#include <cm/string_view> #include <cmext/algorithm> #include <cmext/string_view> @@ -301,15 +303,22 @@ bool InfoWriter::Save(std::string const& filename) return fileStream.Close(); } -void AddAutogenExecutableToDependencies( - cmQtAutoGenInitializer::GenVarsT const& genVars, - std::vector<std::string>& dependencies) +cmQtAutoGen::ConfigStrings<std::vector<std::string>> generateListOptions( + cmQtAutoGen::ConfigStrings<cmQtAutoGen::CompilerFeaturesHandle> const& + executableFeatures, + bool IsMultiConfig) { - if (genVars.ExecutableTarget != nullptr) { - dependencies.push_back(genVars.ExecutableTarget->Target->GetName()); - } else if (!genVars.Executable.empty()) { - dependencies.push_back(genVars.Executable); + cmQtAutoGen::ConfigStrings<std::vector<std::string>> tempListOptions; + if (IsMultiConfig) { + for (auto const& executableFeature : executableFeatures.Config) { + tempListOptions.Config[executableFeature.first] = + executableFeature.second->ListOptions; + } + } else { + tempListOptions.Default = executableFeatures.Default->ListOptions; } + + return tempListOptions; } } // End of unnamed namespace @@ -334,6 +343,42 @@ cmQtAutoGenInitializer::cmQtAutoGenInitializer( this->Rcc.GlobalTarget = globalAutoRccTarget; this->CrossConfig = !this->Makefile->GetSafeDefinition("CMAKE_CROSS_CONFIGS").empty(); + this->UseBetterGraph = + this->GenTarget->GetProperty("AUTOGEN_BETTER_GRAPH_MULTI_CONFIG").IsSet() + ? this->GenTarget->GetProperty("AUTOGEN_BETTER_GRAPH_MULTI_CONFIG").IsOn() + : (this->QtVersion >= IntegerVersion(6, 8)); + // AUTOGEN_BETTER_GRAPH_MULTI_CONFIG is set explicitly because it is read by + // the qt library + this->GenTarget->Target->SetProperty("AUTOGEN_BETTER_GRAPH_MULTI_CONFIG", + this->UseBetterGraph ? "ON" : "OFF"); +} + +void cmQtAutoGenInitializer::AddAutogenExecutableToDependencies( + cmQtAutoGenInitializer::GenVarsT const& genVars, + std::vector<std::string>& dependencies) const +{ + if (genVars.ExecutableTarget != nullptr) { + dependencies.push_back(genVars.ExecutableTarget->Target->GetName()); + } else if (this->MultiConfig && this->UseBetterGraph) { + cm::string_view const& configGenexWithCommandConfig = + "$<COMMAND_CONFIG:$<$<CONFIG:"; + cm::string_view const& configGenex = "$<$<CONFIG:"; + cm::string_view const& configGenexEnd = ">"; + cm::string_view const& configGenexEndWithCommandConfig = ">>"; + auto genexBegin = + this->CrossConfig ? configGenexWithCommandConfig : configGenex; + auto genexEnd = + this->CrossConfig ? configGenexEndWithCommandConfig : configGenexEnd; + for (auto const& config : genVars.Executable.Config) { + auto executableWithConfig = + cmStrCat(genexBegin, config.first, ">:", config.second, genexEnd); + dependencies.emplace_back(std::move(executableWithConfig)); + } + } else { + if (!genVars.Executable.Default.empty()) { + dependencies.push_back(genVars.Executable.Default); + } + } } bool cmQtAutoGenInitializer::InitCustomTargets() @@ -811,18 +856,30 @@ bool cmQtAutoGenInitializer::InitRcc() return false; } // Evaluate test output on demand - CompilerFeatures& features = *this->Rcc.ExecutableFeatures; - if (!features.Evaluated) { - // Look for list options - if (this->QtVersion.Major == 5 || this->QtVersion.Major == 6) { - if (features.HelpOutput.find("--list") != std::string::npos) { - features.ListOptions.emplace_back("--list"); - } else if (features.HelpOutput.find("-list") != std::string::npos) { - features.ListOptions.emplace_back("-list"); + auto& features = this->Rcc.ExecutableFeatures; + auto checkAndAddOptions = [this](CompilerFeaturesHandle& feature) { + if (!feature->Evaluated) { + // Look for list options + if (this->QtVersion.Major == 5 || this->QtVersion.Major == 6) { + static std::array<std::string, 2> const listOptions{ { "--list", + "-list" } }; + for (std::string const& opt : listOptions) { + if (feature->HelpOutput.find(opt) != std::string::npos) { + feature->ListOptions.emplace_back(opt); + break; + } + } } + // Evaluation finished + feature->Evaluated = true; } - // Evaluation finished - features.Evaluated = true; + }; + if (this->MultiConfig && this->UseBetterGraph) { + for (auto const& config : this->ConfigsList) { + checkAndAddOptions(features.Config[config]); + } + } else { + checkAndAddOptions(features.Default); } } @@ -1158,8 +1215,14 @@ bool cmQtAutoGenInitializer::InitScanFiles() // Path checksum qrc.QrcPathChecksum = this->PathCheckSum.getPart(qrc.QrcFile); // Output file name - qrc.OutputFile = cmStrCat(this->Dir.Build, '/', qrc.QrcPathChecksum, - "/qrc_", qrc.QrcName, ".cpp"); + if (this->MultiConfig && !this->GlobalGen->IsXcode() && + this->UseBetterGraph) { + qrc.OutputFile = cmStrCat(this->Dir.Build, '/', qrc.QrcPathChecksum, + "_$<CONFIG>", "/qrc_", qrc.QrcName, ".cpp"); + } else { + qrc.OutputFile = cmStrCat(this->Dir.Build, '/', qrc.QrcPathChecksum, + "/qrc_", qrc.QrcName, ".cpp"); + } std::string const base = cmStrCat(this->Dir.Info, "/AutoRcc_", qrc.QrcName, '_', qrc.QrcPathChecksum); qrc.LockFile = cmStrCat(base, "_Lock.lock"); @@ -1191,11 +1254,25 @@ bool cmQtAutoGenInitializer::InitScanFiles() for (Qrc& qrc : this->Rcc.Qrcs) { if (!qrc.Generated) { std::string error; - RccLister const lister(this->Rcc.Executable, - this->Rcc.ExecutableFeatures->ListOptions); - if (!lister.list(qrc.QrcFile, qrc.Resources, error)) { - cmSystemTools::Error(error); - return false; + if (this->MultiConfig && this->UseBetterGraph) { + for (auto const& config : this->ConfigsList) { + RccLister const lister( + this->Rcc.Executable.Config[config], + this->Rcc.ExecutableFeatures.Config[config]->ListOptions); + if (!lister.list(qrc.QrcFile, qrc.Resources.Config[config], + error)) { + cmSystemTools::Error(error); + return false; + } + } + } else { + RccLister const lister( + this->Rcc.Executable.Default, + this->Rcc.ExecutableFeatures.Default->ListOptions); + if (!lister.list(qrc.QrcFile, qrc.Resources.Default, error)) { + cmSystemTools::Error(error); + return false; + } } } } @@ -1223,8 +1300,9 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() if (this->Moc.Enabled) { this->AddGeneratedSource(this->Moc.CompilationFile, this->Moc, true); if (useDepfile) { - if (this->MultiConfig && this->CrossConfig && - this->GlobalGen->GetName().find("Ninja") != std::string::npos) { + if (this->CrossConfig && + this->GlobalGen->GetName().find("Ninja") != std::string::npos && + !this->UseBetterGraph) { // Make all mocs_compilation_<CONFIG>.cpp files byproducts of the // ${target}_autogen/timestamp custom command. // We cannot just use Moc.CompilationFileGenex here, because that @@ -1267,28 +1345,11 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() // Compose command lines // FIXME: Take advantage of our per-config mocs_compilation_$<CONFIG>.cpp // instead of fiddling with the include directories - std::vector<std::string> configs; - this->GlobalGen->GetQtAutoGenConfigs(configs); + bool constexpr stdPipesUTF8 = true; cmCustomCommandLines commandLines; - if (!this->CrossConfig) { - std::string autogenInfoFileConfig; - if (this->MultiConfig) { - autogenInfoFileConfig = "$<CONFIG>"; - } else { - autogenInfoFileConfig = configs[0]; - } - commandLines.push_back(cmMakeCommandLine( - { cmSystemTools::GetCMakeCommand(), "-E", "cmake_autogen", - this->AutogenTarget.InfoFile, autogenInfoFileConfig })); - - } else { - for (auto const& config : configs) { - commandLines.push_back(cmMakeCommandLine( - { cmSystemTools::GetCMakeCommand(), "-E", "cmake_autogen", - this->AutogenTarget.InfoFile, config })); - } - } + AddCMakeProcessToCommandLines(this->AutogenTarget.InfoFile, "cmake_autogen", + commandLines); // Use PRE_BUILD on demand bool usePRE_BUILD = false; @@ -1456,18 +1517,47 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() AddAutogenExecutableToDependencies(this->Moc, dependencies); AddAutogenExecutableToDependencies(this->Uic, dependencies); - + std::string outputFile; + std::string depFile; // Create the custom command that outputs the timestamp file. - const char timestampFileName[] = "timestamp"; - const std::string outputFile = - cmStrCat(this->Dir.Build, "/", timestampFileName); - this->AutogenTarget.DepFile = cmStrCat(this->Dir.Build, "/deps"); - this->AutogenTarget.DepFileRuleName = - cmStrCat(this->Dir.RelativeBuild, "/", timestampFileName); - commandLines.push_back(cmMakeCommandLine( - { cmSystemTools::GetCMakeCommand(), "-E", "touch", outputFile })); - - this->AddGeneratedSource(outputFile, this->Moc); + if (this->MultiConfig && this->UseBetterGraph) { + // create timestamp file with $<CONFIG> in the name so that + // every cmake_autogen target has its own timestamp file + std::string const configView = "$<CONFIG>"; + std::string const timestampFileWithoutConfig = "timestamp_"; + std::string const depFileWithoutConfig = + cmStrCat(this->Dir.Build, "/deps_"); + std::string const timestampFileName = + timestampFileWithoutConfig + configView; + outputFile = cmStrCat(this->Dir.Build, "/", timestampFileName); + auto const depFileWithConfig = + cmStrCat(depFileWithoutConfig, configView); + depFile = depFileWithConfig; + commandLines.push_back(cmMakeCommandLine( + { cmSystemTools::GetCMakeCommand(), "-E", "touch", outputFile })); + + ConfigString outputFileWithConfig; + for (std::string const& config : this->ConfigsList) { + auto tempTimestampFileName = timestampFileWithoutConfig + config; + auto tempDepFile = depFileWithoutConfig + config; + outputFileWithConfig.Config[config] = tempTimestampFileName; + this->AutogenTarget.DepFileRuleName.Config[config] = + cmStrCat(this->Dir.RelativeBuild, "/", tempTimestampFileName); + this->AutogenTarget.DepFile.Config[config] = tempDepFile; + } + this->AddGeneratedSource(outputFileWithConfig, this->Moc); + } else { + cm::string_view const timestampFileName = "timestamp"; + outputFile = cmStrCat(this->Dir.Build, "/", timestampFileName); + this->AutogenTarget.DepFile.Default = + cmStrCat(this->Dir.Build, "/deps"); + depFile = this->AutogenTarget.DepFile.Default; + this->AutogenTarget.DepFileRuleName.Default = + cmStrCat(this->Dir.RelativeBuild, "/", timestampFileName); + commandLines.push_back(cmMakeCommandLine( + { cmSystemTools::GetCMakeCommand(), "-E", "touch", outputFile })); + this->AddGeneratedSource(outputFile, this->Moc); + } cc = cm::make_unique<cmCustomCommand>(); cc->SetOutputs(outputFile); cc->SetByproducts(timestampByproducts); @@ -1476,14 +1566,11 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() cc->SetComment(autogenComment.c_str()); cc->SetWorkingDirectory(this->Dir.Work.c_str()); cc->SetEscapeOldStyle(false); - cc->SetDepfile(this->AutogenTarget.DepFile); + cc->SetDepfile(depFile); cc->SetStdPipesUTF8(stdPipesUTF8); this->LocalGen->AddCustomCommandToOutput(std::move(cc)); - - // Alter variables for the autogen target which now merely wraps the - // custom command dependencies.clear(); - dependencies.emplace_back(outputFile); + dependencies.emplace_back(std::move(outputFile)); commandLines.clear(); autogenComment.clear(); } @@ -1535,6 +1622,36 @@ bool cmQtAutoGenInitializer::InitAutogenTarget() return true; } +void cmQtAutoGenInitializer::AddCMakeProcessToCommandLines( + std::string const& infoFile, std::string const& processName, + cmCustomCommandLines& commandLines) +{ + if (this->CrossConfig && this->UseBetterGraph) { + commandLines.push_back(cmMakeCommandLine( + { cmSystemTools::GetCMakeCommand(), "-E", processName, infoFile, + "$<CONFIG>", "$<COMMAND_CONFIG:$<CONFIG>>" })); + } else if ((this->MultiConfig && this->GlobalGen->IsXcode()) || + this->CrossConfig) { + for (std::string const& config : this->ConfigsList) { + commandLines.push_back( + cmMakeCommandLine({ cmSystemTools::GetCMakeCommand(), "-E", + processName, infoFile, config })); + } + } else { + std::string autoInfoFileConfig; + if (this->MultiConfig) { + autoInfoFileConfig = "$<CONFIG>"; + } else { + std::vector<std::string> configs; + this->GlobalGen->GetQtAutoGenConfigs(configs); + autoInfoFileConfig = configs[0]; + } + commandLines.push_back( + cmMakeCommandLine({ cmSystemTools::GetCMakeCommand(), "-E", processName, + infoFile, autoInfoFileConfig })); + } +} + bool cmQtAutoGenInitializer::InitRccTargets() { for (Qrc const& qrc : this->Rcc.Qrcs) { @@ -1555,18 +1672,7 @@ bool cmQtAutoGenInitializer::InitRccTargets() ccDepends.push_back(qrc.InfoFile); cmCustomCommandLines commandLines; - if (this->MultiConfig) { - // Build for all configurations - for (std::string const& config : this->ConfigsList) { - commandLines.push_back( - cmMakeCommandLine({ cmSystemTools::GetCMakeCommand(), "-E", - "cmake_autorcc", qrc.InfoFile, config })); - } - } else { - commandLines.push_back( - cmMakeCommandLine({ cmSystemTools::GetCMakeCommand(), "-E", - "cmake_autorcc", qrc.InfoFile, "$<CONFIG>" })); - } + AddCMakeProcessToCommandLines(qrc.InfoFile, "cmake_autorcc", commandLines); std::string const ccComment = cmStrCat("Automatic RCC for ", @@ -1617,13 +1723,28 @@ bool cmQtAutoGenInitializer::InitRccTargets() // Create custom rcc command { // 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); + if (this->MultiConfig && this->UseBetterGraph) { + for (auto const& config : this->ConfigsList) { + // Add resource file to the custom command dependencies + auto resourceFilesWithConfig = cmStrCat( + "$<$<CONFIG:", config, + ">:", cmList{ qrc.Resources.Config.at(config) }.to_string(), + ">"); + ccDepends.emplace_back(std::move(resourceFilesWithConfig)); + } + } else { + for (std::string const& fileName : qrc.Resources.Default) { + // Add resource file to the custom command dependencies + ccDepends.push_back(fileName); + } } + if (!this->Rcc.ExecutableTargetName.empty()) { ccDepends.push_back(this->Rcc.ExecutableTargetName); } + + AddAutogenExecutableToDependencies(this->Rcc, ccDepends); + cc->SetOutputs(ccOutput); cc->SetDepends(ccDepends); this->LocalGen->AddCustomCommandToOutput(std::move(cc)); @@ -1723,6 +1844,8 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo() // General info.SetBool("MULTI_CONFIG", this->MultiConfig); + info.SetBool("CROSS_CONFIG", this->CrossConfig); + info.SetBool("USE_BETTER_GRAPH", this->UseBetterGraph); info.SetUInt("PARALLEL", this->AutogenTarget.Parallel); #ifdef _WIN32 info.SetUInt("AUTOGEN_COMMAND_LINE_LENGTH_MAX", @@ -1740,14 +1863,14 @@ bool cmQtAutoGenInitializer::SetupWriteAutogenInfo() info.SetUInt("QT_VERSION_MAJOR", this->QtVersion.Major); info.SetUInt("QT_VERSION_MINOR", this->QtVersion.Minor); - info.Set("QT_MOC_EXECUTABLE", this->Moc.Executable); - info.Set("QT_UIC_EXECUTABLE", this->Uic.Executable); + info.SetConfig("QT_MOC_EXECUTABLE", this->Moc.Executable); + info.SetConfig("QT_UIC_EXECUTABLE", this->Uic.Executable); info.Set("CMAKE_EXECUTABLE", cmSystemTools::GetCMakeCommand()); info.SetConfig("SETTINGS_FILE", this->AutogenTarget.SettingsFile); info.SetConfig("PARSE_CACHE_FILE", this->AutogenTarget.ParseCacheFile); - info.Set("DEP_FILE", this->AutogenTarget.DepFile); - info.Set("DEP_FILE_RULE_NAME", this->AutogenTarget.DepFileRuleName); + info.SetConfig("DEP_FILE", this->AutogenTarget.DepFile); + info.SetConfig("DEP_FILE_RULE_NAME", this->AutogenTarget.DepFileRuleName); info.SetArray("CMAKE_LIST_FILES", this->Makefile->GetListFiles()); info.SetArray("HEADER_EXTENSIONS", this->Makefile->GetCMakeInstance()->GetHeaderExtensions()); @@ -1874,6 +1997,8 @@ bool cmQtAutoGenInitializer::SetupWriteRccInfo() // General info.SetBool("MULTI_CONFIG", this->MultiConfig); + info.SetBool("CROSS_CONFIG", this->CrossConfig); + info.SetBool("USE_BETTER_GRAPH", this->UseBetterGraph); info.SetUInt("VERBOSITY", this->Verbosity); info.Set("GENERATOR", this->GlobalGen->GetName()); @@ -1890,16 +2015,17 @@ bool cmQtAutoGenInitializer::SetupWriteRccInfo() info.SetConfig("INCLUDE_DIR", this->Dir.Include); // rcc executable - info.Set("RCC_EXECUTABLE", this->Rcc.Executable); - info.SetArray("RCC_LIST_OPTIONS", - this->Rcc.ExecutableFeatures->ListOptions); + info.SetConfig("RCC_EXECUTABLE", this->Rcc.Executable); + info.SetConfigArray( + "RCC_LIST_OPTIONS", + generateListOptions(this->Rcc.ExecutableFeatures, this->MultiConfig)); // qrc file info.Set("SOURCE", qrc.QrcFile); info.Set("OUTPUT_CHECKSUM", qrc.QrcPathChecksum); info.Set("OUTPUT_NAME", cmSystemTools::GetFilenameName(qrc.OutputFile)); info.SetArray("OPTIONS", qrc.Options); - info.SetArray("INPUTS", qrc.Resources); + info.SetConfigArray("INPUTS", qrc.Resources); info.Save(qrc.InfoFile); } @@ -2244,16 +2370,32 @@ bool cmQtAutoGenInitializer::GetQtExecutable(GenVarsT& genVars, cmListFileBacktrace lfbt = this->Makefile->GetBacktrace(); cmGeneratorExpression ge(*this->Makefile->GetCMakeInstance(), lfbt); std::unique_ptr<cmCompiledGeneratorExpression> cge = ge.Parse(val); - genVars.Executable = cge->Evaluate(this->LocalGen, ""); + if (this->MultiConfig && this->UseBetterGraph) { + for (auto const& config : this->ConfigsList) { + genVars.Executable.Config[config] = + cge->Evaluate(this->LocalGen, config); + } + } else { + genVars.Executable.Default = cge->Evaluate(this->LocalGen, ""); + } } - if (genVars.Executable.empty() && !ignoreMissingTarget) { + + if (genVars.Executable.Default.empty() && + genVars.Executable.Config.empty() && !ignoreMissingTarget) { print_err(prop + " evaluates to an empty value"); return false; } // Create empty compiler features. - genVars.ExecutableFeatures = - std::make_shared<cmQtAutoGen::CompilerFeatures>(); + if (this->MultiConfig && this->UseBetterGraph) { + for (auto const& config : this->ConfigsList) { + genVars.ExecutableFeatures.Config[config] = + std::make_shared<cmQtAutoGen::CompilerFeatures>(); + } + } else { + genVars.ExecutableFeatures.Default = + std::make_shared<cmQtAutoGen::CompilerFeatures>(); + } return true; } } @@ -2278,15 +2420,39 @@ bool cmQtAutoGenInitializer::GetQtExecutable(GenVarsT& genVars, genVars.ExecutableTargetName = targetName; genVars.ExecutableTarget = genTarget; if (genTarget->IsImported()) { - genVars.Executable = genTarget->ImportedGetLocation(""); + if (this->MultiConfig && this->UseBetterGraph) { + for (auto const& config : this->ConfigsList) { + genVars.Executable.Config[config] = + genTarget->ImportedGetLocation(config); + } + } else { + genVars.Executable.Default = + genTarget->ImportedGetLocation(this->ConfigDefault); + } + } else { - genVars.Executable = genTarget->GetLocation(""); + if (this->MultiConfig && this->UseBetterGraph) { + for (auto const& config : this->ConfigsList) { + genVars.Executable.Config[config] = genTarget->GetLocation(config); + } + } else { + genVars.Executable.Default = + genTarget->GetLocation(this->ConfigDefault); + } } } else { if (ignoreMissingTarget) { // Create empty compiler features. - genVars.ExecutableFeatures = - std::make_shared<cmQtAutoGen::CompilerFeatures>(); + if (this->MultiConfig && this->UseBetterGraph) { + for (auto const& config : this->ConfigsList) { + genVars.ExecutableFeatures.Config[config] = + std::make_shared<cmQtAutoGen::CompilerFeatures>(); + } + } else { + genVars.ExecutableFeatures.Default = + std::make_shared<cmQtAutoGen::CompilerFeatures>(); + } + return true; } print_err(cmStrCat("Could not find ", executable, " executable target ", @@ -2299,10 +2465,22 @@ bool cmQtAutoGenInitializer::GetQtExecutable(GenVarsT& genVars, { std::string err; genVars.ExecutableFeatures = this->GlobalInitializer->GetCompilerFeatures( - executable, genVars.Executable, err); - if (!genVars.ExecutableFeatures) { - print_err(err); - return false; + executable, genVars.Executable, err, this->MultiConfig, + this->UseBetterGraph); + if (this->MultiConfig && this->UseBetterGraph) { + for (auto const& config : this->ConfigsList) { + if (!genVars.ExecutableFeatures.Config[config]) { + if (!genVars.ExecutableFeatures.Config[config]) { + print_err(err); + return false; + } + } + } + } else { + if (!genVars.ExecutableFeatures.Default) { + print_err(err); + return false; + } } } diff --git a/Source/cmQtAutoGenInitializer.h b/Source/cmQtAutoGenInitializer.h index 3f7ab9f..1ab038b 100644 --- a/Source/cmQtAutoGenInitializer.h +++ b/Source/cmQtAutoGenInitializer.h @@ -19,6 +19,7 @@ #include "cmFilePathChecksum.h" #include "cmQtAutoGen.h" +class cmCustomCommandLines; class cmGeneratorTarget; class cmGlobalGenerator; class cmLocalGenerator; @@ -33,23 +34,6 @@ class cmTarget; class cmQtAutoGenInitializer : public cmQtAutoGen { public: - /** String value with per configuration variants. */ - class ConfigString - { - public: - std::string Default; - std::unordered_map<std::string, std::string> Config; - }; - - /** String values with per configuration variants. */ - template <typename C> - class ConfigStrings - { - public: - C Default; - std::unordered_map<std::string, C> Config; - }; - /** rcc job. */ class Qrc { @@ -64,7 +48,7 @@ public: bool Generated = false; bool Unique = false; std::vector<std::string> Options; - std::vector<std::string> Resources; + ConfigStrings<std::vector<std::string>> Resources; }; /** moc and/or uic file. */ @@ -91,8 +75,8 @@ public: // Executable std::string ExecutableTargetName; cmGeneratorTarget* ExecutableTarget = nullptr; - std::string Executable; - CompilerFeaturesHandle ExecutableFeatures; + ConfigString Executable; + ConfigStrings<CompilerFeaturesHandle> ExecutableFeatures; GenVarsT(GenT gen) : Gen(gen) @@ -142,6 +126,9 @@ private: GenVarsT const& genVars, bool prepend = false); void AddToSourceGroup(std::string const& fileName, cm::string_view genNameUpper); + void AddCMakeProcessToCommandLines(std::string const& infoFile, + std::string const& processName, + cmCustomCommandLines& commandLines); void AddCleanFile(std::string const& fileName); void ConfigFileNames(ConfigString& configString, cm::string_view prefix, @@ -156,6 +143,9 @@ private: bool ignoreMissingTarget) const; void handleSkipPch(cmSourceFile* sf); + void AddAutogenExecutableToDependencies( + cmQtAutoGenInitializer::GenVarsT const& genVars, + std::vector<std::string>& dependencies) const; cmQtAutoGenGlobalInitializer* GlobalInitializer = nullptr; cmGeneratorTarget* GenTarget = nullptr; @@ -169,6 +159,7 @@ private: unsigned int Verbosity = 0; bool MultiConfig = false; bool CrossConfig = false; + bool UseBetterGraph = false; bool CMP0071Accept = false; bool CMP0071Warn = false; bool CMP0100Accept = false; @@ -205,8 +196,8 @@ private: bool DependOrigin = false; std::set<std::string> DependFiles; std::set<cmTarget*> DependTargets; - std::string DepFile; - std::string DepFileRuleName; + ConfigString DepFile; + ConfigString DepFileRuleName; // Sources to process std::unordered_map<cmSourceFile*, MUFileHandle> Headers; std::unordered_map<cmSourceFile*, MUFileHandle> Sources; diff --git a/Source/cmQtAutoGenerator.cxx b/Source/cmQtAutoGenerator.cxx index c048312..ebdec12 100644 --- a/Source/cmQtAutoGenerator.cxx +++ b/Source/cmQtAutoGenerator.cxx @@ -430,10 +430,12 @@ std::string cmQtAutoGenerator::MessagePath(cm::string_view path) const return cmQtAutoGen::Quoted(res); } -bool cmQtAutoGenerator::Run(cm::string_view infoFile, cm::string_view config) +bool cmQtAutoGenerator::Run(cm::string_view infoFile, cm::string_view config, + cm::string_view executableConfig) { // Info config this->InfoConfig_ = std::string(config); + this->ExecutableConfig_ = std::string(executableConfig); // Info file this->InfoFile_ = std::string(infoFile); diff --git a/Source/cmQtAutoGenerator.h b/Source/cmQtAutoGenerator.h index 5c3a8ad..4b15fc7 100644 --- a/Source/cmQtAutoGenerator.h +++ b/Source/cmQtAutoGenerator.h @@ -90,6 +90,10 @@ public: std::string const& InfoDir() const { return this->InfoDir_; } cmFileTime const& InfoFileTime() const { return this->InfoFileTime_; } std::string const& InfoConfig() const { return this->InfoConfig_; } + std::string const& ExecutableConfig() const + { + return this->ExecutableConfig_; + } // -- Info file parsing /** Info file reader class. */ @@ -151,7 +155,8 @@ public: std::string MessagePath(cm::string_view path) const; // -- Run - bool Run(cm::string_view infoFile, cm::string_view config); + bool Run(cm::string_view infoFile, cm::string_view config, + cm::string_view executableConfig); protected: // -- Abstract processing interface @@ -170,6 +175,7 @@ private: std::string InfoDir_; cmFileTime InfoFileTime_; std::string InfoConfig_; + std::string ExecutableConfig_; // -- Directories ProjectDirsT ProjectDirs_; }; diff --git a/Source/cmQtAutoMocUic.cxx b/Source/cmQtAutoMocUic.cxx index a49125e..408a22c 100644 --- a/Source/cmQtAutoMocUic.cxx +++ b/Source/cmQtAutoMocUic.cxx @@ -171,6 +171,8 @@ public: // -- Attributes // - Config bool MultiConfig = false; + bool CrossConfig = false; + bool UseBetterGraph = false; IntegerVersion QtVersion = { 4, 0 }; unsigned int ThreadCount = 0; unsigned int MaxCommandLineLength = @@ -2380,6 +2382,9 @@ bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info) { // -- Required settings if (!info.GetBool("MULTI_CONFIG", this->BaseConst_.MultiConfig, true) || + !info.GetBool("CROSS_CONFIG", this->BaseConst_.CrossConfig, true) || + !info.GetBool("USE_BETTER_GRAPH", this->BaseConst_.UseBetterGraph, + true) || !info.GetUInt("QT_VERSION_MAJOR", this->BaseConst_.QtVersion.Major, true) || !info.GetUInt("QT_VERSION_MINOR", this->BaseConst_.QtVersion.Minor, @@ -2396,19 +2401,49 @@ bool cmQtAutoMocUicT::InitFromInfo(InfoT const& info) true) || !info.GetStringConfig("PARSE_CACHE_FILE", this->BaseConst_.ParseCacheFile, true) || - !info.GetString("DEP_FILE", this->BaseConst_.DepFile, false) || - !info.GetString("DEP_FILE_RULE_NAME", this->BaseConst_.DepFileRuleName, - false) || !info.GetStringConfig("SETTINGS_FILE", this->SettingsFile_, true) || !info.GetArray("CMAKE_LIST_FILES", this->BaseConst_.ListFiles, true) || !info.GetArray("HEADER_EXTENSIONS", this->BaseConst_.HeaderExtensions, - true) || - !info.GetString("QT_MOC_EXECUTABLE", this->MocConst_.Executable, - false) || - !info.GetString("QT_UIC_EXECUTABLE", this->UicConst_.Executable, - false)) { + true)) { return false; } + if (this->BaseConst().UseBetterGraph) { + if (!info.GetStringConfig("DEP_FILE", this->BaseConst_.DepFile, false) || + !info.GetStringConfig("DEP_FILE_RULE_NAME", + this->BaseConst_.DepFileRuleName, false)) { + return false; + } + + if (this->BaseConst_.CrossConfig) { + std::string const mocExecutableWithConfig = + "QT_MOC_EXECUTABLE_" + this->ExecutableConfig(); + std::string const uicExecutableWithConfig = + "QT_UIC_EXECUTABLE_" + this->ExecutableConfig(); + if (!info.GetString(mocExecutableWithConfig, this->MocConst_.Executable, + false) || + !info.GetString(uicExecutableWithConfig, this->UicConst_.Executable, + false)) { + return false; + } + } else { + if (!info.GetStringConfig("QT_MOC_EXECUTABLE", + this->MocConst_.Executable, false) || + !info.GetStringConfig("QT_UIC_EXECUTABLE", + this->UicConst_.Executable, false)) { + return false; + } + } + } else { + if (!info.GetString("QT_MOC_EXECUTABLE", this->MocConst_.Executable, + false) || + !info.GetString("QT_UIC_EXECUTABLE", this->UicConst_.Executable, + false) || + !info.GetString("DEP_FILE", this->BaseConst_.DepFile, false) || + !info.GetString("DEP_FILE_RULE_NAME", this->BaseConst_.DepFileRuleName, + false)) { + return false; + } + } // -- Checks if (!this->BaseConst_.CMakeExecutableTime.Load( @@ -3075,7 +3110,8 @@ std::string cmQtAutoMocUicT::AbsoluteIncludePath( } // End of unnamed namespace -bool cmQtAutoMocUic(cm::string_view infoFile, cm::string_view config) +bool cmQtAutoMocUic(cm::string_view infoFile, cm::string_view config, + cm::string_view executableConfig) { - return cmQtAutoMocUicT().Run(infoFile, config); + return cmQtAutoMocUicT().Run(infoFile, config, executableConfig); } diff --git a/Source/cmQtAutoMocUic.h b/Source/cmQtAutoMocUic.h index 20f9d6e..5cb4ff1 100644 --- a/Source/cmQtAutoMocUic.h +++ b/Source/cmQtAutoMocUic.h @@ -10,4 +10,5 @@ * Process AUTOMOC and AUTOUIC * @return true on success */ -bool cmQtAutoMocUic(cm::string_view infoFile, cm::string_view config); +bool cmQtAutoMocUic(cm::string_view infoFile, cm::string_view config, + cm::string_view executableConfig); diff --git a/Source/cmQtAutoRcc.cxx b/Source/cmQtAutoRcc.cxx index e288645..605dad5 100644 --- a/Source/cmQtAutoRcc.cxx +++ b/Source/cmQtAutoRcc.cxx @@ -35,6 +35,11 @@ public: private: // -- Utility bool IsMultiConfig() const { return this->MultiConfig_; } + std::string const& GetGenerator() const { return this->Generator_; } + bool IsXcode() const + { + return this->GetGenerator().find("Xcode") != std::string::npos; + } std::string MultiConfigOutput() const; // -- Abstract processing interface @@ -53,6 +58,9 @@ private: // -- Config settings bool MultiConfig_ = false; + bool CrossConfig_ = false; + bool UseBetterGraph_ = false; + std::string Generator_; // -- Directories std::string AutogenBuildDir_; std::string IncludeDir_; @@ -92,26 +100,57 @@ bool cmQtAutoRccT::InitFromInfo(InfoT const& info) { // -- Required settings if (!info.GetBool("MULTI_CONFIG", this->MultiConfig_, true) || + !info.GetString("GENERATOR", this->Generator_, true) || + !info.GetBool("CROSS_CONFIG", this->CrossConfig_, true) || + !info.GetBool("USE_BETTER_GRAPH", this->UseBetterGraph_, true) || !info.GetString("BUILD_DIR", this->AutogenBuildDir_, true) || !info.GetStringConfig("INCLUDE_DIR", this->IncludeDir_, true) || - !info.GetString("RCC_EXECUTABLE", this->RccExecutable_, true) || - !info.GetArray("RCC_LIST_OPTIONS", this->RccListOptions_, false) || + !info.GetArrayConfig("RCC_LIST_OPTIONS", this->RccListOptions_, false) || !info.GetString("LOCK_FILE", this->LockFile_, true) || !info.GetStringConfig("SETTINGS_FILE", this->SettingsFile_, true) || !info.GetString("SOURCE", this->QrcFile_, true) || !info.GetString("OUTPUT_CHECKSUM", this->RccPathChecksum_, true) || !info.GetString("OUTPUT_NAME", this->RccFileName_, true) || - !info.GetArray("OPTIONS", this->Options_, false) || - !info.GetArray("INPUTS", this->Inputs_, false)) { + !info.GetArray("OPTIONS", this->Options_, false)) { return false; } + if (this->UseBetterGraph_) { + if (!info.GetArrayConfig("INPUTS", this->Inputs_, false)) { + return false; + } + if (this->CrossConfig_) { + std::string const rccExecutableWithConfig = + "RCC_EXECUTABLE_" + this->ExecutableConfig(); + if (!info.GetString(rccExecutableWithConfig, this->RccExecutable_, + true)) { + return false; + } + } else { + if (!info.GetStringConfig("RCC_EXECUTABLE", this->RccExecutable_, + true)) { + return false; + } + } + } else { + if (!info.GetString("RCC_EXECUTABLE", this->RccExecutable_, true) || + !info.GetArray("RCC_LIST_OPTIONS", this->RccListOptions_, false) || + !info.GetArray("INPUTS", this->Inputs_, false)) { + return false; + } + } // -- Derive information this->QrcFileName_ = cmSystemTools::GetFilenameName(this->QrcFile_); this->QrcFileDir_ = cmSystemTools::GetFilenamePath(this->QrcFile_); - this->RccFilePublic_ = - cmStrCat(this->AutogenBuildDir_, '/', this->RccPathChecksum_, '/', - this->RccFileName_); + if (IsMultiConfig() && !this->IsXcode() && this->UseBetterGraph_) { + this->RccFilePublic_ = + cmStrCat(this->AutogenBuildDir_, '/', this->RccPathChecksum_, "_", + this->InfoConfig(), '/', this->RccFileName_); + } else { + this->RccFilePublic_ = + cmStrCat(this->AutogenBuildDir_, '/', this->RccPathChecksum_, '/', + this->RccFileName_); + } // rcc output file name if (this->IsMultiConfig()) { @@ -520,7 +559,8 @@ bool cmQtAutoRccT::GenerateWrapper() } // End of unnamed namespace -bool cmQtAutoRcc(cm::string_view infoFile, cm::string_view config) +bool cmQtAutoRcc(cm::string_view infoFile, cm::string_view config, + cm::string_view executableConfig) { - return cmQtAutoRccT().Run(infoFile, config); + return cmQtAutoRccT().Run(infoFile, config, executableConfig); } diff --git a/Source/cmQtAutoRcc.h b/Source/cmQtAutoRcc.h index d525efa..9c0a4e9 100644 --- a/Source/cmQtAutoRcc.h +++ b/Source/cmQtAutoRcc.h @@ -10,4 +10,5 @@ * Process AUTORCC * @return true on success */ -bool cmQtAutoRcc(cm::string_view infoFile, cm::string_view config); +bool cmQtAutoRcc(cm::string_view infoFile, cm::string_view config, + cm::string_view executableConfig); diff --git a/Source/cmRST.cxx b/Source/cmRST.cxx index f48330d..3934a29 100644 --- a/Source/cmRST.cxx +++ b/Source/cmRST.cxx @@ -3,7 +3,6 @@ #include "cmRST.h" #include <algorithm> -#include <cctype> #include <cstddef> #include <iterator> #include <utility> @@ -159,7 +158,7 @@ void cmRST::ProcessLine(std::string const& line) // A line starting in .. is an explicit markup start. if (line == ".." || (line.size() >= 3 && line[0] == '.' && line[1] == '.' && - isspace(line[2]))) { + cmIsSpace(line[2]))) { this->Reset(); this->MarkupType = (line.find_first_not_of(" \t", 2) == std::string::npos ? Markup::Empty @@ -219,7 +218,7 @@ void cmRST::ProcessLine(std::string const& line) } // Indented lines following an explicit markup start are explicit markup. else if (this->MarkupType != Markup::None && - (line.empty() || isspace(line[0]))) { + (line.empty() || cmIsSpace(line[0]))) { this->MarkupType = Markup::Normal; // Record markup lines if the start line was recorded. if (!this->MarkupLines.empty()) { diff --git a/Source/cmStringAlgorithms.h b/Source/cmStringAlgorithms.h index 4a9840b..55a1e46 100644 --- a/Source/cmStringAlgorithms.h +++ b/Source/cmStringAlgorithms.h @@ -44,7 +44,10 @@ private: /** Returns true if the character @a ch is a whitespace character. **/ inline bool cmIsSpace(char ch) { - return ((ch & 0x80) == 0) && std::isspace(ch); + // isspace takes 'int' but documents that the value must be representable + // by 'unsigned char', or be EOF. Cast to 'unsigned char' to avoid sign + // extension while converting to 'int'. + return std::isspace(static_cast<unsigned char>(ch)); } /** Returns a string that has whitespace removed from the start and the end. */ diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx index 5a64588..ab87f34 100644 --- a/Source/cmStringCommand.cxx +++ b/Source/cmStringCommand.cxx @@ -6,7 +6,6 @@ #include "cmStringCommand.h" #include <algorithm> -#include <cctype> #include <cstdio> #include <cstdlib> #include <limits> @@ -660,7 +659,7 @@ bool HandleStripCommand(std::vector<std::string> const& args, const char* ptr = stringValue.c_str(); size_t cc; for (cc = 0; cc < inStringLength; ++cc) { - if (!isspace(*ptr)) { + if (!cmIsSpace(*ptr)) { if (startPos > inStringLength) { startPos = cc; } diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx index f606c22..fca8186 100644 --- a/Source/cmSystemTools.cxx +++ b/Source/cmSystemTools.cxx @@ -486,7 +486,7 @@ bool cmSystemTools::SplitProgramFromArgs(std::string const& command, const char* c = command.c_str(); // Skip leading whitespace. - while (isspace(static_cast<unsigned char>(*c))) { + while (cmIsSpace(*c)) { ++c; } @@ -516,7 +516,7 @@ bool cmSystemTools::SplitProgramFromArgs(std::string const& command, in_double = true; } else if (*c == '\'') { in_single = true; - } else if (isspace(static_cast<unsigned char>(*c))) { + } else if (cmIsSpace(*c)) { break; } else { program += *c; @@ -1673,7 +1673,7 @@ void cmSystemTools::EnvDiff::PutEnv(const std::string& env) void cmSystemTools::EnvDiff::UnPutEnv(const std::string& env) { - diff[env] = {}; + diff[env] = cm::nullopt; } bool cmSystemTools::EnvDiff::ParseOperation(const std::string& envmod) @@ -1728,7 +1728,7 @@ bool cmSystemTools::EnvDiff::ParseOperation(const std::string& envmod) } else if (op == "set"_s) { diff[name] = value; } else if (op == "unset"_s) { - diff[name] = {}; + diff[name] = cm::nullopt; } else if (op == "string_append"_s) { apply_diff(name, [&value](std::string& output) { output += value; }); } else if (op == "string_prepend"_s) { diff --git a/Source/cmTarget.cxx b/Source/cmTarget.cxx index a365cd1..e6e1ac4 100644 --- a/Source/cmTarget.cxx +++ b/Source/cmTarget.cxx @@ -557,6 +557,7 @@ TargetProperty const StaticTargetProperties[] = { { "AUTOGEN_ORIGIN_DEPENDS"_s, IC::CanCompileSources }, { "AUTOGEN_PARALLEL"_s, IC::CanCompileSources }, { "AUTOGEN_USE_SYSTEM_INCLUDE"_s, IC::CanCompileSources }, + { "AUTOGEN_BETTER_GRAPH_MULTI_CONFIG"_s, IC::CanCompileSources }, // -- moc { "AUTOMOC_DEPEND_FILTERS"_s, IC::CanCompileSources }, // -- C++ diff --git a/Source/cmXMLParser.cxx b/Source/cmXMLParser.cxx index 24da8c6..f4433e3 100644 --- a/Source/cmXMLParser.cxx +++ b/Source/cmXMLParser.cxx @@ -2,7 +2,6 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmXMLParser.h" -#include <cctype> #include <cstring> #include <iostream> #include <sstream> @@ -143,11 +142,6 @@ void cmXMLParser::CharacterDataHandler(const char* /*inData*/, { } -int cmXMLParser::IsSpace(char c) -{ - return isspace(c); -} - const char* cmXMLParser::FindAttribute(const char** atts, const char* attribute) { diff --git a/Source/cmXMLParser.h b/Source/cmXMLParser.h index 176252d..d35e44f 100644 --- a/Source/cmXMLParser.h +++ b/Source/cmXMLParser.h @@ -89,10 +89,6 @@ protected: /** Called by ReportXmlParseError with basic error info. */ virtual void ReportError(int line, int column, const char* msg); - //! Utility for convenience of subclasses. Wraps isspace C library - // routine. - static int IsSpace(char c); - //! Send the given buffer to the XML parser. virtual int ParseBuffer(const char* buffer, std::string::size_type length); diff --git a/Source/cmake.cxx b/Source/cmake.cxx index 32064b4..7ab7600 100644 --- a/Source/cmake.cxx +++ b/Source/cmake.cxx @@ -2820,7 +2820,7 @@ int cmake::Run(const std::vector<std::string>& args, bool noconfigure) if (cmSystemTools::GetErrorOccurredFlag()) { return -1; } - return 0; + return this->HasScriptModeExitCode() ? this->GetScriptModeExitCode() : 0; } // If MAKEFLAGS are given in the environment, remove the environment diff --git a/Source/cmake.h b/Source/cmake.h index 58f90c9..ccf5154 100644 --- a/Source/cmake.h +++ b/Source/cmake.h @@ -835,7 +835,13 @@ private: std::string DebuggerDapLogFile; #endif + cm::optional<int> ScriptModeExitCode; + public: + bool HasScriptModeExitCode() const { return ScriptModeExitCode.has_value(); } + void SetScriptModeExitCode(int code) { ScriptModeExitCode = code; } + int GetScriptModeExitCode() const { return ScriptModeExitCode.value_or(-1); } + static cmDocumentationEntry CMAKE_STANDARD_OPTIONS_TABLE[18]; }; diff --git a/Source/cmakemain.cxx b/Source/cmakemain.cxx index ced83dc..8462734 100644 --- a/Source/cmakemain.cxx +++ b/Source/cmakemain.cxx @@ -389,13 +389,16 @@ int do_cmake(int ac, char const* const* av) } } - // Always return a non-negative value. Windows tools do not always - // interpret negative return values as errors. + // Always return a non-negative value (except exit code from SCRIPT_MODE). + // Windows tools do not always interpret negative return values as errors. if (res != 0) { + auto scriptModeExitCode = + cm.HasScriptModeExitCode() ? cm.GetScriptModeExitCode() : 0; + res = scriptModeExitCode ? scriptModeExitCode : 1; #ifdef CMake_ENABLE_DEBUGGER - cm.StopDebuggerIfNeeded(1); + cm.StopDebuggerIfNeeded(res); #endif - return 1; + return res; } #ifdef CMake_ENABLE_DEBUGGER cm.StopDebuggerIfNeeded(0); diff --git a/Source/cmcmd.cxx b/Source/cmcmd.cxx index 93b0086..bcf7462 100644 --- a/Source/cmcmd.cxx +++ b/Source/cmcmd.cxx @@ -1443,13 +1443,17 @@ int cmcmd::ExecuteCMakeCommand(std::vector<std::string> const& args, if ((args[1] == "cmake_autogen") && (args.size() >= 4)) { cm::string_view const infoFile = args[2]; cm::string_view const config = args[3]; - return cmQtAutoMocUic(infoFile, config) ? 0 : 1; + cm::string_view const executableConfig = + (args.size() >= 5) ? cm::string_view(args[4]) : cm::string_view(); + return cmQtAutoMocUic(infoFile, config, executableConfig) ? 0 : 1; } if ((args[1] == "cmake_autorcc") && (args.size() >= 3)) { cm::string_view const infoFile = args[2]; cm::string_view const config = (args.size() > 3) ? cm::string_view(args[3]) : cm::string_view(); - return cmQtAutoRcc(infoFile, config) ? 0 : 1; + cm::string_view const executableConfig = + (args.size() >= 5) ? cm::string_view(args[4]) : cm::string_view(); + return cmQtAutoRcc(infoFile, config, executableConfig) ? 0 : 1; } #endif |