As I said in my concluding post nigh CMake, targets are everything in CMake. Unfortunately, not everything is a target though!

If you lot've tried do anything not-trivial in CMake using the add_custom_command() control, you lot may take got stuck in this horrible swamp of confusion. If you desire to generate some kind of file at build time, in some manner other than compiling C or C++ lawmaking, so yous demand to utilize a custom command to generate the file. But files aren't targets and have all sorts of exciting limitations to make you forget everything yous ever new well-nigh dependency management.

What makes information technology so hard is that at that place's not one limitation, but several. Here is a hopefully complete list of things you lot might desire to practice in CMake that involve custom commands and custom targets depending on each other, and some explainations as to why things don't work the fashion that yous might wait.

i. Dependencies between targets

point1-verticalThis is CMake at its simplest (and best).

                cmake_minimum_required(VERSION 3.2)  add_library(foo foo.c)  add_executable(bar bar.c) target_link_libraries(bar foo)              

You lot have a library, and a programme that depends on it. When you run CMake, both of them get built. Ideal! This is great!

What is "all", in the dependency graph to the left? It's a built in target, and it'south the default target. There are also "install" and "examination" targets built in (but no "clean" target).

2. Custom targets

If your projection is a proficient one then peradventure you use a documentation tool like GTK-Md or Doxygen to generate documentation from the code.

This is where add_custom_command() enters your life. You may live to regret e'er letting information technology in.

                cmake_minimum_required(VERSION iii.ii)  add_custom_command(     OUTPUT         docs/doxygen.postage stamp     DEPENDS         docs/Doxyfile     Control         doxygen docs/Doxyfile     COMMAND         cmake -E bear upon docs/doxygen.stamp     Comment         "Generating API documentation with Doxygen"     VERBATIM     )              

We take to create a 'postage stamp' file because Doxygen generates lots of different files, and we tin can't really tell CMake what to expect. Just actually, here'south what to expect: nothing! If yous build this, you get no output. Zilch depends on the documentation, and then it isn't built.

So nosotros need to add a dependency betwixt docs/doxygen.postage stamp and the "all" target. How about using add_dependencies()? No, yous tin't use that with any of the built in targets. Only as a special case, you can utilise add_custom_target(ALL) to create a new target attached to the "all" target:

                add_custom_target(     docs ALL     DEPENDS docs/doxygen.stamp     )              

point2-horizontal.png

In exercise, you might likewise want to make the custom command depend on all your source code, so it gets regenerated every time yous change the code. Or, you might want to remove the ALL from your custom target, so that you have to explicitly run make docs to generate the documentation.

This is as well discussed hither.

3. Custom commands in different directories

Another use case for add_custom_command() is generating source lawmaking files using 3rd political party tools.

                ### Toplevel CMakeLists.txt cmake_minimum_required(VERSION 3.2)  add_subdirectory(src) add_subdirectory(tests)   ### src/CMakeLists.txt add_custom_command(     OUTPUT         ${CMAKE_CURRENT_BINARY_DIR}/foo.c     Command         cmake -E echo "Generate my C code" > foo.c     VERBATIM     )   ### tests/CMakeLists.txt add_executable(     test-foo         test-foo.c ${CMAKE_CURRENT_BINARY_DIR}/../src/foo.c     )  add_test(     Name test-foo     Command test-foo     )              

How does this work? Really information technology doesn't! Yous'll see the following error when you run CMake:

                CMake Error at tests/CMakeLists.txt:1 (add_executable):   Cannot discover source file:      /home/sam/point3/build/src/foo.c    Tried extensions .c .C .c++ .cc .cpp .cxx .k .M .mm .h .hh .h++ .hm .hpp   .hxx .in .txx CMake Mistake: CMake can not determine linker language for target: test-foo CMake Error: Cannot determine link language for target "exam-foo".              

Congratulations, y'all've hit issues 14633! The fun thing here is that generated files don't behave anything like targets. Actually they can only exist referenced in the file that contains the corresponding add_custom_command() call. So when nosotros refer to the generated foo.c in tests/CMakeLists.txt, CMake actually has no idea where information technology could come up from, so information technology raises an error.

point3-1.png

As the corresponding FAQ entry describes, there are ii things you need to exercise to work around this limitation.

The first is to wrap your custom command in a custom target. Are you noticing a pattern still? Virtually of the workarounds here are going to involve wrapping custom commands in custom targets. In src/CMakeLists.txt, you do this:

                add_custom_target(     generate-foo     DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/../src/foo.c     )              

And then, in tests/CMakeLists.txt, yous tin add a dependency betwixt "test-foo" and "generate-foo":

                add_dependencies(test-foo generate-foo)              

That's enough to ensure that foo.c at present gets generated before the build of exam-foo begins, which is apparently of import. If you try to run CMake now, you'll hit the same error, because CMake even so has no idea where that generated foo.c file might come from. The workaround here is to manually fix the GENERATED target property:

                set_source_files_properties(     ${CMAKE_CURRENT_BINARY_DIR}/../src/foo.c     PROPERTIES GENERATED Truthful     )              

