Ninja: Missing dependencies on generated files discovered at build-time
Hi, first of all sorry for not providing a small demo but the situation is a bit complex so I'll try to explain it as is. I have a project that generates multiple C++ headers from XML schema. Generated file names depend only the content of XML, not on the name of XML itself (this comes from the XML schema standard not made by me). Parts related to this issue are:
- schema compiler (
sbepp::sbeppc
target) - CMake helper that creates custom command + custom target + interface library. According to my understanding, they produce the correct dependency chain: interface library -> custom target -> custom command -> XML file +
sbepp::sbeppc
target - test binary,
tests_cpp_11_mf
target that uses the above helper and links to the generated interface library.
From all of the above, my expectation is that changing either, sbepp::sbeppc
source code or schema XML file should automatically lead to tests_cpp_11_mf
rebuild. Now, I have 2 environments:
- Ubuntu, CMake 3.22.1 + Make
- macOS, CMake 3.29.2 + Ninja 1.12.0
When I touch schema XML and then build the test binary:
- on Ubuntu, schema is recompiled, test binary is rebuilt. This is expected behavior.
- on macOS, schema is recompiled and that's it. Test binary is rebuilt only when I run the second build command. This is unexpected.
When I touch sbepp::sbeppc
and then build the test binary:
- on both envs this leads only to
sbepp::sbeppc
rebuild and nothing else even for the following builds.
Looks like test binary doesn't depend on sbepp::sbeppc
but add_custom_command
docs says:
Whenever one of the following target based generator expressions are used as a command to execute or is mentioned in a command argument, a target-level dependency will be added automatically so that the mentioned target will be built before any target using this custom command (see policy CMP0112).
TARGET_FILE
And my helper either uses it or depends on path explicitly.
I used set_property(GLOBAL PROPERTY GLOBAL_DEPENDS_DEBUG_MODE 1)
to check the deps and got:
[cmake] target 43 is [sbepp_sbeppc]
[cmake] target 61 is [compiled_test_schemas_sbeppc_custom_target]
[cmake] depends on target 43 [sbepp_sbeppc] (strong)
[cmake] target 63 is [tests_cpp_11_mf]
[cmake] depends on target 61 [compiled_test_schemas_sbeppc_custom_target] (strong)
Don't know the details but this looks correct.
I tried to explicitly depend on $<TARGET_FILE:sbepp::sbeppc>
and got the following results:
- on Ubuntu,
sbepp::sbeppc
is rebuilt, schema is recompiled and test binary is rebuilt. Works perfectly. - on macOS,
sbepp::sbeppc
is rebuilt, schema is recompiled but not the test binary. As before, it's rebuild only on the second build run.
Non-automatic TARGET_FILE
dependency looks like a bug to me, about the rest I'm not sure, looks like there's a difference between Make and Ninja, hope someone can clarify what's going on here.