From 197a6bf1714267ad536f27fef5a24cbe6fd3fcff Mon Sep 17 00:00:00 2001 From: Ben Boeckel Date: Wed, 27 Sep 2023 20:31:20 -0400 Subject: cxxmodules: rework control logic for scanning regular C++ sources Now that scanning support is no longer experimental, the logic for whether or not to scan C++ 20 sources is now important because all projects are now exposted to the logic. Make the scanning rules explicit in the documentation and rework the queries to localize all of the associated logic. A policy to handle the ultimate fallback logic will be implemented in a following commit. --- Help/manual/cmake-cxxmodules.7.rst | 17 +++ Source/cmGeneratorTarget.cxx | 122 +++++++++++++++------ Source/cmGlobalVisualStudio7Generator.cxx | 8 -- Source/cmGlobalXCodeGenerator.cxx | 8 -- Source/cmMakefileTargetGenerator.cxx | 8 -- Source/cmVisualStudio10TargetGenerator.cxx | 9 -- Tests/RunCMake/CXXModules/NoCXX-stderr.txt | 13 +-- Tests/RunCMake/CXXModules/NoCXX20-stderr.txt | 14 +-- .../RunCMake/CXXModules/NoDyndepSupport-stderr.txt | 8 +- .../NoScanningSourceFileProperty-result.txt | 1 + .../NoScanningSourceFileProperty-stderr.txt | 9 ++ .../CXXModules/NoScanningSourceFileProperty.cmake | 13 +++ .../CXXModules/NoScanningTargetProperty-result.txt | 1 + .../CXXModules/NoScanningTargetProperty-stderr.txt | 9 ++ .../CXXModules/NoScanningTargetProperty.cmake | 10 ++ Tests/RunCMake/CXXModules/RunCMakeTest.cmake | 3 + 16 files changed, 166 insertions(+), 87 deletions(-) create mode 100644 Tests/RunCMake/CXXModules/NoScanningSourceFileProperty-result.txt create mode 100644 Tests/RunCMake/CXXModules/NoScanningSourceFileProperty-stderr.txt create mode 100644 Tests/RunCMake/CXXModules/NoScanningSourceFileProperty.cmake create mode 100644 Tests/RunCMake/CXXModules/NoScanningTargetProperty-result.txt create mode 100644 Tests/RunCMake/CXXModules/NoScanningTargetProperty-stderr.txt create mode 100644 Tests/RunCMake/CXXModules/NoScanningTargetProperty.cmake diff --git a/Help/manual/cmake-cxxmodules.7.rst b/Help/manual/cmake-cxxmodules.7.rst index 91acae1..a082f58 100644 --- a/Help/manual/cmake-cxxmodules.7.rst +++ b/Help/manual/cmake-cxxmodules.7.rst @@ -12,6 +12,23 @@ to scan source files for module dependencies during the build, collates scanning results to infer ordering constraints, and tells the build tool how to dynamically update the build graph. +Scanning Control +================ + +Whether or not sources get scanned for C++ module usage is dependent on the +following queries. The first query that provides a yes/no answer is used. + +- If the source file belongs to a file set of type ``CXX_MODULES``, it will + be scanned. +- If the target does not use at least C++ 20, it will not be scanned. +- If the source file is not the language ``CXX``, it will not be scanned. +- If the :prop_sf:`CXX_SCAN_FOR_MODULES` source file property is set, its + value will be used. +- If the :prop_tgt:`CXX_SCAN_FOR_MODULES` target property is set, its value + will be used. Set the :variable:`CMAKE_CXX_SCAN_FOR_MODULES` variable + to initialize this property on all targets as they are created. +- Otherwise the source will be scanned. + Compiler Support ================ diff --git a/Source/cmGeneratorTarget.cxx b/Source/cmGeneratorTarget.cxx index bbb47e4..93946aa 100644 --- a/Source/cmGeneratorTarget.cxx +++ b/Source/cmGeneratorTarget.cxx @@ -9115,39 +9115,83 @@ cmGeneratorTarget::Cxx20SupportLevel cmGeneratorTarget::HaveCxxModuleSupport( 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::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::MissingRule: - 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 = cmGeneratorTarget::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, @@ -9185,14 +9229,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(); 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/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/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 = diff --git a/Tests/RunCMake/CXXModules/NoCXX-stderr.txt b/Tests/RunCMake/CXXModules/NoCXX-stderr.txt index 5b609a9..da65c26 100644 --- a/Tests/RunCMake/CXXModules/NoCXX-stderr.txt +++ b/Tests/RunCMake/CXXModules/NoCXX-stderr.txt @@ -1,13 +1,8 @@ -CMake Error in CMakeLists.txt: - The target named "nocxx" has C\+\+ sources that export modules but the "CXX" +(CMake Error in CMakeLists.txt: +( The target named "nocxx" has C\+\+ sources that use modules but the "CXX" language has not been enabled - -( -CMake Error in CMakeLists.txt: -( The target named "nocxx" has C\+\+ sources that export modules but the "CXX" - language has not been enabled -| The target named "nocxx" contains C\+\+ sources that export modules which is - not supported by the generator +| The target named "nocxx" contains C\+\+ sources that use modules which is not + supported by the generator | Target "nocxx" has source file .*/Tests/RunCMake/CXXModules/sources/module.cxx diff --git a/Tests/RunCMake/CXXModules/NoCXX20-stderr.txt b/Tests/RunCMake/CXXModules/NoCXX20-stderr.txt index 4a1641b8..5a9b6e7 100644 --- a/Tests/RunCMake/CXXModules/NoCXX20-stderr.txt +++ b/Tests/RunCMake/CXXModules/NoCXX20-stderr.txt @@ -1,15 +1,9 @@ -CMake Error in CMakeLists.txt: - The target named "nocxx20" has C\+\+ sources that export modules but does not +(CMake Error in CMakeLists.txt: +( The target named "nocxx20" has C\+\+ sources that use modules but does not include "cxx_std_20" \(or newer\) among its `target_compile_features`; found "cxx_std_17" - -( -CMake Error in CMakeLists.txt: -( The target named "nocxx20" has C\+\+ sources that export modules but does not - include "cxx_std_20" \(or newer\) among its `target_compile_features`; found - "cxx_std_17" -| The target named "nocxx20" contains C\+\+ sources that export modules which - is not supported by the generator +| The target named "nocxx20" contains C\+\+ sources that use modules which is + not supported by the generator ) )* CMake Generate step failed. Build files cannot be regenerated correctly. diff --git a/Tests/RunCMake/CXXModules/NoDyndepSupport-stderr.txt b/Tests/RunCMake/CXXModules/NoDyndepSupport-stderr.txt index 6640c99..6a9c995 100644 --- a/Tests/RunCMake/CXXModules/NoDyndepSupport-stderr.txt +++ b/Tests/RunCMake/CXXModules/NoDyndepSupport-stderr.txt @@ -6,13 +6,13 @@ due to lack of required features. Ninja 1.11 or higher is required. |CMake Error in CMakeLists.txt: - The target named "nodyndep" contains C\+\+ sources that export modules which - is not supported by the generator + The target named "nodyndep" contains C\+\+ sources that use modules which is + not supported by the generator ( CMake Error in CMakeLists.txt: - The target named "nodyndep" contains C\+\+ sources that export modules which - is not supported by the generator + The target named "nodyndep" contains C\+\+ sources that use modules which is + not supported by the generator )*) CMake Generate step failed. Build files cannot be regenerated correctly. diff --git a/Tests/RunCMake/CXXModules/NoScanningSourceFileProperty-result.txt b/Tests/RunCMake/CXXModules/NoScanningSourceFileProperty-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CXXModules/NoScanningSourceFileProperty-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CXXModules/NoScanningSourceFileProperty-stderr.txt b/Tests/RunCMake/CXXModules/NoScanningSourceFileProperty-stderr.txt new file mode 100644 index 0000000..464627c --- /dev/null +++ b/Tests/RunCMake/CXXModules/NoScanningSourceFileProperty-stderr.txt @@ -0,0 +1,9 @@ +(CMake Error in CMakeLists.txt: +( The target named "noscanning-sf-property" has C\+\+ sources that use modules + but the compiler does not provide a way to discover the import graph + dependencies +| The target named "noscanning-sf-property" contains C\+\+ sources that use modules which + is not supported by the generator +) +)* +CMake Generate step failed. Build files cannot be regenerated correctly. diff --git a/Tests/RunCMake/CXXModules/NoScanningSourceFileProperty.cmake b/Tests/RunCMake/CXXModules/NoScanningSourceFileProperty.cmake new file mode 100644 index 0000000..f356a11 --- /dev/null +++ b/Tests/RunCMake/CXXModules/NoScanningSourceFileProperty.cmake @@ -0,0 +1,13 @@ +enable_language(CXX) +unset(CMAKE_CXX_SCANDEP_SOURCE) + +add_executable(noscanning-sf-property + sources/module-use.cxx) +set_target_properties(noscanning-sf-property + PROPERTIES + CXX_STANDARD 20 + CXX_STANDARD_REQUIRED ON + CXX_SCAN_FOR_MODULES 0) +set_source_files_properties(sources/module-use.cxx + PROPERTIES + CXX_SCAN_FOR_MODULES 1) diff --git a/Tests/RunCMake/CXXModules/NoScanningTargetProperty-result.txt b/Tests/RunCMake/CXXModules/NoScanningTargetProperty-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/CXXModules/NoScanningTargetProperty-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/CXXModules/NoScanningTargetProperty-stderr.txt b/Tests/RunCMake/CXXModules/NoScanningTargetProperty-stderr.txt new file mode 100644 index 0000000..72c7a0a --- /dev/null +++ b/Tests/RunCMake/CXXModules/NoScanningTargetProperty-stderr.txt @@ -0,0 +1,9 @@ +(CMake Error in CMakeLists.txt: +( The target named "noscanning-target-property" has C\+\+ sources that use + modules but the compiler does not provide a way to discover the import + graph dependencies +| The target named "noscanning-target-property" contains C\+\+ sources that use modules which + is not supported by the generator +) +)* +CMake Generate step failed. Build files cannot be regenerated correctly. diff --git a/Tests/RunCMake/CXXModules/NoScanningTargetProperty.cmake b/Tests/RunCMake/CXXModules/NoScanningTargetProperty.cmake new file mode 100644 index 0000000..97a3d44 --- /dev/null +++ b/Tests/RunCMake/CXXModules/NoScanningTargetProperty.cmake @@ -0,0 +1,10 @@ +enable_language(CXX) +unset(CMAKE_CXX_SCANDEP_SOURCE) + +add_executable(noscanning-target-property + sources/module-use.cxx) +set_target_properties(noscanning-target-property + PROPERTIES + CXX_STANDARD 20 + CXX_STANDARD_REQUIRED ON + CXX_SCAN_FOR_MODULES 1) diff --git a/Tests/RunCMake/CXXModules/RunCMakeTest.cmake b/Tests/RunCMake/CXXModules/RunCMakeTest.cmake index 2f32312..a697659 100644 --- a/Tests/RunCMake/CXXModules/RunCMakeTest.cmake +++ b/Tests/RunCMake/CXXModules/RunCMakeTest.cmake @@ -14,6 +14,9 @@ if ("cxx_std_20" IN_LIST CMAKE_CXX_COMPILE_FEATURES) if (NOT forced_cxx_standard) run_cmake(NoCXX20) endif () + + run_cmake(NoScanningSourceFileProperty) + run_cmake(NoScanningTargetProperty) endif () if (RunCMake_GENERATOR MATCHES "Ninja") -- cgit v0.12