5.3.8 · D1Build Systems & Toolchain

Foundations — CMake — CMakeLists.txt, add_executable, add_library, target_link_libraries

2,100 words10 min readBack to topic

Before you can read a single line of a CMakeLists.txt, you need the vocabulary the parent note quietly assumes. This page builds each idea from nothing — plain words first, then a picture, then why the topic needs it. Read top to bottom; every item leans on the one above it.


1. What even is "building"?

The picture below shows why this is not one step but several. This is the compilation pipeline, and CMake exists to drive it.

Figure — CMake — CMakeLists.txt, add_executable, add_library, target_link_libraries

Let us name the two arrows CMake cares about most.


2. Compiling and Linking — the two arrows CMake commands

Figure — CMake — CMakeLists.txt, add_executable, add_library, target_link_libraries

3. Header files — the promise, and the include path

See Header files and Include Guards for why a header can be included many times safely. The one thing to hold here:


4. Static vs. Shared — two ways a library plugs in

There are two flavours, and the parent's STATIC | SHARED keyword picks between them:

Figure — CMake — CMakeLists.txt, add_executable, add_library, target_link_libraries

Full detail lives in Static vs Dynamic Linking. For CMake, this is the choice you hand to add_library.


5. What a CMakeLists.txt actually is


6. Target — the noun the whole topic is built on


7. The dependency graph — the picture behind PUBLIC/PRIVATE

Figure — CMake — CMakeLists.txt, add_executable, add_library, target_link_libraries

8. Configure vs. Build — CMake's two phases


Prerequisite map

The diagram below reads top-to-bottom: an arrow means "you need the upper idea before the lower one makes sense." Start at Source vs binary (the very first thing on this page), follow the arrows down, and you end at the actual CMake commands — every node is a section above.

Source vs binary

Compilation pipeline

Compiling to object files

Linking objects together

Header files and include path

Static vs Shared library

Target as a box of settings

CMakeLists.txt is the script

Dependency graph

PUBLIC PRIVATE INTERFACE propagation

CMakeLists commands you can now read

Configure vs Build phases

How to read it: the two base facts are Source vs binary and CMakeLists.txt is the script. The pipeline splits into compile and link; those feed header/include and static/shared; all of that pours into the idea of a target, which enables the dependency graph and its propagation keywords. Once you hold every node, the bottom box — the CMake commands — is just plain reading.


Equipment checklist

A program is text; the CPU runs
machine code stored in a binary — so text must be built first.
A compiler/linker flag is
a command-line switch (like -I math or -lmath) that tells a tool how to behave.
The pipeline stage that makes one .o from one .cpp is called
compiling.
The pipeline stage that fits all .o pieces into one binary is called
linking.
A header (.h) file contains a
declaration — a promise that a function exists, not its body.
#include "add.h" searches
your own project folders first, then the added include dirs.
#include <vector> searches
only the system include paths the compiler already knows.
A STATIC library's code is
copied into each program that links it, at build time.
A SHARED library's code is
kept separate and borrowed at run time (must be present to run).
CMakeLists.txt is
the fixed-name text script CMake reads to learn about your project.
A CMake target is
one buildable thing (executable or library) that carries its own settings.
An arrow A to B in the dependency graph means
A depends on B.
A transitive dependency is one you get
through another dependency, when the link propagates.
PRIVATE / PUBLIC / INTERFACE control
whether a dependency arrow propagates to your users.
CMake's two phases are
configure (generate build files) then build (run the compiler).
CMake is called meta because
it does not compile; it generates the files a real builder runs.