Dependencies when using custom commands

According to https://cmake.org/cmake/help/latest/command/add_custom_command.html#example-generating-files-for-multiple-targets the recommended practice when multiple targets depend on a file generated through a custom command is to add a custom target for the file, and make the dependent targets depend both on the file and the custom target. I can understand the need for the target-level dependency, but why is the file-level dependency needed? Shouldn’t the target-level dependency be enough to make sure the file exists before trying to build the dependent target?

I don’t see that being implied by the docs you linked to. The whole point of adding the custom target in that case is to avoid dependers having to depend directly on the generated file.

Yes… but this whole area gets a little more complicated when we’re talking about generated header files or sources with C++20 modules. See policy CMP0154, which talks about those cases.

Nevermind, you are correct. I had misread the example, and didn’t notice that it’s only other custom commands that depend explicitly on the file. Still, the question remains: why do these custom commands have the explicit file-level dependencies?

Yes… but this whole area gets a little more complicated when we’re talking about generated header files or sources with C++20 modules. See policy CMP0154, which talks about those cases.

None of this is mentioned in the docs I linked to. The example there shows just a .csv.

Hi @craig.scott I’d like to resurface this thread since I still have the question I wrote on my last comment.

Why do custom commands depending on the outputs of other custom commands require both a target- and file-level dependency, as shown in https://cmake.org/cmake/help/latest/command/add_custom_command.html#example-generating-files-for-multiple-targets ?

Honestly, I feel like there is probably some obscure reason why it has to be that way, but it escapes me right now (sorry, I don’t have the time to delve into researching this one deeply). There are subtle differences between file and target level dependencies, and how they play out when files already exist (e.g. from a previous build). I’ve had to explain those before when there’s an executable target used as the first argument to COMMAND, but that’s not the case here.

Hopefully someone with a bit more time can chime in and explain what’s happening here with this particular example.

1 Like

The example in question was added by @brad.king in MR 8002, which was done in response to this forum discussion.

1 Like

Ah, I see. From that discussion it seems like this is more of a leaky abstraction in CMake than a real constraint, right?

In any case, IMHO it would be good to explicitly state in the docs why both dependencies are needed. Tagging @brad.king for this.

The target-level dependency is for ordering. The file-level dependency is for knowing when dependents are out of date. The distinction is particularly important in non-Ninja generators.

Yes, but from what I’ve seen in the docs, this isn’t explicitly stated so more people can get confused like I did.

In any case, as it was discussed in the link @craig.scott mentioned, this seems to be more of a leaky abstraction since in all cases we’ll want both dependencies. But, that’s a separate discussion; this is more about documentation than fixing the design.