1

When building my C++ projects I would use a bash file where there is all the instructions needed. It didn't present a problem because all the projects that I did were relatively small.

In my last project the build time would take around 4-6 mins so I switched to CMake. The first build was slow but the all the next ones were relatively fast.

My question is:Is compiling only the changed files the only optimization made by CMake to improve build time? Also: How does CMake keep track of changes within files? How does it decide whether to recompile a file or not?

I thought that maybe it saves the time of the last build and so checks last modification time of a file and compares it with the saved time. However I want to know the exact answer of it.

starball
  • 20,030
  • 7
  • 43
  • 238
  • 1
    No idea on the specifics of CMake but generally it is done by comparing timestamps of files. If an object file has an earlier timestamp than the cpp file it was generated from then the cpp file will be recompiled. In C++ header files complicate this, but one way or another they are generally taken into account as well. – john Jul 14 '23 at 21:18

2 Answers2

2

Cmake is a shell that sits on top of the make utility. make compares file dates and times. If the object file is newer than the source file and headers that it was created from make does nothing; if the object file is older, then the source file or a header has been modified since the last time it was compiled, and the source file needs to be compiled again. No rocket science.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165
  • 4
    CMake has some other backends too, such as `ninja`, which is recommended over `make` (as a CMake backend) those days. – HolyBlackCat Jul 14 '23 at 21:44
  • 2
    Not quite true about make. Default is ninja, I believe – Severin Pappadeux Jul 14 '23 at 21:49
  • 2
    @SeverinPappadeux the default generator is platform-dependent. It'll be shown with an asterisk in the output of `cmake --help`. On my Ubuntu system with CMake installed as a Snap, where I have both Make and Ninja, `Unix Makefiles` is the default generator. – starball Jul 15 '23 at 08:06
2

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.

starball
  • 20,030
  • 7
  • 43
  • 238