point3-2.png

Note that this is a bit of a contrived example. In most cases, the right solution is to do this:

                ### src/CMakeLists.txt add_library(foo foo.c)  ### tests/CMakeLists.txt target_link_libraries(test-foo foo)              

Then you don't take to worry nearly any of the nonsense above, because libraries are proper targets, and you can employ them anywhere.

Even if information technology's not practical to brand a library containing 'foo.c', in that location must be some other target that links against information technology in the same directory that it is generated in. So instead of creating a "generate-foo" target, yous can make "exam-foo" depend on whatever other target links to "foo.c".

iv. Custom commands and parallel make

I came into this outcome while doing something pretty unusual with CMake: wrapping a series of Buildroot builds. Imagine my please at discovering that, when parallel make was used, my CMake-generated Makefile was running the same Buildroot build multiple times at the aforementioned fourth dimension! That is not what I wanted!

It turns out this is a pretty common issue. The crux of information technology is that with the "Unix Makefiles" backend, multiple toplevel targets run as an independent, parallel make processes. Files aren't targets, and unless something is a target then information technology doesn't get propagated around similar y'all would look.

Hither is the test case:

                cmake_minimum_required(VERSION 3.ii)  add_custom_command(     OUTPUT gen     Control sleep one     Command cmake -Due east echo Hullo > gen     )  add_custom_target(     my-all-ane ALL DEPENDS gen     )  add_custom_target(     my-all-2 ALL DEPENDS gen     )              

If yous generate a Makefile from this and run brand -j 2, you'll see the following:

                Scanning dependencies of target my-all-2 Scanning dependencies of target my-all-one [ 50%] Generating gen [100%] Generating gen [100%] Congenital target my-all-2 [100%] Congenital target my-all-1              

If creating 'gen' takes a long fourth dimension, so you lot actually don't desire it to happen multiple times! It may even cause disasters, for example running make twice at once in the same Buildroot build tree is not pretty at all.

point4-1.png

As explained in bug 10082, the solution is (estimate what!) to wrap the custom command in a custom target!

                add_custom_target(make-gen DEPENDS gen)                  point4-2.png                              

So you change the custom targets to depend on "make-gen", instead of the file 'gen'. Except! Be careful when doing that — considering there is another trap waiting for you!

v. File-level dependencies of custom targets are non propagated

If you read the documentation of add_custom_command() closely, and you expect at the DEPENDS keyword statement, you'll come across this text:

If DEPENDS specifies any target (created past the add_custom_target(), add_executable(), or add_library() command) a target-level dependency is created to brand certain the target is built before any target using this custom control. Additionally, if the target is an executable or library a file-level dependency is created to cause the custom command to re-run whenever the target is recompiled.

This sounds quite nice, like more or less what you would expect. But the important bit of information hither is what CMake doesn't practice: when a custom target depends on another custom target, all the file level dependencies are completely ignored.

Here's your concluding example for the evening:

                cmake_minimum_required(VERSION 3.ii)  set up(SPECIAL_TEXT foo)  add_custom_command(     OUTPUT gen1     COMMAND cmake -E echo ${SPECIAL_TEXT} > gen1     )  add_custom_target(     gen1-wrapper     DEPENDS gen1     )  add_custom_command(     OUTPUT gen2     DEPENDS gen1-wrapper     COMMAND cmake -E copy gen1 gen2     )  add_custom_target(     all-generated ALL     DEPENDS gen2     )              

This is subtly wrong, fifty-fifty though you did what you were told, and wrapped the custom control in a custom target.

The first fourth dimension you build it:

                Scanning dependencies of target gen1-wrapper [ l%] Generating gen1 [ 50%] Built target gen1-wrapper Scanning dependencies of target all-generated [100%] Generating gen2 [100%] Built target all-generated              

But then bear on the file 'gen1', or overwrite it with something other text, or modify the value of SPECIAL_TEXT in CMakeLists.txt to something else, and yous will meet this:

                [ l%] Generating gen1 [ 50%] Congenital target gen1-wrapper [100%] Congenital target all-generated              

In that location's no file-level dependency created between 'gen2' and 'gen1', so 'gen2' never gets updated, and things get all weird.

point5-1-horizontal.png

Y'all tin't just depend on gen1 instead of gen1-wrapper, because information technology may end up being built multiple times! Encounter the previous point. Instead, you need to depend on the "gen1-wrapper" target and the file itself:

                add_custom_command(     OUTPUT gen2     DEPENDS gen1-wrapper gen1     COMMAND cmake -East re-create gen1 gen2     )              

As the documentation says, this only applies to targets wrapping add_custom_command() output. If 'gen1' was a library created with add_library, things would work how yous look.

point5-2-horizontal.png

Decision

Maybe I only have a edgeless caput, but I institute all of this quite hard to work out. I can sympathize why CMake works this way, but I call up there is plenty of room for improvement in the documentation where this is explained. Hopefully this guide has gone some style to making things clearer.

If yous have any other dependency-related traps in CMake that y'all've hit, please comment and I'll add them to this listing…