From baa307d08c03dd37e9fe97c2e297a6cf968d4bed Mon Sep 17 00:00:00 2001 From: YL Wang <121748352+code4yonglei@users.noreply.github.com> Date: Wed, 2 Oct 2024 23:12:54 +0200 Subject: [PATCH] update the demo example in `cmake syntax` episode --- content/targets.rst | 95 ++++++++++++++++++++------------------------- 1 file changed, 42 insertions(+), 53 deletions(-) diff --git a/content/targets.rst b/content/targets.rst index 5e0bf33..4643a9b 100644 --- a/content/targets.rst +++ b/content/targets.rst @@ -70,7 +70,7 @@ There are additional commands in the ``target_*`` family: -Visibility levels [#adapt_from_CR]_ +Visibility levels ----------------- @@ -91,73 +91,67 @@ Why it is robust to use targets and properties than using variables? Given a tar Properties on targets have varied **visibility levels**, which determine how CMake should propagate them between interdependent targets. +.. typealong:: Understanding visibility levels -.. callout:: Understanding visibility levels + Visibility levels ``PRIVATE``, ``PUBLIC``, or ``INTERFACE`` are very powerful and herein we will briefly demonstrate their difference. + A complete source code is available in the ``content/code/04_visibility-levels/`` folder. + + In this code example, we want to compile a C++ library and an executable: - Visibility levels ``PRIVATE``, ``PUBLIC``, or ``INTERFACE`` are very powerful and herein we will briefly demonstrate their difference. - - In this demo, we split the source code into 3 libraries and all files are available in the ``content/code/04_visibility-levels/`` folder. + - The library code is in the ``account`` subfolder. It consists of one source (``account.cpp``) and one header file (``account.hpp``). + - The header file and the shared library are needed for the ``bank.cpp`` to produce the ``bank`` executable. + - We also want to use the ``-ffast-math`` compiler flag and propagate it throughout the project. - .. figure:: img/visibility-levels.png - :align: center + Thus code structure is arranged in the following format: -In this source code, the main function links to greeting which links to hello_world which links to world. + 1. The ``account`` target declares the ``account.cpp`` source file as ``PRIVATE`` since it is only needed to produce the shared library. + .. code-block:: cmake -.. typealong:: The internal dependency tree - - If you have installed ``Graphviz``, you can visualize the dependencies between these targets: - - .. code-block:: console - - $ cd build - $ cmake --graphviz=project.dot .. - $ dot -T svg project.dot -o graphviz-greeting-hello-world.svg - - .. figure:: img/graphviz-greeting-hello-world.svg - :align: center - - The dependencies between the four targets in the code example. - - + target_sources(account + PRIVATE + account.cpp + ) -Take a look at the ``CMakeLists.txt``: + 2. The ``-ffast-math`` is instead ``PUBLIC`` as since it needs to be propagated to all targets consuming ``account``. + .. code-block:: cmake -.. literalinclude:: code/04_visibility-levels/CMakeLists.txt - :language: cmake - :linenos: - :emphasize-lines: 17 + target_compile_options(account + PUBLIC + "-ffast-math" + ) + 3. The ``account`` folder is an include directory with ``INTERFACE`` + visibility because only targets consuming ``account`` need to know where + ``account.hpp`` is located. -.. exercise:: Testing the 3 different visibility levels + .. code-block:: cmake - 1. Browse, configure, build, and run the code. + target_include_directories(account + INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR} + ) - 2. Uncomment the highlighted line (line 17) with ``target_compile_definitions``, configure into a fresh folder, and build using the commands below. You will see that the definition is used in ``world.cpp`` but nowhere else. - .. code-block:: console +.. callout:: Rule of thumb for visibility settings - $ cmake -S. -Bbuild_private - $ cmake --build build_private + When working out which visibility settings to use for the properties of your + targets you can refer to the following table: - 3. Change the definition to ``PUBLIC``, configure into a fresh folder, and build. You will see that the definition is used both in ``world.cpp`` and ``hello_world.cpp``. + ============== ================ ============ + Who needs? Others + -------------- ----------------------------- + Target **YES** **NO** + ============== ================ ============ + **YES** ``PUBLIC`` ``PRIVATE`` + **NO** ``INTERFACE`` N/A + ============== ================ ============ - .. code-block:: console - $ cmake -S. -Bbuild_public - $ cmake --build build_public - - 4. Then change the definition to ``INTERFACE``, configure into a fresh folder, and build. You will see that the definition is used only in ``hello_world.cpp`` but not in ``world.cpp``. - - .. code-block:: console - - $ cmake -S. -Bbuild_interface - $ cmake --build build_interface - - 5. What will happen if we change the visibility in line 14 of the above code to ``PRIVATE``? +An additional code example to demonstrate the difference of the visibility levels ``PRIVATE``, ``PUBLIC``, or ``INTERFACE`` is available in the `CodeRefinery CMake Workshop `_. @@ -277,8 +271,3 @@ Typically, you only need to pass the first argument: the folder within the build - Avoid using variables to express dependencies between targets: use visibility levels ``PRIVATE``, ``INTERFACE``, ``PUBLIC`` and let CMake figure out the details. - To keep the complexity of the build system at a minimum, each folder in a multi-folder project should have its own CMake script. - -.. rubric:: Footnotes - -.. [#adapt_from_CR] This subsection is adapted, with permission, from the `CodeRefinery CMake lesson `_. -