Jelajahi Sumber

cxxmodules: support command templates for BMI compilation

Some compilers (Clang) warn when using their BMI-only flag with `-c`.
Support a complete template for BMI compilation rather than an
additional flag to support such toolchains.

Fixes: #27600
Ben Boeckel 2 minggu lalu
induk
melakukan
4a4986d28a

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

@@ -470,13 +470,18 @@ Additionally, toolchains should set the following variables:
 * ``CMAKE_CXX_MODULE_MAP_FLAG``: The arguments used to inform the compiler of
   the :term:`module map` file.  It should use the ``<MODULE_MAP_FILE>``
   placeholder.
+* ``CMAKE_CXX_COMPILE_BMI``: The command template to compile a :term:`BMI`
+  file from a :term:`module interface unit`.  Used when
+  ``CMAKE_CXX_MODULE_BMI_ONLY_FLAG`` is not completely additive to an
+  object compilation template.
 * ``CMAKE_CXX_MODULE_BMI_ONLY_FLAG``: The arguments used to compile only a
   :term:`BMI` file from a :term:`module interface unit`.  This is used when
   consuming modules from external projects to compile :term:`BMI` files for
   use within the current build.
 
-If a toolchain does not provide the ``CMAKE_CXX_MODULE_BMI_ONLY_FLAG``, it
-will not be able to consume modules provided by ``IMPORTED`` targets.
+If a toolchain does not provide the ``CMAKE_CXX_COMPILE_BMI`` or
+``CMAKE_CXX_MODULE_BMI_ONLY_FLAG`` variables, it will not be able to consume
+modules provided by ``IMPORTED`` targets.
 
 Configure
 ^^^^^^^^^

+ 2 - 1
Modules/Compiler/Clang-CXX.cmake

@@ -56,6 +56,7 @@ if(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 16.0)
     unset(_clang_scan_deps_mv)
     set(CMAKE_CXX_MODULE_MAP_FORMAT "clang")
     set(CMAKE_CXX_MODULE_MAP_FLAG "@<MODULE_MAP_FILE>")
-    set(CMAKE_CXX_MODULE_BMI_ONLY_FLAG "--precompile")
+    set(CMAKE_CXX_COMPILE_BMI
+      "<CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -o <OBJECT> --precompile <SOURCE>")
   endif()
 endif()

+ 14 - 8
Source/cmGeneratorTarget.cxx

@@ -2335,6 +2335,7 @@ cmGeneratorTarget::GetClassifiedFlagsForSource(cmSourceFile const* sf,
   }
 
   // C++ module flags.
+  bool useBmiTemplate = false;
   if (lang == "CXX"_s) {
     FlagClassification cls = FlagClassification::LocationFlag;
     FlagKind kind = FlagKind::BuildSystem;
@@ -2353,13 +2354,17 @@ cmGeneratorTarget::GetClassifiedFlagsForSource(cmSourceFile const* sf,
       }
 
       if (!this->Target->IsNormal()) {
-        auto flag = mf->GetSafeDefinition("CMAKE_CXX_MODULE_BMI_ONLY_FLAG");
-        cmRulePlaceholderExpander::RuleVariables compileObjectVars;
-        compileObjectVars.Object = sfVars.ObjectFileDir.c_str();
-        auto rulePlaceholderExpander = lg->CreateRulePlaceholderExpander();
-        rulePlaceholderExpander->ExpandRuleVariables(lg, flag,
-                                                     compileObjectVars);
-        lg->AppendCompileOptions(bmiFlags, flag);
+        if (!mf->GetDefinition("CMAKE_CXX_COMPILE_BMI").IsEmpty()) {
+          useBmiTemplate = true;
+        } else {
+          auto flag = mf->GetSafeDefinition("CMAKE_CXX_MODULE_BMI_ONLY_FLAG");
+          cmRulePlaceholderExpander::RuleVariables compileObjectVars;
+          compileObjectVars.Object = sfVars.ObjectFileDir.c_str();
+          auto rulePlaceholderExpander = lg->CreateRulePlaceholderExpander();
+          rulePlaceholderExpander->ExpandRuleVariables(lg, flag,
+                                                       compileObjectVars);
+          lg->AppendCompileOptions(bmiFlags, flag);
+        }
       }
     }
 
