CMake dependencies on subdirectories

Added by Remko over 6 years ago

The problem

After long struggling with this, I finally figured out how to build dependencies on stuff that is built in a subdirectory.
There is no example for this in the book, and the explanation and the shortcomings are hard to find.
The result of my quest is that this can only be done with a "trick".

Partial solution

There is some hint of how to do this here:
But this is for the special, and not general, case of creating executables from source code.
What if I wanted to create documentation, for example.


Say we have this little setup:

# CMakeLists.txt
cmake_minimum_required (VERSION 2.8)
add_custom_target (a_txt DEPENDS a.txt)
add_custom_command (OUTPUT a.txt COMMAND cat {b,b}.txt > a.txt DEPENDS b.txt)
add_custom_command (OUTPUT b.txt COMMAND paste {c,c}.txt > b.txt DEPENDS c.txt)
Here a.txt is made from b.txt which is made from c.txt. If I update c.txt and run make a_txt, a.txt will be updated. Simple.

The solution

But now what if b.txt is actually made in a subdirectory called sub. Then this is the (only) solution.

# CMakeLists.txt
cmake_minimum_required (VERSION 2.8)
add_subdirectory (sub)
add_custom_target (a_txt DEPENDS a.txt)
add_custom_command (OUTPUT a.txt COMMAND cat sub/{b,b}.txt > a.txt DEPENDS b_txt sub/b.txt)
# sub/CMakeLists.txt
add_custom_target (b_txt DEPENDS b.txt)
add_custom_command (OUTPUT b.txt COMMAND paste {c,c}.txt > b.txt DEPENDS c.txt)
Note that we must add an extra target b_txt, because the dependency sub/b.txt for a.txt is no longer sufficient. If run without the new target b_txt you will get an error that make does not know how to make sub/b.txt.
But you also have to keep the dependency on sub/b.txt. Without that dependency and I would change c.txt, then b.txt is made, but a.txt is not remade because it doesn't know that it actually depends on something that was updated.
Hence a dependency on something in a subdirectory requires both a dependency on a file and on a target.

General application

If you have to make many things in the subdirectory to which a.txt depends, like a whole slew of images, then this becomes cumbersome, because you have to make a target the depends on all those files, but you also have to add a dependency to all those files in a.txt. A simpler solution is to make a dummy file and a target depending on that. That dummy file would depend then on all the images to be made. Example:

# sub/CMakeLists.txt
add_custom_target (all_images DEPENDS .all_images)
add_custom_command (OUTPUT .all_image COMMAND touch .all_images DEPENDS ${all_images})
Now you can add to the DEPENDS of a.txt both all_images and sub/.all_images.