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
This commit is contained in:
Ben Boeckel
2026-03-25 22:39:32 -04:00
parent 8ba08a0000
commit 4a4986d28a
12 changed files with 64 additions and 30 deletions

View File

@@ -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
^^^^^^^^^

View File

@@ -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()

View File

@@ -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];

View File

@@ -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);

View File

@@ -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,

View File

@@ -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": [

View File

@@ -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": [

View File

@@ -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": [

View File

@@ -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": [

View File

@@ -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": [

View File

@@ -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": [

View File

@@ -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>")