@@ -2382,7 +2387,8 @@ cmGeneratorTarget::GetClassifiedFlagsForSource(cmSourceFile const* sf,
     FlagClassification cls = FlagClassification::ExecutionFlag;
     FlagKind kind = FlagKind::NotAFlag;
 
-    std::string const cmdVar = cmStrCat("CMAKE_", lang, "_COMPILE_OBJECT");
+    std::string const cmdVar =
+      cmStrCat("CMAKE_", lang, "_COMPILE_", useBmiTemplate ? "BMI" : "OBJECT");
     std::string const& compileCmd = mf->GetRequiredDefinition(cmdVar);
     cmList compileCmds(compileCmd); // FIXME: which command to use?
     std::string& cmd = compileCmds[0];

+ 28 - 11
Source/cmNinjaTargetGenerator.cxx

@@ -265,15 +265,19 @@ std::string cmNinjaTargetGenerator::ComputeFlagsForObject(
     }
 
     if (!this->GeneratorTarget->Target->IsNormal()) {
-      auto flag = this->GetMakefile()->GetSafeDefinition(
-        "CMAKE_CXX_MODULE_BMI_ONLY_FLAG");
-      cmRulePlaceholderExpander::RuleVariables compileObjectVars;
-      compileObjectVars.Object = objectFileName.c_str();
-      auto rulePlaceholderExpander =
-        this->GetLocalGenerator()->CreateRulePlaceholderExpander();
-      rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(),
-                                                   flag, compileObjectVars);
-      this->LocalGenerator->AppendCompileOptions(flags, flag);
+      if (this->GetMakefile()
+            ->GetDefinition("CMAKE_CXX_COMPILE_BMI")
+            .IsEmpty()) {
+        auto flag = this->GetMakefile()->GetSafeDefinition(
+          "CMAKE_CXX_MODULE_BMI_ONLY_FLAG");
+        cmRulePlaceholderExpander::RuleVariables compileObjectVars;
+        compileObjectVars.Object = objectFileName.c_str();
+        auto rulePlaceholderExpander =
+          this->GetLocalGenerator()->CreateRulePlaceholderExpander();
+        rulePlaceholderExpander->ExpandRuleVariables(this->GetLocalGenerator(),
+                                                     flag, compileObjectVars);
+        this->LocalGenerator->AppendCompileOptions(flags, flag);
+      }
     }
   }
 
@@ -652,6 +656,19 @@ void cmNinjaTargetGenerator::WriteCompileRule(std::string const& lang,
   this->WriteCompileRule(lang, config, WithScanning::No);
 }
 
+std::string cmNinjaTargetGenerator::GetCompileTemplateVar(
+  std::string const& lang) const
+{
+  std::string cmdVar = cmStrCat("CMAKE_", lang, "_COMPILE_OBJECT");
+  if (!this->GetGeneratorTarget()->IsNormal()) {
+    std::string bmiCmdVar = cmStrCat("CMAKE_", lang, "_COMPILE_BMI");
+    if (!this->GetMakefile()->GetDefinition(bmiCmdVar).IsEmpty()) {
+      cmdVar = std::move(bmiCmdVar);
+    }
+  }
+  return cmdVar;
+}
+
 void cmNinjaTargetGenerator::WriteCompileRule(std::string const& lang,
                                               std::string const& config,
                                               WithScanning withScanning)
@@ -928,7 +945,7 @@ void cmNinjaTargetGenerator::WriteCompileRule(std::string const& lang,
   }
 
   // Rule for compiling object file.
-  std::string const cmdVar = cmStrCat("CMAKE_", lang, "_COMPILE_OBJECT");
+  std::string const cmdVar = this->GetCompileTemplateVar(lang);
   std::string const& compileCmd = mf->GetRequiredDefinition(cmdVar);
   cmList compileCmds(compileCmd);
 
@@ -2313,7 +2330,7 @@ void cmNinjaTargetGenerator::ExportObjectCompileCommand(
     compileObjectVars.CudaCompileMode = cudaCompileMode.c_str();
   }
 
-  std::string const cmdVar = cmStrCat("CMAKE_", language, "_COMPILE_OBJECT");
+  std::string const cmdVar = this->GetCompileTemplateVar(language);
   std::string const& compileCmd =
     this->Makefile->GetRequiredDefinition(cmdVar);
   cmList compileCmds(compileCmd);

+ 1 - 0
Source/cmNinjaTargetGenerator.h

@@ -168,6 +168,7 @@ protected:
 
   void WriteLanguageRules(std::string const& language,
                           std::string const& config);
