Imported Upstream version 3.25.0
[platform/upstream/cmake.git] / Help / guide / tutorial / Adding Generator Expressions.rst
1 Step 4: Adding Generator Expressions
2 =====================================
3
4 :manual:`Generator expressions <cmake-generator-expressions(7)>` are evaluated
5 during build system generation to produce information specific to each build
6 configuration.
7
8 :manual:`Generator expressions <cmake-generator-expressions(7)>` are allowed in
9 the context of many target properties, such as :prop_tgt:`LINK_LIBRARIES`,
10 :prop_tgt:`INCLUDE_DIRECTORIES`, :prop_tgt:`COMPILE_DEFINITIONS` and others.
11 They may also be used when using commands to populate those properties, such as
12 :command:`target_link_libraries`, :command:`target_include_directories`,
13 :command:`target_compile_definitions` and others.
14
15 :manual:`Generator expressions <cmake-generator-expressions(7)>`  may be used
16 to enable conditional linking, conditional definitions used when compiling,
17 conditional include directories and more. The conditions may be based on the
18 build configuration, target properties, platform information or any other
19 queryable information.
20
21 There are different types of
22 :manual:`generator expressions <cmake-generator-expressions(7)>` including
23 Logical, Informational, and Output expressions.
24
25 Logical expressions are used to create conditional output. The basic
26 expressions are the ``0`` and ``1`` expressions. A ``$<0:...>`` results in the
27 empty string, and ``<1:...>`` results in the content of ``...``.  They can also
28 be nested.
29
30 Exercise 1 - Setting the C++ Standard with Interface Libraries
31 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
32
33 Before we use :manual:`generator expressions <cmake-generator-expressions(7)>`
34 let's refactor our existing code to use an ``INTERFACE`` library. We will
35 use that library in the next step to demonstrate a common use for
36 :manual:`generator expressions <cmake-generator-expressions(7)>`.
37
38 Goal
39 ----
40
41 Add an ``INTERFACE`` library target to specify the required C++ standard.
42
43 Helpful Resources
44 -----------------
45
46 * :command:`add_library`
47 * :command:`target_compile_features`
48 * :command:`target_link_libraries`
49
50 Files to Edit
51 -------------
52
53 * ``CMakeLists.txt``
54 * ``MathFunctions/CMakeLists.txt``
55
56 Getting Started
57 ---------------
58
59 In this exercise, we will refactor our code to use an ``INTERFACE`` library to
60 specify the C++ standard.
61
62 The starting source code is provided in the ``Step4`` directory. In this
63 exercise, complete ``TODO 1`` through ``TODO 3``.
64
65 Start by editing the top level ``CMakeLists.txt`` file. Construct an
66 ``INTERFACE`` library target called ``tutorial_compiler_flags`` and
67 specify ``cxx_std_11`` as a target compiler feature.
68
69 Modify ``CMakeLists.txt`` and ``MathFunctions/CMakeLists.txt`` so that all
70 targets have a :command:`target_link_libraries` call to
71 ``tutorial_compiler_flags``.
72
73 Build and Run
74 -------------
75
76 Make a new directory called ``Step4_build``, run the :manual:`cmake <cmake(1)>`
77 executable or the :manual:`cmake-gui <cmake-gui(1)>` to configure the project
78 and then build it with your chosen build tool or by using ``cmake --build .``
79 from the build directory.
80
81 Here's a refresher of what that looks like from the command line:
82
83 .. code-block:: console
84
85   mkdir Step4_build
86   cd Step4_build
87   cmake ../Step4
88   cmake --build .
89
90 Next, use the newly built ``Tutorial`` and verify that it is working as
91 expected.
92
93 Solution
94 --------
95
96 Let's update our code from the previous step to use interface libraries
97 to set our C++ requirements.
98
99 To start, we need to remove the two :command:`set` calls on the variables
100 :variable:`CMAKE_CXX_STANDARD` and :variable:`CMAKE_CXX_STANDARD_REQUIRED`.
101 The specific lines to remove are as follows:
102
103 .. literalinclude:: Step4/CMakeLists.txt
104   :caption: CMakeLists.txt
105   :name: CMakeLists.txt-CXX_STANDARD-variable-remove
106   :language: cmake
107   :start-after: # specify the C++ standard
108   :end-before: # TODO 5: Create helper variables
109
110 Next, we need to create an interface library, ``tutorial_compiler_flags``. And
111 then use :command:`target_compile_features` to add the compiler feature
112 ``cxx_std_11``.
113
114
115 .. raw:: html
116
117   <details><summary>TODO 1: Click to show/hide answer</summary>
118
119 .. literalinclude:: Step5/CMakeLists.txt
120   :caption: TODO 1: CMakeLists.txt
121   :name: CMakeLists.txt-cxx_std-feature
122   :language: cmake
123   :start-after: # specify the C++ standard
124   :end-before: # add compiler warning flags just
125
126 .. raw:: html
127
128   </details>
129
130 Finally, with our interface library set up, we need to link our
131 executable ``Target`` and our ``MathFunctions`` library to our new
132 ``tutorial_compiler_flags`` library. Respectively, the code will look like
133 this:
134
135 .. raw:: html
136
137   <details><summary>TODO 2: Click to show/hide answer</summary>
138
139 .. literalinclude:: Step5/CMakeLists.txt
140   :caption: TODO 2: CMakeLists.txt
141   :name: CMakeLists.txt-target_link_libraries-step4
142   :language: cmake
143   :start-after: add_executable(Tutorial tutorial.cxx)
144   :end-before: # add the binary tree to the search path for include file
145
146 .. raw:: html
147
148   </details>
149
150 and this:
151
152 .. raw:: html
153
154   <details><summary>TODO 3: Click to show/hide answer</summary>
155
156 .. literalinclude:: Step5/MathFunctions/CMakeLists.txt
157   :caption: TODO 3: MathFunctions/CMakeLists.txt
158   :name: MathFunctions-CMakeLists.txt-target_link_libraries-step4
159   :language: cmake
160   :start-after: # link our compiler flags interface library
161   :end-before: # TODO 1
162
163 .. raw:: html
164
165   </details>
166
167 With this, all of our code still requires C++ 11 to build. Notice
168 though that with this method, it gives us the ability to be specific about
169 which targets get specific requirements. In addition, we create a single
170 source of truth in our interface library.
171
172 Exercise 2 - Adding Compiler Warning Flags with Generator Expressions
173 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
174
175 A common usage of
176 :manual:`generator expressions <cmake-generator-expressions(7)>` is to
177 conditionally add compiler flags, such as those for language levels or
178 warnings. A nice pattern is to associate this information to an ``INTERFACE``
179 target allowing this information to propagate.
180
181 Goal
182 ----
183
184 Add compiler warning flags when building but not for installed versions.
185
186 Helpful Resources
187 -----------------
188
189 * :manual:`cmake-generator-expressions(7)`
190 * :command:`cmake_minimum_required`
191 * :command:`set`
192 * :command:`target_compile_options`
193
194 Files to Edit
195 -------------
196
197 * ``CMakeLists.txt``
198
199 Getting Started
200 ---------------
201
202 Start with the resulting files from Exercise 1. Complete ``TODO 4`` through
203 ``TODO 7``.
204
205 First, in the top level ``CMakeLists.txt`` file, we need to set the
206 :command:`cmake_minimum_required` to ``3.15``. In this exercise we are going
207 to use a generator expression which was introduced in CMake 3.15.
208
209 Next we add the desired compiler warning flags that we want for our project.
210 As warning flags vary based on the compiler, we use the
211 ``COMPILE_LANG_AND_ID`` generator expression to control which flags to apply
212 given a language and a set of compiler ids.
213
214 Build and Run
215 -------------
216
217 Since we have our build directory already configured from Exercise 1, simply
218 rebuild our code by calling the following:
219
220 .. code-block:: console
221
222   cd Step4_build
223   cmake --build .
224
225 Solution
226 --------
227
228 Update the :command:`cmake_minimum_required` to require at least CMake
229 version ``3.15``:
230
231 .. raw:: html
232
233   <details><summary>TODO 4: Click to show/hide answer</summary>
234
235 .. literalinclude:: Step5/CMakeLists.txt
236   :caption: TODO 4: CMakeLists.txt
237   :name: MathFunctions-CMakeLists.txt-minimum-required-step4
238   :language: cmake
239   :end-before: # set the project name and version
240
241 .. raw:: html
242
243   </details>
244
245 Next we determine which compiler our system is currently using to build
246 since warning flags vary based on the compiler we use. This is done with
247 the ``COMPILE_LANG_AND_ID`` generator expression. We set the result in the
248 variables ``gcc_like_cxx`` and ``msvc_cxx`` as follows:
249
250 .. raw:: html
251
252   <details><summary>TODO 5: Click to show/hide answer</summary>
253
254 .. literalinclude:: Step5/CMakeLists.txt
255   :caption: TODO 5: CMakeLists.txt
256   :name: CMakeLists.txt-compile_lang_and_id
257   :language: cmake
258   :start-after: # the BUILD_INTERFACE genex
259   :end-before: target_compile_options(tutorial_compiler_flags INTERFACE
260
261 .. raw:: html
262
263   </details>
264
265 Next we add the desired compiler warning flags that we want for our project.
266 Using our variables ``gcc_like_cxx`` and ``msvc_cxx``, we can use another
267 generator expression to apply the respective flags only when the variables are
268 true. We use :command:`target_compile_options` to apply these flags to our
269 interface library.
270
271 .. raw:: html
272
273   <details><summary>TODO 6: Click to show/hide answer</summary>
274
275 .. code-block:: cmake
276   :caption: TODO 6: CMakeLists.txt
277   :name: CMakeLists.txt-compile_flags
278
279   target_compile_options(tutorial_compiler_flags INTERFACE
280     "$<${gcc_like_cxx}:-Wall;-Wextra;-Wshadow;-Wformat=2;-Wunused>"
281     "$<${msvc_cxx}:-W3>"
282   )
283
284 .. raw:: html
285
286   </details>
287
288 Lastly, we only want these warning flags to be used during builds. Consumers
289 of our installed project should not inherit our warning flags. To specify
290 this, we wrap our flags in a generator expression using the ``BUILD_INTERFACE``
291 condition. The resulting full code looks like the following:
292
293 .. raw:: html
294
295   <details><summary>TODO 7: Click to show/hide answer</summary>
296
297 .. literalinclude:: Step5/CMakeLists.txt
298   :caption: TODO 7: CMakeLists.txt
299   :name: CMakeLists.txt-target_compile_options-genex
300   :language: cmake
301   :start-after: set(msvc_cxx "$<COMPILE_LANG_AND_ID:CXX,MSVC>")
302   :end-before: # should we use our own math functions
303
304 .. raw:: html
305
306   </details>