Răsfoiți Sursa

Tutorial: Update step 4 style

Markus Ferrell 3 ani în urmă
părinte
comite
37fceb6fd3

+ 253 - 32
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>

+ 1 - 0
Help/guide/tutorial/Adding Usage Requirements for a Library.rst

@@ -96,6 +96,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
 

+ 1 - 0
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

+ 26 - 0
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

+ 2 - 0
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

+ 1 - 0
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)

+ 1 - 0
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

+ 1 - 0
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

+ 1 - 0
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?

+ 1 - 0
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