CMake: add dependency to add_custom_command dynamically
Asked Answered
A

1

8

I have a CMake project with many subprojects. Each of them can use a function I provide to generate a small text file with some certain information (by calling add_custom_command). At the final step I'd like to combine all those files into one big text file.

I've created a custom command which searches for created files (all in one place) and merges them.

The problem is that I'd like to make this final step dependend on all of small steps being made in subprojects while I don't actually know how many files will be provided.

My final command looks like:

add_custom_command(OUTPUT combination.txt
                   COMMAND create combination.txt from all files from /path/)

and my create-small-text-file-for-each-subproject command looks like:

add_custom_command(OUTPUT /path/${sub_project_name}.txt
                   COMMAND create /path/${sub_project_name}.txt)

And when I create those small files I'd like to do something like to make "combination.txt" depend on /path/${sub_project_name}.txt

So I wish I could:

add_dependency(combination.txt /path/${sub_project_name}.txt)

However this only works for targets.

I've also tried to use set_source_files_properties with OBJECT_DEPENDS, but it seems to doesn't work (maybe its intend to be used with add_target's cpp files ?)

The last way to get it work I see is to use a cache variable which would accumulate all those small files paths and then use it like this:

add_custom_command(OUTPUT combination.txt
                   COMMAND create combination.txt from all files from /path/
                   DEPENDS ${all_small_files_list})

but this is the last thing I want to do.

Acred answered 16/10, 2012 at 10:51 Comment(0)
P
6

Instead of using add_custom_command you could use add_custom_target with a correct dependency-definition (so that is it not built every time).

add_custom_target(project
                   COMMAND touch project.txt)

add_custom_target(project2
                   COMMAND touch project2.txt)

add_custom_target(combination
                   COMMAND cat project.txt project2.txt > combination.txt)

add_dependencies(combination project2)
add_dependencies(combination project)

add_executable(t t.c)
add_dependencies(t combination.txt)

Again: make sure you're using the DEPENDS argument of add_custom_target to create a real dependency chain so that a project-target and thus the combination-target gets out of date.

UPDATE: I was too premature. In fact cmake (at least up to 2.8.9) works as follows for dependencies: with a call to add_dependencies you cannot add a dependency which is the OUTPUT of a custom command IOW a (generated) file. With add_dependencies you can only add target as created by add_custom_target. However in a add_custom_target you can depend on an output of add_custom_command by using the DEPENDS-directive. That said this makes it work:

add_custom_command(OUTPUT project.txt
                   COMMAND uptime >> project.txt MAIN_DEPENDENCY t2.c)
add_custom_target(project DEPENDS project.txt)

add_custom_target(combination
                   COMMAND cat project.txt project2.txt > combination.txt)
add_dependencies(combination project)

This will make the combination target always be regenerated as it has no MAIN_DEPENDENCY or DEPENDS, but the usage of add_dependencies is allowed.

Palaestra answered 16/10, 2012 at 12:29 Comment(7)
It's gonna work but not exactly as expected: Everytime I call make, all targets (combination, project and project2) will be rebuild - so files will be regenrated. This isn't as nice as it could be ;) The expected behaviour for me is to do not regenerate any files unless its necessary. According to CMake's docs - add_custom_target is being built everytime. I wish I had a solution working as add_custom_command - which builds only when any dependency changed.Stitching
What do you use as dependency to generate project.txt? I think what the cmake-doc wants to say is, that a custom_target is always checked whether it has to be rebuilt or not - at least it seems to work like that for me.Palaestra
Well, after some proper reading of how we do it, I must admit that I was too premature. See my update of the answer.Palaestra
the solution You provided works, but has one downside: everytime you type: make combination - a cat command will be launched. This is redundand ;) Have a look at add_custom_target description: "add_custom_target: Add a target with no output so it will always be built. (...) The target has no output file and is ALWAYS CONSIDERED OUT OF DATE even if the commands try to create a file with the name of the target."Stitching
Well, then you'll be bind to add_custom_target(... DEPENDS file1 file2). This will work.Palaestra
even if I add DEPENDS keywork to custom target, it will do nothing else but calling build rules for specified targets. It will not prevent build system from building custom target everytimeStitching
I agree with Michael, when I have two add_custom_targets. I can not make one depend on the other.Imprecate

© 2022 - 2024 — McMap. All rights reserved.