Forráskód Böngészése

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.
Ben Boeckel 2 éve
szülő
commit
197a6bf171

+ 17 - 0
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
 ================
 

+ 91 - 31
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();

+ 0 - 8
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) {

+ 0 - 8
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) {

+ 0 - 8
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

+ 0 - 9
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 =

+ 4 - 9
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

+ 4 - 10
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.

+ 4 - 4
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.

+ 1 - 0
Tests/RunCMake/CXXModules/NoScanningSourceFileProperty-result.txt

@@ -0,0 +1 @@
+1

+ 9 - 0
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.

+ 13 - 0
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)

+ 1 - 0
Tests/RunCMake/CXXModules/NoScanningTargetProperty-result.txt

@@ -0,0 +1 @@
+1

+ 9 - 0
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.

+ 10 - 0
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)

+ 3 - 0
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")