Commit d7b098fb authored by Betsy McPhail's avatar Betsy McPhail
Browse files

Some suggestions!

parent 98cf9de0
Step 4: Adding Generator Expressions
=====================================
Exercise 1 - Set C++ Standard with Interface Libraries
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
: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.
Interface libraries are a library target that is not compiled.
They serve as a container to store target features that many targets need.
Linking a target to the interface library transitively passes all of the
interface library requirements to the consuming library. This is the
same as using the ``INTERFACE`` usage requirement for other commands.
There are different types of
:manual:`generator expressions <cmake-generator-expressions(7)>` including
Logical, Informational, and Output expressions.
Using interface libraries also reduces repeated code as multiple targets use
the same interface library.
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.
Exercise 1 - Setting the C++ Standard with Interface Libraries
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Before we use :manual:`generator expressions <cmake-generator-expressions(7)>`
let's refactor our existing code to use an ``INTERFACE`` library. We will
use that library in the next step to demonstrate a common use for
:manual:`generator expressions <cmake-generator-expressions(7)>`.
Goal
----
Use interface libraries to specify the C++ standard.
Add an ``INTERFACE`` library target to specify the required C++ standard.
Helpful Resources
-----------------
......@@ -34,32 +56,35 @@ Files to Edit
Getting Started
---------------
In this exercise, we will refactor our code to use interface libraries when
specifying the C++ standard.
In this exercise, we will refactor our code to use an ``INTERFACE`` library to
specify the C++ standard.
The starting source code is provided in the ``Step4`` directory. In this
exercise, complete ``TODO 1`` through ``TODO 5``.
exercise, complete ``TODO 1`` through ``TODO 3``.
Start by editing the top level ``CMakeLists.txt`` file. Construct an
``INTERFACE`` library target called ``tutorial_compiler_flags`` and
specify ``cxx_std_11`` as a target compiler feature.
Let's start by constructing an
``INTERFACE`` library target and specifying the required C++ standard level
of ``11`` instead of using :variable:`CMAKE_CXX_STANDARD`. Then, link this
library to all of our existing targets.
Modify ``CMakeLists.txt`` and ``MathFunctions/CMakeLists.txt`` so that all
targets have a :command:`target_link_libraries` call to
``tutorial_compiler_flags``.
Build and Run
-------------
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.
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. Here's a refresher of
what that looks like from the command line:
Here's a refresher of what that looks like from the command line:
.. code-block:: console
mkdir Step3_build
cd Step3_build
cmake ../Step3
mkdir Step4_build
cd Step4_build
cmake ../Step4
cmake --build .
Next, use the newly built ``Tutorial`` and verify that it is working as
......@@ -72,71 +97,47 @@ Let's update our code from the previous step to use interface libraries
to set our C++ requirements.
To start, we need to remove the two :command:`set` calls on the variables
``CMAKE_CXX_STANDARD`` and ``CMAKE_CXX_STANDARD_REQUIRED``. The specific
lines to remove are as follows:
.. raw:: html
<details><summary>TODO 1: Click to show/hide answer</summary>
:variable:`CMAKE_CXX_STANDARD` and :variable:`CMAKE_CXX_STANDARD_REQUIRED`.
The specific lines to remove are as follows:
.. literalinclude:: Step4/CMakeLists.txt
:caption: TODO 1: CMakeLists.txt
:caption: CMakeLists.txt
:name: CMakeLists.txt-CXX_STANDARD-variable-remove
:language: cmake
:start-after: # specify the C++ standard
:end-before: # TODO 2:
:end-before: # TODO 5: Create helper variables
.. raw:: html
Next, we need to create an interface library, ``tutorial_compiler_flags``. And
then use :command:`target_compile_features` to add the compiler feature
``cxx_std_11``.
</details>
Next, we need to create an interface library.
This will be used as a container to hold our C++ requirement feature.
.. raw:: html
<details><summary>TODO 2: Click to show/hide answer</summary>
<details><summary>TODO 1: Click to show/hide answer</summary>
.. literalinclude:: Step5/CMakeLists.txt
:caption: TODO 2: CMakeLists.txt
:caption: TODO 1: CMakeLists.txt
:name: CMakeLists.txt-cxx_std-feature
:language: cmake
:start-after: # specify the C++ standard
:end-before: target_compile_features
.. raw:: html
</details>
Now that we have our library, use :command:`target_compile_features` to
add the feature ``cxx_std_11``. This feature sets the required C++ standard
to 11 for the target.
.. raw:: html
<details><summary>TODO 3: Click to show/hide answer</summary>
.. literalinclude:: Step5/CMakeLists.txt
:caption: TODO 3: CMakeLists.txt
:name: CMakeLists.txt-target_compile_features
:language: cmake
:start-after: add_library(tutorial_compiler_flags INTERFACE)
:end-before: # add compiler warning flags just
.. raw:: html
</details>
Finally, with our interface library set up, we simply need to link our
executable target and our MathFunctions library to our library. Respectively,
the code will look like this:
Finally, with our interface library set up, we need to link our
executable ``Target`` and our ``MathFunctions`` library to our new
``tutorial_compiler_flags`` library. Respectively, the code will look like
this:
.. raw:: html
<details><summary>TODO 4: Click to show/hide answer</summary>
<details><summary>TODO 2: Click to show/hide answer</summary>
.. literalinclude:: Step5/CMakeLists.txt
:caption: TODO 4: CMakeLists.txt
:caption: TODO 2: CMakeLists.txt
:name: CMakeLists.txt-target_link_libraries-step4
:language: cmake
:start-after: add_executable(Tutorial tutorial.cxx)
......@@ -150,10 +151,10 @@ and this:
.. raw:: html
<details><summary>TODO 5: Click to show/hide answer</summary>
<details><summary>TODO 3: Click to show/hide answer</summary>
.. literalinclude:: Step5/MathFunctions/CMakeLists.txt
:caption: TODO 5: MathFunctions/CMakeLists.txt
:caption: TODO 3: MathFunctions/CMakeLists.txt
:name: MathFunctions-CMakeLists.txt-target_link_libraries-step4
:language: cmake
:start-after: # link our compiler flags interface library
......@@ -162,39 +163,13 @@ and this:
</details>
With this, all of our code is once again requiring C++ 11 to build. Notice
With this, all of our code is still requiring C++ 11 to build. Notice
though that with this method, it gives us the ability to be specific about
which targets get specific requirements. In addition, we create a single
source of truth in our interface library.
Exercise 2 - Build Phase Flags with 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.
Exercise 2 - Adding Compiler Warning Flags with Generator Expressions
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
A common usage of
:manual:`generator expressions <cmake-generator-expressions(7)>` is to
......@@ -205,12 +180,14 @@ target allowing this information to propagate.
Goal
----
Add flags when building but not for installed versions.
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
......@@ -221,14 +198,17 @@ Files to Edit
Getting Started
---------------
Start with the resulting files from Exercise 1. Complete ``TODO 6`` through
``TODO 10``.
Start with the resulting files from Exercise 1. Complete ``TODO 4`` through
``TODO 7``.
First, set the :command:`cmake_minimum_required` to `3.15` since we are using
generator expressions. Next, with generator expressions, determine which
compiler our code is being built with. Then, use that information to set the
appropriate warning flags. Lastly, take the expression further by only using
these for build time and not for installed versions.
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 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
-------------
......@@ -238,26 +218,24 @@ rebuild our code by calling the following:
.. code-block:: console
cd Step3_build
cd Step4_build
cmake --build .
Solution
--------
This section requires 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:
Update the :command:`cmake_minimum_required` to require at least CMake
version ``3.15``:
.. raw:: html
<details><summary>TODO 6: Click to show/hide answer</summary>
.. code-block:: cmake
:caption: TODO 6: CMakeLists.txt
:name: CMakeLists.txt-version-update
<details><summary>TODO 4: Click to show/hide answer</summary>
cmake_minimum_required(VERSION 3.15)
.. literalinclude:: Step5/CMakeLists.txt
:caption: TODO 4: CMakeLists.txt
:name: MathFunctions-CMakeLists.txt-minimum-required-step4
:language: cmake
:end-before: # set the project name and version
.. raw:: html
......@@ -270,14 +248,14 @@ variables ``gcc_like_cxx`` and ``msvc_cxx`` as follows:
.. raw:: html
<details><summary>TODO 7,8: Click to show/hide answer</summary>
<details><summary>TODO 5: Click to show/hide answer</summary>
.. code-block:: cmake
:caption: TODO 7,8: CMakeLists.txt
.. literalinclude:: Step5/CMakeLists.txt
:caption: TODO 5: CMakeLists.txt
:name: CMakeLists.txt-compile_lang_and_id
set(gcc_like_cxx "$<COMPILE_LANG_AND_ID:CXX,ARMClang,AppleClang,Clang,GNU,LCC>")
set(msvc_cxx "$<COMPILE_LANG_AND_ID:CXX,MSVC>")
:language: cmake
:start-after: # the BUILD_INTERFACE genex
:end-before: target_compile_options(tutorial_compiler_flags INTERFACE
.. raw:: html
......@@ -291,10 +269,10 @@ interface library.
.. raw:: html
<details><summary>TODO 9: Click to show/hide answer</summary>
<details><summary>TODO 6: Click to show/hide answer</summary>
.. code-block:: cmake
:caption: TODO 9: CMakeLists.txt
:caption: TODO 6: CMakeLists.txt
:name: CMakeLists.txt-compile_flags
target_compile_options(tutorial_compiler_flags INTERFACE
......@@ -313,13 +291,13 @@ condition. The resulting full code looks like the following:
.. raw:: html
<details><summary>TODO 10: Click to show/hide answer</summary>
<details><summary>TODO 7: Click to show/hide answer</summary>
.. literalinclude:: Step5/CMakeLists.txt
:caption: TODO 10: CMakeLists.txt
:caption: TODO 7: CMakeLists.txt
:name: CMakeLists.txt-target_compile_options-genex
:language: cmake
:start-after: # the BUILD_INTERFACE genex
:start-after: set(msvc_cxx "$<COMPILE_LANG_AND_ID:CXX,MSVC>")
:end-before: # should we use our own math functions
.. raw:: html
......
......@@ -96,7 +96,7 @@ follows:
:name: MathFunctions/CMakeLists.txt-target_include_directories-INTERFACE
:language: cmake
:start-after: # to find MathFunctions.h
:end-before: # TODO 5: Link the interface library to the MathFunctions
:end-before: # TODO 3: Link to
.. raw:: html
......
# TODO 6: Update the minimum required version to 3.15
# TODO 4: Update the minimum required version to 3.15
cmake_minimum_required(VERSION 3.10)
# set the project name and version
project(Tutorial VERSION 1.0)
# TODO 1: Delete the following two set commands
# TODO 1: Replace the following code by:
# * Creating an interface library called tutorial_compiler_flags
# Hint: use add_library() with the INTERFACE signature
# * Add compiler feature cxx_std_11 to tutorial_compiler_flags
# Hint: Use target_compile_features()
# specify the C++ standard
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)
# TODO 2: Create an interface library
# TODO 3: Add cxx_std_11 to the interface library's compile features
# TODO 7: Set a new variable gcc_like_cxx to determine if one of the following
# compilers is using C++: ARMClang, AppleClang, Clang, GNU, LCC
# Hint: Use COMPILE_LANG_AND_ID
# TODO 5: Create helper variables to determine which compiler we are using:
# * Create a new variable gcc_like_cxx that is true if we are using CXX and
# any of the following compilers: ARMClang, AppleClang, Clang, GNU, LCC
# * Create a new variable msvc_cxx that is true if we are using CXX and MSVC
# Hint: Use set() and COMPILE_LANG_AND_ID
# TODO 8: Set a new variable msvc_cxx to determine if the following compiler
# is used: MSVC
# TODO 6: Add warning flag compile options to the interface library
# tutorial_compiler_flags.
# * For gcc_like_cxx, add flags -Wall;-Wextra;-Wshadow;-Wformat=2;-Wunused
# * For msvc_cxx, add flags -W3
# Hint: Use target_compile_options()
# TODO 9: Add warning flag compile options to the interface library
# Hint: For gcc_like_cxx, add flags -Wall;-Wextra;-Wshadow;-Wformat=2;-Wunused
# Hint: For msvc_cxx, add flags -W3
# TODO 10: With nested generator expressions, only use the flags during build
# TODO 7: With nested generator expressions, only use the flags for the
# build-tree
# Hint: Use BUILD_INTERFACE
# should we use our own math functions
......@@ -42,7 +47,8 @@ endif()
# add the executable
add_executable(Tutorial tutorial.cxx)
# TODO 4: Link the interface library to the executable target
# TODO 2: Link to tutorial_compiler_flags
target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS})
# add the binary tree to the search path for include files
......
......@@ -6,4 +6,4 @@ target_include_directories(MathFunctions
INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
)
# TODO 5: Link the interface library to the MathFunctions library target
# TODO 3: Link to tutorial_compiler_flags
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment