Adding Generator Expressions.rst 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. Step 4: Adding Generator Expressions
  2. =====================================
  3. :manual:`Generator expressions <cmake-generator-expressions(7)>` are evaluated
  4. during build system generation to produce information specific to each build
  5. configuration.
  6. :manual:`Generator expressions <cmake-generator-expressions(7)>` are allowed in
  7. the context of many target properties, such as :prop_tgt:`LINK_LIBRARIES`,
  8. :prop_tgt:`INCLUDE_DIRECTORIES`, :prop_tgt:`COMPILE_DEFINITIONS` and others.
  9. They may also be used when using commands to populate those properties, such as
  10. :command:`target_link_libraries`, :command:`target_include_directories`,
  11. :command:`target_compile_definitions` and others.
  12. :manual:`Generator expressions <cmake-generator-expressions(7)>` may be used
  13. to enable conditional linking, conditional definitions used when compiling,
  14. conditional include directories and more. The conditions may be based on the
  15. build configuration, target properties, platform information or any other
  16. queryable information.
  17. There are different types of
  18. :manual:`generator expressions <cmake-generator-expressions(7)>` including
  19. Logical, Informational, and Output expressions.
  20. Logical expressions are used to create conditional output. The basic
  21. expressions are the ``0`` and ``1`` expressions. A ``$<0:...>`` results in the
  22. empty string, and ``$<1:...>`` results in the content of ``...``. They can also
  23. be nested.
  24. Exercise 1 - Adding Compiler Warning Flags with Generator Expressions
  25. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  26. A common usage of
  27. :manual:`generator expressions <cmake-generator-expressions(7)>` is to
  28. conditionally add compiler flags, such as those for language levels or
  29. warnings. A nice pattern is to associate this information to an ``INTERFACE``
  30. target allowing this information to propagate.
  31. Goal
  32. ----
  33. Add compiler warning flags when building but not for installed versions.
  34. Helpful Resources
  35. -----------------
  36. * :manual:`cmake-generator-expressions(7)`
  37. * :command:`cmake_minimum_required`
  38. * :command:`set`
  39. * :command:`target_compile_options`
  40. Files to Edit
  41. -------------
  42. * ``CMakeLists.txt``
  43. Getting Started
  44. ---------------
  45. Open the file ``Step4/CMakeLists.txt`` and complete ``TODO 1`` through
  46. ``TODO 4``.
  47. First, in the top level ``CMakeLists.txt`` file, we need to set the
  48. :command:`cmake_minimum_required` to ``3.15``. In this exercise we are going
  49. to use a generator expression which was introduced in CMake 3.15.
  50. Next we add the desired compiler warning flags that we want for our project.
  51. As warning flags vary based on the compiler, we use the
  52. ``COMPILE_LANG_AND_ID`` generator expression to control which flags to apply
  53. given a language and a set of compiler ids.
  54. Build and Run
  55. -------------
  56. Make a new directory called ``Step4_build``, run the :manual:`cmake <cmake(1)>`
  57. executable or the :manual:`cmake-gui <cmake-gui(1)>` to configure the project
  58. and then build it with your chosen build tool or by using ``cmake --build .``
  59. from the build directory.
  60. .. code-block:: console
  61. mkdir Step4_build
  62. cd Step4_build
  63. cmake ../Step4
  64. cmake --build .
  65. Solution
  66. --------
  67. Update the :command:`cmake_minimum_required` to require at least CMake
  68. version ``3.15``:
  69. .. raw:: html
  70. <details><summary>TODO 1: Click to show/hide answer</summary>
  71. .. literalinclude:: Step5/CMakeLists.txt
  72. :caption: TODO 1: CMakeLists.txt
  73. :name: MathFunctions-CMakeLists.txt-minimum-required-step4
  74. :language: cmake
  75. :end-before: # set the project name and version
  76. .. raw:: html
  77. </details>
  78. Next we determine which compiler our system is currently using to build
  79. since warning flags vary based on the compiler we use. This is done with
  80. the ``COMPILE_LANG_AND_ID`` generator expression. We set the result in the
  81. variables ``gcc_like_cxx`` and ``msvc_cxx`` as follows:
  82. .. raw:: html
  83. <details><summary>TODO 2: Click to show/hide answer</summary>
  84. .. literalinclude:: Step5/CMakeLists.txt
  85. :caption: TODO 2: CMakeLists.txt
  86. :name: CMakeLists.txt-compile_lang_and_id
  87. :language: cmake
  88. :start-after: # the BUILD_INTERFACE genex
  89. :end-before: target_compile_options(tutorial_compiler_flags INTERFACE
  90. .. raw:: html
  91. </details>
  92. Next we add the desired compiler warning flags that we want for our project.
  93. Using our variables ``gcc_like_cxx`` and ``msvc_cxx``, we can use another
  94. generator expression to apply the respective flags only when the variables are
  95. true. We use :command:`target_compile_options` to apply these flags to our
  96. interface library.
  97. .. raw:: html
  98. <details><summary>TODO 3: Click to show/hide answer</summary>
  99. .. code-block:: cmake
  100. :caption: TODO 3: CMakeLists.txt
  101. :name: CMakeLists.txt-compile_flags
  102. target_compile_options(tutorial_compiler_flags INTERFACE
  103. "$<${gcc_like_cxx}:-Wall;-Wextra;-Wshadow;-Wformat=2;-Wunused>"
  104. "$<${msvc_cxx}:-W3>"
  105. )
  106. .. raw:: html
  107. </details>
  108. Lastly, we only want these warning flags to be used during builds. Consumers
  109. of our installed project should not inherit our warning flags. To specify
  110. this, we wrap our flags from TODO 3 in a generator expression using the
  111. ``BUILD_INTERFACE`` condition. The resulting full code looks like the following:
  112. .. raw:: html
  113. <details><summary>TODO 4: Click to show/hide answer</summary>
  114. .. literalinclude:: Step5/CMakeLists.txt
  115. :caption: TODO 4: CMakeLists.txt
  116. :name: CMakeLists.txt-target_compile_options-genex
  117. :language: cmake
  118. :start-after: set(msvc_cxx "$<COMPILE_LANG_AND_ID:CXX,MSVC>")
  119. :end-before: # configure a header file to pass some of the CMake settings
  120. .. raw:: html
  121. </details>