cmake/Help/guide/tutorial/Adding Generator Expressions.rst

169 lines
5.4 KiB
ReStructuredText
Raw Normal View History

2022-11-16 20:14:03 +01:00
Step 4: Adding Generator Expressions
2021-09-14 00:13:48 +02:00
=====================================
:manual:`Generator expressions <cmake-generator-expressions(7)>` are evaluated
during build system generation to produce information specific to each build
configuration.
:manual:`Generator expressions <cmake-generator-expressions(7)>` are allowed in
the context of many target properties, such as :prop_tgt:`LINK_LIBRARIES`,
:prop_tgt:`INCLUDE_DIRECTORIES`, :prop_tgt:`COMPILE_DEFINITIONS` and others.
They may also be used when using commands to populate those properties, such as
:command:`target_link_libraries`, :command:`target_include_directories`,
:command:`target_compile_definitions` and others.
:manual:`Generator expressions <cmake-generator-expressions(7)>` may be used
to enable conditional linking, conditional definitions used when compiling,
conditional include directories and more. The conditions may be based on the
build configuration, target properties, platform information or any other
queryable information.
There are different types of
:manual:`generator expressions <cmake-generator-expressions(7)>` including
Logical, Informational, and Output expressions.
Logical expressions are used to create conditional output. The basic
expressions are the ``0`` and ``1`` expressions. A ``$<0:...>`` results in the
empty string, and ``<1:...>`` results in the content of ``...``. They can also
be nested.
2023-07-02 19:51:09 +02:00
Exercise 1 - Adding Compiler Warning Flags with Generator Expressions
2022-11-16 20:14:03 +01:00
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
2021-09-14 00:13:48 +02:00
A common usage of
:manual:`generator expressions <cmake-generator-expressions(7)>` is to
conditionally add compiler flags, such as those for language levels or
warnings. A nice pattern is to associate this information to an ``INTERFACE``
2022-11-16 20:14:03 +01:00
target allowing this information to propagate.
2021-09-14 00:13:48 +02:00
2022-11-16 20:14:03 +01:00
Goal
----
2021-09-14 00:13:48 +02:00
2022-11-16 20:14:03 +01:00
Add compiler warning flags when building but not for installed versions.
Helpful Resources
-----------------
* :manual:`cmake-generator-expressions(7)`
* :command:`cmake_minimum_required`
* :command:`set`
* :command:`target_compile_options`
Files to Edit
-------------
* ``CMakeLists.txt``
Getting Started
---------------
2023-07-02 19:51:09 +02:00
Open the file ``Step4/CMakeLists.txt`` and complete ``TODO 1`` through
``TODO 4``.
2022-11-16 20:14:03 +01:00
First, in the top level ``CMakeLists.txt`` file, we need to set the
:command:`cmake_minimum_required` to ``3.15``. In this exercise we are going
to use a generator expression which was introduced in CMake 3.15.
Next we add the desired compiler warning flags that we want for our project.
As warning flags vary based on the compiler, we use the
``COMPILE_LANG_AND_ID`` generator expression to control which flags to apply
given a language and a set of compiler ids.
Build and Run
-------------
2023-07-02 19:51:09 +02:00
Make a new directory called ``Step4_build``, run the :manual:`cmake <cmake(1)>`
executable or the :manual:`cmake-gui <cmake-gui(1)>` to configure the project
and then build it with your chosen build tool or by using ``cmake --build .``
from the build directory.
2022-11-16 20:14:03 +01:00
.. code-block:: console
2023-07-02 19:51:09 +02:00
mkdir Step4_build
2022-11-16 20:14:03 +01:00
cd Step4_build
2023-07-02 19:51:09 +02:00
cmake ../Step4
2022-11-16 20:14:03 +01:00
cmake --build .
Solution
--------
Update the :command:`cmake_minimum_required` to require at least CMake
version ``3.15``:
.. raw:: html
2023-07-02 19:51:09 +02:00
<details><summary>TODO 1: Click to show/hide answer</summary>
2022-11-16 20:14:03 +01:00
.. literalinclude:: Step5/CMakeLists.txt
2023-07-02 19:51:09 +02:00
:caption: TODO 1: CMakeLists.txt
2022-11-16 20:14:03 +01:00
:name: MathFunctions-CMakeLists.txt-minimum-required-step4
2021-09-14 00:13:48 +02:00
:language: cmake
2022-11-16 20:14:03 +01:00
:end-before: # set the project name and version
2021-09-14 00:13:48 +02:00
2022-11-16 20:14:03 +01:00
.. raw:: html
2021-09-14 00:13:48 +02:00
2022-11-16 20:14:03 +01:00
</details>
Next we determine which compiler our system is currently using to build
since warning flags vary based on the compiler we use. This is done with
the ``COMPILE_LANG_AND_ID`` generator expression. We set the result in the
variables ``gcc_like_cxx`` and ``msvc_cxx`` as follows:
.. raw:: html
2023-07-02 19:51:09 +02:00
<details><summary>TODO 2: Click to show/hide answer</summary>
2022-11-16 20:14:03 +01:00
.. literalinclude:: Step5/CMakeLists.txt
2023-07-02 19:51:09 +02:00
:caption: TODO 2: CMakeLists.txt
2022-11-16 20:14:03 +01:00
:name: CMakeLists.txt-compile_lang_and_id
2021-09-14 00:13:48 +02:00
:language: cmake
2022-11-16 20:14:03 +01:00
:start-after: # the BUILD_INTERFACE genex
:end-before: target_compile_options(tutorial_compiler_flags INTERFACE
2021-09-14 00:13:48 +02:00
2022-11-16 20:14:03 +01:00
.. raw:: html
</details>
Next we add the desired compiler warning flags that we want for our project.
Using our variables ``gcc_like_cxx`` and ``msvc_cxx``, we can use another
generator expression to apply the respective flags only when the variables are
true. We use :command:`target_compile_options` to apply these flags to our
interface library.
.. raw:: html
2023-07-02 19:51:09 +02:00
<details><summary>TODO 3: Click to show/hide answer</summary>
2021-11-20 13:41:27 +01:00
.. code-block:: cmake
2023-07-02 19:51:09 +02:00
:caption: TODO 3: CMakeLists.txt
2022-11-16 20:14:03 +01:00
:name: CMakeLists.txt-compile_flags
2021-11-20 13:41:27 +01:00
2022-11-16 20:14:03 +01:00
target_compile_options(tutorial_compiler_flags INTERFACE
"$<${gcc_like_cxx}:-Wall;-Wextra;-Wshadow;-Wformat=2;-Wunused>"
"$<${msvc_cxx}:-W3>"
)
2021-09-14 00:13:48 +02:00
2022-11-16 20:14:03 +01:00
.. raw:: html
2021-09-14 00:13:48 +02:00
2022-11-16 20:14:03 +01:00
</details>
Lastly, we only want these warning flags to be used during builds. Consumers
of our installed project should not inherit our warning flags. To specify
2023-12-07 09:12:54 +01:00
this, we wrap our flags from TODO 3 in a generator expression using the
``BUILD_INTERFACE`` condition. The resulting full code looks like the following:
2022-11-16 20:14:03 +01:00
.. raw:: html
2023-07-02 19:51:09 +02:00
<details><summary>TODO 4: Click to show/hide answer</summary>
2022-11-16 20:14:03 +01:00
.. literalinclude:: Step5/CMakeLists.txt
2023-07-02 19:51:09 +02:00
:caption: TODO 4: CMakeLists.txt
2021-09-14 00:13:48 +02:00
:name: CMakeLists.txt-target_compile_options-genex
:language: cmake
2022-11-16 20:14:03 +01:00
:start-after: set(msvc_cxx "$<COMPILE_LANG_AND_ID:CXX,MSVC>")
2023-07-02 19:51:09 +02:00
:end-before: # configure a header file to pass some of the CMake settings
2021-09-14 00:13:48 +02:00
2022-11-16 20:14:03 +01:00
.. raw:: html
2021-09-14 00:13:48 +02:00
2022-11-16 20:14:03 +01:00
</details>