I've touched on this here under "Does CMake track header dependencies?".
CMake is a buildsystem generator. Tracking changes that require rebuild is usually the (generated) buildsystem's job. From what I've read, CMake used to do some of that job, but started to rely more on buildsystems and compilers to do that in later versions. See for example the CMAKE_DEPENDS_USE_COMPILER
variable, which was added in version 3.20. There are some related undocumented variables in the platform/compiler builtin parts of CMake with "DEPFILE
" in their names if you want to go exploring through the Modules code.
If you want to know about a specific buildsystem which CMake supports, consult the documentation for that buildsystem, which may or may not include such info. For example, the Ninja docs have a section on header dependencies, which state:
To get C/C++ header dependencies (or any other build dependency that works in a similar way) correct Ninja has some extra functionality.
The problem with headers is that the full list of files that a given source file depends on can only be discovered by the compiler: different preprocessor defines and include paths cause different files to be used. Some compilers can emit this information while building, and Ninja can use that to get its dependencies perfect.
As for those compiler mechanisms, for example, see the GCC flags that start with -M
. Ex.
-M
: Instead of outputting the result of preprocessing, output a rule suitable for make describing the dependencies of the main source file. The preprocessor outputs one make rule containing the object file name for that source file, a colon, and the names of all the included files, including those coming from -include or -imacros command-line options.
As for how the buildsystem knows when a file has changed, usually the buildsystem will look at filesystem timestamps. Ex. from the Ninja docs:
Ninja is closest in spirit and functionality to Make, relying on simple dependencies between file timestamps.
But that's not to say they could technically use other mechanisms, such as content hashes.
CMake does track other types of dependencies that the compiler is not suitable or able to track, such as those in add_custom_command
and add_custom_target
. Craig Scott (one of the CMake maintainers) has a related blogpost here if you want some extra, related readings. CMake also takes care of things like knowing when to rebuild if project configuration or the CMake cache has changed. I pretty sure that it does those things by generating custom rules in the generated buildsystem to handle those things.