Feature Request: add_custom_command(ALL)

Hey all,

would it be possible to add the ALL flag from add_custom_target for add_custom_command too? Or otherwise get the ability to manually add a dependency for the ALL pseudo target for a custom command?

The motivation comes from generation of runtime artifacts that are consumed by multiple targets, like tests or libraries or … Having to manually list these dependencies everywhere is cumbersome.

In practice, many projects just opt for using add_custom_target instead then to get the ALL dependency chain. But that has the really unfortunate side-effect of always-dirty builds. I.e. from the documentation from add_custom_target:

The target has no output file and is always considered out of date

Due to this issue, add_custom_target is even banned at work to ensure we get a ninja: no work to do. after invoking it once (and not changing anything else).

To give a concrete example for a widely used cmake snippet that causes issues in that regard: the KDE i18n framework (ab)uses add_custom_target to generate mo/ts translation files, which is a costly operation. And because it’s always dirty, this runs every time we run ninja :frowning: See
cmake/KF6I18nMacros.cmake.in · master · Frameworks / Ki18n · GitLab and 460245 – ki18n_install(po) slows down each build, even if nothing has changed

I would love to improve that situation, but the only hack that I could think of is adding a add_custom_command for each of these add_custom_target that do the actual generation, and then keeping the add_custom_target for the ALL convenience. This would at least prevent us from wasting cycles in re-generating the translations all the time, but it would still keep the ALL target always-dirty which is still sub-optimal.

As such: Could we just get a add_custom_command(ALL) instead? Or how do other projects handle situations like this?

The traditional way to handle this is:

add_custom_command(OUTPUT file.txt COMMAND ${CMAKE_COMMAND} -E touch file.txt)
add_custom_target(tgt ALL DEPENDS file.txt)

Right, but as I said this has a really bad side-effect: Your normal ninja run will never be able to get into the no work to do state, right? I find this really not acceptable myself, do you simply not care?

The sample I gave above works differently from:

add_custom_target(tgt ALL COMMAND ${CMAKE_COMMAND} -E touch file.txt BYPRODUCTS file.txt)

In the add_custom_command() + add_custom_target() example I gave above, once file.txt is created, when you run the build the next time around, it will say “no work to do” because file.txt already exists. Whereas with a standalone add_custom_target(), it always creates file.txt even if it already exists. Try the example I gave above - I think you’ll find that it works the way you want.

1 Like