mirror of
https://github.com/Kitware/CMake.git
synced 2025-10-19 19:43:23 +08:00
Ninja Multi-Config: Fix custom command target dependencies in cross-configs
Generator expressions in a non-cross custom command's `COMMAND` arguments are evaluated in the command config. Target-level dependencies implied by `TARGET_FILE` must therefore be cross dependencies. This is important to generate proper target-level dependencies on the cross-config build statements for the target to which the custom command is attached. Fixes: #22855
This commit is contained in:
@@ -91,7 +91,7 @@ std::string EvaluateSplitConfigGenex(
|
|||||||
|
|
||||||
// Record targets referenced by the genex.
|
// Record targets referenced by the genex.
|
||||||
if (utils) {
|
if (utils) {
|
||||||
// FIXME: What is the proper condition for a cross-dependency?
|
// Use a cross-dependency if we referenced the command config.
|
||||||
bool const cross = !useOutputConfig;
|
bool const cross = !useOutputConfig;
|
||||||
for (cmGeneratorTarget* gt : cge->GetTargets()) {
|
for (cmGeneratorTarget* gt : cge->GetTargets()) {
|
||||||
utils->emplace(BT<std::pair<std::string, bool>>(
|
utils->emplace(BT<std::pair<std::string, bool>>(
|
||||||
@@ -176,6 +176,8 @@ cmCustomCommandGenerator::cmCustomCommandGenerator(
|
|||||||
cmGeneratorTarget const* target{ lg->FindGeneratorTargetToUse(
|
cmGeneratorTarget const* target{ lg->FindGeneratorTargetToUse(
|
||||||
this->Target) };
|
this->Target) };
|
||||||
|
|
||||||
|
bool const distinctConfigs = this->OutputConfig != this->CommandConfig;
|
||||||
|
|
||||||
const cmCustomCommandLines& cmdlines = this->CC->GetCommandLines();
|
const cmCustomCommandLines& cmdlines = this->CC->GetCommandLines();
|
||||||
for (cmCustomCommandLine const& cmdline : cmdlines) {
|
for (cmCustomCommandLine const& cmdline : cmdlines) {
|
||||||
cmCustomCommandLine argv;
|
cmCustomCommandLine argv;
|
||||||
@@ -191,16 +193,18 @@ cmCustomCommandGenerator::cmCustomCommandGenerator(
|
|||||||
argv.push_back(std::move(parsed_arg));
|
argv.push_back(std::move(parsed_arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (distinctConfigs) {
|
||||||
// For remaining arguments, we default to the OUTPUT_CONFIG.
|
// For remaining arguments, we default to the OUTPUT_CONFIG.
|
||||||
useOutputConfig = true;
|
useOutputConfig = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!argv.empty()) {
|
if (!argv.empty()) {
|
||||||
// If the command references an executable target by name,
|
// If the command references an executable target by name,
|
||||||
// collect the target to add a target-level dependency on it.
|
// collect the target to add a target-level dependency on it.
|
||||||
cmGeneratorTarget* gt = this->LG->FindGeneratorTargetToUse(argv.front());
|
cmGeneratorTarget* gt = this->LG->FindGeneratorTargetToUse(argv.front());
|
||||||
if (gt && gt->GetType() == cmStateEnums::EXECUTABLE) {
|
if (gt && gt->GetType() == cmStateEnums::EXECUTABLE) {
|
||||||
// FIXME: What is the proper condition for a cross-dependency?
|
// GetArgv0Location uses the command config, so use a cross-dependency.
|
||||||
bool const cross = true;
|
bool const cross = true;
|
||||||
this->Utilities.emplace(BT<std::pair<std::string, bool>>(
|
this->Utilities.emplace(BT<std::pair<std::string, bool>>(
|
||||||
{ gt->GetName(), cross }, cc.GetBacktrace()));
|
{ gt->GetName(), cross }, cc.GetBacktrace()));
|
||||||
|
@@ -0,0 +1,2 @@
|
|||||||
|
^\[1/1\] Generating echo_depend_target\.txt
|
||||||
|
'[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build'\$ '[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Release[\/]echo(\.exe)?' 'Release'$
|
@@ -0,0 +1,2 @@
|
|||||||
|
^\[1/1\] Generating echo_depend_target\.txt
|
||||||
|
'[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build'\$ '[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Debug[\/]echo(\.exe)?' 'Debug'$
|
@@ -0,0 +1,2 @@
|
|||||||
|
^\[1/1\] Generating echo_depend_target\.txt
|
||||||
|
'[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build'\$ '[^']*[\/]Tests[\/]RunCMake[\/]NinjaMultiConfig[\/]CustomCommandOutputGenex-build[\/]Release[\/]echo(\.exe)?' 'Release'$
|
@@ -143,6 +143,16 @@ add_custom_command(
|
|||||||
PROPERTY SYMBOLIC 1)
|
PROPERTY SYMBOLIC 1)
|
||||||
add_custom_target(echo_dbgx DEPENDS "$<$<CONFIG:Debug>:echo_dbgx_Debug.txt>")
|
add_custom_target(echo_dbgx DEPENDS "$<$<CONFIG:Debug>:echo_dbgx_Debug.txt>")
|
||||||
|
|
||||||
|
# A non-cross-config custom command expresses target dependencies in command config.
|
||||||
|
add_custom_command(
|
||||||
|
OUTPUT echo_depend_target.txt
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E env $<TARGET_FILE:echo> $<CONFIG>
|
||||||
|
# A real project should do:
|
||||||
|
# DEPENDS $<TARGET_FILE:echo>
|
||||||
|
# but here we are testing the target-level dependency implied by TARGET_FILE.
|
||||||
|
)
|
||||||
|
add_custom_target(echo_depend_target DEPENDS echo_depend_target.txt)
|
||||||
|
|
||||||
add_custom_target(echo_target_raw
|
add_custom_target(echo_target_raw
|
||||||
BYPRODUCTS echo_target_raw_$<CONFIG>.txt
|
BYPRODUCTS echo_target_raw_$<CONFIG>.txt
|
||||||
COMMENT echo_target_raw
|
COMMENT echo_target_raw
|
||||||
|
@@ -344,6 +344,16 @@ run_ninja(CustomCommandOutputGenex echo_dbgx-release build-Release.ninja echo_db
|
|||||||
run_ninja(CustomCommandOutputGenex clean-release-graph build-Release.ninja -t clean)
|
run_ninja(CustomCommandOutputGenex clean-release-graph build-Release.ninja -t clean)
|
||||||
run_ninja(CustomCommandOutputGenex echo_dbgx-debug-in-release-graph build-Release.ninja echo_dbgx:Debug)
|
run_ninja(CustomCommandOutputGenex echo_dbgx-debug-in-release-graph build-Release.ninja echo_dbgx:Debug)
|
||||||
run_ninja(CustomCommandOutputGenex clean-release-graph build-Release.ninja -t clean)
|
run_ninja(CustomCommandOutputGenex clean-release-graph build-Release.ninja -t clean)
|
||||||
|
# echo_depend_target
|
||||||
|
run_ninja(CustomCommandOutputGenex echo_depend_target-debug-prep build-Debug.ninja echo:Debug)
|
||||||
|
run_ninja(CustomCommandOutputGenex echo_depend_target-debug build-Debug.ninja echo_depend_target)
|
||||||
|
run_ninja(CustomCommandOutputGenex clean-debug-graph build-Debug.ninja -t clean)
|
||||||
|
run_ninja(CustomCommandOutputGenex echo_depend_target-release-prep build-Release.ninja echo:Release)
|
||||||
|
run_ninja(CustomCommandOutputGenex echo_depend_target-release build-Release.ninja echo_depend_target)
|
||||||
|
run_ninja(CustomCommandOutputGenex clean-release-graph build-Release.ninja -t clean)
|
||||||
|
run_ninja(CustomCommandOutputGenex echo_depend_target-debug-in-release-graph-prep build-Release.ninja echo:Release)
|
||||||
|
run_ninja(CustomCommandOutputGenex echo_depend_target-debug-in-release-graph build-Release.ninja echo_depend_target:Debug)
|
||||||
|
run_ninja(CustomCommandOutputGenex clean-release-graph build-Release.ninja -t clean)
|
||||||
# echo_target_raw
|
# echo_target_raw
|
||||||
run_ninja(CustomCommandOutputGenex echo_target_raw-debug build-Debug.ninja echo_target_raw:Debug)
|
run_ninja(CustomCommandOutputGenex echo_target_raw-debug build-Debug.ninja echo_target_raw:Debug)
|
||||||
run_ninja(CustomCommandOutputGenex clean-debug-graph build-Debug.ninja -t clean)
|
run_ninja(CustomCommandOutputGenex clean-debug-graph build-Debug.ninja -t clean)
|
||||||
|
Reference in New Issue
Block a user