Ninja: Account for explicit target dependencies via CODEGEN

When a "normal" target (e.g., an executable) depends on a custom target
that is not part of `all`, and that custom target owns the output of a
custom command marked `CODEGEN`, an explicit `add_dependencies` from
the normal to custom target must be incorporated in `codegen`.

Amends commit 197cb419d1 (add_custom_command: Add CODEGEN support,
2024-05-27, v3.31.0-rc1~394^2), which already incorporated such logic
in the Unix Makefile generator, but was not tested nor implemented for
Ninja.

Fixes: #28092
This commit is contained in:
Tyler Yankee
2026-09-15 10:34:09 -04:00
parent d099b15c62
commit 2d85779126
6 changed files with 46 additions and 1 deletions
+18
View File
@@ -1558,6 +1558,21 @@ void cmGlobalNinjaGenerator::AppendTargetDependsClosure(
outputs.insert(outs.begin(), outs.end());
}
void cmGlobalNinjaGenerator::AppendCodegenTargetDepends(
cmGeneratorTarget const* target, cmNinjaDeps& deps,
std::string const& config) const
{
std::set<std::string> const& codegenDeps = target->Target->GetCodegenDeps();
for (cmTargetDepend const& targetDep :
this->GetTargetDirectDepends(target)) {
if (targetDep->IsInBuildSystem() &&
codegenDeps.count(targetDep->GetName())) {
this->AppendTargetOutputs(targetDep, deps, config,
DependOnTargetArtifact);
}
}
}
void cmGlobalNinjaGenerator::AddTargetAlias(std::string const& alias,
cmGeneratorTarget* target,
std::string const& config)
@@ -1727,6 +1742,9 @@ void cmGlobalNinjaGenerator::WriteFolderTargets(std::ostream& os)
if (this->IsExcludedFromAllInConfig(t, config)) {
continue;
}
this->AppendCodegenTargetDepends(t.GT, build.ExplicitDeps, config);
std::vector<cmSourceFile const*> customCommandSources;
t.GT->GetCustomCommands(customCommandSources, config);
for (cmSourceFile const* sf : customCommandSources) {
+4
View File
@@ -524,6 +524,10 @@ private:
void CloseRulesFileStream();
void CleanMetaData();
void AppendCodegenTargetDepends(cmGeneratorTarget const* target,
cmNinjaDeps& deps,
std::string const& config) const;
/// Write the common disclaimer text at the top of each build file.
void WriteDisclaimer(std::ostream& os) const;
@@ -25,6 +25,7 @@ run_codegen("min-graph-3")
run_codegen("add-dependencies")
run_codegen("add-custom-command-depends")
run_codegen("byproducts")
run_codegen("add-dependencies-not-all")
# Error handling
run_cmake("implicit-depends")
@@ -0,0 +1,5 @@
set(filename "${RunCMake_TEST_BINARY_DIR}/generated.h")
if (NOT EXISTS "${filename}")
set(RunCMake_TEST_FAILED "expected file NOT created:\n ${filename}")
return()
endif()
@@ -0,0 +1,17 @@
add_executable(main
main.c
)
add_custom_command(
OUTPUT generated.h
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/generated.h.in
${CMAKE_CURRENT_BINARY_DIR}/generated.h
CODEGEN
)
# N.B. h_creator is *not* added to ALL.
add_custom_target(h_creator DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/generated.h)
# This test will fail if add_dependencies isn't accounted for in the
# codegen build graph
add_dependencies(main h_creator)
@@ -13,6 +13,6 @@ add_custom_command(
add_custom_target(hpp_creator ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/generated.hpp)
# This test will fail if add_dependencies isn't account for in the
# This test will fail if add_dependencies isn't accounted for in the
# codegen build graph
add_dependencies(hpp_creator foobar)