From 2d857791262d3ccb1c5f4e581bc020037d1dc37f Mon Sep 17 00:00:00 2001 From: Tyler Yankee Date: Tue, 15 Sep 2026 10:14:14 -0400 Subject: [PATCH] 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 --- Source/cmGlobalNinjaGenerator.cxx | 18 ++++++++++++++++++ Source/cmGlobalNinjaGenerator.h | 4 ++++ Tests/RunCMake/Codegen/RunCMakeTest.cmake | 1 + .../add-dependencies-not-all-build-check.cmake | 5 +++++ .../Codegen/add-dependencies-not-all.cmake | 17 +++++++++++++++++ Tests/RunCMake/Codegen/add-dependencies.cmake | 2 +- 6 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 Tests/RunCMake/Codegen/add-dependencies-not-all-build-check.cmake create mode 100644 Tests/RunCMake/Codegen/add-dependencies-not-all.cmake diff --git a/Source/cmGlobalNinjaGenerator.cxx b/Source/cmGlobalNinjaGenerator.cxx index 52a7158f4b..2f45a76d72 100644 --- a/Source/cmGlobalNinjaGenerator.cxx +++ b/Source/cmGlobalNinjaGenerator.cxx @@ -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 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 customCommandSources; t.GT->GetCustomCommands(customCommandSources, config); for (cmSourceFile const* sf : customCommandSources) { diff --git a/Source/cmGlobalNinjaGenerator.h b/Source/cmGlobalNinjaGenerator.h index 284c23c810..74b1ff0093 100644 --- a/Source/cmGlobalNinjaGenerator.h +++ b/Source/cmGlobalNinjaGenerator.h @@ -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; diff --git a/Tests/RunCMake/Codegen/RunCMakeTest.cmake b/Tests/RunCMake/Codegen/RunCMakeTest.cmake index 7b072bac31..5a86b34b17 100644 --- a/Tests/RunCMake/Codegen/RunCMakeTest.cmake +++ b/Tests/RunCMake/Codegen/RunCMakeTest.cmake @@ -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") diff --git a/Tests/RunCMake/Codegen/add-dependencies-not-all-build-check.cmake b/Tests/RunCMake/Codegen/add-dependencies-not-all-build-check.cmake new file mode 100644 index 0000000000..fab168b6a9 --- /dev/null +++ b/Tests/RunCMake/Codegen/add-dependencies-not-all-build-check.cmake @@ -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() diff --git a/Tests/RunCMake/Codegen/add-dependencies-not-all.cmake b/Tests/RunCMake/Codegen/add-dependencies-not-all.cmake new file mode 100644 index 0000000000..0d2b950e70 --- /dev/null +++ b/Tests/RunCMake/Codegen/add-dependencies-not-all.cmake @@ -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) diff --git a/Tests/RunCMake/Codegen/add-dependencies.cmake b/Tests/RunCMake/Codegen/add-dependencies.cmake index fbb7e99cd7..98209bfa2d 100644 --- a/Tests/RunCMake/Codegen/add-dependencies.cmake +++ b/Tests/RunCMake/Codegen/add-dependencies.cmake @@ -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)