Browse Source

CMP0155: ignore scanning for sources if no scanner is available

This allows for a more graceful transition for projects using C++20
without scanner support (e.g., Clang 15 or GCC 13). While newer
compilers will (needlessly) scan, it allows C++20-using projects to use
older compilers without having to set `CMAKE_CXX_SCAN_FOR_MODULES` to
support newer CMake minimum versions.

Fixes: #25357
Ben Boeckel 2 years ago
parent
commit
889aa0354a

+ 2 - 1
Help/manual/cmake-cxxmodules.7.rst

@@ -27,7 +27,8 @@ following queries. The first query that provides a yes/no answer is used.
 - If the :prop_tgt:`CXX_SCAN_FOR_MODULES` target property is set, its value
 - 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
   will be used.  Set the :variable:`CMAKE_CXX_SCAN_FOR_MODULES` variable
   to initialize this property on all targets as they are created.
   to initialize this property on all targets as they are created.
-- Otherwise, the source file will be scanned.  See policy :policy:`CMP0155`.
+- Otherwise, the source file will be scanned if the compiler and generator
+  support scanning.  See policy :policy:`CMP0155`.
 
 
 Compiler Support
 Compiler Support
 ================
 ================

+ 1 - 1
Help/manual/cmake-policies.7.rst

@@ -57,7 +57,7 @@ Policies Introduced by CMake 3.28
 .. toctree::
 .. toctree::
    :maxdepth: 1
    :maxdepth: 1
 
 
-   CMP0155: C++ sources in targets with at least C++20 are scanned for imports. </policy/CMP0155>
+   CMP0155: C++ sources in targets with at least C++20 are scanned for imports when supported. </policy/CMP0155>
    CMP0154: Generated files are private by default in targets using file sets. </policy/CMP0154>
    CMP0154: Generated files are private by default in targets using file sets. </policy/CMP0154>
    CMP0153: The exec_program command should not be called. </policy/CMP0153>
    CMP0153: The exec_program command should not be called. </policy/CMP0153>
    CMP0152: file(REAL_PATH) resolves symlinks before collapsing ../ components.  </policy/CMP0152>
    CMP0152: file(REAL_PATH) resolves symlinks before collapsing ../ components.  </policy/CMP0152>

+ 4 - 2
Help/policy/CMP0155.rst

@@ -3,7 +3,8 @@ CMP0155
 
 
 .. versionadded:: 3.28
 .. versionadded:: 3.28
 
 
-C++ sources in targets with at least C++20 are scanned for imports.
+C++ sources in targets with at least C++20 are scanned for imports
+when supported.
 
 
 CMake 3.27 and below assume that C++ sources do not ``import`` modules.
 CMake 3.27 and below assume that C++ sources do not ``import`` modules.
 CMake 3.28 and above prefer to assume that C++ sources in targets using C++20
 CMake 3.28 and above prefer to assume that C++ sources in targets using C++20
@@ -16,7 +17,8 @@ support.
 
 
 The ``OLD`` behavior for this policy is to assume that C++ 20 and newer
 The ``OLD`` behavior for this policy is to assume that C++ 20 and newer
 sources do not import modules.  The ``NEW`` behavior for this policy is to
 sources do not import modules.  The ``NEW`` behavior for this policy is to
-assume that C++ 20 and newer files may import modules, and need to be scanned.
+assume that C++ 20 and newer files may import modules if the compiler
+understands how to scan for their dependencies, and need to be scanned.
 
 
 This policy was introduced in CMake version 3.28.  Use the
 This policy was introduced in CMake version 3.28.  Use the
 :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.
 :command:`cmake_policy` command to set it to ``OLD`` or ``NEW`` explicitly.

+ 8 - 2
Source/cmGeneratorTarget.cxx

@@ -9292,14 +9292,19 @@ bool cmGeneratorTarget::NeedDyndepForSource(std::string const& lang,
     return true;
     return true;
   }
   }
 
 
+  bool haveRule = false;
   switch (this->HaveCxxModuleSupport(config)) {
   switch (this->HaveCxxModuleSupport(config)) {
     case Cxx20SupportLevel::MissingCxx:
     case Cxx20SupportLevel::MissingCxx:
     case Cxx20SupportLevel::NoCxx20:
     case Cxx20SupportLevel::NoCxx20:
       return false;
       return false;
     case Cxx20SupportLevel::MissingRule:
     case Cxx20SupportLevel::MissingRule:
+      break;
     case Cxx20SupportLevel::Supported:
     case Cxx20SupportLevel::Supported:
+      haveRule = true;
       break;
       break;
   }
   }
+  bool haveGeneratorSupport =
+    this->GetGlobalGenerator()->CheckCxxModuleSupport();
   auto const sfProp = sf->GetProperty("CXX_SCAN_FOR_MODULES");
   auto const sfProp = sf->GetProperty("CXX_SCAN_FOR_MODULES");
   if (sfProp.IsSet()) {
   if (sfProp.IsSet()) {
     return sfProp.IsOn();
     return sfProp.IsOn();
@@ -9319,8 +9324,9 @@ bool cmGeneratorTarget::NeedDyndepForSource(std::string const& lang,
     case cmPolicies::REQUIRED_ALWAYS:
     case cmPolicies::REQUIRED_ALWAYS:
     case cmPolicies::REQUIRED_IF_USED:
     case cmPolicies::REQUIRED_IF_USED:
     case cmPolicies::NEW:
     case cmPolicies::NEW:
-      // The NEW behavior is to scan the source.
-      policyAnswer = true;
+      // The NEW behavior is to scan the source if the compiler supports
+      // scanning and the generator supports it.
+      policyAnswer = haveRule && haveGeneratorSupport;
       break;
       break;
   }
   }
   return policyAnswer;
   return policyAnswer;

+ 4 - 4
Source/cmPolicies.h

@@ -470,10 +470,10 @@ class cmMakefile;
     POLICY, CMP0154,                                                          \
     POLICY, CMP0154,                                                          \
     "Generated files are private by default in targets using file sets.", 3,  \
     "Generated files are private by default in targets using file sets.", 3,  \
     28, 0, cmPolicies::WARN)                                                  \
     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)
+  SELECT(POLICY, CMP0155,                                                     \
+         "C++ sources in targets with at least C++20 are scanned for "        \
+         "imports when supported.",                                           \
+         3, 28, 0, cmPolicies::WARN)
 
 
 #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
 #define CM_SELECT_ID(F, A1, A2, A3, A4, A5, A6) F(A1)
 #define CM_FOR_EACH_POLICY_ID(POLICY)                                         \
 #define CM_FOR_EACH_POLICY_ID(POLICY)                                         \

+ 0 - 1
Tests/RunCMake/CXXModules/CMP0155-NEW-result.txt

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

+ 0 - 10
Tests/RunCMake/CXXModules/CMP0155-NEW-stderr.txt

@@ -1,10 +0,0 @@
-(CMake Error in CMakeLists.txt:
-  The target named "cmp0155-new" has C\+\+ sources that may use modules, but
-  the compiler does not provide a way to discover the import graph
-  dependencies\.  See the cmake-cxxmodules\(7\) manual and the
-  CMAKE_CXX_SCAN_FOR_MODULES variable\.
-|CMake Error in CMakeLists.txt:
-  The target named "cmp0155-new" has C\+\+ sources that may use modules, but
-  modules are not supported by this generator\.  See the cmake-cxxmodules\(7\)
-  manual and the CMAKE_CXX_SCAN_FOR_MODULES variable\.
-)

+ 11 - 0
Tests/RunCMake/CXXModules/CMP0155-NEW-with-rule.cmake

@@ -0,0 +1,11 @@
+enable_language(CXX)
+set(CMAKE_CXX_SCANDEP_SOURCE "echo")
+
+cmake_policy(SET CMP0155 NEW)
+
+add_executable(cmp0155-new-with-rule
+  sources/module-use.cxx)
+set_target_properties(cmp0155-new-with-rule
+  PROPERTIES
+    CXX_STANDARD 20
+    CXX_STANDARD_REQUIRED ON)

+ 2 - 2
Tests/RunCMake/CXXModules/CMP0155-NEW.cmake

@@ -3,8 +3,8 @@ unset(CMAKE_CXX_SCANDEP_SOURCE)
 
 
 cmake_policy(SET CMP0155 NEW)
 cmake_policy(SET CMP0155 NEW)
 
 
-add_executable(cmp0155-new
-  sources/module-use.cxx)
+add_library(cmp0155-new
+  sources/cxx-anchor.cxx)
 set_target_properties(cmp0155-new
 set_target_properties(cmp0155-new
   PROPERTIES
   PROPERTIES
     CXX_STANDARD 20
     CXX_STANDARD 20

+ 1 - 0
Tests/RunCMake/CXXModules/RunCMakeTest.cmake

@@ -23,6 +23,7 @@ if ("cxx_std_20" IN_LIST CMAKE_CXX_COMPILE_FEATURES)
   run_cmake(NoScanningVariable)
   run_cmake(NoScanningVariable)
   run_cmake(CMP0155-OLD)
   run_cmake(CMP0155-OLD)
   run_cmake(CMP0155-NEW)
   run_cmake(CMP0155-NEW)
+  run_cmake(CMP0155-NEW-with-rule)
 endif ()
 endif ()
 
 
 if (RunCMake_GENERATOR MATCHES "Ninja")
 if (RunCMake_GENERATOR MATCHES "Ninja")