.. ot-topic:: linux.toolchain.cmake_local :dependencies: linux.toolchain.static_library .. include:: CMake: Local Build ================== .. sidebar:: **See also** * :doc:`Entire CMake course ` **Source Code** The example code in this section is maintained on `Github `__ .. contents:: :local: ``make``: Problems ------------------ * Writing a ``Makefile`` is tedious * "Assembly language of build systems" * Way too much boilerplate * |longrightarrow| Targets ``all``, ``clean``, ``install`` * Error prone * **Unmaintainable!!** **Missing features ...** * Out-of-source build * Toolchain-independent build descriptions * Packaging * Dependency management CMake To The Rescue ------------------- .. sidebar:: Rant Well, CMake language does not deserve that name. It is more of a brute force macro expander. * CMake: higher level build system * Generates ``Makefile`` (and files for other low level build tools, like `Ninja `__) * ``CMakeLists.txt`` instead of ``Makefile`` * Written in a dedicated "language" **Listing of the project directory** .. program-output:: ls -l :caption: ``../jfasch-home-linux-toolchain/cmake/`` :cwd: ../jfasch-home-linux-toolchain/cmake .. literalinclude:: ../jfasch-home-linux-toolchain/cmake/CMakeLists.txt :caption: :download:`../jfasch-home-linux-toolchain/cmake/CMakeLists.txt` :language: cmake Out-Of-Source Build ------------------- * Build artifacts (object files, libraries, executables) *pollute source directory* * Hiccups with version control systems |longrightarrow| e.g. ``.gitignore`` * |longrightarrow| CMake can build into a separate directory, the *build directory* For the remainder, lets define these directories ... .. list-table:: :align: left :widths: auto * * Source directory * ``/home/jfasch/source`` * * Build directory * ``/home/jfasch/build`` Step 1: Generate ``Makefile`` In Build Directory ------------------------------------------------ .. code-block:: console $ 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 |longrightarrow| ``make`` * The file is generated |longrightarrow| basically unreadable Step 2: Build Using ``make`` ---------------------------- .. code-block:: console $ 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: .. code-block:: console $ 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 .. code-block:: cmake 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* * |longrightarrow| want to be visualized * |longrightarrow| `Graphviz `__ package .. code-block:: console :caption: Debian/Ubuntu # apt install graphviz .. code-block:: console :caption: Fedora # dnf install graphviz * During ``Makefile`` generation, pass the ``--graphviz`` option |longrightarrow| ``.dot`` file .. code-block:: console $ pwd /home/jfasch/build $ cmake --graphviz=dependencies.dot /home/jfasch/source ... roedel ... * Massage the ``.dot`` file, e.g. turning it into a ``.png`` (or a ``.pdf``, ...) .. code-block:: console $ dot -Tpng dependencies.dot > dependencies.png .. graphviz:: dependencies.dot .. ot-graph:: :entries: linux.toolchain.cmake_local