diff options
10 files changed, 288 insertions, 32 deletions
diff --git a/Help/guide/tutorial/Adding Generator Expressions.rst b/Help/guide/tutorial/Adding Generator Expressions.rst index 0efce8d..ba728bd 100644 --- a/Help/guide/tutorial/Adding Generator Expressions.rst +++ b/Help/guide/tutorial/Adding Generator Expressions.rst @@ -27,58 +27,279 @@ 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`. +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 +---- + +Add an ``INTERFACE`` library target to specify the required C++ standard. + +Helpful Resources +----------------- + +* :command:`add_library` +* :command:`target_compile_features` +* :command:`target_link_libraries` + +Files to Edit +------------- + +* ``CMakeLists.txt`` +* ``MathFunctions/CMakeLists.txt`` + +Getting Started +--------------- + +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 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. + +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. + +Here's a refresher of what that looks like from the command line: + +.. code-block:: console + + mkdir Step4_build + cd Step4_build + cmake ../Step4 + cmake --build . + +Next, use the newly built ``Tutorial`` and verify that it is working as +expected. + +Solution +-------- + +Let's update our code from the previous step to use interface libraries +to set our C++ requirements. -So the following code: +To start, we need to remove the two :command:`set` calls on the variables +:variable:`CMAKE_CXX_STANDARD` and :variable:`CMAKE_CXX_STANDARD_REQUIRED`. +The specific lines to remove are as follows: .. literalinclude:: Step4/CMakeLists.txt :caption: CMakeLists.txt :name: CMakeLists.txt-CXX_STANDARD-variable-remove :language: cmake - :start-after: project(Tutorial VERSION 1.0) - :end-before: # should we use our own math functions + :start-after: # specify the C++ standard + :end-before: # TODO 5: Create helper variables + +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``. + -Would be replaced with: +.. raw:: html + + <details><summary>TODO 1: Click to show/hide answer</summary> .. literalinclude:: Step5/CMakeLists.txt - :caption: CMakeLists.txt + :caption: TODO 1: 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 + :start-after: # specify the C++ standard + :end-before: # add compiler warning flags just + +.. raw:: html + + </details> + +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 2: Click to show/hide answer</summary> + +.. literalinclude:: Step5/CMakeLists.txt + :caption: TODO 2: CMakeLists.txt + :name: CMakeLists.txt-target_link_libraries-step4 + :language: cmake + :start-after: add_executable(Tutorial tutorial.cxx) + :end-before: # add the binary tree to the search path for include file + +.. raw:: html + + </details> + +and this: + +.. raw:: html + + <details><summary>TODO 3: Click to show/hide answer</summary> + +.. literalinclude:: Step5/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 + +.. raw:: html + + </details> + +With this, all of our code still requires 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 - Adding Compiler Warning Flags with Generator Expressions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +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. + +Goal +---- + +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 +--------------- + +Start with the resulting files from Exercise 1. Complete ``TODO 4`` through +``TODO 7``. + +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 +------------- + +Since we have our build directory already configured from Exercise 1, simply +rebuild our code by calling the following: + +.. code-block:: console + + cd Step4_build + cmake --build . + +Solution +-------- + +Update the :command:`cmake_minimum_required` to require at least CMake +version ``3.15``: + +.. raw:: html + + <details><summary>TODO 4: Click to show/hide answer</summary> + +.. 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 + + </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 + + <details><summary>TODO 5: Click to show/hide answer</summary> + +.. literalinclude:: Step5/CMakeLists.txt + :caption: TODO 5: CMakeLists.txt + :name: CMakeLists.txt-compile_lang_and_id + :language: cmake + :start-after: # the BUILD_INTERFACE genex + :end-before: target_compile_options(tutorial_compiler_flags INTERFACE -**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: +.. 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 + + <details><summary>TODO 6: Click to show/hide answer</summary> .. code-block:: cmake - :caption: CMakeLists.txt - :name: CMakeLists.txt-version-update + :caption: TODO 6: CMakeLists.txt + :name: CMakeLists.txt-compile_flags + + target_compile_options(tutorial_compiler_flags INTERFACE + "$<${gcc_like_cxx}:-Wall;-Wextra;-Wshadow;-Wformat=2;-Wunused>" + "$<${msvc_cxx}:-W3>" + ) - cmake_minimum_required(VERSION 3.15) +.. raw:: html -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: + </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 +this, we wrap our flags in a generator expression using the ``BUILD_INTERFACE`` +condition. The resulting full code looks like the following: + +.. raw:: html + + <details><summary>TODO 7: Click to show/hide answer</summary> .. literalinclude:: Step5/CMakeLists.txt - :caption: 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 -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. +.. raw:: html -**Exercise**: Modify ``MathFunctions/CMakeLists.txt`` so that all targets have -a :command:`target_link_libraries` call to ``tutorial_compiler_flags``. + </details> diff --git a/Help/guide/tutorial/Adding Usage Requirements for a Library.rst b/Help/guide/tutorial/Adding Usage Requirements for a Library.rst index 9d3bf64..f9dc7cc 100644 --- a/Help/guide/tutorial/Adding Usage Requirements for a Library.rst +++ b/Help/guide/tutorial/Adding Usage Requirements for a Library.rst @@ -100,6 +100,7 @@ follows: :name: MathFunctions/CMakeLists.txt-target_include_directories-INTERFACE :language: cmake :start-after: # to find MathFunctions.h + :end-before: # TODO 3: Link to .. raw:: html diff --git a/Help/guide/tutorial/Step10/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step10/MathFunctions/CMakeLists.txt index 746f966..d7f30d6 100644 --- a/Help/guide/tutorial/Step10/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Step10/MathFunctions/CMakeLists.txt @@ -22,6 +22,7 @@ target_include_directories(MathFunctions PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ) +# link our compiler flags interface library target_link_libraries(MathFunctions tutorial_compiler_flags) # install rules diff --git a/Help/guide/tutorial/Step4/CMakeLists.txt b/Help/guide/tutorial/Step4/CMakeLists.txt index 38e9b1f..fa4aab2 100644 --- a/Help/guide/tutorial/Step4/CMakeLists.txt +++ b/Help/guide/tutorial/Step4/CMakeLists.txt @@ -1,12 +1,36 @@ +# 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: 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 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 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 7: With nested generator expressions, only use the flags for the +# build-tree +# Hint: Use BUILD_INTERFACE + # should we use our own math functions option(USE_MYMATH "Use tutorial provided math implementation" ON) @@ -23,6 +47,8 @@ endif() # add the executable add_executable(Tutorial tutorial.cxx) +# 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 diff --git a/Help/guide/tutorial/Step4/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step4/MathFunctions/CMakeLists.txt index 0515852..5f7369c 100644 --- a/Help/guide/tutorial/Step4/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Step4/MathFunctions/CMakeLists.txt @@ -5,3 +5,5 @@ add_library(MathFunctions mysqrt.cxx) target_include_directories(MathFunctions INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} ) + +# TODO 3: Link to tutorial_compiler_flags diff --git a/Help/guide/tutorial/Step5/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step5/MathFunctions/CMakeLists.txt index e02f211..fc932af 100644 --- a/Help/guide/tutorial/Step5/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Step5/MathFunctions/CMakeLists.txt @@ -6,4 +6,5 @@ target_include_directories(MathFunctions INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} ) +# link our compiler flags interface library target_link_libraries(MathFunctions tutorial_compiler_flags) diff --git a/Help/guide/tutorial/Step6/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step6/MathFunctions/CMakeLists.txt index 226099a..e7667ab 100644 --- a/Help/guide/tutorial/Step6/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Step6/MathFunctions/CMakeLists.txt @@ -6,6 +6,7 @@ target_include_directories(MathFunctions INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} ) +# link our compiler flags interface library target_link_libraries(MathFunctions tutorial_compiler_flags) # install rules diff --git a/Help/guide/tutorial/Step7/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step7/MathFunctions/CMakeLists.txt index 226099a..e7667ab 100644 --- a/Help/guide/tutorial/Step7/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Step7/MathFunctions/CMakeLists.txt @@ -6,6 +6,7 @@ target_include_directories(MathFunctions INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} ) +# link our compiler flags interface library target_link_libraries(MathFunctions tutorial_compiler_flags) # install rules diff --git a/Help/guide/tutorial/Step8/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step8/MathFunctions/CMakeLists.txt index a832003..4a19684 100644 --- a/Help/guide/tutorial/Step8/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Step8/MathFunctions/CMakeLists.txt @@ -6,6 +6,7 @@ target_include_directories(MathFunctions INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} ) +# link our compiler flags interface library target_link_libraries(MathFunctions tutorial_compiler_flags) # does this system provide the log and exp functions? diff --git a/Help/guide/tutorial/Step9/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step9/MathFunctions/CMakeLists.txt index 8a08157..6a1a108 100644 --- a/Help/guide/tutorial/Step9/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Step9/MathFunctions/CMakeLists.txt @@ -24,6 +24,7 @@ target_include_directories(MathFunctions PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ) +# link our compiler flags interface library target_link_libraries(MathFunctions tutorial_compiler_flags) # install rules |