5

I've just inherited a terrible mess of projects built with CMake. I have zero CMake knowledge and I suspect the previous maintainer had just as much.

I need to force the build order between projects. It used to be:

=== BUILD TARGET foo1 OF PROJECT bar ...
=== BUILD TARGET foo2 OF PROJECT bar ...
=== BUILD TARGET foo3 OF PROJECT bar ...

I had to add a project and dependencies (in different targets not the ones above). But the code is riddled with

# don't change the library order, it will break xyz  
target_link_libraries(foo3 other1 foo2 other2 foo1 other3)

As you can guess, after my changes, I now get

=== BUILD TARGET foo1 OF PROJECT bar ...
=== BUILD TARGET foo3 OF PROJECT bar ...

And foo3 doesn't build due to foo2 headers not being copied/installed/whatever. I'm pretty sure that if I could force CMake to trigger foo2 before foo3 the issue would be resolved.

However, I tried:

target_link_libraries(foo3 foo2)

to no avail. I still see foo3 trigger before foo2.

I also tried

add_dependencies(foo3 foo2)

So, my questions:

  • Can I see the dependency graph that CMake must be building internally ?
  • If there happened to be a cycle somewhere, how would I know and find it ?
  • Can I force the order of target builds ?
  • Is there any other gotchas around build order ?
Jeffrey
  • 11,063
  • 1
  • 21
  • 42
  • 1
    The call `add_dependencies(foo3 foo2)` should force `foo2` target to be built before `foo3`. At least, this is true if you have not reverse dependency. The call `target_link_libraries(foo3 foo2)` should work too. "Can I see the dependency graph that CMake must be building internally?" - CMake just generates files for the build tool(e.g. Makefile). Request the dependency graph from the build tool you use. "Can I force the order of target builds?" - I know no other way except dependencies (direct or indirect). – Tsyvarev Sep 03 '20 at 22:01
  • [This answer](https://stackoverflow.com/questions/22021312/how-can-i-get-the-list-of-dependencies-of-cmake-target) shows how to get a dependency graph. To debug the actual dependencies, try to build each target separately from a clean build tree. – Botje Sep 03 '20 at 22:12
  • @Botje that is an awesome first step. The graph will definitely help! – Jeffrey Sep 03 '20 at 22:21
  • Also check and fix any warnings produced by `cmake -Wdev` – Botje Sep 03 '20 at 22:48

1 Answers1

4

CMake is a declarative build system.

While the CMake programs that you write in the CMakeLists.txt files are executed in a pure imperative way, the build system that they build is declarative.

This means you can't control the build order of targets. You specify what you want get done but not how it will be done. That's abstracted away.

The only way is to add dependencies in the targets. First, all dependency targets are built before the depending target is built.

You add dependencies via commands like "target_link_libraries" and "target_sources". You can use the very general "add_dependencies" to add more that are not basic C/C++ programming relevant files.

Nike
  • 1,223
  • 2
  • 19
  • 42
Lothar
  • 12,537
  • 6
  • 72
  • 121