+  std::string GetCompileTemplateVar(std::string const& lang) const;
   void WriteCompileRule(std::string const& language,
                         std::string const& config);
   void WriteCompileRule(std::string const& language, std::string const& config,

+ 2 - 2
Tests/RunCMake/CXXModulesCompile/expect/exp-builddb-imped-all-multi.json

@@ -143,7 +143,7 @@
             "REGEX:PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_DIR>/.d\"",
             "REGEX:<BMI_ONLY_FLAG>",
             "REGEX:PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_DIR>/",
-            "-c",
+            "REGEX:-[cv]",
             "PATH:<SOURCE_DIR>/exp-builddb/importable.cxx"
           ],
           "baseline-arguments": [
@@ -229,7 +229,7 @@
             "REGEX:PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_OTHER_DIR>/.d\"",
             "REGEX:<BMI_ONLY_FLAG>",
             "REGEX:PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_OTHER_DIR>/",
-            "-c",
+            "REGEX:-[cv]",
             "PATH:<SOURCE_DIR>/exp-builddb/importable.cxx"
           ],
           "baseline-arguments": [

+ 1 - 1
Tests/RunCMake/CXXModulesCompile/expect/exp-builddb-imped-all.json

@@ -87,7 +87,7 @@
             "REGEX:PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_DIR>/.d\"",
             "REGEX:<BMI_ONLY_FLAG>",
             "REGEX:PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_DIR>/",
-            "-c",
+            "REGEX:-[cv]",
             "PATH:<SOURCE_DIR>/exp-builddb/importable.cxx"
           ],
           "baseline-arguments": [

+ 1 - 1
Tests/RunCMake/CXXModulesCompile/expect/exp-builddb-imped-config.json

@@ -87,7 +87,7 @@
             "REGEX:PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_DIR>/.d\"",
             "REGEX:<BMI_ONLY_FLAG>",
             "REGEX:PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_DIR>/",
-            "-c",
+            "REGEX:-[cv]",
             "PATH:<SOURCE_DIR>/exp-builddb/importable.cxx"
           ],
           "baseline-arguments": [

+ 1 - 1
Tests/RunCMake/CXXModulesCompile/expect/exp-builddb-imped-cxx-config.json

@@ -87,7 +87,7 @@
             "REGEX:PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_DIR>/.d\"",
             "REGEX:<BMI_ONLY_FLAG>",
             "REGEX:PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_DIR>/",
-            "-c",
+            "REGEX:-[cv]",
             "PATH:<SOURCE_DIR>/exp-builddb/importable.cxx"
           ],
           "baseline-arguments": [

+ 2 - 2
Tests/RunCMake/CXXModulesCompile/expect/exp-builddb-imped-cxx-multi.json

@@ -143,7 +143,7 @@
             "REGEX:PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_DIR>/.d\"",
             "REGEX:<BMI_ONLY_FLAG>",
             "REGEX:PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_DIR>/",
-            "-c",
+            "REGEX:-[cv]",
             "PATH:<SOURCE_DIR>/exp-builddb/importable.cxx"
           ],
           "baseline-arguments": [
@@ -229,7 +229,7 @@
             "REGEX:PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_OTHER_DIR>/.d\"",
             "REGEX:<BMI_ONLY_FLAG>",
             "REGEX:PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_OTHER_DIR>/",
-            "-c",
+            "REGEX:-[cv]",
             "PATH:<SOURCE_DIR>/exp-builddb/importable.cxx"
           ],
           "baseline-arguments": [

+ 1 - 1
Tests/RunCMake/CXXModulesCompile/expect/exp-builddb-imped-cxx.json

@@ -87,7 +87,7 @@
             "REGEX:PATH:-Ddepflag=\"CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_DIR>/.d\"",
             "REGEX:<BMI_ONLY_FLAG>",
             "REGEX:PATH:<OUTPUT_FLAG>CMakeFiles/CXXModules__export_build_database@synth_<HEX>.dir<CONFIG_DIR>/",
-            "-c",
+            "REGEX:-[cv]",
             "PATH:<SOURCE_DIR>/exp-builddb/importable.cxx"
           ],
           "baseline-arguments": [

+ 4 - 0
Tests/RunCMake/CXXModulesCompile/export-build-database-setup.cmake

@@ -36,6 +36,10 @@ if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
 else ()
   set(output_flag "-o")
 endif ()
+if (CMAKE_CXX_COMPILE_BMI) # Only `clang` does this today.
+  set(CMAKE_CXX_COMPILE_BMI
+    "<CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> --precompile ${output_flag}<OBJECT> -v <SOURCE>")
+endif ()
 set(CMAKE_CXX_COMPILE_OBJECT
   "<CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> ${output_flag}<OBJECT> -c <SOURCE>")