Show which files will be rebuilt when building a target in a cmake project

794 Views Asked by At

I have a huge legacy project which uses cmake as its build system which takes an awful time to run full and partial builds. The long build times are mainly due to a mix of lack of modularity and dragging in too many unnecessary include headers into interface headers.

I would like to start refactoring the project hoping to minimize the time it takes to run partial and full builds, but before that I would like to know where the bottlenecks might be when rebuilding some projects, including checking which files are rebuilt if any specific file is touched.

With this usecase in mind, does anyone know if cmake offers a way to show which targets/translation units will be rebuilt when I explicitly run a target or if I touch any file in the project tree?

1

There are 1 best solutions below

0
On

This depends on the backend you're using. I think Visual Studio (msbuild) has some features for this, but I find Ninja's -d explain debug mode to be the most useful as it's cross-platform (Windows, macOS, and Linux).

Here's a toy example:

cmake_minimum_required(VERSION 3.18)
project(test)

add_library(example src1.cpp src2.cpp src3.cpp)

Where all three src*.cpp are just empty files. Now we'll configure the build:

$ cmake -G Ninja -S . -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo
....

and now we'll build it for the first time with -d explain:

$ cmake --build build/ -- -d explain
ninja explain: deps for 'CMakeFiles/example.dir/src1.cpp.o' are missing
ninja explain: CMakeFiles/example.dir/src1.cpp.o is dirty
ninja explain: deps for 'CMakeFiles/example.dir/src2.cpp.o' are missing
ninja explain: CMakeFiles/example.dir/src2.cpp.o is dirty
ninja explain: deps for 'CMakeFiles/example.dir/src3.cpp.o' are missing
ninja explain: CMakeFiles/example.dir/src3.cpp.o is dirty
ninja explain: libexample.a is dirty
[4/4] Linking CXX static library libexample.a

As you can see, all three objects were missing, so it prints that it needed to regenerate all of them.

Now we'll touch the timestamp of src2.cpp and run an incremental build, again with -d explain:

$ touch src2.cpp
$ cmake --build build/ -- -d explain
ninja explain: output CMakeFiles/example.dir/src2.cpp.o older than most recent input ../src2.cpp (1657545617908948058 vs 1657545747611703486)
ninja explain: CMakeFiles/example.dir/src2.cpp.o is dirty
ninja explain: libexample.a is dirty
[2/2] Linking CXX static library libexample.a

And now you can see that it gives an informative message about why, precisely, it believes the src2 object needs to be rebuilt (the timestamps differ).

For another example, let's try changing the build type:

$ cmake build/ -DCMAKE_BUILD_TYPE=Debug
...
$ cmake --build build/ -- -d explain
ninja explain: command line changed for CMakeFiles/example.dir/src1.cpp.o
ninja explain: CMakeFiles/example.dir/src1.cpp.o is dirty
ninja explain: command line changed for CMakeFiles/example.dir/src2.cpp.o
ninja explain: CMakeFiles/example.dir/src2.cpp.o is dirty
ninja explain: command line changed for CMakeFiles/example.dir/src3.cpp.o
ninja explain: CMakeFiles/example.dir/src3.cpp.o is dirty
ninja explain: libexample.a is dirty
[4/4] Linking CXX static library libexample.a

Now you can see that Ninja accurately determined that the command line had changed since the last build, so the object is stale.

This is sometimes useful to combine with either of the following two flags:

  1. -n -- dry run. print usual output, but don't execute any commands.
  2. -v -- verbose. print full command lines instead of brief descriptions.