CMake: Local Build#
make: Problems#
Writing a
Makefileis tedious“Assembly language of build systems”
Way too much boilerplate
⟶ Targets
all,clean,installError prone
Unmaintainable!!
Missing features …
Out-of-source build
Toolchain-independent build descriptions
Packaging
Dependency management
CMake To The Rescue#
CMake: higher level build system
Generates
Makefile(and files for other low level build tools, like Ninja)CMakeLists.txtinstead ofMakefileWritten in a dedicated “language”
Listing of the project directory
../jfasch-home-linux-toolchain/cmake/#total 32
-rw-r--r--. 1 jfasch jfasch 303 Jun 2 2022 CMakeLists.txt
-rw-r--r--. 1 jfasch jfasch 89 Jun 26 2022 hello.c
-rw-r--r--. 1 jfasch jfasch 81 Jun 26 2022 hello-first.c
-rw-r--r--. 1 jfasch jfasch 122 Jun 26 2022 hello-flexible.c
-rw-r--r--. 1 jfasch jfasch 98 Jun 26 2022 hello-flexible.h
-rw-r--r--. 1 jfasch jfasch 59 Jun 26 2022 hello.h
-rw-r--r--. 1 jfasch jfasch 269 Jun 26 2022 hello-second.c
-rw-r--r--. 1 jfasch jfasch 746 Apr 26 2022 Toolchain-RaspberryPi.cmake
CMAKE_MINIMUM_REQUIRED(VERSION 3.16)
PROJECT(Toolchain-CMake-Demo LANGUAGES C)
ADD_LIBRARY(greet hello.h hello.c hello-flexible.c)
ADD_EXECUTABLE(hello-first hello-first.c)
TARGET_LINK_LIBRARIES(hello-first greet)
ADD_EXECUTABLE(hello-second hello-second.c)
TARGET_LINK_LIBRARIES(hello-second greet)
Out-Of-Source Build#
Build artifacts (object files, libraries, executables) pollute source directory
Hiccups with version control systems ⟶ e.g.
.gitignore⟶ CMake can build into a separate directory, the build directory
For the remainder, lets define these directories …
Source directory |
|
Build directory |
|
Step 1: Generate Makefile In Build Directory#
$ cd /home/jfasch/build # <--- CWD is the *build* directory
$ cmake /home/jfasch/source # <--- parameter is the *source* directory
-- The C compiler identification is GNU 11.2.1
-- The CXX compiler identification is GNU 11.2.1
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /home/jfasch/build
Note
Please be careful to pass the source directory to cmake,
not the CMakeLists.txt file in that directory! (CMake builds in
the source if you pass the file)
This creates a Makefile in the build directory
Used as usual ⟶
makeThe file is generated ⟶ basically unreadable
Step 2: Build Using make#
$ pwd # <--- CWD is the *build* directory when you call make
/home/jfasch/build
$ make
[ 14%] Building C object CMakeFiles/greet.dir/hello.c.o
[ 28%] Building C object CMakeFiles/greet.dir/hello-flexible.c.o
[ 42%] Linking C static library libgreet.a
[ 42%] Built target greet
[ 57%] Building C object CMakeFiles/hello-second.dir/hello-second.c.o
[ 71%] Linking C executable hello-second
[ 71%] Built target hello-second
[ 85%] Building C object CMakeFiles/hello-first.dir/hello-first.c.o
[100%] Linking C executable hello-first
[100%] Built target hello-first
Et voila:
$ ls -l
total 96
-rw-rw-r--. 1 jfasch jfasch 13921 Apr 22 10:58 CMakeCache.txt
drwxrwxr-x. 7 jfasch jfasch 280 Apr 22 11:02 CMakeFiles
-rw-rw-r--. 1 jfasch jfasch 1688 Apr 22 10:58 cmake_install.cmake
-rwxrwxr-x. 1 jfasch jfasch 26192 Apr 22 11:02 hello-first
-rwxrwxr-x. 1 jfasch jfasch 27920 Apr 22 11:02 hello-second
-rw-rw-r--. 1 jfasch jfasch 8102 Apr 22 11:02 libgreet.a
-rw-rw-r--. 1 jfasch jfasch 8503 Apr 22 10:58 Makefile
Goodie: Dependency Management#
Executables depend on libraries
ADD_LIBRARY(greet hello.h hello.c hello-flexible.c) ADD_EXECUTABLE(hello-first hello-first.c) TARGET_LINK_LIBRARIES(hello-first greet) ADD_EXECUTABLE(hello-second hello-second.c) TARGET_LINK_LIBRARIES(hello-second greet)
These relationships are not always so simple
Directed acyclic graph
⟶ want to be visualized
⟶ Graphviz package
Debian/Ubuntu## apt install graphviz
Fedora## dnf install graphviz
During
Makefilegeneration, pass the--graphvizoption ⟶.dotfile$ pwd /home/jfasch/build $ cmake --graphviz=dependencies.dot /home/jfasch/source ... roedel ...
Massage the
.dotfile, e.g. turning it into a.png(or a.pdf, …)$ dot -Tpng dependencies.dot > dependencies.png
![digraph "Toolchain-CMake-Demo" {
node [
fontsize = "12"
];
subgraph clusterLegend {
label = "Legend";
color = black;
edge [ style = invis ];
legendNode0 [ label = "Executable", shape = egg ];
legendNode1 [ label = "Static Library", shape = octagon ];
legendNode2 [ label = "Shared Library", shape = doubleoctagon ];
legendNode3 [ label = "Module Library", shape = tripleoctagon ];
legendNode4 [ label = "Interface Library", shape = pentagon ];
legendNode5 [ label = "Object Library", shape = hexagon ];
legendNode6 [ label = "Unknown Library", shape = septagon ];
legendNode7 [ label = "Custom Target", shape = box ];
legendNode0 -> legendNode1 [ style = solid ];
legendNode0 -> legendNode2 [ style = solid ];
legendNode0 -> legendNode3;
legendNode1 -> legendNode4 [ label = "Interface", style = dashed ];
legendNode2 -> legendNode5 [ label = "Private", style = dotted ];
legendNode3 -> legendNode6 [ style = solid ];
legendNode0 -> legendNode7;
}
"node0" [ label = "greet", shape = octagon ];
"node1" [ label = "hello-first", shape = egg ];
"node1" -> "node0" [ style = dotted ] // hello-first -> greet
"node2" [ label = "hello-second", shape = egg ];
"node2" -> "node0" [ style = dotted ] // hello-second -> greet
}](../../../../../../_images/graphviz-10732c08488757f53c9c749672009d5b0a5ef430.png)