diff options
Diffstat (limited to 'Source')
-rw-r--r-- | Source/CMakeVersion.cmake | 6 | ||||
-rw-r--r-- | Source/CTest/cmCTestRunTest.cxx | 11 | ||||
-rw-r--r-- | Source/cmCoreTryCompile.cxx | 24 | ||||
-rw-r--r-- | Source/cmDebugTools.h | 23 | ||||
-rw-r--r-- | Source/cmDocumentation.cxx | 86 | ||||
-rw-r--r-- | Source/cmDocumentation.h | 3 | ||||
-rw-r--r-- | Source/cmExperimental.cxx | 11 | ||||
-rw-r--r-- | Source/cmExperimental.h | 1 | ||||
-rw-r--r-- | Source/cmExportCommand.cxx | 15 | ||||
-rw-r--r-- | Source/cmGeneratorTarget.cxx | 182 | ||||
-rw-r--r-- | Source/cmGeneratorTarget.h | 4 | ||||
-rw-r--r-- | Source/cmGlobalVisualStudio7Generator.cxx | 8 | ||||
-rw-r--r-- | Source/cmGlobalXCodeGenerator.cxx | 8 | ||||
-rw-r--r-- | Source/cmInstallCommand.cxx | 25 | ||||
-rw-r--r-- | Source/cmMakefileTargetGenerator.cxx | 8 | ||||
-rw-r--r-- | Source/cmNinjaTargetGenerator.cxx | 44 | ||||
-rw-r--r-- | Source/cmPolicies.h | 7 | ||||
-rw-r--r-- | Source/cmTargetSourcesCommand.cxx | 31 | ||||
-rw-r--r-- | Source/cmVisualStudio10TargetGenerator.cxx | 9 |
19 files changed, 310 insertions, 196 deletions
diff --git a/Source/CMakeVersion.cmake b/Source/CMakeVersion.cmake index 23556d9..c1f5c25 100644 --- a/Source/CMakeVersion.cmake +++ b/Source/CMakeVersion.cmake @@ -1,8 +1,8 @@ # CMake version number components. set(CMake_VERSION_MAJOR 3) -set(CMake_VERSION_MINOR 27) -set(CMake_VERSION_PATCH 20230928) -#set(CMake_VERSION_RC 0) +set(CMake_VERSION_MINOR 28) +set(CMake_VERSION_PATCH 0) +set(CMake_VERSION_RC 0) set(CMake_VERSION_IS_DIRTY 0) # Start with the full version number used in tags. It has no dev info. diff --git a/Source/CTest/cmCTestRunTest.cxx b/Source/CTest/cmCTestRunTest.cxx index 4c57cf6..8ceb9db 100644 --- a/Source/CTest/cmCTestRunTest.cxx +++ b/Source/CTest/cmCTestRunTest.cxx @@ -791,11 +791,12 @@ bool cmCTestRunTest::ForkProcess() timeout = this->CTest->GetGlobalTimeout(); } - // Check CTEST_TEST_TIMEOUT. - cmDuration ctestTestTimeout = this->CTest->GetTimeOut(); - if (ctestTestTimeout > cmDuration::zero() && - (!timeout || ctestTestTimeout < *timeout)) { - timeout = ctestTestTimeout; + if (!timeout) { + // Check CTEST_TEST_TIMEOUT. + cmDuration ctestTestTimeout = this->CTest->GetTimeOut(); + if (ctestTestTimeout > cmDuration::zero()) { + timeout = ctestTestTimeout; + } } } diff --git a/Source/cmCoreTryCompile.cxx b/Source/cmCoreTryCompile.cxx index ee40bd5..67462f5 100644 --- a/Source/cmCoreTryCompile.cxx +++ b/Source/cmCoreTryCompile.cxx @@ -235,25 +235,16 @@ ArgumentParser::Continue cmCoreTryCompile::Arguments::SetSourceType( this->SourceTypeContext = SourceType::Normal; matched = true; } else if (sourceType == "CXX_MODULE"_s) { - bool const supportCxxModuleSources = cmExperimental::HasSupportEnabled( - *this->Makefile, cmExperimental::Feature::CxxModuleCMakeApi); - if (supportCxxModuleSources) { - this->SourceTypeContext = SourceType::CxxModule; - matched = true; - } + this->SourceTypeContext = SourceType::CxxModule; + matched = true; } if (!matched && this->SourceTypeError.empty()) { - bool const supportCxxModuleSources = cmExperimental::HasSupportEnabled( - *this->Makefile, cmExperimental::Feature::CxxModuleCMakeApi); - auto const* message = "'SOURCE'"; - if (supportCxxModuleSources) { - message = "one of 'SOURCE' or 'CXX_MODULE'"; - } // Only remember one error at a time; all other errors related to argument // parsing are "indicate one error and return" anyways. this->SourceTypeError = - cmStrCat("Invalid 'SOURCE_TYPE' '", sourceType, "'; must be ", message); + cmStrCat("Invalid 'SOURCE_TYPE' '", sourceType, + "'; must be one of 'SOURCE' or 'CXX_MODULE'"); } return ArgumentParser::Continue::Yes; } @@ -880,6 +871,13 @@ cm::optional<cmTryCompileResult> cmCoreTryCompile::TryCompileCode( ? "NEW" : "OLD"); + /* Set the appropriate policy information for C++ module support */ + fprintf(fout, "cmake_policy(SET CMP0155 %s)\n", + this->Makefile->GetPolicyStatus(cmPolicies::CMP0155) == + cmPolicies::NEW + ? "NEW" + : "OLD"); + // Workaround for -Wl,-headerpad_max_install_names issue until we can avoid // adding that flag in the platform and compiler language files fprintf(fout, diff --git a/Source/cmDebugTools.h b/Source/cmDebugTools.h new file mode 100644 index 0000000..99c0c6b --- /dev/null +++ b/Source/cmDebugTools.h @@ -0,0 +1,23 @@ +/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying + file Copyright.txt or https://cmake.org/licensing for details. */ +#pragma once + +#include <iostream> + +#define CM_DBG(expr) cm::dbg_impl(__FILE__, __LINE__, #expr, expr) + +namespace cm { + +namespace { + +template <typename T> +T dbg_impl(const char* fname, int line, const char* expr, T value) +{ + std::cerr << fname << ':' << line << ": " << expr << " = " << value + << std::endl; + return value; +} + +} // namespace + +} // namespace cm diff --git a/Source/cmDocumentation.cxx b/Source/cmDocumentation.cxx index 77c5295..db2a606 100644 --- a/Source/cmDocumentation.cxx +++ b/Source/cmDocumentation.cxx @@ -9,17 +9,20 @@ #include "cmsys/FStream.hxx" #include "cmsys/Glob.hxx" +#include "cmsys/RegularExpression.hxx" #include "cmDocumentationEntry.h" #include "cmDocumentationSection.h" #include "cmRST.h" +#include "cmStringAlgorithms.h" #include "cmSystemTools.h" #include "cmVersion.h" namespace { -const cmDocumentationEntry cmDocumentationStandardOptions[20] = { +const cmDocumentationEntry cmDocumentationStandardOptions[21] = { { "-h,-H,--help,-help,-usage,/?", "Print usage information and exit." }, { "--version,-version,/V [<file>]", "Print version number and exit." }, + { "--help <keyword> [<file>]", "Print help for one keyword and exit." }, { "--help-full [<file>]", "Print all help manuals and exit." }, { "--help-manual <man> [<file>]", "Print one help manual and exit." }, { "--help-manual-list [<file>]", "List help manuals available and exit." }, @@ -92,6 +95,8 @@ bool cmDocumentation::PrintDocumentation(Type ht, std::ostream& os) return this->PrintHelp(os); case cmDocumentation::Full: return this->PrintHelpFull(os); + case cmDocumentation::OneArbitrary: + return this->PrintHelpOneArbitrary(os); case cmDocumentation::OneManual: return this->PrintHelpOneManual(os); case cmDocumentation::OneCommand: @@ -176,6 +181,30 @@ void cmDocumentation::WarnFormFromFilename( } } +std::string cmDocumentation::GeneralizeKeyword(std::string cname) +{ + std::map<std::string, const std::vector<std::string>> conversions; + std::vector<std::string> languages = { + "C", "CXX", "CSharp", "CUDA", "OBJC", + "OBJCXX", "Fortran", "HIP", "ISPC", "Swift", + "ASM", "ASM_NASM", "ASM_MARMASM", "ASM_MASM", "ASM-ATT" + }; + std::vector<std::string> configs = { "DEBUG", "RELEASE", "RELWITHDEBINFO", + "MINSIZEREL" }; + conversions.emplace("LANG", std::move(languages)); + conversions.emplace("CONFIG", std::move(configs)); + for (auto const& it : conversions) { + for (auto const& to_replace : it.second) { + cmsys::RegularExpression reg( + cmStrCat("(^|_)(", to_replace, ")(\\.|$|_)")); + if (reg.find(cname)) { + cname.replace(reg.start(2), to_replace.length(), it.first); + } + } + } + return cname; +} + void cmDocumentation::addCommonStandardDocSections() { cmDocumentationSection sec{ "Options" }; @@ -237,10 +266,10 @@ bool cmDocumentation::CheckOptions(int argc, const char* const* argv, (strcmp(argv[i], "-h") == 0) || (strcmp(argv[i], "-H") == 0)) { help.HelpType = cmDocumentation::Help; i += int(get_opt_argument(i + 1, help.Argument)); - help.Argument = cmSystemTools::LowerCase(help.Argument); - // special case for single command + // special case for arbitrary keyword help if (!help.Argument.empty()) { - help.HelpType = cmDocumentation::OneCommand; + help.HelpType = cmDocumentation::OneArbitrary; + i += int(get_opt_argument(i + 1, help.Filename)); } } else if (strcmp(argv[i], "--help-properties") == 0) { help.HelpType = cmDocumentation::OneManual; @@ -400,7 +429,7 @@ void cmDocumentation::GlobHelp(std::vector<std::string>& files, { cmsys::Glob gl; std::string findExpr = - cmSystemTools::GetCMakeRoot() + "/Help/" + pattern + ".rst"; + cmStrCat(cmSystemTools::GetCMakeRoot(), "/Help/", pattern, ".rst"); if (gl.FindFiles(findExpr)) { files = gl.GetFiles(); } @@ -452,8 +481,8 @@ bool cmDocumentation::PrintHelpOneManual(std::ostream& os) if (mlen > 3 && mname[mlen - 3] == '(' && mname[mlen - 1] == ')') { mname = mname.substr(0, mlen - 3) + "." + mname[mlen - 2]; } - if (this->PrintFiles(os, "manual/" + mname) || - this->PrintFiles(os, "manual/" + mname + ".[0-9]")) { + if (this->PrintFiles(os, cmStrCat("manual/", mname)) || + this->PrintFiles(os, cmStrCat("manual/", mname, ".[0-9]"))) { return true; } // Argument was not a manual. Complain. @@ -469,10 +498,43 @@ bool cmDocumentation::PrintHelpListManuals(std::ostream& os) return true; } +bool cmDocumentation::PrintHelpOneArbitrary(std::ostream& os) +{ + std::string word = cmSystemTools::HelpFileName(this->CurrentArgument); + std::string word_m = GeneralizeKeyword(word); + + // Support legacy style uppercase commands, with LANG and CONFIG + // substitutions + bool found = this->PrintFiles(os, cmStrCat("*/", word)); + if (found) { + os << "\n"; + } + found = this->PrintFiles( + os, cmStrCat("command/", cmSystemTools::LowerCase(word))) || + found; + if (found) { + return true; + } + found = this->PrintFiles(os, cmStrCat("*/", word_m)); + if (found) { + os << "\n"; + } + found = this->PrintFiles( + os, cmStrCat("command/", cmSystemTools::LowerCase(word_m))) || + found; + if (found) { + return true; + } + os << "Argument \"" << this->CurrentArgument + << "\" to --help did not match any keywords. " + "Use --help without any arguments to print CMake help information.\n"; + return false; +} + bool cmDocumentation::PrintHelpOneCommand(std::ostream& os) { std::string cname = cmSystemTools::LowerCase(this->CurrentArgument); - if (this->PrintFiles(os, "command/" + cname)) { + if (this->PrintFiles(os, cmStrCat("command/", cname))) { return true; } // Argument was not a command. Complain. @@ -491,7 +553,7 @@ bool cmDocumentation::PrintHelpListCommands(std::ostream& os) bool cmDocumentation::PrintHelpOneModule(std::ostream& os) { std::string mname = this->CurrentArgument; - if (this->PrintFiles(os, "module/" + mname)) { + if (this->PrintFiles(os, cmStrCat("module/", mname))) { return true; } // Argument was not a module. Complain. @@ -519,7 +581,7 @@ bool cmDocumentation::PrintHelpListModules(std::ostream& os) bool cmDocumentation::PrintHelpOneProperty(std::ostream& os) { std::string pname = cmSystemTools::HelpFileName(this->CurrentArgument); - if (this->PrintFiles(os, "prop_*/" + pname)) { + if (this->PrintFiles(os, cmStrCat("prop_*/", pname))) { return true; } // Argument was not a property. Complain. @@ -539,7 +601,7 @@ bool cmDocumentation::PrintHelpOnePolicy(std::ostream& os) { std::string pname = this->CurrentArgument; std::vector<std::string> files; - if (this->PrintFiles(os, "policy/" + pname)) { + if (this->PrintFiles(os, cmStrCat("policy/", pname))) { return true; } @@ -567,7 +629,7 @@ bool cmDocumentation::PrintHelpListGenerators(std::ostream& os) bool cmDocumentation::PrintHelpOneVariable(std::ostream& os) { std::string vname = cmSystemTools::HelpFileName(this->CurrentArgument); - if (this->PrintFiles(os, "variable/" + vname)) { + if (this->PrintFiles(os, cmStrCat("variable/", vname))) { return true; } // Argument was not a variable. Complain. diff --git a/Source/cmDocumentation.h b/Source/cmDocumentation.h index 6930986..3e6bdfb 100644 --- a/Source/cmDocumentation.h +++ b/Source/cmDocumentation.h @@ -34,6 +34,7 @@ public: ListVariables, ListPolicies, ListGenerators, + OneArbitrary, OneManual, OneCommand, OneModule, @@ -118,6 +119,7 @@ private: bool PrintUsage(std::ostream& os); bool PrintHelp(std::ostream& os); bool PrintHelpFull(std::ostream& os); + bool PrintHelpOneArbitrary(std::ostream& os); bool PrintHelpOneManual(std::ostream& os); bool PrintHelpOneCommand(std::ostream& os); bool PrintHelpOneModule(std::ostream& os); @@ -154,4 +156,5 @@ private: cmDocumentationFormatter Formatter; static void WarnFormFromFilename(RequestedHelpItem& request, bool& result); + static std::string GeneralizeKeyword(std::string word); }; diff --git a/Source/cmExperimental.cxx b/Source/cmExperimental.cxx index 104ab81..d75879f 100644 --- a/Source/cmExperimental.cxx +++ b/Source/cmExperimental.cxx @@ -19,17 +19,6 @@ namespace { * up-to-date. */ cmExperimental::FeatureData LookupTable[] = { - // CxxModuleCMakeApi - { "CxxModuleCMakeApi", - "ac01f462-0f5f-432a-86aa-acef252918a6", - "CMAKE_EXPERIMENTAL_CXX_MODULE_CMAKE_API", - "CMake's C++ module support is experimental. It is meant only for " - "experimentation and feedback to CMake developers.", - { "CMAKE_EXPERIMENTAL_CXX_SCANDEP_SOURCE", - "CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FORMAT", - "CMAKE_EXPERIMENTAL_CXX_MODULE_MAP_FLAG" }, - cmExperimental::TryCompileCondition::SkipCompilerChecks, - false }, // WindowsKernelModeDriver { "WindowsKernelModeDriver", "5c2d848d-4efa-4529-a768-efd57171bf68", diff --git a/Source/cmExperimental.h b/Source/cmExperimental.h index c958ab6..e4c1448 100644 --- a/Source/cmExperimental.h +++ b/Source/cmExperimental.h @@ -15,7 +15,6 @@ class cmExperimental public: enum class Feature { - CxxModuleCMakeApi, WindowsKernelModeDriver, Sentinel, diff --git a/Source/cmExportCommand.cxx b/Source/cmExportCommand.cxx index 273296d..e78b869 100644 --- a/Source/cmExportCommand.cxx +++ b/Source/cmExportCommand.cxx @@ -16,7 +16,6 @@ #include "cmArgumentParserTypes.h" #include "cmCryptoHash.h" #include "cmExecutionStatus.h" -#include "cmExperimental.h" #include "cmExportBuildAndroidMKGenerator.h" #include "cmExportBuildFileGenerator.h" #include "cmExportSet.h" @@ -69,15 +68,11 @@ bool cmExportCommand(std::vector<std::string> const& args, bool ExportOld = false; }; - auto parser = cmArgumentParser<Arguments>{} - .Bind("NAMESPACE"_s, &Arguments::Namespace) - .Bind("FILE"_s, &Arguments::Filename); - - bool const supportCxx20FileSetTypes = cmExperimental::HasSupportEnabled( - status.GetMakefile(), cmExperimental::Feature::CxxModuleCMakeApi); - if (supportCxx20FileSetTypes) { - parser.Bind("CXX_MODULES_DIRECTORY"_s, &Arguments::CxxModulesDirectory); - } + auto parser = + cmArgumentParser<Arguments>{} + .Bind("NAMESPACE"_s, &Arguments::Namespace) + .Bind("FILE"_s, &Arguments::Filename) + .Bind("CXX_MODULES_DIRECTORY"_s, &Arguments::CxxModulesDirectory); if (args[0] == "EXPORT") { parser.Bind("EXPORT"_s, &Arguments::ExportSetName); diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index 04d7bb1..422d927 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -31,7 +31,6 @@ #include "cmCustomCommandGenerator.h" #include "cmCxxModuleUsageEffects.h" #include "cmEvaluatedTargetProperty.h" -#include "cmExperimental.h" #include "cmFileSet.h" #include "cmFileTimes.h" #include "cmGeneratedFileStream.h" @@ -9047,7 +9046,7 @@ std::string cmGeneratorTarget::GetImportedXcFrameworkPath( bool cmGeneratorTarget::HaveFortranSources(std::string const& config) const { - auto sources = cmGeneratorTarget::GetSourceFiles(config); + auto sources = this->GetSourceFiles(config); return std::any_of(sources.begin(), sources.end(), [](BT<cmSourceFile*> const& sf) -> bool { return sf.Value->GetLanguage() == "Fortran"_s; @@ -9094,66 +9093,112 @@ cmGeneratorTarget::Cxx20SupportLevel cmGeneratorTarget::HaveCxxModuleSupport( if (!state->GetLanguageEnabled("CXX")) { return Cxx20SupportLevel::MissingCxx; } + cmValue standardDefault = - this->Target->GetMakefile()->GetDefinition("CMAKE_CXX_STANDARD_DEFAULT"); - if (standardDefault && !standardDefault->empty()) { - cmStandardLevelResolver standardResolver(this->Makefile); - if (!standardResolver.HaveStandardAvailable(this, "CXX", config, - "cxx_std_20")) { - return Cxx20SupportLevel::NoCxx20; - } + this->Makefile->GetDefinition("CMAKE_CXX_STANDARD_DEFAULT"); + if (!standardDefault || standardDefault->empty()) { + // We do not know any meaningful C++ standard levels for this compiler. + return Cxx20SupportLevel::NoCxx20; + } + + cmStandardLevelResolver standardResolver(this->Makefile); + if (!standardResolver.HaveStandardAvailable(this, "CXX", config, + "cxx_std_20") || + // During the ABI detection step we do not know the compiler's features. + // HaveStandardAvailable may return true as a fallback, but in this code + // path we do not want to assume C++ 20 is available. + this->Makefile->GetDefinition("CMAKE_CXX20_COMPILE_FEATURES") + .IsEmpty()) { + return Cxx20SupportLevel::NoCxx20; } - // Else, an empty CMAKE_CXX_STANDARD_DEFAULT means CMake does not detect and - // set a default standard level for this compiler, so assume all standards - // are available. - if (!cmExperimental::HasSupportEnabled( - *this->Makefile, cmExperimental::Feature::CxxModuleCMakeApi)) { - return Cxx20SupportLevel::MissingExperimentalFlag; + + cmValue scandepRule = + this->Makefile->GetDefinition("CMAKE_CXX_SCANDEP_SOURCE"); + if (!scandepRule) { + return Cxx20SupportLevel::MissingRule; } return Cxx20SupportLevel::Supported; } void cmGeneratorTarget::CheckCxxModuleStatus(std::string const& config) const { + bool haveScannableSources = false; + // Check for `CXX_MODULE*` file sets and a lack of support. if (this->HaveCxx20ModuleSources()) { - switch (this->HaveCxxModuleSupport(config)) { - case cmGeneratorTarget::Cxx20SupportLevel::MissingCxx: - this->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - cmStrCat("The target named \"", this->GetName(), - "\" has C++ sources that export modules but the \"CXX\" " - "language has not been enabled")); - break; - case cmGeneratorTarget::Cxx20SupportLevel::MissingExperimentalFlag: - this->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - cmStrCat("The target named \"", this->GetName(), - "\" has C++ sources that export modules but its " - "experimental support has not been requested")); - break; - case cmGeneratorTarget::Cxx20SupportLevel::NoCxx20: { - cmStandardLevelResolver standardResolver(this->Makefile); - auto effStandard = - standardResolver.GetEffectiveStandard(this, "CXX", config); - if (effStandard.empty()) { - effStandard = "; no C++ standard found"; - } else { - effStandard = cmStrCat("; found \"cxx_std_", effStandard, '"'); - } - this->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - cmStrCat( - "The target named \"", this->GetName(), - "\" has C++ sources that export modules but does not include " - "\"cxx_std_20\" (or newer) among its `target_compile_features`", - effStandard)); - } break; - case cmGeneratorTarget::Cxx20SupportLevel::Supported: - // All is well. - break; + haveScannableSources = true; + } + + if (!haveScannableSources) { + // Check to see if there are regular sources that have requested scanning. + auto sources = this->GetSourceFiles(config); + for (auto const& source : sources) { + auto const* sf = source.Value; + auto const& lang = sf->GetLanguage(); + if (lang != "CXX"_s) { + continue; + } + // Ignore sources which do not need dyndep. + if (this->NeedDyndepForSource(lang, config, sf)) { + haveScannableSources = true; + } } } + + // If there isn't anything scannable, ignore it. + if (!haveScannableSources) { + return; + } + + // If the generator doesn't support modules at all, error that we have + // sources that require the support. + if (!this->GetGlobalGenerator()->CheckCxxModuleSupport()) { + this->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat( + "The target named \"", this->GetName(), + "\" contains C++ " + "sources that use modules which is not supported by the generator")); + return; + } + + switch (this->HaveCxxModuleSupport(config)) { + case cmGeneratorTarget::Cxx20SupportLevel::MissingCxx: + this->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("The target named \"", this->GetName(), + "\" has C++ sources that use modules but the \"CXX\" " + "language has not been enabled")); + break; + case cmGeneratorTarget::Cxx20SupportLevel::NoCxx20: { + cmStandardLevelResolver standardResolver(this->Makefile); + auto effStandard = + standardResolver.GetEffectiveStandard(this, "CXX", config); + if (effStandard.empty()) { + effStandard = "; no C++ standard found"; + } else { + effStandard = cmStrCat("; found \"cxx_std_", effStandard, '"'); + } + this->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat( + "The target named \"", this->GetName(), + "\" has C++ sources that use modules but does not include " + "\"cxx_std_20\" (or newer) among its `target_compile_features`", + effStandard)); + } break; + case cmGeneratorTarget::Cxx20SupportLevel::MissingRule: { + this->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("The target named \"", this->GetName(), + "\" has C++ sources that use modules but the compiler does " + "not provide a way to discover the import graph " + "dependencies")); + } break; + case cmGeneratorTarget::Cxx20SupportLevel::Supported: + // All is well. + break; + } } bool cmGeneratorTarget::NeedCxxModuleSupport(std::string const& lang, @@ -9191,14 +9236,30 @@ bool cmGeneratorTarget::NeedDyndepForSource(std::string const& lang, std::string const& config, cmSourceFile const* sf) const { - bool const needDyndep = this->NeedDyndep(lang, config); - if (!needDyndep) { + // Fortran always needs to be scanned. + if (lang == "Fortran"_s) { + return true; + } + // Only C++ code needs scanned otherwise. + if (lang != "CXX"_s) { return false; } + + // Any file in `CXX_MODULES` file sets need scanned (it being `CXX` is + // enforced elsewhere). auto const* fs = this->GetFileSetForSource(config, sf); if (fs && fs->GetType() == "CXX_MODULES"_s) { return true; } + + switch (this->HaveCxxModuleSupport(config)) { + case Cxx20SupportLevel::MissingCxx: + case Cxx20SupportLevel::NoCxx20: + return false; + case Cxx20SupportLevel::MissingRule: + case Cxx20SupportLevel::Supported: + break; + } auto const sfProp = sf->GetProperty("CXX_SCAN_FOR_MODULES"); if (sfProp.IsSet()) { return sfProp.IsOn(); @@ -9207,7 +9268,22 @@ bool cmGeneratorTarget::NeedDyndepForSource(std::string const& lang, if (tgtProp.IsSet()) { return tgtProp.IsOn(); } - return true; + + bool policyAnswer = false; + switch (this->GetPolicyStatusCMP0155()) { + case cmPolicies::WARN: + case cmPolicies::OLD: + // The OLD behavior is to not scan the source. + policyAnswer = false; + break; + case cmPolicies::REQUIRED_ALWAYS: + case cmPolicies::REQUIRED_IF_USED: + case cmPolicies::NEW: + // The NEW behavior is to scan the source. + policyAnswer = true; + break; + } + return policyAnswer; } void cmGeneratorTarget::BuildFileSetInfoCache(std::string const& config) const diff --git a/Source/cmGeneratorTarget.h b/Source/cmGeneratorTarget.h index 751f907..72920d6 100644 --- a/Source/cmGeneratorTarget.h +++ b/Source/cmGeneratorTarget.h @@ -1288,10 +1288,10 @@ public: { // C++ is not available. MissingCxx, - // The experimental feature is not available. - MissingExperimentalFlag, // The target does not require at least C++20. NoCxx20, + // C++20 module scanning rules are not present. + MissingRule, // C++20 modules are available and working. Supported, }; diff --git a/Source/cmGlobalVisualStudio7Generator.cxx b/Source/cmGlobalVisualStudio7Generator.cxx index 6953ec6..1abdd0b 100644 --- a/Source/cmGlobalVisualStudio7Generator.cxx +++ b/Source/cmGlobalVisualStudio7Generator.cxx @@ -435,14 +435,6 @@ void cmGlobalVisualStudio7Generator::WriteTargetsToSolution( target->CheckCxxModuleStatus(c); } - if (target->HaveCxx20ModuleSources() && !this->SupportsCxxModuleDyndep()) { - root->GetMakefile()->IssueMessage( - MessageType::FATAL_ERROR, - cmStrCat("The target named \"", target->GetName(), - "\" contains C++ sources that export modules which is not " - "supported by the generator")); - } - // handle external vc project files cmValue expath = target->GetProperty("EXTERNAL_MSPROJECT"); if (expath) { diff --git a/Source/cmGlobalXCodeGenerator.cxx b/Source/cmGlobalXCodeGenerator.cxx index 90b8839..5076e6c 100644 --- a/Source/cmGlobalXCodeGenerator.cxx +++ b/Source/cmGlobalXCodeGenerator.cxx @@ -1384,14 +1384,6 @@ bool cmGlobalXCodeGenerator::CreateXCodeTarget( gtgt->CheckCxxModuleStatus(configName); } - if (gtgt->HaveCxx20ModuleSources()) { - gtgt->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - cmStrCat("The target named \"", gtgt->GetName(), - "\" contains C++ sources that export modules which is not " - "supported by the generator")); - } - auto& gtgt_visited = this->CommandsVisited[gtgt]; auto const& deps = this->GetTargetDirectDepends(gtgt); for (auto const& d : deps) { diff --git a/Source/cmInstallCommand.cxx b/Source/cmInstallCommand.cxx index 1b47ec4..0fc4011 100644 --- a/Source/cmInstallCommand.cxx +++ b/Source/cmInstallCommand.cxx @@ -21,7 +21,6 @@ #include "cmArgumentParser.h" #include "cmArgumentParserTypes.h" #include "cmExecutionStatus.h" -#include "cmExperimental.h" #include "cmExportSet.h" #include "cmFileSet.h" #include "cmGeneratorExpression.h" @@ -491,6 +490,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args, publicHeaderArgs.Parse(argVectors.PublicHeader, &unknownArgs); resourceArgs.Parse(argVectors.Resource, &unknownArgs); includesArgs.Parse(&argVectors.Includes, &unknownArgs); + cxxModuleBmiArgs.Parse(argVectors.CxxModulesBmi, &unknownArgs); for (std::size_t i = 0; i < argVectors.FileSets.size(); i++) { // We have to create a separate object for the parsing because // cmArgumentParser<void>::Bind() binds to a specific address, but the @@ -501,15 +501,6 @@ bool HandleTargetsMode(std::vector<std::string> const& args, fileSetArgs[i] = std::move(fileSetArg); } - bool const supportCxx20FileSetTypes = cmExperimental::HasSupportEnabled( - *helper.Makefile, cmExperimental::Feature::CxxModuleCMakeApi); - if (!supportCxx20FileSetTypes) { - std::copy(argVectors.CxxModulesBmi.begin(), argVectors.CxxModulesBmi.end(), - std::back_inserter(unknownArgs)); - } else { - cxxModuleBmiArgs.Parse(argVectors.CxxModulesBmi, &unknownArgs); - } - if (!unknownArgs.empty()) { // Unknown argument. status.SetError( @@ -541,12 +532,10 @@ bool HandleTargetsMode(std::vector<std::string> const& args, success = success && privateHeaderArgs.Finalize(); success = success && publicHeaderArgs.Finalize(); success = success && resourceArgs.Finalize(); + success = success && cxxModuleBmiArgs.Finalize(); for (auto& fileSetArg : fileSetArgs) { success = success && fileSetArg.Finalize(); } - if (supportCxx20FileSetTypes) { - success = success && cxxModuleBmiArgs.Finalize(); - } if (!success) { return false; @@ -1173,8 +1162,7 @@ bool HandleTargetsMode(std::vector<std::string> const& args, } } - if (supportCxx20FileSetTypes && - !cxxModuleBmiArgs.GetDestination().empty()) { + if (!cxxModuleBmiArgs.GetDestination().empty()) { cxxModuleBmiGenerator = cm::make_unique<cmInstallCxxModuleBmiGenerator>( target.GetName(), helper.GetCxxModulesBmiDestination(&cxxModuleBmiArgs), @@ -2071,12 +2059,7 @@ bool HandleExportMode(std::vector<std::string> const& args, ica.Bind("NAMESPACE"_s, name_space); ica.Bind("EXPORT_LINK_INTERFACE_LIBRARIES"_s, exportOld); ica.Bind("FILE"_s, filename); - - bool const supportCxx20FileSetTypes = cmExperimental::HasSupportEnabled( - *helper.Makefile, cmExperimental::Feature::CxxModuleCMakeApi); - if (supportCxx20FileSetTypes) { - ica.Bind("CXX_MODULES_DIRECTORY"_s, cxx_modules_directory); - } + ica.Bind("CXX_MODULES_DIRECTORY"_s, cxx_modules_directory); std::vector<std::string> unknownArgs; ica.Parse(args, &unknownArgs); diff --git a/Source/cmMakefileTargetGenerator.cxx b/Source/cmMakefileTargetGenerator.cxx index caa5e67..0c2a719 100644 --- a/Source/cmMakefileTargetGenerator.cxx +++ b/Source/cmMakefileTargetGenerator.cxx @@ -204,14 +204,6 @@ void cmMakefileTargetGenerator::WriteTargetBuildRules() { this->GeneratorTarget->CheckCxxModuleStatus(this->GetConfigName()); - if (this->GeneratorTarget->HaveCxx20ModuleSources()) { - this->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - cmStrCat("The target named \"", this->GeneratorTarget->GetName(), - "\" contains C++ sources that export modules which is not " - "supported by the generator")); - } - // -- Write the custom commands for this target // Evaluates generator expressions and expands prop_value diff --git a/Source/cmNinjaTargetGenerator.cxx b/Source/cmNinjaTargetGenerator.cxx index 193cc0f..0bda945 100644 --- a/Source/cmNinjaTargetGenerator.cxx +++ b/Source/cmNinjaTargetGenerator.cxx @@ -266,7 +266,7 @@ std::string cmNinjaTargetGenerator::ComputeFlagsForObject( if (!this->GeneratorTarget->Target->IsNormal()) { auto flag = this->GetMakefile()->GetSafeDefinition( - "CMAKE_EXPERIMENTAL_CXX_MODULE_BMI_ONLY_FLAG"); + "CMAKE_CXX_MODULE_BMI_ONLY_FLAG"); cmRulePlaceholderExpander::RuleVariables compileObjectVars; compileObjectVars.Object = objectFileName.c_str(); auto rulePlaceholderExpander = @@ -710,7 +710,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, } } std::string const modmapFormatVar = - cmStrCat("CMAKE_EXPERIMENTAL_", lang, "_MODULE_MAP_FORMAT"); + cmStrCat("CMAKE_", lang, "_MODULE_MAP_FORMAT"); std::string const modmapFormat = this->Makefile->GetSafeDefinition(modmapFormatVar); @@ -734,7 +734,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, if (withScanning == WithScanning::Yes) { const auto& scanDepType = this->GetMakefile()->GetSafeDefinition( - cmStrCat("CMAKE_EXPERIMENTAL_", lang, "_SCANDEP_DEPFILE_FORMAT")); + cmStrCat("CMAKE_", lang, "_SCANDEP_DEPFILE_FORMAT")); // Rule to scan dependencies of sources that need preprocessing. { @@ -745,7 +745,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, scanRuleName = this->LanguageScanRule(lang, config); ppFileName = "$PREPROCESSED_OUTPUT_FILE"; std::string const& scanCommand = mf->GetRequiredDefinition( - cmStrCat("CMAKE_EXPERIMENTAL_", lang, "_SCANDEP_SOURCE")); + cmStrCat("CMAKE_", lang, "_SCANDEP_SOURCE")); scanCommands.assign(scanCommand); for (auto& i : scanCommands) { i = cmStrCat(launcher, i); @@ -893,8 +893,8 @@ void cmNinjaTargetGenerator::WriteCompileRule(const std::string& lang, } if (withScanning == WithScanning::Yes && !modmapFormat.empty()) { - std::string modmapFlags = mf->GetRequiredDefinition( - cmStrCat("CMAKE_EXPERIMENTAL_", lang, "_MODULE_MAP_FLAG")); + std::string modmapFlags = + mf->GetRequiredDefinition(cmStrCat("CMAKE_", lang, "_MODULE_MAP_FLAG")); cmSystemTools::ReplaceString(modmapFlags, "<MODULE_MAP_FILE>", "$DYNDEP_MODULE_MAP_FILE"); flags += cmStrCat(' ', modmapFlags); @@ -1143,6 +1143,30 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatements( } } + // Detect sources in `CXX_MODULES` which are not compiled. + { + std::vector<cmSourceFile*> sources; + this->GeneratorTarget->GetSourceFiles(sources, config); + for (cmSourceFile const* sf : sources) { + cmFileSet const* fs = + this->GeneratorTarget->GetFileSetForSource(config, sf); + if (!fs) { + continue; + } + if (fs->GetType() != "CXX_MODULES"_s) { + continue; + } + if (sf->GetLanguage().empty()) { + this->GeneratorTarget->Makefile->IssueMessage( + MessageType::FATAL_ERROR, + cmStrCat("Target \"", this->GeneratorTarget->GetName(), + "\" has source file\n ", sf->GetFullPath(), + "\nin a \"FILE_SET TYPE CXX_MODULES\" but it is not " + "scheduled for compilation.")); + } + } + } + for (auto const& langScanningFiles : this->Configs[config].ScanningInfo) { std::string const& language = langScanningFiles.first; std::vector<ScanningFiles> const& scanningFiles = langScanningFiles.second; @@ -1477,7 +1501,7 @@ void cmNinjaTargetGenerator::WriteObjectBuildStatement( std::string modmapFormat; if (needDyndep) { std::string const modmapFormatVar = - cmStrCat("CMAKE_EXPERIMENTAL_", language, "_MODULE_MAP_FORMAT"); + cmStrCat("CMAKE_", language, "_MODULE_MAP_FORMAT"); modmapFormat = this->Makefile->GetSafeDefinition(modmapFormatVar); } @@ -1758,7 +1782,7 @@ void cmNinjaTargetGenerator::WriteCxxModuleBmiBuildStatement( std::string modmapFormat; if (true) { std::string const modmapFormatVar = - cmStrCat("CMAKE_EXPERIMENTAL_", language, "_MODULE_MAP_FORMAT"); + cmStrCat("CMAKE_", language, "_MODULE_MAP_FORMAT"); modmapFormat = this->Makefile->GetSafeDefinition(modmapFormatVar); } @@ -1969,12 +1993,12 @@ void cmNinjaTargetGenerator::ExportObjectCompileCommand( bool const needDyndep = this->GetGeneratorTarget()->NeedDyndep(language, outputConfig); std::string const modmapFormatVar = - cmStrCat("CMAKE_EXPERIMENTAL_", language, "_MODULE_MAP_FORMAT"); + cmStrCat("CMAKE_", language, "_MODULE_MAP_FORMAT"); std::string const modmapFormat = this->Makefile->GetSafeDefinition(modmapFormatVar); if (needDyndep && !modmapFormat.empty()) { std::string modmapFlags = this->GetMakefile()->GetRequiredDefinition( - cmStrCat("CMAKE_EXPERIMENTAL_", language, "_MODULE_MAP_FLAG")); + cmStrCat("CMAKE_", language, "_MODULE_MAP_FLAG")); // XXX(modmap): If changing this path construction, change // `cmGlobalNinjaGenerator::WriteDyndep` and // `cmNinjaTargetGenerator::WriteObjectBuildStatement` to expect the diff --git a/Source/cmPolicies.h b/Source/cmPolicies.h index e894073..1ea2ce2 100644 --- a/Source/cmPolicies.h +++ b/Source/cmPolicies.h @@ -469,6 +469,10 @@ class cmMakefile; SELECT( \ POLICY, CMP0154, \ "Generated files are private by default in targets using file sets.", 3, \ + 28, 0, cmPolicies::WARN) \ + SELECT( \ + POLICY, CMP0155, \ + "C++ sources in targets with at least C++20 are scanned for imports", 3, \ 28, 0, cmPolicies::WARN) #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1) @@ -508,7 +512,8 @@ class cmMakefile; F(CMP0119) \ F(CMP0131) \ F(CMP0142) \ - F(CMP0154) + F(CMP0154) \ + F(CMP0155) #define CM_FOR_EACH_CUSTOM_COMMAND_POLICY(F) \ F(CMP0116) \ diff --git a/Source/cmTargetSourcesCommand.cxx b/Source/cmTargetSourcesCommand.cxx index 3d484f5..babbaa5 100644 --- a/Source/cmTargetSourcesCommand.cxx +++ b/Source/cmTargetSourcesCommand.cxx @@ -10,7 +10,6 @@ #include "cmArgumentParser.h" #include "cmArgumentParserTypes.h" -#include "cmExperimental.h" #include "cmFileSet.h" #include "cmGeneratorExpression.h" #include "cmList.h" @@ -260,28 +259,18 @@ bool TargetSourcesImpl::HandleOneFileSet( this->SetError("Must specify a TYPE when creating file set"); return false; } - bool const supportCxx20FileSetTypes = cmExperimental::HasSupportEnabled( - *this->Makefile, cmExperimental::Feature::CxxModuleCMakeApi); + if (type != "HEADERS"_s && type != "CXX_MODULES"_s) { + this->SetError( + R"(File set TYPE may only be "HEADERS" or "CXX_MODULES")"); + return false; + } - if (supportCxx20FileSetTypes) { - if (type != "HEADERS"_s && type != "CXX_MODULES"_s) { + if (cmFileSetVisibilityIsForInterface(visibility) && + !cmFileSetVisibilityIsForSelf(visibility) && + !this->Target->IsImported()) { + if (type == "CXX_MODULES"_s) { this->SetError( - R"(File set TYPE may only be "HEADERS" or "CXX_MODULES")"); - return false; - } - - if (cmFileSetVisibilityIsForInterface(visibility) && - !cmFileSetVisibilityIsForSelf(visibility) && - !this->Target->IsImported()) { - if (type == "CXX_MODULES"_s) { - this->SetError( - R"(File set TYPE "CXX_MODULES" may not have "INTERFACE" visibility)"); - return false; - } - } - } else { - if (type != "HEADERS"_s) { - this->SetError("File set TYPE may only be \"HEADERS\""); + R"(File set TYPE "CXX_MODULES" may not have "INTERFACE" visibility)"); return false; } } diff --git a/Source/cmVisualStudio10TargetGenerator.cxx b/Source/cmVisualStudio10TargetGenerator.cxx index 2a54a55..ce94fe1 100644 --- a/Source/cmVisualStudio10TargetGenerator.cxx +++ b/Source/cmVisualStudio10TargetGenerator.cxx @@ -362,15 +362,6 @@ void cmVisualStudio10TargetGenerator::Generate() this->GeneratorTarget->CheckCxxModuleStatus(config); } - if (this->GeneratorTarget->HaveCxx20ModuleSources() && - !this->GlobalGenerator->SupportsCxxModuleDyndep()) { - this->Makefile->IssueMessage( - MessageType::FATAL_ERROR, - cmStrCat("The target named \"", this->GeneratorTarget->GetName(), - "\" contains C++ sources that export modules which is not " - "supported by the generator")); - } - this->ProjectType = computeProjectType(this->GeneratorTarget); this->Managed = this->ProjectType == VsProjectType::csproj; const std::string ProjectFileExtension = |