| Step 10: Adding Generator Expressions | |
| ===================================== | |
| :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. | |
| 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`` | |
| target allowing this information to propagate. Let's start by constructing an | |
| ``INTERFACE`` target and specifying the required C++ standard level of ``11`` | |
| instead of using :variable:`CMAKE_CXX_STANDARD`. | |
| So the following code: | |
| .. literalinclude:: Step10/CMakeLists.txt | |
| :caption: CMakeLists.txt | |
| :name: CMakeLists.txt-CXX_STANDARD-variable-remove | |
| :language: cmake | |
| :start-after: project(Tutorial VERSION 1.0) | |
| :end-before: # control where the static and shared libraries are built so that on windows | |
| Would be replaced with: | |
| .. literalinclude:: Step11/CMakeLists.txt | |
| :caption: CMakeLists.txt | |
| :name: CMakeLists.txt-cxx_std-feature | |
| :language: cmake | |
| :start-after: project(Tutorial VERSION 1.0) | |
| :end-before: # add compiler warning flags just when building this project via | |
| **Note**: This upcoming section will require a change to the | |
| :command:`cmake_minimum_required` usage in the code. The Generator Expression | |
| that is about to be used was introduced in `3.15`. Update the call to require | |
| that more recent version: | |
| .. code-block:: cmake | |
| :caption: CMakeLists.txt | |
| :name: CMakeLists.txt-version-update | |
| cmake_minimum_required(VERSION 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 as seen below: | |
| .. literalinclude:: Step11/CMakeLists.txt | |
| :caption: CMakeLists.txt | |
| :name: CMakeLists.txt-target_compile_options-genex | |
| :language: cmake | |
| :start-after: # the BUILD_INTERFACE genex | |
| :end-before: # control where the static and shared libraries are built so that on windows | |
| Looking at this we see that the warning flags are encapsulated inside a | |
| ``BUILD_INTERFACE`` condition. This is done so that consumers of our installed | |
| project will not inherit our warning flags. | |
| **Exercise**: Modify ``MathFunctions/CMakeLists.txt`` so that all targets have | |
| a :command:`target_link_libraries` call to ``tutorial_compiler_flags``. |