Procházet zdrojové kódy

Tutorial: Rewrite using conventions enabled by CMake 3.23

This is a full re-write of the CMake Tutorial for CMake 3.23, both
the functionality it provides, as well as the modern workflows that
developers use when interfacing with CMake.

Issue: #22663, #23086, #23799, #26053, #26105, #26153, #26914
Vito Gamberini před 3 měsíci
rodič
revize
b2e3e3e30e
100 změnil soubory, kde provedl 6326 přidání a 2987 odebrání
  1. 0 473
      Help/guide/tutorial/A Basic Starting Point.rst
  2. 0 140
      Help/guide/tutorial/Adding Export Configuration.rst
  3. 0 168
      Help/guide/tutorial/Adding Generator Expressions.rst
  4. 0 108
      Help/guide/tutorial/Adding Support for a Testing Dashboard.rst
  5. 0 163
      Help/guide/tutorial/Adding System Introspection.rst
  6. 0 304
      Help/guide/tutorial/Adding Usage Requirements for a Library.rst
  7. 0 103
      Help/guide/tutorial/Adding a Custom Command and Generated File.rst
  8. 0 455
      Help/guide/tutorial/Adding a Library.rst
  9. 583 0
      Help/guide/tutorial/CMake Language Fundamentals.rst
  10. 0 127
      Help/guide/tutorial/Complete/CMakeLists.txt
  11. 0 3
      Help/guide/tutorial/Complete/CTestConfig.cmake
  12. 0 4
      Help/guide/tutorial/Complete/Config.cmake.in
  13. 0 2
      Help/guide/tutorial/Complete/License.txt
  14. 0 62
      Help/guide/tutorial/Complete/MathFunctions/CMakeLists.txt
  15. 0 10
      Help/guide/tutorial/Complete/MathFunctions/MakeTable.cmake
  16. 0 20
      Help/guide/tutorial/Complete/MathFunctions/MathFunctions.cxx
  17. 0 14
      Help/guide/tutorial/Complete/MathFunctions/MathFunctions.h
  18. 0 37
      Help/guide/tutorial/Complete/MathFunctions/mysqrt.cxx
  19. 0 6
      Help/guide/tutorial/Complete/MathFunctions/mysqrt.h
  20. 0 6
      Help/guide/tutorial/Complete/MultiCPackConfig.cmake
  21. 53 0
      Help/guide/tutorial/Complete/SimpleTest/CMakeLists.txt
  22. 16 0
      Help/guide/tutorial/Complete/SimpleTest/CMakePresets.json
  23. 155 0
      Help/guide/tutorial/Complete/SimpleTest/SimpleTest.h
  24. 5 0
      Help/guide/tutorial/Complete/SimpleTest/cmake/SimpleTestConfig.cmake
  25. 32 0
      Help/guide/tutorial/Complete/SimpleTest/cmake/simpletest_discover_impl.cmake
  26. 27 0
      Help/guide/tutorial/Complete/SimpleTest/cmake/simpletest_discover_tests.cmake
  27. 0 3
      Help/guide/tutorial/Complete/TutorialConfig.h.in
  28. 59 0
      Help/guide/tutorial/Complete/TutorialProject/CMakeLists.txt
  29. 16 0
      Help/guide/tutorial/Complete/TutorialProject/CMakePresets.json
  30. 55 0
      Help/guide/tutorial/Complete/TutorialProject/MathFunctions/CMakeLists.txt
  31. 28 0
      Help/guide/tutorial/Complete/TutorialProject/MathFunctions/MakeTable/CMakeLists.txt
  32. 0 0
      Help/guide/tutorial/Complete/TutorialProject/MathFunctions/MakeTable/MakeTable.cxx
  33. 3 0
      Help/guide/tutorial/Complete/TutorialProject/MathFunctions/MathExtensions/CMakeLists.txt
  34. 11 0
      Help/guide/tutorial/Complete/TutorialProject/MathFunctions/MathExtensions/OpAdd/CMakeLists.txt
  35. 6 0
      Help/guide/tutorial/Complete/TutorialProject/MathFunctions/MathExtensions/OpAdd/OpAdd.cxx
  36. 5 0
      Help/guide/tutorial/Complete/TutorialProject/MathFunctions/MathExtensions/OpAdd/OpAdd.h
  37. 11 0
      Help/guide/tutorial/Complete/TutorialProject/MathFunctions/MathExtensions/OpMul/CMakeLists.txt
  38. 6 0
      Help/guide/tutorial/Complete/TutorialProject/MathFunctions/MathExtensions/OpMul/OpMul.cxx
  39. 5 0
      Help/guide/tutorial/Complete/TutorialProject/MathFunctions/MathExtensions/OpMul/OpMul.h
  40. 11 0
      Help/guide/tutorial/Complete/TutorialProject/MathFunctions/MathExtensions/OpSub/CMakeLists.txt
  41. 6 0
      Help/guide/tutorial/Complete/TutorialProject/MathFunctions/MathExtensions/OpSub/OpSub.cxx
  42. 5 0
      Help/guide/tutorial/Complete/TutorialProject/MathFunctions/MathExtensions/OpSub/OpSub.h
  43. 101 0
      Help/guide/tutorial/Complete/TutorialProject/MathFunctions/MathFunctions.cxx
  44. 9 0
      Help/guide/tutorial/Complete/TutorialProject/MathFunctions/MathFunctions.h
  45. 6 0
      Help/guide/tutorial/Complete/TutorialProject/MathFunctions/MathLogger/CMakeLists.txt
  46. 27 0
      Help/guide/tutorial/Complete/TutorialProject/MathFunctions/MathLogger/MathFormatting.h
  47. 22 0
      Help/guide/tutorial/Complete/TutorialProject/MathFunctions/MathLogger/MathLogger.h
  48. 11 0
      Help/guide/tutorial/Complete/TutorialProject/MathFunctions/MathLogger/MathOutput.h
  49. 16 0
      Help/guide/tutorial/Complete/TutorialProject/Tests/CMakeLists.txt
  50. 22 0
      Help/guide/tutorial/Complete/TutorialProject/Tests/TestMathFunctions.cxx
  51. 39 0
      Help/guide/tutorial/Complete/TutorialProject/Tutorial/CMakeLists.txt
  52. 27 0
      Help/guide/tutorial/Complete/TutorialProject/Tutorial/Tutorial.cxx
  53. 1 0
      Help/guide/tutorial/Complete/TutorialProject/cmake/TutorialConfig.cmake
  54. 3 0
      Help/guide/tutorial/Complete/install/include/Unpackaged/Unpackaged.h
  55. 50 0
      Help/guide/tutorial/Complete/install/lib/cmake/TransitiveDep/TransitiveDepConfig.cmake
  56. 606 0
      Help/guide/tutorial/Configuration and Cache Variables.rst
  57. 279 0
      Help/guide/tutorial/Custom Commands and Generated Files.rst
  58. 529 0
      Help/guide/tutorial/Finding Dependencies.rst
  59. 805 0
      Help/guide/tutorial/Getting Started with CMake.rst
  60. 446 0
      Help/guide/tutorial/In-Depth CMake Library Concepts.rst
  61. 532 0
      Help/guide/tutorial/In-Depth CMake Target Commands.rst
  62. 418 0
      Help/guide/tutorial/In-Depth System Introspection.rst
  63. 596 0
      Help/guide/tutorial/Installation Commands and Concepts.rst
  64. 0 311
      Help/guide/tutorial/Installing and Testing.rst
  65. 188 0
      Help/guide/tutorial/Miscellaneous Features.rst
  66. 0 86
      Help/guide/tutorial/Packaging Debug and Release.rst
  67. 0 64
      Help/guide/tutorial/Packaging an Installer.rst
  68. 0 61
      Help/guide/tutorial/Selecting Static or Shared Libraries.rst
  69. 15 10
      Help/guide/tutorial/Step1/CMakeLists.txt
  70. 2 0
      Help/guide/tutorial/Step1/MathFunctions/CMakeLists.txt
  71. 7 4
      Help/guide/tutorial/Step1/MathFunctions/MathFunctions.cxx
  72. 0 0
      Help/guide/tutorial/Step1/MathFunctions/MathFunctions.h
  73. 2 0
      Help/guide/tutorial/Step1/Tutorial/CMakeLists.txt
  74. 4 8
      Help/guide/tutorial/Step1/Tutorial/Tutorial.cxx
  75. 0 2
      Help/guide/tutorial/Step1/TutorialConfig.h.in
  76. 0 27
      Help/guide/tutorial/Step1/tutorial.cxx
  77. 0 77
      Help/guide/tutorial/Step10/CMakeLists.txt
  78. 0 3
      Help/guide/tutorial/Step10/CTestConfig.cmake
  79. 0 2
      Help/guide/tutorial/Step10/License.txt
  80. 0 45
      Help/guide/tutorial/Step10/MathFunctions/CMakeLists.txt
  81. 0 10
      Help/guide/tutorial/Step10/MathFunctions/MakeTable.cmake
  82. 0 20
      Help/guide/tutorial/Step10/MathFunctions/MathFunctions.cxx
  83. 0 3
      Help/guide/tutorial/Step10/MathFunctions/MathFunctions.h
  84. 0 37
      Help/guide/tutorial/Step10/MathFunctions/mysqrt.cxx
  85. 0 6
      Help/guide/tutorial/Step10/MathFunctions/mysqrt.h
  86. 52 0
      Help/guide/tutorial/Step10/SimpleTest/CMakeLists.txt
  87. 16 0
      Help/guide/tutorial/Step10/SimpleTest/CMakePresets.json
  88. 151 0
      Help/guide/tutorial/Step10/SimpleTest/SimpleTest.h
  89. 6 0
      Help/guide/tutorial/Step10/SimpleTest/cmake/SimpleTestConfig.cmake
  90. 32 0
      Help/guide/tutorial/Step10/SimpleTest/cmake/simpletest_discover_impl.cmake
  91. 27 0
      Help/guide/tutorial/Step10/SimpleTest/cmake/simpletest_discover_tests.cmake
  92. 0 3
      Help/guide/tutorial/Step10/TutorialConfig.h.in
  93. 63 0
      Help/guide/tutorial/Step10/TutorialProject/CMakeLists.txt
  94. 16 0
      Help/guide/tutorial/Step10/TutorialProject/CMakePresets.json
  95. 54 0
      Help/guide/tutorial/Step10/TutorialProject/MathFunctions/CMakeLists.txt
  96. 28 0
      Help/guide/tutorial/Step10/TutorialProject/MathFunctions/MakeTable/CMakeLists.txt
  97. 0 0
      Help/guide/tutorial/Step10/TutorialProject/MathFunctions/MakeTable/MakeTable.cxx
  98. 3 0
      Help/guide/tutorial/Step10/TutorialProject/MathFunctions/MathExtensions/CMakeLists.txt
  99. 11 0
      Help/guide/tutorial/Step10/TutorialProject/MathFunctions/MathExtensions/OpAdd/CMakeLists.txt
  100. 6 0
      Help/guide/tutorial/Step10/TutorialProject/MathFunctions/MathExtensions/OpAdd/OpAdd.cxx

+ 0 - 473
Help/guide/tutorial/A Basic Starting Point.rst

@@ -1,473 +0,0 @@
-Step 1: A Basic Starting Point
-==============================
-
-Where do I start with CMake? This step will provide an introduction to some of
-CMake's basic syntax, commands, and variables. As these concepts are
-introduced, we will work through three exercises and create a simple CMake
-project.
-
-Each exercise in this step will start with some background information. Then, a
-goal and list of helpful resources are provided. Each file in the
-``Files to Edit`` section is in the ``Step1`` directory and contains one or
-more ``TODO`` comments. Each ``TODO`` represents a line or two of code to
-change or add. The ``TODO`` s are intended to be completed in numerical order,
-first complete  ``TODO 1`` then ``TODO 2``, etc. The ``Getting Started``
-section will give some helpful hints and guide you through the exercise. Then
-the ``Build and Run`` section will walk step-by-step through how to build and
-test the exercise. Finally, at the end of each exercise the intended solution
-is discussed.
-
-Also note that each step in the tutorial builds on the previous. For example,
-the starting code for ``Step2`` is the complete solution to ``Step1``.
-
-Exercise 1 - Building a Basic Project
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The most basic CMake project is an executable built from a single source code
-file. For simple projects like this, a ``CMakeLists.txt`` file with three
-commands is all that is required.
-
-**Note:** Although upper, lower and mixed case commands are supported by CMake,
-lower case commands are preferred and will be used throughout the tutorial.
-
-Any project's top most CMakeLists.txt must start by specifying a minimum CMake
-version using the :command:`cmake_minimum_required` command. This establishes
-policy settings and ensures that the following CMake functions are run with a
-compatible version of CMake.
-
-To start a project, we use the :command:`project` command to set the project
-name. This call is required with every project and should be called soon after
-:command:`cmake_minimum_required`. As we will see later, this command can
-also be used to specify other project level information such as the language
-or version number.
-
-Finally, the :command:`add_executable` command tells CMake to create an
-executable using the specified source code files.
-
-Goal
-----
-
-Understand how to create a simple CMake project.
-
-Helpful Resources
------------------
-
-* :command:`add_executable`
-* :command:`cmake_minimum_required`
-* :command:`project`
-
-Files to Edit
--------------
-
-* ``CMakeLists.txt``
-
-Getting Started
-----------------
-
-The source code for ``tutorial.cxx`` is provided in the
-``Help/guide/tutorial/Step1`` directory and can be used to compute the square
-root of a number. This file does not need to be edited in this step.
-
-In the same directory is a ``CMakeLists.txt`` file which you will complete.
-Start with ``TODO 1`` and work through ``TODO 3``.
-
-Build and Run
--------------
-
-Once ``TODO 1`` through ``TODO 3`` have been completed, we are ready to build
-and run our project! First, 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.
-
-For example, from the command line we could navigate to the
-``Help/guide/tutorial`` directory of the CMake source code tree and create a
-build directory:
-
-.. code-block:: console
-
-  mkdir Step1_build
-
-Next, navigate to that build directory and run
-:manual:`cmake <cmake(1)>` to configure the project and generate a native build
-system:
-
-.. code-block:: console
-
-  cd Step1_build
-  cmake ../Step1
-
-Then call that build system to actually compile/link the project:
-
-.. code-block:: console
-
-  cmake --build .
-
-For multi-config generators (e.g. Visual Studio), first navigate to the
-appropriate subdirectory, for example:
-
-.. code-block:: console
-
-  cd Debug
-
-Finally, try to use the newly built ``Tutorial``:
-
-.. code-block:: console
-
-  Tutorial 4294967296
-  Tutorial 10
-  Tutorial
-
-
-**Note:** Depending on the shell, the correct syntax may be ``Tutorial``,
-``./Tutorial`` or ``.\Tutorial``. For simplicity, the exercises will use
-``Tutorial`` throughout.
-
-Solution
---------
-
-As mentioned above, a three line ``CMakeLists.txt`` is all that we need to get
-up and running. The first line is to use :command:`cmake_minimum_required` to
-set the CMake version as follows:
-
-.. raw:: html
-
-  <details><summary>TODO 1: Click to show/hide answer</summary>
-
-.. literalinclude:: Step2/CMakeLists.txt
-  :caption: TODO 1: CMakeLists.txt
-  :name: CMakeLists.txt-cmake_minimum_required
-  :language: cmake
-  :end-before: # set the project name and version
-
-.. raw:: html
-
-  </details>
-
-The next step to make a basic project is to use the :command:`project`
-command as follows to set the project name:
-
-.. raw:: html
-
-  <details><summary>TODO 2: Click to show/hide answer</summary>
-
-.. code-block:: cmake
-  :caption: TODO 2: CMakeLists.txt
-  :name: CMakeLists.txt-project
-
-  project(Tutorial)
-
-.. raw:: html
-
-  </details>
-
-The last command to call for a basic project is
-:command:`add_executable`. We call it as follows:
-
-.. raw:: html
-
-  <details><summary>TODO 3: Click to show/hide answer</summary>
-
-.. literalinclude:: Step2/CMakeLists.txt
-  :caption: TODO 3: CMakeLists.txt
-  :name: CMakeLists.txt-add_executable
-  :language: cmake
-  :start-after: # add the executable
-  :end-before: # TODO 3:
-
-.. raw:: html
-
-  </details>
-
-Exercise 2 - Specifying the C++ Standard
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-CMake has some special variables that are either created behind the scenes or
-have meaning to CMake when set by project code. Many of these variables start
-with ``CMAKE_``. Avoid this naming convention when creating variables for your
-projects. Two of these special user settable variables are
-:variable:`CMAKE_CXX_STANDARD` and :variable:`CMAKE_CXX_STANDARD_REQUIRED`.
-These may be used together to specify the C++ standard needed to build the
-project.
-
-Goal
-----
-
-Add a feature that requires C++11.
-
-Helpful Resources
------------------
-
-* :variable:`CMAKE_CXX_STANDARD`
-* :variable:`CMAKE_CXX_STANDARD_REQUIRED`
-* :command:`set`
-
-Files to Edit
--------------
-
-* ``CMakeLists.txt``
-* ``tutorial.cxx``
-
-Getting Started
----------------
-
-Continue editing files in the ``Step1`` directory. Start with ``TODO 4`` and
-complete through ``TODO 6``.
-
-First, edit ``tutorial.cxx`` by adding a feature that requires C++11. Then
-update ``CMakeLists.txt`` to require C++11.
-
-Build and Run
--------------
-
-Let's build our project again. Since we already created a build directory and
-ran CMake for Exercise 1, we can skip to the build step:
-
-.. code-block:: console
-
-  cd Step1_build
-  cmake --build .
-
-Now we can try to use the newly built ``Tutorial`` with same commands as
-before:
-
-.. code-block:: console
-
-  Tutorial 4294967296
-  Tutorial 10
-  Tutorial
-
-Solution
---------
-
-We start by adding some C++11 features to our project by replacing
-``atof`` with ``std::stod`` in ``tutorial.cxx``. This looks like
-the following:
-
-.. raw:: html
-
-  <details><summary>TODO 4: Click to show/hide answer</summary>
-
-.. literalinclude:: Step2/tutorial.cxx
-  :caption: TODO 4: tutorial.cxx
-  :name: tutorial.cxx-cxx11
-  :language: c++
-  :start-after: // convert input to double
-  :end-before: // TODO 6:
-
-.. raw:: html
-
-  </details>
-
-To complete ``TODO 5``, simply remove ``#include <cstdlib>``.
-
-We will need to explicitly state in the CMake code that it should use the
-correct flags. One way to enable support for a specific C++ standard in CMake
-is by using the :variable:`CMAKE_CXX_STANDARD` variable. For this tutorial, set
-the :variable:`CMAKE_CXX_STANDARD` variable in the ``CMakeLists.txt`` file to
-``11`` and :variable:`CMAKE_CXX_STANDARD_REQUIRED` to ``True``. Make sure to
-add the :variable:`CMAKE_CXX_STANDARD` declarations above the call to
-:command:`add_executable`.
-
-.. raw:: html
-
-  <details><summary>TODO 6: Click to show/hide answer</summary>
-
-.. literalinclude:: Step2/CMakeLists.txt
-  :caption: TODO 6: CMakeLists.txt
-  :name: CMakeLists.txt-CXX_STANDARD
-  :language: cmake
-  :start-after: # specify the C++ standard
-  :end-before: # configure a header file
-
-.. raw:: html
-
-  </details>
-
-Exercise 3 - Adding a Version Number and Configured Header File
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Sometimes it may be useful to have a variable that is defined in your
-``CMakelists.txt`` file also be available in your source code. In this case, we
-would like to print the project version.
-
-One way to accomplish this is by using a configured header file. We create an
-input file with one or more variables to replace. These variables have special
-syntax which looks like ``@VAR@``.
-Then, we use the :command:`configure_file` command to copy the input file to a
-given output file and replace these variables with the current value of ``VAR``
-in the ``CMakelists.txt`` file.
-
-While we could edit the version directly in the source code, using this
-feature is preferred since it creates a single source of truth and avoids
-duplication.
-
-Goal
-----
-
-Define and report the project's version number.
-
-Helpful Resources
------------------
-
-* :variable:`<PROJECT-NAME>_VERSION_MAJOR`
-* :variable:`<PROJECT-NAME>_VERSION_MINOR`
-* :command:`configure_file`
-* :command:`target_include_directories`
-
-Files to Edit
--------------
-
-* ``CMakeLists.txt``
-* ``tutorial.cxx``
-* ``TutorialConfig.h.in``
-
-Getting Started
----------------
-
-Continue to edit files from ``Step1``. Start on ``TODO 7`` and complete through
-``TODO 12``. In this exercise, we start by adding a project version number in
-``CMakeLists.txt``. In that same file, use :command:`configure_file` to copy a
-given input file to an output file and substitute some variable values in the
-input file content.
-
-Next, create an input header file ``TutorialConfig.h.in`` defining version
-numbers which will accept variables passed from :command:`configure_file`.
-
-Finally, update ``tutorial.cxx`` to print out its version number.
-
-Build and Run
--------------
-
-Let's build our project again. As before, we already created a build directory
-and ran CMake so we can skip to the build step:
-
-.. code-block:: console
-
-  cd Step1_build
-  cmake --build .
-
-Verify that the version number is now reported when running the executable
-without any arguments.
-
-Solution
---------
-
-In this exercise, we improve our executable by printing a version number.
-While we could do this exclusively in the source code, using ``CMakeLists.txt``
-lets us maintain a single source of data for the version number.
-
-First, we modify the ``CMakeLists.txt`` file to use the
-:command:`project` command to set both the project name and version number.
-When the :command:`project` command is called, CMake defines
-``Tutorial_VERSION_MAJOR`` and ``Tutorial_VERSION_MINOR`` behind the scenes.
-
-.. raw:: html
-
-  <details><summary>TODO 7: Click to show/hide answer</summary>
-
-.. literalinclude:: Step2/CMakeLists.txt
-  :caption: TODO 7: CMakeLists.txt
-  :name: CMakeLists.txt-project-VERSION
-  :language: cmake
-  :start-after: # set the project name and version
-  :end-before: # specify the C++ standard
-
-.. raw:: html
-
-  </details>
-
-Then we used :command:`configure_file` to copy the input file with the
-specified CMake variables replaced:
-
-.. raw:: html
-
-  <details><summary>TODO 8: Click to show/hide answer</summary>
-
-.. literalinclude:: Step2/CMakeLists.txt
-  :caption: TODO 8: CMakeLists.txt
-  :name: CMakeLists.txt-configure_file
-  :language: cmake
-  :start-after: # to the source code
-  :end-before: # TODO 2:
-
-.. raw:: html
-
-  </details>
-
-Since the configured file will be written into the project binary
-directory, we must add that directory to the list of paths to search for
-include files.
-
-**Note:** Throughout this tutorial, we will refer to the project build and
-the project binary directory interchangeably. These are the same and are not
-meant to refer to a ``bin/`` directory.
-
-We used :command:`target_include_directories` to specify
-where the executable target should look for include files.
-
-.. raw:: html
-
-  <details><summary>TODO 9: Click to show/hide answer</summary>
-
-.. literalinclude:: Step2/CMakeLists.txt
-  :caption: TODO 9: CMakeLists.txt
-  :name: CMakeLists.txt-target_include_directories
-  :language: cmake
-  :start-after: # so that we will find TutorialConfig.h
-
-.. raw:: html
-
-  </details>
-
-``TutorialConfig.h.in`` is the input header file to be configured.
-When :command:`configure_file` is called from our ``CMakeLists.txt``, the
-values for ``@Tutorial_VERSION_MAJOR@`` and ``@Tutorial_VERSION_MINOR@`` will
-be replaced with the corresponding version numbers from the project in
-``TutorialConfig.h``.
-
-.. raw:: html
-
-  <details><summary>TODO 10: Click to show/hide answer</summary>
-
-.. literalinclude:: Step2/TutorialConfig.h.in
-  :caption: TODO 10: TutorialConfig.h.in
-  :name: TutorialConfig.h.in
-  :language: c++
-
-.. raw:: html
-
-  </details>
-
-Next, we need to modify ``tutorial.cxx`` to include the configured header file,
-``TutorialConfig.h``.
-
-.. raw:: html
-
-  <details><summary>TODO 11: Click to show/hide answer</summary>
-
-.. code-block:: c++
-  :caption: TODO 11: tutorial.cxx
-
-  #include "TutorialConfig.h"
-
-.. raw:: html
-
-  </details>
-
-Finally, we print out the executable name and version number by updating
-``tutorial.cxx`` as follows:
-
-.. raw:: html
-
-  <details><summary>TODO 12: Click to show/hide answer</summary>
-
-.. literalinclude:: Step2/tutorial.cxx
-  :caption: TODO 12 : tutorial.cxx
-  :name: tutorial.cxx-print-version
-  :language: c++
-  :start-after: {
-  :end-before: // convert input to double
-
-.. raw:: html
-
-  </details>

+ 0 - 140
Help/guide/tutorial/Adding Export Configuration.rst

@@ -1,140 +0,0 @@
-Step 11: Adding Export Configuration
-====================================
-
-During :guide:`tutorial/Installing and Testing` of the tutorial we added the
-ability for CMake to install the library and headers of the project. During
-:guide:`tutorial/Packaging an Installer` we added the ability to package up
-this information so it could be distributed to other people.
-
-The next step is to add the necessary information so that other CMake projects
-can use our project, be it from a build directory, a local install or when
-packaged.
-
-The first step is to update our :command:`install(TARGETS)` commands to not
-only specify a ``DESTINATION`` but also an ``EXPORT``. The ``EXPORT`` keyword
-generates a CMake file containing code to import all targets listed in the
-install command from the installation tree. So let's go ahead and explicitly
-``EXPORT`` the ``MathFunctions`` library by updating the ``install`` command
-in ``MathFunctions/CMakeLists.txt`` to look like:
-
-.. literalinclude:: Complete/MathFunctions/CMakeLists.txt
-  :caption: MathFunctions/CMakeLists.txt
-  :name: MathFunctions/CMakeLists.txt-install-TARGETS-EXPORT
-  :language: cmake
-  :start-after: # install libs
-
-Now that we have ``MathFunctions`` being exported, we also need to explicitly
-install the generated ``MathFunctionsTargets.cmake`` file. This is done by
-adding the following to the bottom of the top-level ``CMakeLists.txt``:
-
-.. literalinclude:: Complete/CMakeLists.txt
-  :caption: CMakeLists.txt
-  :name: CMakeLists.txt-install-EXPORT
-  :language: cmake
-  :start-after: # install the configuration targets
-  :end-before: include(CMakePackageConfigHelpers)
-
-At this point you should try and run CMake. If everything is setup properly
-you will see that CMake will generate an error that looks like:
-
-.. code-block:: console
-
-  Target "MathFunctions" INTERFACE_INCLUDE_DIRECTORIES property contains
-  path:
-
-    "/Users/robert/Documents/CMakeClass/Tutorial/Step11/MathFunctions"
-
-  which is prefixed in the source directory.
-
-CMake is telling you that during the generation of the export information
-it will export a path that is intrinsically tied to the current machine and
-will not be valid on other machines. The solution to this is to update the
-``MathFunctions`` :command:`target_include_directories` to understand that it
-needs different ``INTERFACE`` locations when being used from within the build
-directory and from an install / package. This means converting the
-:command:`target_include_directories` call for ``MathFunctions`` to look like:
-
-.. literalinclude:: Step12/MathFunctions/CMakeLists.txt
-  :caption: MathFunctions/CMakeLists.txt
-  :name: MathFunctions/CMakeLists.txt-target_include_directories
-  :language: cmake
-  :start-after: # to find MathFunctions.h, while we don't.
-  :end-before: # should we use our own math functions
-
-Once this has been updated, we can re-run CMake and verify that it doesn't
-warn anymore.
-
-At this point, we have CMake properly packaging the target information that is
-required but we will still need to generate a ``MathFunctionsConfig.cmake`` so
-that the CMake :command:`find_package` command can find our project. So let's go
-ahead and add a new file to the top-level of the project called
-``Config.cmake.in`` with the following contents:
-
-.. literalinclude:: Step12/Config.cmake.in
-  :caption: Config.cmake.in
-  :name: Config.cmake.in
-
-Then, to properly configure and install that file, add the following to the
-bottom of the top-level ``CMakeLists.txt``:
-
-.. literalinclude:: Step12/CMakeLists.txt
-  :caption: CMakeLists.txt
-  :name: CMakeLists.txt-install-Config.cmake
-  :language: cmake
-  :start-after: # install the configuration targets
-  :end-before: # generate the config file
-
-
-Next, we execute the :command:`configure_package_config_file`.  This command
-will configure a provided file but with a few specific differences from the
-standard :command:`configure_file` way.
-To properly utilize this function, the input file should have a single line
-with the text ``@PACKAGE_INIT@`` in addition to the content that is desired.
-That variable will be replaced with a block of code which turns set values into
-relative paths.  These values which are new can be referenced by the same name
-but prepended with a ``PACKAGE_`` prefix.
-
-.. literalinclude:: Step12/CMakeLists.txt
-  :caption: CMakeLists.txt
-  :name: CMakeLists.txt-configure-package-config.cmake
-  :language: cmake
-  :start-after: # install the configuration targets
-  :end-before: # generate the version file
-
-The :command:`write_basic_package_version_file` is next.  This command writes
-a file which is used by :command:`find_package`, documenting the version and
-compatibility of the desired package.  Here, we use the ``Tutorial_VERSION_*``
-variables and say that it is compatible with ``AnyNewerVersion``, which
-denotes that this version or any higher one are compatible with the requested
-version.
-
-.. literalinclude:: Step12/CMakeLists.txt
-  :caption: CMakeLists.txt
-  :name: CMakeLists.txt-basic-version-file.cmake
-  :language: cmake
-  :start-after: # generate the version file
-  :end-before: # install the generated configuration files
-
-Finally, set both generated files to be installed:
-
-.. literalinclude:: Step12/CMakeLists.txt
-  :caption: CMakeLists.txt
-  :name: CMakeLists.txt-install-configured-files.cmake
-  :language: cmake
-  :start-after: # install the generated configuration files
-  :end-before: # generate the export
-
-At this point, we have generated a relocatable CMake Configuration for our
-project that can be used after the project has been installed or packaged. If
-we want our project to also be used from a build directory we only have to add
-the following to the bottom of the top level ``CMakeLists.txt``:
-
-.. literalinclude:: Step12/CMakeLists.txt
-  :caption: CMakeLists.txt
-  :name: CMakeLists.txt-export
-  :language: cmake
-  :start-after: # needs to be after the install(TARGETS) command
-
-With this export call we now generate a ``MathFunctionsTargets.cmake``, allowing the
-configured ``MathFunctionsConfig.cmake`` in the build directory to be used by
-other projects, without needing it to be installed.

+ 0 - 168
Help/guide/tutorial/Adding Generator Expressions.rst

@@ -1,168 +0,0 @@
-Step 4: Adding 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 1 - 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
----------------
-
-Open the file ``Step4/CMakeLists.txt`` and complete ``TODO 1`` through
-``TODO 4``.
-
-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
--------------
-
-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.
-
-.. code-block:: console
-
-  mkdir Step4_build
-  cd Step4_build
-  cmake ../Step4
-  cmake --build .
-
-Solution
---------
-
-Update the :command:`cmake_minimum_required` to require at least CMake
-version ``3.15``:
-
-.. raw:: html
-
-  <details><summary>TODO 1: Click to show/hide answer</summary>
-
-.. literalinclude:: Step5/CMakeLists.txt
-  :caption: TODO 1: 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 2: Click to show/hide answer</summary>
-
-.. literalinclude:: Step5/CMakeLists.txt
-  :caption: TODO 2: 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
-
-.. 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 3: Click to show/hide answer</summary>
-
-.. code-block:: cmake
-  :caption: TODO 3: 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>"
-  )
-
-.. raw:: html
-
-  </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 from TODO 3 in a generator expression using the
-``BUILD_INTERFACE`` condition. The resulting full code looks like the following:
-
-.. raw:: html
-
-  <details><summary>TODO 4: Click to show/hide answer</summary>
-
-.. literalinclude:: Step5/CMakeLists.txt
-  :caption: TODO 4: CMakeLists.txt
-  :name: CMakeLists.txt-target_compile_options-genex
-  :language: cmake
-  :start-after: set(msvc_cxx "$<COMPILE_LANG_AND_ID:CXX,MSVC>")
-  :end-before: # configure a header file to pass some of the CMake settings
-
-.. raw:: html
-
-  </details>

+ 0 - 108
Help/guide/tutorial/Adding Support for a Testing Dashboard.rst

@@ -1,108 +0,0 @@
-Step 6: Adding Support for a Testing Dashboard
-==============================================
-
-Adding support for submitting our test results to a dashboard is simple. We
-already defined a number of tests for our project in
-:ref:`Testing Support <Tutorial Testing Support>`. Now we just have to run
-those tests and submit them to CDash.
-
-
-Exercise 1 - Send Results to a Testing Dashboard
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Goal
-----
-
-Display our CTest results with CDash.
-
-Helpful Resources
------------------
-
-* :manual:`ctest(1)`
-* :command:`include`
-* :module:`CTest`
-
-Files to Edit
--------------
-
-* ``CMakeLists.txt``
-
-Getting Started
----------------
-
-For this exercise, complete ``TODO 1`` in the top-level ``CMakeLists.txt`` by
-including the :module:`CTest` module. This will enable testing with CTest as
-well as dashboard submissions to CDash, so we can safely remove the call to
-:command:`enable_testing`.
-
-We will also need to acquire a ``CTestConfig.cmake`` file to be placed in the
-top-level directory. When run, the :manual:`ctest <ctest(1)>` executable will
-read this file to gather information about the testing dashboard. It contains:
-
-* The project "Nightly" start time
-
-  *  The time when a 24 hour "day" starts for this project.
-
-* The URL of the CDash instance where the submission's generated documents
-  will be sent
-
-For this tutorial, a public dashboard server is used and its corresponding
-``CTestConfig.cmake`` file is provided for you in this step's root directory.
-In practice, this file would be downloaded from a project's ``Settings`` page
-on the CDash instance intended to host the test results. Once downloaded from
-CDash, the file should not be modified locally.
-
-.. literalinclude:: Step7/CTestConfig.cmake
-  :caption: CTestConfig.cmake
-  :name: CTestConfig.cmake
-  :language: cmake
-
-
-Build and Run
--------------
-
-Note that as part of the CDash submission some information about your
-development system (e.g. site name or full pathnames) may displayed publicly.
-
-To create a simple test dashboard, run the :manual:`cmake <cmake(1)>`
-executable or the :manual:`cmake-gui <cmake-gui(1)>` to configure the project
-but do not build it yet. Instead, navigate to the build directory and run:
-
-.. code-block:: console
-
-  ctest [-VV] -D Experimental
-
-Remember, for multi-config generators (e.g. Visual Studio), the configuration
-type must be specified:
-
-.. code-block:: console
-
-  ctest [-VV] -C Debug -D Experimental
-
-Or, from an IDE, build the ``Experimental`` target.
-
-The :manual:`ctest <ctest(1)>` executable will build the project, run any
-tests, and submit the results to Kitware's public dashboard:
-https://my.cdash.org/index.php?project=CMakeTutorial.
-
-Solution
---------
-
-The only CMake code changed needed in this step was to enable dashboard
-submissions to CDash by including the :module:`CTest` module in our top-level
-``CMakeLists.txt``:
-
-.. raw:: html
-
-  <details><summary>TODO 1: Click to show/hide answer</summary>
-
-.. literalinclude:: Step7/CMakeLists.txt
-  :caption: TODO 1: CMakeLists.txt
-  :name: CMakeLists.txt-include-CTest
-  :language: cmake
-  :start-after: # enable testing
-  :end-before: # does the application run
-
-.. raw:: html
-
-  </details>

+ 0 - 163
Help/guide/tutorial/Adding System Introspection.rst

@@ -1,163 +0,0 @@
-Step 7: Adding System Introspection
-===================================
-
-Let us consider adding some code to our project that depends on features the
-target platform may not have. For this example, we will add some code that
-depends on whether or not the target platform has the ``log`` and ``exp``
-functions. Of course almost every platform has these functions but for this
-tutorial assume that they are not common.
-
-Exercise 1 - Assessing Dependency Availability
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Goal
-----
-
-Change implementation based on available system dependencies.
-
-Helpful Resources
------------------
-
-* :module:`CheckCXXSourceCompiles`
-* :command:`target_compile_definitions`
-
-Files to Edit
--------------
-
-* ``MathFunctions/CMakeLists.txt``
-* ``MathFunctions/mysqrt.cxx``
-
-Getting Started
----------------
-
-The starting source code is provided in the ``Step7`` directory. In this
-exercise, complete ``TODO 1`` through ``TODO 5``.
-
-Start by editing ``MathFunctions/CMakeLists.txt``. Include the
-:module:`CheckCXXSourceCompiles` module. Then, use
-``check_cxx_source_compiles()`` to determine whether ``log`` and ``exp`` are
-available from ``cmath``. If they are available, use
-:command:`target_compile_definitions` to specify ``HAVE_LOG`` and ``HAVE_EXP``
-as compile definitions.
-
-In the ``MathFunctions/mysqrt.cxx``, include ``cmath``. Then, if the system has
-``log`` and ``exp``, use them to compute the square root.
-
-Build and Run
--------------
-
-Make a new directory called ``Step7_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 and run the ``Tutorial`` executable.
-
-This can look like the following:
-
-.. code-block:: console
-
-  mkdir Step7_build
-  cd Step7_build
-  cmake ../Step7
-  cmake --build .
-
-Which function gives better results now, ``sqrt`` or ``mysqrt``?
-
-Solution
---------
-
-In this exercise we will use functions from the
-:module:`CheckCXXSourceCompiles` module so first we must include it in
-``MathFunctions/CMakeLists.txt``.
-
-.. raw:: html
-
-  <details><summary>TODO 1: Click to show/hide answer</summary>
-
-.. literalinclude:: Step8/MathFunctions/CMakeLists.txt
-  :caption: TODO 1: MathFunctions/CMakeLists.txt
-  :name: MathFunctions/CMakeLists.txt-include-check_cxx_source_compiles
-  :language: cmake
-  :start-after: # does this system provide the log and exp functions?
-  :end-before: check_cxx_source_compiles
-
-.. raw:: html
-
-  </details>
-
-Then test for the availability of
-``log`` and ``exp`` using ``check_cxx_compiles_source``. This function
-lets us try compiling simple code with the required dependency prior to
-the true source code compilation. The resulting variables ``HAVE_LOG``
-and ``HAVE_EXP`` represent whether those dependencies are available.
-
-.. raw:: html
-
-  <details><summary>TODO 2: Click to show/hide answer</summary>
-
-.. literalinclude:: Step8/MathFunctions/CMakeLists.txt
-  :caption: TODO 2: MathFunctions/CMakeLists.txt
-  :name: MathFunctions/CMakeLists.txt-check_cxx_source_compiles
-  :language: cmake
-  :start-after: include(CheckCXXSourceCompiles)
-  :end-before: # add compile definitions
-
-.. raw:: html
-
-  </details>
-
-Next, we need to pass these CMake variables to our source code. This way,
-our source code can tell what resources are available. If both ``log`` and
-``exp`` are available, use :command:`target_compile_definitions` to specify
-``HAVE_LOG`` and ``HAVE_EXP`` as ``PRIVATE`` compile definitions.
-
-.. raw:: html
-
-  <details><summary>TODO 3: Click to show/hide answer</summary>
-
-.. literalinclude:: Step8/MathFunctions/CMakeLists.txt
-  :caption: TODO 3: MathFunctions/CMakeLists.txt
-  :name: MathFunctions/CMakeLists.txt-target_compile_definitions
-  :language: cmake
-  :start-after: # add compile definitions
-  :end-before: # state
-
-.. raw:: html
-
-  </details>
-
-Since we may be using ``log`` and ``exp``, we need to modify
-``mysqrt.cxx`` to include ``cmath``.
-
-.. raw:: html
-
-  <details><summary>TODO 4: Click to show/hide answer</summary>
-
-.. literalinclude:: Step8/MathFunctions/mysqrt.cxx
-  :caption: TODO 4: MathFunctions/mysqrt.cxx
-  :name: MathFunctions/mysqrt.cxx-include-cmath
-  :language: c++
-  :start-after: #include "mysqrt.h"
-  :end-before: include <iostream>
-
-.. raw:: html
-
-  </details>
-
-If ``log`` and ``exp`` are available on the system, then use them to
-compute the square root in the ``mysqrt`` function. The ``mysqrt`` function in
-``MathFunctions/mysqrt.cxx`` will look as follows:
-
-.. raw:: html
-
-  <details><summary>TODO 5: Click to show/hide answer</summary>
-
-.. literalinclude:: Step8/MathFunctions/mysqrt.cxx
-  :caption: TODO 5: MathFunctions/mysqrt.cxx
-  :name: MathFunctions/mysqrt.cxx-ifdef
-  :language: c++
-  :start-after: // if we have both log and exp then use them
-  :end-before: return result;
-
-.. raw:: html
-
-  </details>

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

@@ -1,304 +0,0 @@
-Step 3: Adding Usage Requirements for a Library
-===============================================
-
-Exercise 1 - Adding Usage Requirements for a Library
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-:ref:`Usage requirements <Target Usage Requirements>` of a target parameters
-allow for far better control over a library or executable's link and include
-line while also giving more control over the transitive property of targets
-inside CMake. The primary commands that
-leverage usage requirements are:
-
-* :command:`target_compile_definitions`
-* :command:`target_compile_options`
-* :command:`target_include_directories`
-* :command:`target_link_directories`
-* :command:`target_link_options`
-* :command:`target_precompile_headers`
-* :command:`target_sources`
-
-
-Goal
-----
-
-Add usage requirements for a library.
-
-Helpful Materials
------------------
-
-* :variable:`CMAKE_CURRENT_SOURCE_DIR`
-
-Files to Edit
--------------
-
-* ``MathFunctions/CMakeLists.txt``
-* ``CMakeLists.txt``
-
-Getting Started
----------------
-
-In this exercise, we will refactor our code from
-:guide:`tutorial/Adding a Library` to use the modern CMake approach. We will
-let our library define its own usage requirements so they are passed
-transitively to other targets as necessary. In this case, ``MathFunctions``
-will specify any needed include directories itself. Then, the consuming target
-``Tutorial`` simply needs to link to ``MathFunctions`` and not worry about
-any additional include directories.
-
-The starting source code is provided in the ``Step3`` directory. In this
-exercise, complete ``TODO 1`` through ``TODO 3``.
-
-First, add a call to :command:`target_include_directories` in
-``MathFunctions/CMakeLists``. Remember that
-:variable:`CMAKE_CURRENT_SOURCE_DIR` is the path to the source directory
-currently being processed.
-
-Then, update (and simplify!) the call to
-:command:`target_include_directories` in the top-level ``CMakeLists.txt``.
-
-Build and Run
--------------
-
-Make a new directory called ``Step3_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 :option:`cmake --build . <cmake --build>` from the build directory.
-Here's a refresher of what that looks like from the command line:
-
-.. code-block:: console
-
-  mkdir Step3_build
-  cd Step3_build
-  cmake ../Step3
-  cmake --build .
-
-Next, use the newly built ``Tutorial`` and verify that it is working as
-expected.
-
-Solution
---------
-
-Let's update the code from the previous step to use the modern CMake
-approach of usage requirements.
-
-We want to state that anybody linking to ``MathFunctions`` needs to include
-the current source directory, while ``MathFunctions`` itself doesn't. This
-can be expressed with an ``INTERFACE`` usage requirement. Remember
-``INTERFACE`` means things that consumers require but the producer doesn't.
-
-At the end of ``MathFunctions/CMakeLists.txt``, use
-:command:`target_include_directories` with the ``INTERFACE`` keyword, as
-follows:
-
-.. raw:: html
-
-  <details><summary>TODO 1: Click to show/hide answer</summary>
-
-.. literalinclude:: Step4/MathFunctions/CMakeLists.txt
-  :caption: TODO 1: MathFunctions/CMakeLists.txt
-  :name: MathFunctions/CMakeLists.txt-target_include_directories-INTERFACE
-  :language: cmake
-  :start-after: # to find MathFunctions.h
-  :end-before: # should we use our own
-
-.. raw:: html
-
-  </details>
-
-Now that we've specified usage requirements for ``MathFunctions`` we can
-safely remove our uses of the ``EXTRA_INCLUDES`` variable from the top-level
-``CMakeLists.txt``.
-
-Remove this line:
-
-.. raw:: html
-
-  <details><summary>TODO 2: Click to show/hide answer</summary>
-
-.. literalinclude:: Step3/CMakeLists.txt
-  :caption: TODO 2: CMakeLists.txt
-  :name: CMakeLists.txt-remove-EXTRA_INCLUDES
-  :language: cmake
-  :start-after: add_subdirectory(MathFunctions)
-  :end-before: # add the executable
-
-.. raw:: html
-
-  </details>
-
-And remove ``EXTRA_INCLUDES`` from ``target_include_directories``:
-
-.. raw:: html
-
-  <details><summary>TODO 3: Click to show/hide answer</summary>
-
-.. literalinclude:: Step4/CMakeLists.txt
-  :caption: TODO 3: CMakeLists.txt
-  :name: CMakeLists.txt-target_include_directories-remove-EXTRA_INCLUDES
-  :language: cmake
-  :start-after: # so that we will find TutorialConfig.h
-
-.. raw:: html
-
-  </details>
-
-Notice that with this technique, the only thing our executable target does to
-use our library is call :command:`target_link_libraries` with the name
-of the library target. In larger projects, the classic method of specifying
-library dependencies manually becomes very complicated very quickly.
-
-Exercise 2 - Setting the C++ Standard with Interface Libraries
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Now that we have switched our code to a more modern approach, let's demonstrate
-a modern technique to set properties to multiple targets.
-
-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.
-
-Start this exercise from what we left at the end of Step3 exercise 1. You will
-have to complete ``TODO 4`` through ``TODO 7``.
-
-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
--------------
-
-Since we have our build directory already configured from Exercise 1, simply
-rebuild our code by calling the following:
-
-.. code-block:: console
-
-  cd Step3_build
-  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.
-
-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:: Step3/CMakeLists.txt
-  :caption: CMakeLists.txt
-  :name: CMakeLists.txt-CXX_STANDARD-variable-remove
-  :language: cmake
-  :start-after: # specify the C++ standard
-  :end-before: # configure a header file
-
-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``.
-
-
-.. raw:: html
-
-  <details><summary>TODO 4: Click to show/hide answer</summary>
-
-.. literalinclude:: Step4/CMakeLists.txt
-  :caption: TODO 4: CMakeLists.txt
-  :name: CMakeLists.txt-cxx_std-feature
-  :language: cmake
-  :start-after: # specify the C++ standard
-  :end-before: # TODO 2: Create helper
-
-.. raw:: html
-
-  </details>
-
-Finally, with our interface library set up, we need to link our
-executable ``Tutorial``, our ``SqrtLibrary`` library and our ``MathFunctions``
-library to our new ``tutorial_compiler_flags`` library. Respectively, the code
-will look like this:
-
-.. raw:: html
-
-  <details><summary>TODO 5: Click to show/hide answer</summary>
-
-.. literalinclude:: Step4/CMakeLists.txt
-  :caption: TODO 5: 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>
-
-this:
-
-.. raw:: html
-
-  <details><summary>TODO 6: Click to show/hide answer</summary>
-
-.. literalinclude:: Step4/MathFunctions/CMakeLists.txt
-  :caption: TODO 6: MathFunctions/CMakeLists.txt
-  :name: MathFunctions-CMakeLists.txt-target_link_libraries-step4
-  :language: cmake
-  :start-after: # link SqrtLibrary to tutorial_compiler_flags
-  :end-before: target_link_libraries(MathFunctions
-
-.. raw:: html
-
-  </details>
-
-and this:
-
-.. raw:: html
-
-  <details><summary>TODO 7: Click to show/hide answer</summary>
-
-.. literalinclude:: Step4/MathFunctions/CMakeLists.txt
-  :caption: TODO 7: MathFunctions/CMakeLists.txt
-  :name: MathFunctions-SqrtLibrary-target_link_libraries-step4
-  :language: cmake
-  :start-after: # link MathFunctions to tutorial_compiler_flags
-
-.. 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.

+ 0 - 103
Help/guide/tutorial/Adding a Custom Command and Generated File.rst

@@ -1,103 +0,0 @@
-Step 8: Adding a Custom Command and Generated File
-==================================================
-
-Suppose, for the purpose of this tutorial, we decide that we never want to use
-the platform ``log`` and ``exp`` functions and instead would like to
-generate a table of precomputed values to use in the ``mysqrt`` function.
-In this section, we will create the table as part of the build process,
-and then compile that table into our application.
-
-First, let's remove the check for the ``log`` and ``exp`` functions in
-``MathFunctions/CMakeLists.txt``. Then remove the check for ``HAVE_LOG`` and
-``HAVE_EXP`` from ``mysqrt.cxx``. At the same time, we can remove
-:code:`#include <cmath>`.
-
-In the ``MathFunctions`` subdirectory, a new source file named
-``MakeTable.cxx`` has been provided to generate the table.
-
-After reviewing the file, we can see that the table is produced as valid C++
-code and that the output filename is passed in as an argument.
-
-The next step is to create ``MathFunctions/MakeTable.cmake``. Then, add the
-appropriate commands to the file to build the ``MakeTable`` executable and
-then run it as part of the build process. A few commands are needed to
-accomplish this.
-
-First, we add an executable for ``MakeTable``.
-
-.. literalinclude:: Step9/MathFunctions/MakeTable.cmake
-  :caption: MathFunctions/MakeTable.cmake
-  :name: MathFunctions/MakeTable.cmake-add_executable-MakeTable
-  :language: cmake
-  :start-after: # first we add the executable that generates the table
-  :end-before: target_link_libraries
-
-After creating the executable, we add the ``tutorial_compiler_flags`` to our
-executable using :command:`target_link_libraries`.
-
-.. literalinclude:: Step9/MathFunctions/MakeTable.cmake
-  :caption: MathFunctions/MakeTable.cmake
-  :name: MathFunctions/MakeTable.cmake-link-tutorial-compiler-flags
-  :language: cmake
-  :start-after: add_executable
-  :end-before: # add the command to generate
-
-Then we add a custom command that specifies how to produce ``Table.h``
-by running MakeTable.
-
-.. literalinclude:: Step9/MathFunctions/MakeTable.cmake
-  :caption: MathFunctions/MakeTable.cmake
-  :name: MathFunctions/MakeTable.cmake-add_custom_command-Table.h
-  :language: cmake
-  :start-after: # add the command to generate the source code
-
-Next we have to let CMake know that ``mysqrt.cxx`` depends on the generated
-file ``Table.h``. This is done by adding the generated ``Table.h`` to the list
-of sources for the library ``SqrtLibrary``.
-
-.. literalinclude:: Step9/MathFunctions/CMakeLists.txt
-  :caption: MathFunctions/CMakeLists.txt
-  :name: MathFunctions/CMakeLists.txt-add_library-Table.h
-  :language: cmake
-  :start-after:   # library that just does sqrt
-  :end-before: # state that we depend on
-
-We also have to add the current binary directory to the list of include
-directories so that ``Table.h`` can be found and included by ``mysqrt.cxx``.
-
-.. literalinclude:: Step9/MathFunctions/CMakeLists.txt
-  :caption: MathFunctions/CMakeLists.txt
-  :name: MathFunctions/CMakeLists.txt-target_include_directories-Table.h
-  :language: cmake
-  :start-after: # state that we depend on our bin
-  :end-before: target_link_libraries
-
-As the last step, we need to include
-``MakeTable.cmake`` at the top of the ``MathFunctions/CMakeLists.txt``.
-
-.. literalinclude:: Step9/MathFunctions/CMakeLists.txt
-  :caption: MathFunctions/CMakeLists.txt
-  :name: MathFunctions/CMakeLists.txt-include-MakeTable.cmake
-  :language: cmake
-  :start-after: # generate Table.h
-  :end-before: # library that just does sqrt
-
-Now let's use the generated table. First, modify ``mysqrt.cxx`` to include
-``Table.h``. Next, we can rewrite the ``mysqrt`` function to use the table:
-
-.. literalinclude:: Step9/MathFunctions/mysqrt.cxx
-  :caption: MathFunctions/mysqrt.cxx
-  :name: MathFunctions/mysqrt.cxx
-  :language: c++
-  :start-after: // a hack square root calculation using simple operations
-
-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.
-
-When this project is built it will first build the ``MakeTable`` executable.
-It will then run ``MakeTable`` to produce ``Table.h``. Finally, it will
-compile ``mysqrt.cxx`` which includes ``Table.h`` to produce the
-``MathFunctions`` library.
-
-Run the Tutorial executable and verify that it is using the table.

+ 0 - 455
Help/guide/tutorial/Adding a Library.rst

@@ -1,455 +0,0 @@
-Step 2: Adding a Library
-========================
-
-At this point, we have seen how to create a basic project using CMake. In this
-step, we will learn how to create and use a library in our project. We will
-also see how to make the use of our library optional.
-
-Exercise 1 - Creating a Library
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-To add a library in CMake, use the :command:`add_library` command and specify
-which source files should make up the library.
-
-Rather than placing all of the source files in one directory, we can organize
-our project with one or more subdirectories. In this case, we will create a
-subdirectory specifically for our library. Here, we can add a new
-``CMakeLists.txt`` file and one or more source files. In the top level
-``CMakeLists.txt`` file, we will use the :command:`add_subdirectory` command
-to add the subdirectory to the build.
-
-Once the library is created, it is connected to our executable target with
-:command:`target_include_directories` and :command:`target_link_libraries`.
-
-Goal
-----
-
-Add and use a library.
-
-Helpful Resources
------------------
-
-* :command:`add_library`
-* :command:`add_subdirectory`
-* :command:`target_include_directories`
-* :command:`target_link_libraries`
-* :variable:`PROJECT_SOURCE_DIR`
-
-Files to Edit
--------------
-
-* ``CMakeLists.txt``
-* ``tutorial.cxx``
-* ``MathFunctions/CMakeLists.txt``
-
-Getting Started
----------------
-
-In this exercise, we will add a library to our project that contains our own
-implementation for computing the square root of a number. The executable can
-then use this library instead of the standard square root function provided by
-the compiler.
-
-For this tutorial we will put the library into a subdirectory called
-``MathFunctions``. This directory already contains the header files
-``MathFunctions.h`` and ``mysqrt.h``. Their respective source files
-``MathFunctions.cxx`` and ``mysqrt.cxx`` are also provided. We will not need
-to modify any of these files. ``mysqrt.cxx`` has one function called
-``mysqrt`` that provides similar functionality to the compiler's ``sqrt``
-function. ``MathFunctions.cxx`` contains one function ``sqrt`` which serves
-to hide the implementation details of ``sqrt``.
-
-From the ``Help/guide/tutorial/Step2`` directory, start with ``TODO 1`` and
-complete through ``TODO 6``.
-
-First, fill in the one line ``CMakeLists.txt`` in the ``MathFunctions``
-subdirectory.
-
-Next, edit the top level ``CMakeLists.txt``.
-
-Finally, use the newly created ``MathFunctions`` library in ``tutorial.cxx``
-
-Build and Run
--------------
-
-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.
-
-Below is a refresher of what that looks like from the command line:
-
-.. code-block:: console
-
-  mkdir Step2_build
-  cd Step2_build
-  cmake ../Step2
-  cmake --build .
-
-Try to use the newly built ``Tutorial`` and ensure that it is still
-producing accurate square root values.
-
-Solution
---------
-
-In the ``CMakeLists.txt`` file in the ``MathFunctions`` directory, we create
-a library target called ``MathFunctions`` with :command:`add_library`. The
-source files for the library are passed as an argument to
-:command:`add_library`. This looks like the following line:
-
-.. raw:: html
-
-  <details><summary>TODO 1: Click to show/hide answer</summary>
-
-.. code-block:: cmake
-  :caption: TODO 1: MathFunctions/CMakeLists.txt
-  :name: MathFunctions/CMakeLists.txt-add_library
-
-  add_library(MathFunctions MathFunctions.cxx mysqrt.cxx)
-
-.. raw:: html
-
-  </details>
-
-To make use of the new library we will add an :command:`add_subdirectory`
-call in the top-level ``CMakeLists.txt`` file so that the library will get
-built.
-
-.. raw:: html
-
-  <details><summary>TODO 2: Click to show/hide answer</summary>
-
-.. code-block:: cmake
-  :caption: TODO 2: CMakeLists.txt
-  :name: CMakeLists.txt-add_subdirectory
-
-  add_subdirectory(MathFunctions)
-
-.. raw:: html
-
-  </details>
-
-Next, the new library target is linked to the executable target using
-:command:`target_link_libraries`.
-
-.. raw:: html
-
-  <details><summary>TODO 3: Click to show/hide answer</summary>
-
-.. code-block:: cmake
-  :caption: TODO 3: CMakeLists.txt
-  :name: CMakeLists.txt-target_link_libraries
-
-  target_link_libraries(Tutorial PUBLIC MathFunctions)
-
-.. raw:: html
-
-  </details>
-
-Finally we need to specify the library's header file location.
-Modify the existing :command:`target_include_directories` call
-to add the ``MathFunctions`` subdirectory as an include directory
-so that the ``MathFunctions.h`` header file can be found.
-
-.. raw:: html
-
-  <details><summary>TODO 4: Click to show/hide answer</summary>
-
-.. code-block:: cmake
-  :caption: TODO 4: CMakeLists.txt
-  :name: CMakeLists.txt-target_include_directories-step2
-
-  target_include_directories(Tutorial PUBLIC
-                            "${PROJECT_BINARY_DIR}"
-                            "${PROJECT_SOURCE_DIR}/MathFunctions"
-                            )
-
-.. raw:: html
-
-  </details>
-
-Now let's use our library. In ``tutorial.cxx``, include ``MathFunctions.h``:
-
-.. raw:: html
-
-  <details><summary>TODO 5: Click to show/hide answer</summary>
-
-.. literalinclude:: Step3/tutorial.cxx
-  :caption: TODO 5: tutorial.cxx
-  :name: CMakeLists.txt-include-MathFunctions.h
-  :language: cmake
-  :start-after: #include <string>
-  :end-before: #include "TutorialConfig.h"
-
-.. raw:: html
-
-  </details>
-
-Lastly, replace ``sqrt`` with the wrapper function ``mathfunctions::sqrt``.
-
-.. raw:: html
-
-  <details><summary>TODO 6: Click to show/hide answer</summary>
-
-.. literalinclude:: Step3/tutorial.cxx
-  :caption: TODO 6: tutorial.cxx
-  :name: CMakeLists.txt-option
-  :language: cmake
-  :start-after:   double const inputValue = std::stod(argv[1]);
-  :end-before: std::cout
-
-.. raw:: html
-
-  </details>
-
-Exercise 2 - Adding an Option
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Now let us add an option in the MathFunctions library to allow developers to
-select either the custom square root implementation or the built in standard
-implementation. While for the tutorial
-there really isn't any need to do so, for larger projects this is a common
-occurrence.
-
-CMake can do this using the :command:`option` command. This gives users a
-variable which they can change when configuring their cmake build. This
-setting will be stored in the cache so that the user does not need to set
-the value each time they run CMake on a build directory.
-
-Goal
-----
-
-Add the option to build without ``MathFunctions``.
-
-
-Helpful Resources
------------------
-
-* :command:`if`
-* :command:`option`
-* :command:`target_compile_definitions`
-
-Files to Edit
--------------
-
-* ``MathFunctions/CMakeLists.txt``
-* ``MathFunctions/MathFunctions.cxx``
-
-Getting Started
----------------
-
-Start with the resulting files from Exercise 1. Complete ``TODO 7`` through
-``TODO 14``.
-
-First create a variable ``USE_MYMATH`` using the :command:`option` command
-in ``MathFunctions/CMakeLists.txt``. In that same file, use that option
-to pass a compile definition to the ``MathFunctions`` library.
-
-Then, update ``MathFunctions.cxx`` to redirect compilation based on
-``USE_MYMATH``.
-
-Lastly, prevent ``mysqrt.cxx`` from being compiled when ``USE_MYMATH`` is on
-by making it its own library inside of the ``USE_MYMATH`` block of
-``MathFunctions/CMakeLists.txt``.
-
-Build and Run
--------------
-
-Since we have our build directory already configured from Exercise 1, we can
-rebuild by simply calling the following:
-
-.. code-block:: console
-
-  cd ../Step2_build
-  cmake --build .
-
-Next, run the ``Tutorial`` executable on a few numbers to verify that it's
-still correct.
-
-Now let's update the value of ``USE_MYMATH`` to ``OFF``. The easiest way is to
-use the :manual:`cmake-gui <cmake-gui(1)>` or  :manual:`ccmake <ccmake(1)>`
-if you're in the terminal. Or, alternatively, if you want to change the
-option from the command-line, try:
-
-.. code-block:: console
-
-  cmake ../Step2 -DUSE_MYMATH=OFF
-
-Now, rebuild the code with the following:
-
-.. code-block:: console
-
-  cmake --build .
-
-Then, run the executable again to ensure that it still works with
-``USE_MYMATH`` set to ``OFF``. Which function gives better results, ``sqrt``
-or ``mysqrt``?
-
-Solution
---------
-
-The first step is to add an option to ``MathFunctions/CMakeLists.txt``.
-This option will be displayed in the :manual:`cmake-gui <cmake-gui(1)>` and
-:manual:`ccmake <ccmake(1)>` with a default value of ``ON`` that can be
-changed by the user.
-
-.. raw:: html
-
-  <details><summary>TODO 7: Click to show/hide answer</summary>
-
-.. literalinclude:: Step3/MathFunctions/CMakeLists.txt
-  :caption: TODO 7: MathFunctions/CMakeLists.txt
-  :name: CMakeLists.txt-option-library-level
-  :language: cmake
-  :start-after: # should we use our own math functions
-  :end-before: if (USE_MYMATH)
-
-.. raw:: html
-
-  </details>
-
-Next, make building and linking our library with ``mysqrt`` function
-conditional using this new option.
-
-Create an :command:`if` statement which checks the value of
-``USE_MYMATH``. Inside the :command:`if` block, put the
-:command:`target_compile_definitions` command with the compile
-definition ``USE_MYMATH``.
-
-.. raw:: html
-
-  <details><summary>TODO 8: Click to show/hide answer</summary>
-
-.. code-block:: cmake
-  :caption: TODO 8: MathFunctions/CMakeLists.txt
-  :name: CMakeLists.txt-USE_MYMATH
-
-  if (USE_MYMATH)
-    target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH")
-  endif()
-
-.. raw:: html
-
-  </details>
-
-When ``USE_MYMATH`` is ``ON``, the compile definition ``USE_MYMATH`` will
-be set. We can then use this compile definition to enable or disable
-sections of our source code.
-
-The corresponding changes to the source code are fairly straightforward.
-In ``MathFunctions.cxx``, we make ``USE_MYMATH`` control which square root
-function is used:
-
-.. raw:: html
-
-  <details><summary>TODO 9: Click to show/hide answer</summary>
-
-.. literalinclude:: Step3/MathFunctions/MathFunctions.cxx
-  :caption: TODO 9: MathFunctions/MathFunctions.cxx
-  :name: MathFunctions-USE_MYMATH-if
-  :language: c++
-  :start-after: which square root function should we use?
-  :end-before: }
-
-.. raw:: html
-
-  </details>
-
-Next, we need to include ``mysqrt.h`` if ``USE_MYMATH`` is defined.
-
-.. raw:: html
-
-  <details><summary>TODO 10: Click to show/hide answer</summary>
-
-.. literalinclude:: Step3/MathFunctions/MathFunctions.cxx
-  :caption: TODO 10: MathFunctions/MathFunctions.cxx
-  :name: MathFunctions-USE_MYMATH-if-include
-  :language: c++
-  :start-after: include <cmath>
-  :end-before: namespace mathfunctions
-
-.. raw:: html
-
-  </details>
-
-Finally, we need to include ``cmath`` now that we are using ``std::sqrt``.
-
-.. raw:: html
-
-  <details><summary>TODO 11: Click to show/hide answer</summary>
-
-.. code-block:: c++
-  :caption: TODO 11 : MathFunctions/MathFunctions.cxx
-  :name: tutorial.cxx-include_cmath
-
-  #include <cmath>
-
-.. raw:: html
-
-  </details>
-
-At this point, if ``USE_MYMATH`` is ``OFF``, ``mysqrt.cxx`` would not be used
-but it will still be compiled because the ``MathFunctions`` target has
-``mysqrt.cxx`` listed under sources.
-
-There are a few ways to fix this. The first option is to use
-:command:`target_sources` to add ``mysqrt.cxx`` from within the ``USE_MYMATH``
-block. Another option is to create an additional library within the
-``USE_MYMATH`` block which is responsible for compiling ``mysqrt.cxx``. For
-the sake of this tutorial, we are going to create an additional library.
-
-First, from within ``USE_MYMATH`` create a library called ``SqrtLibrary``
-that has sources ``mysqrt.cxx``.
-
-.. raw:: html
-
-  <details><summary>TODO 12: Click to show/hide answer</summary>
-
-.. literalinclude:: Step3/MathFunctions/CMakeLists.txt
-  :caption: TODO 12 : MathFunctions/CMakeLists.txt
-  :name: MathFunctions/CMakeLists.txt-add_library-SqrtLibrary
-  :language: cmake
-  :start-after: # library that just does sqrt
-  :end-before: # TODO 7: Link
-
-.. raw:: html
-
-  </details>
-
-Next, we link ``SqrtLibrary`` onto ``MathFunctions`` when ``USE_MYMATH`` is
-enabled.
-
-.. raw:: html
-
-  <details><summary>TODO 13: Click to show/hide answer</summary>
-
-.. literalinclude:: Step3/MathFunctions/CMakeLists.txt
-  :caption: TODO 13 : MathFunctions/CMakeLists.txt
-  :name: MathFunctions/CMakeLists.txt-target_link_libraries-SqrtLibrary
-  :language: cmake
-  :start-after: to tutorial_compiler_flags
-  :end-before: endif()
-
-.. raw:: html
-
-  </details>
-
-Finally, we can remove ``mysqrt.cxx`` from our ``MathFunctions`` library
-source list because it will be pulled in when ``SqrtLibrary`` is included.
-
-.. raw:: html
-
-  <details><summary>TODO 14: Click to show/hide answer</summary>
-
-.. literalinclude:: Step3/MathFunctions/CMakeLists.txt
-  :caption: TODO 14 : MathFunctions/CMakeLists.txt
-  :name: MathFunctions/CMakeLists.txt-remove-mysqrt.cxx-MathFunctions
-  :language: cmake
-  :end-before: # TODO 1:
-
-.. raw:: html
-
-  </details>
-
-With these changes, the ``mysqrt`` function is now completely optional to
-whoever is building and using the ``MathFunctions`` library. Users can toggle
-``USE_MYMATH`` to manipulate what library is used in the build.

+ 583 - 0
Help/guide/tutorial/CMake Language Fundamentals.rst

@@ -0,0 +1,583 @@
+Step 2: CMake Language Fundamentals
+===================================
+
+In the previous step we rushed through and handwaved several aspects of the
+CMake language which is used within ``CMakeLists.txt`` in order to get useful,
+building programs as soon as possible. However, in the wild we encounter
+a great deal more complexity than simply describing lists of source and
+header files.
+
+To deal with this complexity CMake provides a Turing-complete domain-specific
+language for describing the process of building software. Understanding the
+fundamentals of this language will be necessary as we write more complex
+CMLs and other CMake files. The language is formally known as
+":manual:`CMake Language <cmake-language(7)>`", or more colloquially as CMakeLang.
+
+.. note::
+  The CMake Language is not well suited to describing things which are not
+  related to building software. While it has some features for general purpose
+  use, developers should use caution when solving problems not directly related
+  to their build in CMake Language.
+
+  Oftentimes the correct answer is to write a tool in a general purpose
+  programming language which solves the problem, and teach CMake how to invoke
+  that tool as part of the build process. Code generation, cryptographic
+  signature utilities, and even ray-tracers have been written in CMake Language,
+  but this is not a recommended practice.
+
+Because we want to fully explore the language features, this step is an
+exception to the tutorial sequencing. It neither builds on ``Step1``, nor is the
+starting point for ``Step3``. This will be a sandbox to explore language
+features without building any software. We'll pick back up with the Tutorial
+program in ``Step3``.
+
+.. note::
+  This tutorial endeavors to demonstrate best practices and solutions to real
+  problems. However, for this one step we're going to be re-implementing some
+  built-in CMake functions. In "real life", do not write your own
+  :command:`list(APPEND)`.
+
+Background
+^^^^^^^^^^
+
+The only fundamental types in CMakeLang are strings and lists. Every object in
+CMake is a string, and lists are themselves strings which contain semicolons
+as separators. Any command which appears to operate on something other than a
+string, whether they be booleans, numbers, JSON objects, or otherwise, is in
+fact consuming a string, doing some internal conversion logic (in a language
+other than CMakeLang), and then converting back to a string for any potential
+output.
+
+We can create a variable, which is to say a name for a string, using the
+:command:`set` command.
+
+.. code-block:: cmake
+
+  set(var "World!")
+
+A variable's value can be accessed using brace expansion, for example if we want
+to use the :command:`message` command to print the string named by ``var``.
+
+.. code-block:: cmake
+
+  set(var "World!")
+  message("Hello ${var}")
+
+.. code-block:: console
+
+  $ cmake -P CMakeLists.txt
+  Hello World!
+
+.. note::
+  :option:`cmake -P` is called "script mode", it informs CMake this file is not
+  intended to have a :command:`project` command. We're not building any
+  software, instead using CMake only as a command interpreter.
+
+Because CMakeLang has only strings, conditionals are entirely by convention of
+which strings are considered true and which are considered false. These are
+*supposed* to be intuitive, "True", "On", "Yes", and (strings representing)
+non-zero numbers are truthy, while "False" "Off", "No", "0", "Ignore",
+"NotFound", and the empty string are all considered false.
+
+However, some of the rules are more complex than that, so taking some time
+to consult the :command:`if` documentation on expressions is worthwhile. It's
+recommended to stick to a single pair for a given context, such as
+"True"/"False" or "On"/"Off".
+
+As mentioned, lists are strings containing semicolons. The :command:`list`
+command is useful for manipulating these, and many structures within CMake
+expect to operate with this convention. As an example, we can use the
+:command:`foreach` command to iterate over a list.
+
+.. code-block:: cmake
+
+  set(stooges "Moe;Larry")
+  list(APPEND stooges "Curly")
+
+  message("Stooges contains: ${stooges}")
+
+  foreach(stooge IN LISTS stooges)
+    message("Hello, ${stooge}")
+  endforeach()
+
+.. code-block:: console
+
+  $ cmake -P CMakeLists.txt
+  Stooges contains: Moe;Larry;Curly
+  Hello, Moe
+  Hello, Larry
+  Hello, Curly
+
+Exercise 1 - Macros, Functions, and Lists
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+CMake allows us to craft our own functions and macros. This can be very helpful
+when constructing lots of similar targets, like tests, for which we will want
+to call similar sets of commands over and over again. We do so with
+:command:`function` and :command:`macro`.
+
+.. code-block:: cmake
+
+  macro(MyMacro MacroArgument)
+    message("${MacroArgument}\n\t\tFrom Macro")
+  endmacro()
+
+  function(MyFunc FuncArgument)
+    MyMacro("${FuncArgument}\n\tFrom Function")
+  endfunction()
+
+  MyFunc("From TopLevel")
+
+.. code-block:: console
+
+  $ cmake -P CMakeLists.txt
+  From TopLevel
+        From Function
+                From Macro
+
+Like with many languages, the difference between functions and macros is one
+of scope. In CMakeLang, both :command:`function` and :command:`macro` can "see"
+all the variables created in all the frames above them. However, a
+:command:`macro` acts semantically like a text replacement, similar to C/C++
+macros, so any side effects the macro creates are visible in their calling
+context. If we create or change a variable in a macro, the caller will see the
+change.
+
+:command:`function` creates its own variable scope, so side effects are not
+visible to the caller. In order to propagate changes to the parent which called
+the function, we must use ``set(<var> <value> PARENT_SCOPE)``, which works the
+same as :command:`set` but for variables belonging to the caller's context.
+
+.. note::
+  In CMake 3.25, the :command:`return(PROPAGATE)` option was added, which
+  works the same as :command:`set(PARENT_SCOPE)` but provides slightly better
+  ergonomics.
+
+While not necessary for this exercise, it bears mentioning that :command:`macro`
+and :command:`function` both support variadic arguments via the ``ARGV``
+variable, a list containing all arguments passed to the command, and the
+``ARGN`` variable, containing all arguments past the last expected argument.
+
+We're not going to build any targets in this exercise, so instead we'll
+construct our own version of :command:`list(APPEND)`, which adds a value to a
+list.
+
+Goal
+----
+
+Implement a macro and a function which append a value to a list, without using
+the :command:`list(APPEND)` command.
+
+The desired usage of these commands is as follows:
+
+.. code-block:: cmake
+
+  set(Letters "Alpha;Beta")
+  MacroAppend(Letters "Gamma")
+  message("Letters contains: ${Letters}")
+
+.. code-block:: console
+
+  $ cmake -P Exercise1.cmake
+  Letters contains: Alpha;Beta;Gamma
+
+.. note::
+  The extension for these exercises is ``.cmake``, that's the standard extension
+  for CMakeLang files when not contained in a ``CMakeLists.txt``
+
+Helpful Resources
+-----------------
+
+* :command:`macro`
+* :command:`function`
+* :command:`set`
+* :command:`if`
+
+Files to Edit
+-------------
+
+* ``Exercise1.cmake``
+
+Getting Started
+----------------
+
+The source code for ``Exercise1.cmake`` is provided in the
+``Help/guide/tutorial/Step2`` directory. It contains tests to verify the
+append behavior described above.
+
+.. note::
+  You're not expected to handle the case of an empty or undefined list to
+  append to. However, as a bonus, the case is tested if you want to try out
+  your understanding of CMakeLang conditionals.
+
+Complete ``TODO 1`` and ``TODO 2``.
+
+Build and Run
+-------------
+
+We're going to use script mode to run these exercises. First navigate to the
+``Help/guide/tutorial/Step2`` folder then you can run the code with:
+
+.. code-block:: console
+
+  cmake -P Exercise1.cmake
+
+The script will report if the commands were implemented correctly.
+
+Solution
+--------
+
+This problem relies on an understanding of the mechanisms of CMake variables.
+CMake variables are names for strings; or put another way, a CMake variable
+is itself a string which can brace expand into a different string.
+
+This leads to a common pattern in CMake code where functions and macros aren't
+passed values, but rather, they are passed the names of variables which contain
+those values. Thus ``ListVar`` does not contain the *value* of the list we need
+to append to, it contains the *name* of a list, which contains the value we
+need to append to.
+
+When expanding the variable with ``${ListVar}``, we will get the name of the
+list. If we expand that name with ``${${ListVar}}``, we will get the values
+the list contains.
+
+To implement ``MacroAppend``, we need only combine this understanding of
+``ListVar`` with our knowledge of the :command:`set` command.
+
+.. raw:: html
+
+  <details><summary>TODO 1: Click to show/hide answer</summary>
+
+.. code-block:: cmake
+  :caption: TODO 1: Exercise1.cmake
+  :name: Exercise1.cmake-MacroAppend
+
+  macro(MacroAppend ListVar Value)
+    set(${ListVar} "${${ListVar}};${Value}")
+  endmacro()
+
+.. raw:: html
+
+  </details>
+
+We don't need to worry about scope here, because a macro operates in the same
+scope as its parent.
+
+``FuncAppend`` is almost identical, in fact it could be implemented in the
+same one liner but with an added ``PARENT_SCOPE``, but the instructions ask
+us to implement it in terms of ``MacroAppend``.
+
+.. raw:: html
+
+  <details><summary>TODO 2: Click to show/hide answer</summary>
+
+.. code-block:: cmake
+  :caption: TODO 2: Exercise1.cmake
+  :name: Exercise1.cmake-FuncAppend
+
+  function(FuncAppend ListVar Value)
+    MacroAppend(${ListVar} ${Value})
+    set(${ListVar} "${${ListVar}}" PARENT_SCOPE)
+  endfunction()
+
+.. raw:: html
+
+  </details>
+
+``MacroAppend`` transforms ``ListVar`` for us, but it won't propagate the result
+to the parent scope. Because this is a function, we need to do so ourselves
+with :command:`set(PARENT_SCOPE)`.
+
+Exercise 2 - Conditionals and Loops
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The two most common flow control elements in any structured programming
+language are conditionals and their close sibling loops. CMakeLang is no
+different. As previously mentioned, the truthiness of a given CMake string is a
+convention established by the :command:`if` command.
+
+When given a string, :command:`if` will first check if it is one of the known
+constant values previously discussed. If the string isn't one of those values
+the command assumes it is a variable, and checks the brace-expanded contents of
+that variable to determine the result of the conditional.
+
+.. code-block:: cmake
+
+  if(True)
+    message("Constant Value: True")
+  else()
+    message("Constant Value: False")
+  endif()
+
+  if(ConditionalValue)
+    message("Undefined Variable: True")
+  else()
+    message("Undefined Variable: False")
+  endif()
+
+  set(ConditionalValue True)
+
+  if(ConditionalValue)
+    message("Defined Variable: True")
+  else()
+    message("Defined Variable: False")
+  endif()
+
+.. code-block:: console
+
+  $ cmake -P ConditionalValue.cmake
+  Constant Value: True
+  Undefined Variable: False
+  Defined Variable: True
+
+.. note::
+    This is a good a time as any to discuss quoting in CMake. All objects in
+    CMake are strings, thus the double quote, ``"``, is often unnecessary.
+    CMake knows the object is a string, everything is a string.
+
+    However, it is needed in some contexts. Strings containing whitespace require
+    double quotes, else they are treated like lists; CMake will concatenate the
+    elements together with semicolons. The reverse is also true, when
+    brace-expanding lists it is necessary to do so inside quotes if we want to
+    *preserve* the semicolons. Otherwise CMake will expand the list items into
+    space-separate strings.
+
+    A handful of commands, such as :command:`if`, recognize the difference
+    between quoted and unquoted strings. :command:`if` will only check that the
+    given string represents a variable when the string is unquoted.
+
+Finally, :command:`if` provides several useful comparison modes such as
+``STREQUAL`` for string matching, ``DEFINED`` for checking the existence of
+a variable, and ``MATCHES`` for regular expression checks. It also supports the
+typical logical operators, ``NOT``, ``AND``, and ``OR``.
+
+In addition to conditionals CMake provides two loop structures,
+:command:`while`, which follows the same rules as :command:`if` for checking a
+loop variable, and the more useful :command:`foreach`, which iterates over lists
+of strings and was demonstrated in the `Background`_ section.
+
+For this exercise, we're going to use loops and conditionals to solve some
+simple problems. We'll be using the aforementioned ``ARGN`` variable from
+:command:`function` as the list to operate on.
+
+Goal
+----
+
+Loop over a list, and return all the strings containing the string ``Foo``.
+
+.. note::
+  Those who read the command documentation will be aware that this is
+  :command:`list(FILTER)`, resist the temptation to use it.
+
+Helpful Resources
+-----------------
+
+* :command:`function`
+* :command:`foreach`
+* :command:`if`
+* :command:`list`
+
+Files to Edit
+-------------
+
+* ``Exercise2.cmake``
+
+Getting Started
+----------------
+
+The source code for ``Exercise2.cmake`` is provided in the ``Help/guide/tutorial/Step2``
+directory. It contains tests to verify the append behavior described above.
+
+.. note::
+  You should use the :command:`list(APPEND)` command this time to collect your
+  final result into a list. The input can be consumed from the ``ARGN`` variable
+  of the provided function.
+
+Complete ``TODO 3``.
+
+Build and Run
+-------------
+
+Navigate to the ``Help/guide/tutorial/Step2`` folder then you can run the code with:
+
+.. code-block:: console
+
+  cmake -P Exercise2.cmake
+
+The script will report if the ``FilterFoo`` function was implemented correctly.
+
+Solution
+--------
+
+We need to do three things, loop over the ``ARGN`` list, check if a given
+item in that list matches ``"Foo"``, and if so append it to the ``OutVar``
+list.
+
+While there are a couple ways we could invoke :command:`foreach`, the
+recommended way is to allow the command to do the variable expansion for us
+via ``IN LISTS`` to access the ``ARGN`` list items.
+
+The :command:`if` comparison we need is ``MATCHES`` which will check if
+``"FOO"`` exists in the item. All that remains is to append the item to the
+``OutVar`` list.  The trickiest part is remembering that ``OutVar`` *names* a
+list, it is not the list itself, so we need to access it via ``${OutVar}``.
+
+.. raw:: html
+
+  <details><summary>TODO 3: Click to show/hide answer</summary>
+
+.. code-block:: cmake
+  :caption: TODO 3: Exercise2.cmake
+  :name: Exercise2.cmake-FilterFoo
+
+  function(FilterFoo OutVar)
+
+    foreach(item IN LISTS ARGN)
+      if(item MATCHES Foo)
+        list(APPEND ${OutVar} ${item})
+      endif()
+    endforeach()
+
+    set(${OutVar} ${${OutVar}} PARENT_SCOPE)
+  endfunction()
+
+.. raw:: html
+
+  </details>
+
+Exercise 3 - Organizing with Include
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+We have already discussed how to incorporate subdirectories containing their
+own CMLs with :command:`add_subdirectory`. In later steps we will explore
+the various way CMake code can be packaged and shared across projects.
+
+However for small CMake functions and utilities, it is often beneficial for them
+to live in their own ``.cmake`` files outside the project CMLs and separate
+from the rest of the build system. This allows for separation of concerns,
+removing the project-specific elements from the utilities we are using to
+describe them.
+
+To incorporate these separate ``.cmake`` files into our project, we use the
+:command:`include` command. This command immediately begins interpreting the
+contents of the :command:`include`'d file in the scope of the parent CML. It
+is as if the entire file were being called as a macro.
+
+Traditionally, these kinds of ``.cmake`` files live in a folder named "cmake"
+inside the project root. For this exercise, we'll use the ``Step2`` folder instead.
+
+Goal
+----
+
+Use the functions from Exercises 1 and 2 to build and filter our own list of items.
+
+Helpful Resources
+-----------------
+
+* :command:`include`
+
+Files to Edit
+-------------
+
+* ``Exercise3.cmake``
+
+Getting Started
+----------------
+
+The source code for ``Exercise3.cmake`` is provided in the ``Help/guide/tutorial/Step2``
+directory. It contains tests to verify the correct usage of our functions
+from the previous two exercises.
+
+.. note::
+  Actually it reuses tests from Exercise2.cmake, reusable code is good for
+  everyone.
+
+Complete ``TODO 4`` through ``TODO 7``.
+
+Build and Run
+-------------
+
+Navigate to the ``Help/guide/tutorial/Step2`` folder then you can run the code with:
+
+.. code-block:: console
+
+  cmake -P Exercise3.cmake
+
+The script will report if the functions were invoked and composed correctly.
+
+Solution
+--------
+
+The :command:`include` command will interpret the included file completely,
+including the tests from the first two exercises. We don't want to run these
+tests again. Thanks to some forethought, these files check a variable called
+``SKIP_TESTS`` prior to running their tests, setting this to ``True`` will
+get us the behavior we want.
+
+.. raw:: html
+
+  <details><summary>TODO 4: Click to show/hide answer</summary>
+
+.. code-block:: cmake
+  :caption: TODO 4: Exercise3.cmake
+  :name: Exercise3.cmake-SKIP_TESTS
+
+  set(SKIP_TESTS True)
+
+.. raw:: html
+
+  </details>
+
+Now we're ready to :command:`include` the previous exercises to grab their
+functions.
+
+.. raw:: html
+
+  <details><summary>TODO 5: Click to show/hide answer</summary>
+
+.. code-block:: cmake
+  :caption: TODO 5: Exercise3.cmake
+  :name: Exercise3.cmake-include
+
+  include(Exercise1.cmake)
+  include(Exercise2.cmake)
+
+.. raw:: html
+
+  </details>
+
+Now that ``FuncAppend`` is available to us, we can use it to append new elements
+to the ``InList``.
+
+.. raw:: html
+
+  <details><summary>TODO 6: Click to show/hide answer</summary>
+
+.. code-block:: cmake
+  :caption: TODO 6: Exercise3.cmake
+  :name: Exercise3.cmake-FuncAppend
+
+  FuncAppend(InList FooBaz)
+  FuncAppend(InList QuxBaz)
+
+.. raw:: html
+
+  </details>
+
+Finally, we can use ``FilterFoo`` to filter the full list. The tricky part to
+remember here is that our ``FilterFoo`` wants to operate on list values via
+``ARGN``, so we need to expand the ``InList`` when we call ``FilterFoo``.
+
+.. raw:: html
+
+  <details><summary>TODO 7: Click to show/hide answer</summary>
+
+.. code-block:: cmake
+  :caption: TODO 7: Exercise3.cmake
+  :name: Exercise3.cmake-FilterFoo
+
+  FilterFoo(OutList ${InList})
+
+.. raw:: html
+
+  </details>

+ 0 - 127
Help/guide/tutorial/Complete/CMakeLists.txt

@@ -1,127 +0,0 @@
-cmake_minimum_required(VERSION 3.15)
-
-# set the project name and version
-project(Tutorial VERSION 1.0)
-
-set(CMAKE_DEBUG_POSTFIX d)
-
-add_library(tutorial_compiler_flags INTERFACE)
-target_compile_features(tutorial_compiler_flags INTERFACE cxx_std_11)
-
-# add compiler warning flags just when building this project via
-# the BUILD_INTERFACE genex
-set(gcc_like_cxx "$<COMPILE_LANG_AND_ID:CXX,ARMClang,AppleClang,Clang,GNU,LCC>")
-set(msvc_cxx "$<COMPILE_LANG_AND_ID:CXX,MSVC>")
-target_compile_options(tutorial_compiler_flags INTERFACE
-  "$<${gcc_like_cxx}:$<BUILD_INTERFACE:-Wall;-Wextra;-Wshadow;-Wformat=2;-Wunused>>"
-  "$<${msvc_cxx}:$<BUILD_INTERFACE:-W3>>"
-)
-
-# control where the static and shared libraries are built so that on windows
-# we don't need to tinker with the path to run the executable
-set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
-set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
-set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}")
-
-option(BUILD_SHARED_LIBS "Build using shared libraries" ON)
-
-if(APPLE)
-  set(CMAKE_INSTALL_RPATH "@executable_path/../lib")
-elseif(UNIX)
-  set(CMAKE_INSTALL_RPATH "$ORIGIN/../lib")
-endif()
-
-# configure a header file to pass the version number only
-configure_file(TutorialConfig.h.in TutorialConfig.h)
-
-# add the MathFunctions library
-add_subdirectory(MathFunctions)
-
-# add the executable
-add_executable(Tutorial tutorial.cxx)
-set_target_properties(Tutorial PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX})
-
-target_link_libraries(Tutorial PUBLIC MathFunctions tutorial_compiler_flags)
-
-# add the binary tree to the search path for include files
-# so that we will find TutorialConfig.h
-target_include_directories(Tutorial PUBLIC
-                           "${PROJECT_BINARY_DIR}"
-                           )
-
-# add the install targets
-install(TARGETS Tutorial DESTINATION bin)
-install(FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h"
-  DESTINATION include
-  )
-
-# enable testing
-enable_testing()
-
-# does the application run
-add_test(NAME Runs COMMAND Tutorial 25)
-
-# does the usage message work?
-add_test(NAME Usage COMMAND Tutorial)
-set_tests_properties(Usage
-  PROPERTIES PASS_REGULAR_EXPRESSION "Usage:.*number"
-  )
-
-# define a function to simplify adding tests
-function(do_test target arg result)
-  add_test(NAME Comp${arg} COMMAND ${target} ${arg})
-  set_tests_properties(Comp${arg}
-    PROPERTIES PASS_REGULAR_EXPRESSION ${result}
-    )
-endfunction()
-
-# do a bunch of result based tests
-do_test(Tutorial 4 "4 is 2")
-do_test(Tutorial 9 "9 is 3")
-do_test(Tutorial 5 "5 is 2.236")
-do_test(Tutorial 7 "7 is 2.645")
-do_test(Tutorial 25 "25 is 5")
-do_test(Tutorial -25 "-25 is (-nan|nan|0)")
-do_test(Tutorial 0.0001 "0.0001 is 0.01")
-
-# setup installer
-include(InstallRequiredSystemLibraries)
-set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/License.txt")
-set(CPACK_PACKAGE_VERSION_MAJOR "${Tutorial_VERSION_MAJOR}")
-set(CPACK_PACKAGE_VERSION_MINOR "${Tutorial_VERSION_MINOR}")
-set(CPACK_GENERATOR "TGZ")
-set(CPACK_SOURCE_GENERATOR "TGZ")
-include(CPack)
-
-# install the configuration targets
-install(EXPORT MathFunctionsTargets
-  FILE MathFunctionsTargets.cmake
-  DESTINATION lib/cmake/MathFunctions
-)
-
-include(CMakePackageConfigHelpers)
-# generate the config file that is includes the exports
-configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
-  "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake"
-  INSTALL_DESTINATION "lib/cmake/example"
-  NO_SET_AND_CHECK_MACRO
-  NO_CHECK_REQUIRED_COMPONENTS_MACRO
-  )
-# generate the version file for the config file
-write_basic_package_version_file(
-  "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake"
-  VERSION "${Tutorial_VERSION_MAJOR}.${Tutorial_VERSION_MINOR}"
-  COMPATIBILITY AnyNewerVersion
-)
-
-# install the configuration file
-install(FILES
-  ${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake
-  DESTINATION lib/cmake/MathFunctions
-  )
-
-# generate the export targets for the build tree
-# needs to be after the install(TARGETS) command
-export(EXPORT MathFunctionsTargets
-  FILE "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsTargets.cmake"
-)

+ 0 - 3
Help/guide/tutorial/Complete/CTestConfig.cmake

@@ -1,3 +0,0 @@
-set(CTEST_NIGHTLY_START_TIME "00:00:00 EST")
-
-set(CTEST_SUBMIT_URL "https://my.cdash.org/submit.php?project=CMakeTutorial")

+ 0 - 4
Help/guide/tutorial/Complete/Config.cmake.in

@@ -1,4 +0,0 @@
-
-@PACKAGE_INIT@
-
-include ( "${CMAKE_CURRENT_LIST_DIR}/MathFunctionsTargets.cmake" )

+ 0 - 2
Help/guide/tutorial/Complete/License.txt

@@ -1,2 +0,0 @@
-This is the open source License.txt file introduced in
-CMake/Tutorial/Step9...

+ 0 - 62
Help/guide/tutorial/Complete/MathFunctions/CMakeLists.txt

@@ -1,62 +0,0 @@
-# add the library that runs
-add_library(MathFunctions MathFunctions.cxx)
-
-# state that anybody linking to us needs to include the current source dir
-# to find MathFunctions.h, while we don't.
-target_include_directories(MathFunctions
-                           INTERFACE
-                            $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
-                            $<INSTALL_INTERFACE:include>
-                           )
-
-# should we use our own math functions
-option(USE_MYMATH "Use tutorial provided math implementation" ON)
-if(USE_MYMATH)
-
-  target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH")
-
-  include(MakeTable.cmake) # generates Table.h
-
-  # library that just does sqrt
-  add_library(SqrtLibrary STATIC
-              mysqrt.cxx
-              ${CMAKE_CURRENT_BINARY_DIR}/Table.h
-              )
-
-  # state that we depend on our binary dir to find Table.h
-  target_include_directories(SqrtLibrary PRIVATE
-                             ${CMAKE_CURRENT_BINARY_DIR}
-                             )
-
-  # state that SqrtLibrary need PIC when the default is shared libraries
-  set_target_properties(SqrtLibrary PROPERTIES
-                        POSITION_INDEPENDENT_CODE ${BUILD_SHARED_LIBS}
-                        )
-
-  # link SqrtLibrary to tutorial_compiler_flags
-  target_link_libraries(SqrtLibrary PUBLIC tutorial_compiler_flags)
-
-  target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
-endif()
-
-# link MathFunctions to tutorial_compiler_flags
-target_link_libraries(MathFunctions PUBLIC tutorial_compiler_flags)
-
-# define the symbol stating we are using the declspec(dllexport) when
-# building on windows
-target_compile_definitions(MathFunctions PRIVATE "EXPORTING_MYMATH")
-
-# setup the version numbering
-set_property(TARGET MathFunctions PROPERTY VERSION "1.0.0")
-set_property(TARGET MathFunctions PROPERTY SOVERSION "1")
-
-# install libs
-set(installable_libs MathFunctions tutorial_compiler_flags)
-if(TARGET SqrtLibrary)
-  list(APPEND installable_libs SqrtLibrary)
-endif()
-install(TARGETS ${installable_libs}
-        EXPORT MathFunctionsTargets
-        DESTINATION lib)
-# install include headers
-install(FILES MathFunctions.h DESTINATION include)

+ 0 - 10
Help/guide/tutorial/Complete/MathFunctions/MakeTable.cmake

@@ -1,10 +0,0 @@
-# first we add the executable that generates the table
-add_executable(MakeTable MakeTable.cxx)
-target_link_libraries(MakeTable PRIVATE tutorial_compiler_flags)
-
-# add the command to generate the source code
-add_custom_command(
-  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h
-  COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h
-  DEPENDS MakeTable
-  )

+ 0 - 20
Help/guide/tutorial/Complete/MathFunctions/MathFunctions.cxx

@@ -1,20 +0,0 @@
-
-#include "MathFunctions.h"
-
-#include <cmath>
-
-#ifdef USE_MYMATH
-#  include "mysqrt.h"
-#endif
-
-namespace mathfunctions {
-double sqrt(double x)
-{
-// which square root function should we use?
-#ifdef USE_MYMATH
-  return detail::mysqrt(x);
-#else
-  return std::sqrt(x);
-#endif
-}
-}

+ 0 - 14
Help/guide/tutorial/Complete/MathFunctions/MathFunctions.h

@@ -1,14 +0,0 @@
-
-#if defined(_WIN32)
-#  if defined(EXPORTING_MYMATH)
-#    define DECLSPEC __declspec(dllexport)
-#  else
-#    define DECLSPEC __declspec(dllimport)
-#  endif
-#else // non windows
-#  define DECLSPEC
-#endif
-
-namespace mathfunctions {
-double DECLSPEC sqrt(double x);
-}

+ 0 - 37
Help/guide/tutorial/Complete/MathFunctions/mysqrt.cxx

@@ -1,37 +0,0 @@
-#include <iostream>
-
-#include "MathFunctions.h"
-
-// include the generated table
-#include "Table.h"
-
-namespace mathfunctions {
-namespace detail {
-// a hack square root calculation using simple operations
-double mysqrt(double x)
-{
-  if (x <= 0) {
-    return 0;
-  }
-
-  // use the table to help find an initial value
-  double result = x;
-  if (x >= 1 && x < 10) {
-    std::cout << "Use the table to help find an initial value " << std::endl;
-    result = sqrtTable[static_cast<int>(x)];
-  }
-
-  // do ten iterations
-  for (int i = 0; i < 10; ++i) {
-    if (result <= 0) {
-      result = 0.1;
-    }
-    double delta = x - (result * result);
-    result = result + 0.5 * delta / result;
-    std::cout << "Computing sqrt of " << x << " to be " << result << std::endl;
-  }
-
-  return result;
-}
-}
-}

+ 0 - 6
Help/guide/tutorial/Complete/MathFunctions/mysqrt.h

@@ -1,6 +0,0 @@
-
-namespace mathfunctions {
-namespace detail {
-double mysqrt(double x);
-}
-}

+ 0 - 6
Help/guide/tutorial/Complete/MultiCPackConfig.cmake

@@ -1,6 +0,0 @@
-include("release/CPackConfig.cmake")
-
-set(CPACK_INSTALL_CMAKE_PROJECTS
-    "debug;Tutorial;ALL;/"
-    "release;Tutorial;ALL;/"
-    )

+ 53 - 0
Help/guide/tutorial/Complete/SimpleTest/CMakeLists.txt

@@ -0,0 +1,53 @@
+# A very simple test framework for demonstrating how dependencies work
+cmake_minimum_required(VERSION 3.23)
+
+project(SimpleTest
+  VERSION 0.0.1
+)
+
+add_library(SimpleTest INTERFACE)
+target_sources(SimpleTest
+  INTERFACE
+    FILE_SET HEADERS
+    FILES
+      SimpleTest.h
+)
+target_compile_features(SimpleTest INTERFACE cxx_std_20)
+
+target_compile_definitions(SimpleTest INTERFACE "SIMPLETEST_CONFIG=$<CONFIG>")
+
+find_package(TransitiveDep REQUIRED)
+target_link_libraries(SimpleTest
+  INTERFACE
+    TransitiveDep::TransitiveDep
+)
+
+include(GNUInstallDirs)
+include(CMakePackageConfigHelpers)
+
+install(
+  TARGETS SimpleTest
+  EXPORT SimpleTestTargets
+  FILE_SET HEADERS
+)
+
+install(
+  EXPORT SimpleTestTargets
+  DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/SimpleTest
+  NAMESPACE SimpleTest::
+)
+
+write_basic_package_version_file(
+  ${CMAKE_CURRENT_BINARY_DIR}/SimpleTestConfigVersion.cmake
+  COMPATIBILITY ExactVersion
+  ARCH_INDEPENDENT
+)
+
+install(
+  FILES
+    cmake/simpletest_discover_impl.cmake
+    cmake/simpletest_discover_tests.cmake
+    cmake/SimpleTestConfig.cmake
+    ${CMAKE_CURRENT_BINARY_DIR}/SimpleTestConfigVersion.cmake
+  DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/SimpleTest
+)

+ 16 - 0
Help/guide/tutorial/Complete/SimpleTest/CMakePresets.json

@@ -0,0 +1,16 @@
+{
+  "version": 4,
+  "configurePresets": [
+    {
+      "name": "tutorial",
+      "displayName": "SimpleTest Preset",
+      "description": "Preset to use with the tutorial's SimpleTest library",
+      "binaryDir": "${sourceDir}/build",
+      "installDir": "${sourceParentDir}/install",
+      "cacheVariables": {
+        "CMAKE_CXX_STANDARD": "20",
+        "CMAKE_PREFIX_PATH": "${sourceParentDir}/install"
+      }
+    }
+  ]
+}

+ 155 - 0
Help/guide/tutorial/Complete/SimpleTest/SimpleTest.h

@@ -0,0 +1,155 @@
+#pragma once
+
+#include <cstdio>
+#include <map>
+#include <string_view>
+
+namespace SimpleTest {
+
+using TestFunc = void (*)();
+
+using Registry = std::map<std::string_view, TestFunc, std::less<>>;
+inline Registry g_registry;
+
+inline Registry& registry()
+{
+  return g_registry;
+}
+
+struct failure
+{
+  char const* file;
+  int line;
+  char const* expr;
+};
+
+struct Registrar
+{
+  template <std::size_t N>
+  Registrar(char const (&name)[N], TestFunc f)
+  {
+    auto [it, inserted] =
+      registry().emplace(std::string_view{ name, N ? (N - 1) : 0 }, f);
+    if (!inserted) {
+      std::printf("[  WARN    ] duplicate test name: %.*s\n",
+                  int(it->first.size()), it->first.data());
+    }
+  }
+};
+
+inline Registry const& all()
+{
+  return registry();
+}
+inline TestFunc find(std::string_view name)
+{
+  auto it = registry().find(name);
+  return it == registry().end() ? nullptr : it->second;
+}
+
+}
+
+#define SIMPLETEST_STRINGIFY(a) #a
+#define SIMPLETEST_XSTRINGIFY(a) SIMPLETEST_STRINGIFY(a)
+#define SIMPLETEST_CONCAT_(a, b) a##b
+#define SIMPLETEST_CONCAT(a, b) SIMPLETEST_CONCAT_(a, b)
+
+#define TEST(name_literal)                                                    \
+  static void SIMPLETEST_CONCAT(_simpletest_fn_, __LINE__)();                 \
+  static ::SimpleTest::Registrar SIMPLETEST_CONCAT(_simpletest_reg_,          \
+                                                   __LINE__)(                 \
+    name_literal, &SIMPLETEST_CONCAT(_simpletest_fn_, __LINE__));             \
+  static void SIMPLETEST_CONCAT(_simpletest_fn_, __LINE__)()
+
+// Minimal assertion
+#define REQUIRE(expr)                                                         \
+  do {                                                                        \
+    if (!(expr))                                                              \
+      throw ::SimpleTest::failure{ __FILE__, __LINE__, #expr };               \
+  } while (0)
+
+int main(int argc, char** argv)
+{
+  using namespace ::SimpleTest;
+
+  std::string_view arg1 =
+    (argc >= 2) ? std::string_view{ argv[1] } : std::string_view{};
+
+  if (arg1 == "--list") {
+    bool first = true;
+    for (auto const& [name, _] : registry()) {
+      if (!first)
+        std::printf(",");
+      std::printf("%.*s", int(name.size()), name.data());
+      first = false;
+    }
+    std::printf("\n");
+    return 0;
+  }
+
+  if (arg1 == "--test") {
+    if (argc < 3) {
+      std::printf("usage: %s [--list] [--test <name>]\n", argv[0]);
+      return 2;
+    }
+
+#ifdef SIMPLETEST_CONFIG
+    std::printf("SimpleTest built with config: " SIMPLETEST_XSTRINGIFY(
+      SIMPLETEST_CONFIG) "\n");
+#endif
+
+    std::string_view name{ argv[2] };
+    auto it = registry().find(name);
+    if (it == registry().end()) {
+      std::printf("[ NOTFOUND ] %s\n", argv[2]);
+      return 2;
+    }
+
+    int failed = 0;
+    std::printf("[ RUN      ] %.*s\n", int(it->first.size()),
+                it->first.data());
+    try {
+      it->second();
+      std::printf("[       OK] %.*s\n", int(it->first.size()),
+                  it->first.data());
+    } catch (failure const& f) {
+      std::printf("[  FAILED  ] %.*s at %s:%d : %s\n", int(it->first.size()),
+                  it->first.data(), f.file, f.line, f.expr);
+      failed = 1;
+    } catch (...) {
+      std::printf("[  FAILED  ] %.*s : unknown exception\n",
+                  int(it->first.size()), it->first.data());
+      failed = 1;
+    }
+    return failed;
+  }
+
+  if (argc > 1) {
+    std::printf("usage: %s [--list] [--test <name>]\n", argv[0]);
+    return 2;
+  }
+
+#ifdef SIMPLETEST_CONFIG
+  std::printf("SimpleTest built with config: " SIMPLETEST_XSTRINGIFY(
+    SIMPLETEST_CONFIG) "\n");
+#endif
+
+  // Default: run all tests.
+  int failed = 0;
+  for (auto const& [name, func] : all()) {
+    std::printf("[ RUN      ] %.*s\n", int(name.size()), name.data());
+    try {
+      func();
+      std::printf("[       OK ] %.*s\n", int(name.size()), name.data());
+    } catch (failure const& f) {
+      std::printf("[  FAILED  ] %.*s at %s:%d : %s\n", int(name.size()),
+                  name.data(), f.file, f.line, f.expr);
+      failed = 1;
+    } catch (...) {
+      std::printf("[  FAILED  ] %.*s : unknown exception\n", int(name.size()),
+                  name.data());
+      failed = 1;
+    }
+  }
+  return failed;
+}

+ 5 - 0
Help/guide/tutorial/Complete/SimpleTest/cmake/SimpleTestConfig.cmake

@@ -0,0 +1,5 @@
+include(CMakeFindDependencyMacro)
+find_dependency(TransitiveDep)
+
+include(${CMAKE_CURRENT_LIST_DIR}/SimpleTestTargets.cmake)
+include(${CMAKE_CURRENT_LIST_DIR}/simpletest_discover_tests.cmake)

+ 32 - 0
Help/guide/tutorial/Complete/SimpleTest/cmake/simpletest_discover_impl.cmake

@@ -0,0 +1,32 @@
+if(NOT DEFINED TEST_EXE OR NOT DEFINED OUT_FILE)
+# noqa: spellcheck off
+  message(FATAL_ERROR "simpletest_discover: need -DTEST_EXE and -DOUT_FILE")
+# noqa: spellcheck on
+endif()
+
+execute_process(
+  COMMAND ${TEST_EXE} --list
+  RESULT_VARIABLE _rc
+  OUTPUT_VARIABLE _out
+  ERROR_VARIABLE _err
+  OUTPUT_STRIP_TRAILING_WHITESPACE
+)
+
+if(NOT _rc EQUAL 0)
+  file(WRITE ${OUT_FILE} "# simpletest: --list failed (rc=${_rc})\n")
+  message(FATAL_ERROR "simpletest_discover: '${TEST_EXE} --list' failed (${_rc})\n${_err}")
+endif()
+
+if(_out STREQUAL "")
+  file(WRITE ${OUT_FILE} "# simpletest: no tests\n")
+  return()
+endif()
+
+string(REPLACE "," ";" _names "${_out}")
+
+file(WRITE ${OUT_FILE} "# Auto-generated by simpletest_discover_impl.cmake\n")
+foreach(_name IN LISTS _names)
+  file(APPEND ${OUT_FILE}
+    "add_test([=[${_name}]=] \"${TEST_EXE}\" \"--test\" \"${_name}\")\n"
+  )
+endforeach()

+ 27 - 0
Help/guide/tutorial/Complete/SimpleTest/cmake/simpletest_discover_tests.cmake

@@ -0,0 +1,27 @@
+set(_simpletest_impl_script ${CMAKE_CURRENT_LIST_DIR}/simpletest_discover_impl.cmake)
+
+function(simpletest_discover_tests target)
+  if(NOT TARGET ${target})
+    message(FATAL_ERROR "simpletest_discover_tests: no such target '${target}'")
+  endif()
+
+  set(_out ${CMAKE_CURRENT_BINARY_DIR}/${target}_ctests.cmake)
+
+  if(NOT EXISTS ${_out})
+    file(WRITE ${_out} "# Populated after building ${target}\n")
+  endif()
+
+# noqa: spellcheck off
+  add_custom_command(TARGET ${target} POST_BUILD
+    COMMAND ${CMAKE_COMMAND}
+      -DTEST_EXE=$<TARGET_FILE:${target}>
+      -DOUT_FILE=${_out}
+      -P ${_simpletest_impl_script}
+    BYPRODUCTS ${_out}
+    COMMENT "SimpleTest: Discovering tests in ${target}"
+    VERBATIM
+  )
+# noqa: spellcheck on
+
+  set_property(DIRECTORY APPEND PROPERTY TEST_INCLUDE_FILES ${_out})
+endfunction()

+ 0 - 3
Help/guide/tutorial/Complete/TutorialConfig.h.in

@@ -1,3 +0,0 @@
-// the configured options and settings for Tutorial
-#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
-#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@

+ 59 - 0
Help/guide/tutorial/Complete/TutorialProject/CMakeLists.txt

@@ -0,0 +1,59 @@
+cmake_minimum_required(VERSION 3.23)
+
+project(Tutorial
+  VERSION 1.0.0
+)
+
+option(TUTORIAL_BUILD_UTILITIES "Build the Tutorial executable" ON)
+option(TUTORIAL_USE_STD_SQRT "Use std::sqrt" OFF)
+option(TUTORIAL_ENABLE_IPO "Check for and use IPO support" ON)
+option(BUILD_TESTING "Enable testing and build tests" ON)
+
+if(TUTORIAL_ENABLE_IPO)
+  include(CheckIPOSupported)
+  check_ipo_supported(RESULT result OUTPUT output)
+  if(result)
+    set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON)
+  else()
+    message(WARNING "IPO is not supported ${message}")
+  endif()
+endif()
+
+if(TUTORIAL_BUILD_UTILITIES)
+  add_subdirectory(Tutorial)
+endif()
+
+if(BUILD_TESTING)
+  enable_testing()
+  add_subdirectory(Tests)
+endif()
+
+add_subdirectory(MathFunctions)
+
+include(GNUInstallDirs)
+
+install(
+  TARGETS MathFunctions OpAdd OpMul OpSub MathLogger SqrtTable
+  EXPORT TutorialTargets
+  FILE_SET HEADERS
+)
+
+install(
+  EXPORT TutorialTargets
+  DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Tutorial
+  NAMESPACE Tutorial::
+)
+
+include(CMakePackageConfigHelpers)
+
+write_basic_package_version_file(
+  ${CMAKE_CURRENT_BINARY_DIR}/TutorialConfigVersion.cmake
+  COMPATIBILITY ExactVersion
+)
+
+install(
+  FILES
+    cmake/TutorialConfig.cmake
+    ${CMAKE_CURRENT_BINARY_DIR}/TutorialConfigVersion.cmake
+  DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Tutorial
+)

+ 16 - 0
Help/guide/tutorial/Complete/TutorialProject/CMakePresets.json

@@ -0,0 +1,16 @@
+{
+  "version": 4,
+  "configurePresets": [
+    {
+      "name": "tutorial",
+      "displayName": "Tutorial Preset",
+      "description": "Preset to use with the tutorial",
+      "binaryDir": "${sourceDir}/build",
+      "cacheVariables": {
+        "CMAKE_PREFIX_PATH": "${sourceParentDir}/install",
+        "TUTORIAL_USE_STD_SQRT": "OFF",
+        "TUTORIAL_ENABLE_IPO": "OFF"
+      }
+    }
+  ]
+}

+ 55 - 0
Help/guide/tutorial/Complete/TutorialProject/MathFunctions/CMakeLists.txt

@@ -0,0 +1,55 @@
+add_library(MathFunctions)
+add_library(Tutorial::MathFunctions ALIAS MathFunctions)
+
+target_sources(MathFunctions
+  PRIVATE
+    MathFunctions.cxx
+
+  PUBLIC
+    FILE_SET HEADERS
+    FILES
+      MathFunctions.h
+)
+
+target_link_libraries(MathFunctions
+  PRIVATE
+    MathLogger
+    SqrtTable
+
+  PUBLIC
+    OpAdd
+    OpMul
+    OpSub
+)
+
+target_compile_features(MathFunctions PRIVATE cxx_std_20)
+
+if(TUTORIAL_USE_STD_SQRT)
+  target_compile_definitions(MathFunctions PRIVATE TUTORIAL_USE_STD_SQRT)
+endif()
+
+include(CheckIncludeFiles)
+check_include_files(emmintrin.h HAS_EMMINTRIN LANGUAGE CXX)
+
+if(HAS_EMMINTRIN)
+  target_compile_definitions(MathFunctions PRIVATE TUTORIAL_USE_SSE2)
+endif()
+
+include(CheckSourceCompiles)
+check_source_compiles(CXX
+  [=[
+    typedef double v2df __attribute__((vector_size(16)));
+    int main() {
+      __builtin_ia32_sqrtsd(v2df{});
+    }
+  ]=]
+  HAS_GNU_BUILTIN
+)
+
+if(HAS_GNU_BUILTIN)
+  target_compile_definitions(MathFunctions PRIVATE TUTORIAL_USE_GNU_BUILTIN)
+endif()
+
+add_subdirectory(MathLogger)
+add_subdirectory(MathExtensions)
+add_subdirectory(MakeTable)

+ 28 - 0
Help/guide/tutorial/Complete/TutorialProject/MathFunctions/MakeTable/CMakeLists.txt

@@ -0,0 +1,28 @@
+add_executable(MakeTable)
+
+target_sources(MakeTable
+  PRIVATE
+    MakeTable.cxx
+)
+
+add_custom_command(
+  OUTPUT SqrtTable.h
+  COMMAND MakeTable SqrtTable.h
+  DEPENDS MakeTable
+  VERBATIM
+)
+
+add_custom_target(RunMakeTable DEPENDS SqrtTable.h)
+
+add_library(SqrtTable INTERFACE)
+
+target_sources(SqrtTable
+  INTERFACE
+    FILE_SET HEADERS
+    BASE_DIRS
+      ${CMAKE_CURRENT_BINARY_DIR}
+    FILES
+      ${CMAKE_CURRENT_BINARY_DIR}/SqrtTable.h
+)
+
+add_dependencies(SqrtTable RunMakeTable)

+ 0 - 0
Help/guide/tutorial/Complete/MathFunctions/MakeTable.cxx → Help/guide/tutorial/Complete/TutorialProject/MathFunctions/MakeTable/MakeTable.cxx


+ 3 - 0
Help/guide/tutorial/Complete/TutorialProject/MathFunctions/MathExtensions/CMakeLists.txt

@@ -0,0 +1,3 @@
+add_subdirectory(OpAdd)
+add_subdirectory(OpMul)
+add_subdirectory(OpSub)

+ 11 - 0
Help/guide/tutorial/Complete/TutorialProject/MathFunctions/MathExtensions/OpAdd/CMakeLists.txt

@@ -0,0 +1,11 @@
+add_library(OpAdd OBJECT)
+
+target_sources(OpAdd
+  PRIVATE
+    OpAdd.cxx
+
+  INTERFACE
+    FILE_SET HEADERS
+    FILES
+      OpAdd.h
+)

+ 6 - 0
Help/guide/tutorial/Complete/TutorialProject/MathFunctions/MathExtensions/OpAdd/OpAdd.cxx

@@ -0,0 +1,6 @@
+namespace mathfunctions {
+double OpAdd(double a, double b)
+{
+  return a + b;
+}
+}

+ 5 - 0
Help/guide/tutorial/Complete/TutorialProject/MathFunctions/MathExtensions/OpAdd/OpAdd.h

@@ -0,0 +1,5 @@
+#pragma once
+
+namespace mathfunctions {
+double OpAdd(double a, double b);
+}

+ 11 - 0
Help/guide/tutorial/Complete/TutorialProject/MathFunctions/MathExtensions/OpMul/CMakeLists.txt

@@ -0,0 +1,11 @@
+add_library(OpMul OBJECT)
+
+target_sources(OpMul
+  PRIVATE
+    OpMul.cxx
+
+  INTERFACE
+    FILE_SET HEADERS
+    FILES
+      OpMul.h
+)

+ 6 - 0
Help/guide/tutorial/Complete/TutorialProject/MathFunctions/MathExtensions/OpMul/OpMul.cxx

@@ -0,0 +1,6 @@
+namespace mathfunctions {
+double OpMul(double a, double b)
+{
+  return a * b;
+}
+}

+ 5 - 0
Help/guide/tutorial/Complete/TutorialProject/MathFunctions/MathExtensions/OpMul/OpMul.h

@@ -0,0 +1,5 @@
+#pragma once
+
+namespace mathfunctions {
+double OpMul(double a, double b);
+}

+ 11 - 0
Help/guide/tutorial/Complete/TutorialProject/MathFunctions/MathExtensions/OpSub/CMakeLists.txt

@@ -0,0 +1,11 @@
+add_library(OpSub OBJECT)
+
+target_sources(OpSub
+  PRIVATE
+    OpSub.cxx
+
+  INTERFACE
+    FILE_SET HEADERS
+    FILES
+      OpSub.h
+)

+ 6 - 0
Help/guide/tutorial/Complete/TutorialProject/MathFunctions/MathExtensions/OpSub/OpSub.cxx

@@ -0,0 +1,6 @@
+namespace mathfunctions {
+double OpSub(double a, double b)
+{
+  return a - b;
+}
+}

+ 5 - 0
Help/guide/tutorial/Complete/TutorialProject/MathFunctions/MathExtensions/OpSub/OpSub.h

@@ -0,0 +1,5 @@
+#pragma once
+
+namespace mathfunctions {
+double OpSub(double a, double b);
+}

+ 101 - 0
Help/guide/tutorial/Complete/TutorialProject/MathFunctions/MathFunctions.cxx

@@ -0,0 +1,101 @@
+#include <cmath>
+#include <format>
+
+#include <MathLogger.h>
+
+#ifdef TUTORIAL_USE_SSE2
+#  include <emmintrin.h>
+#endif
+
+namespace {
+
+mathlogger::Logger Logger;
+
+#if defined(TUTORIAL_USE_GNU_BUILTIN)
+typedef double v2df __attribute__((vector_size(16)));
+
+double gnu_mysqrt(double x)
+{
+  v2df root = __builtin_ia32_sqrtsd(v2df{ x, 0.0 });
+  double result = root[0];
+  Logger.Log(std::format("Computed sqrt of {} to be {} with GNU-builtins\n", x,
+                         result));
+  return result;
+}
+#elif defined(TUTORIAL_USE_SSE2)
+double sse2_mysqrt(double x)
+{
+  __m128d root = _mm_sqrt_sd(_mm_setzero_pd(), _mm_set_sd(x));
+  double result = _mm_cvtsd_f64(root);
+  Logger.Log(
+    std::format("Computed sqrt of {} to be {} with SSE2\n", x, result));
+  return result;
+}
+#endif
+
+// a hack square root calculation using simple operations
+double fallback_mysqrt(double x)
+{
+  if (x <= 0) {
+    return 0;
+  }
+
+  double result = x;
+
+  // do ten iterations
+  for (int i = 0; i < 10; ++i) {
+    if (result <= 0) {
+      result = 0.1;
+    }
+    double delta = x - (result * result);
+    result = result + 0.5 * delta / result;
+
+    Logger.Log(std::format("Computing sqrt of {} to be {}\n", x, result));
+  }
+  return result;
+}
+
+#include <SqrtTable.h>
+
+double table_sqrt(double x)
+{
+  double result = sqrtTable[static_cast<int>(x)];
+  // do ten iterations
+  for (int i = 0; i < 10; ++i) {
+    if (result <= 0) {
+      result = 0.1;
+    }
+    double delta = x - (result * result);
+    result = result + 0.5 * delta / result;
+  }
+  Logger.Log(
+    std::format("Computed sqrt of {} to be {} with TableSqrt\n", x, result));
+  return result;
+}
+
+double mysqrt(double x)
+{
+  if (x >= 1 && x < 10) {
+    return table_sqrt(x);
+  }
+
+#if defined(TUTORIAL_USE_GNU_BUILTIN)
+  return gnu_mysqrt(x);
+#elif defined(TUTORIAL_USE_SSE2)
+  return sse2_mysqrt(x);
+#else
+  return fallback_mysqrt(x);
+#endif
+}
+}
+
+namespace mathfunctions {
+double sqrt(double x)
+{
+#ifdef TUTORIAL_USE_STD_SQRT
+  return std::sqrt(x);
+#else
+  return mysqrt(x);
+#endif
+}
+}

+ 9 - 0
Help/guide/tutorial/Complete/TutorialProject/MathFunctions/MathFunctions.h

@@ -0,0 +1,9 @@
+#pragma once
+
+#include <OpAdd.h>
+#include <OpMul.h>
+#include <OpSub.h>
+
+namespace mathfunctions {
+double sqrt(double x);
+}

+ 6 - 0
Help/guide/tutorial/Complete/TutorialProject/MathFunctions/MathLogger/CMakeLists.txt

@@ -0,0 +1,6 @@
+add_library(MathLogger INTERFACE)
+
+target_sources(MathLogger
+  INTERFACE
+    FILE_SET HEADERS
+)

+ 27 - 0
Help/guide/tutorial/Complete/TutorialProject/MathFunctions/MathLogger/MathFormatting.h

@@ -0,0 +1,27 @@
+#pragma once
+
+#include <string>
+
+namespace mathlogger {
+
+enum LogLevel
+{
+  INFO,
+  WARN,
+  ERROR,
+};
+
+inline std::string FormatLog(LogLevel level, std::string const& message)
+{
+  switch (level) {
+    case INFO:
+      return "INFO: " + message;
+    case WARN:
+      return "WARN: " + message;
+    case ERROR:
+      return "ERROR: " + message;
+  }
+  return "UNKNOWN: " + message;
+}
+
+}

+ 22 - 0
Help/guide/tutorial/Complete/TutorialProject/MathFunctions/MathLogger/MathLogger.h

@@ -0,0 +1,22 @@
+#pragma once
+
+#include <string>
+
+#include "MathFormatting.h"
+#include "MathOutput.h"
+
+namespace mathlogger {
+
+struct Logger
+{
+  LogLevel level = INFO;
+
+  void SetLevel(LogLevel new_level) { level = new_level; }
+  void Log(std::string const& message)
+  {
+    std::string formatted = FormatLog(level, message);
+    WriteLog(formatted);
+  }
+};
+
+}

+ 11 - 0
Help/guide/tutorial/Complete/TutorialProject/MathFunctions/MathLogger/MathOutput.h

@@ -0,0 +1,11 @@
+#pragma once
+
+#include <iostream>
+#include <string>
+
+namespace mathlogger {
+inline void WriteLog(std::string const& msg)
+{
+  std::cout << msg;
+}
+}

+ 16 - 0
Help/guide/tutorial/Complete/TutorialProject/Tests/CMakeLists.txt

@@ -0,0 +1,16 @@
+add_executable(TestMathFunctions)
+
+target_sources(TestMathFunctions
+  PRIVATE
+    TestMathFunctions.cxx
+)
+
+find_package(SimpleTest REQUIRED)
+
+target_link_libraries(TestMathFunctions
+  PRIVATE
+    MathFunctions
+    SimpleTest::SimpleTest
+)
+
+simpletest_discover_tests(TestMathFunctions)

+ 22 - 0
Help/guide/tutorial/Complete/TutorialProject/Tests/TestMathFunctions.cxx

@@ -0,0 +1,22 @@
+#include <MathFunctions.h>
+#include <SimpleTest.h>
+
+TEST("add")
+{
+  REQUIRE(mathfunctions::OpAdd(2.0, 2.0) == 4.0);
+}
+
+TEST("sub")
+{
+  REQUIRE(mathfunctions::OpSub(4.0, 2.0) == 2.0);
+}
+
+TEST("mul")
+{
+  REQUIRE(mathfunctions::OpMul(5.0, 5.0) == 25.0);
+}
+
+TEST("sqrt")
+{
+  REQUIRE(mathfunctions::sqrt(25.0) == 5.0);
+}

+ 39 - 0
Help/guide/tutorial/Complete/TutorialProject/Tutorial/CMakeLists.txt

@@ -0,0 +1,39 @@
+add_executable(Tutorial)
+
+target_sources(Tutorial
+  PRIVATE
+    Tutorial.cxx
+)
+
+target_link_libraries(Tutorial
+  PRIVATE
+    MathFunctions
+)
+
+target_compile_features(Tutorial PRIVATE cxx_std_20)
+
+if(
+  (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") OR
+  (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
+)
+
+  target_compile_options(Tutorial PRIVATE /W3)
+
+elseif(
+  (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") OR
+  (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+)
+
+  target_compile_options(Tutorial PRIVATE -Wall)
+
+endif()
+
+find_path(UnpackagedIncludeFolder Unpackaged.h REQUIRED
+  PATH_SUFFIXES
+    Unpackaged
+)
+
+target_include_directories(Tutorial
+  PRIVATE
+    ${UnpackagedIncludeFolder}
+)

+ 27 - 0
Help/guide/tutorial/Complete/TutorialProject/Tutorial/Tutorial.cxx

@@ -0,0 +1,27 @@
+// A simple program that computes the square root of a number
+#include <format>
+#include <iostream>
+#include <string>
+
+#include <MathFunctions.h>
+#include <Unpackaged.h>
+
+int main(int argc, char* argv[])
+{
+  if (argc < 2) {
+    std::cout << std::format("Usage: {} number\n", argv[0]);
+    return 1;
+  }
+
+  // convert input to double
+  double const inputValue = std::stod(argv[1]);
+
+  // calculate square root
+  double const outputValue = mathfunctions::sqrt(inputValue);
+  std::cout << std::format("The square root of {} is {}\n", inputValue,
+                           outputValue);
+
+  double const checkValue = mathfunctions::OpMul(outputValue, outputValue);
+  std::cout << std::format("The square of {} is {}\n", outputValue,
+                           checkValue);
+}

+ 1 - 0
Help/guide/tutorial/Complete/TutorialProject/cmake/TutorialConfig.cmake

@@ -0,0 +1 @@
+include(${CMAKE_CURRENT_LIST_DIR}/TutorialTargets.cmake)

+ 3 - 0
Help/guide/tutorial/Complete/install/include/Unpackaged/Unpackaged.h

@@ -0,0 +1,3 @@
+#pragma once
+
+#define UNPACKAGED_HEADER_FOUND

+ 50 - 0
Help/guide/tutorial/Complete/install/lib/cmake/TransitiveDep/TransitiveDepConfig.cmake

@@ -0,0 +1,50 @@
+# Abridged import written for the Tutorial
+
+if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.8)
+   message(FATAL_ERROR "CMake >= 3.0.0 required")
+endif()
+if(CMAKE_VERSION VERSION_LESS "3.0.0")
+   message(FATAL_ERROR "CMake >= 3.0.0 required")
+endif()
+cmake_policy(PUSH)
+cmake_policy(VERSION 3.0.0...3.30)
+
+# Commands may need to know the format version.
+set(CMAKE_IMPORT_FILE_VERSION 1)
+
+# Protect against multiple inclusion, which would fail when already imported targets are added once more.
+set(_cmake_targets_defined "")
+set(_cmake_targets_not_defined "")
+set(_cmake_expected_targets "")
+foreach(_cmake_expected_target IN ITEMS TransitiveDep::TransitiveDep)
+  list(APPEND _cmake_expected_targets "${_cmake_expected_target}")
+  if(TARGET "${_cmake_expected_target}")
+    list(APPEND _cmake_targets_defined "${_cmake_expected_target}")
+  else()
+    list(APPEND _cmake_targets_not_defined "${_cmake_expected_target}")
+  endif()
+endforeach()
+unset(_cmake_expected_target)
+if(_cmake_targets_defined STREQUAL _cmake_expected_targets)
+  unset(_cmake_targets_defined)
+  unset(_cmake_targets_not_defined)
+  unset(_cmake_expected_targets)
+  unset(CMAKE_IMPORT_FILE_VERSION)
+  cmake_policy(POP)
+  return()
+endif()
+if(NOT _cmake_targets_defined STREQUAL "")
+  string(REPLACE ";" ", " _cmake_targets_defined_text "${_cmake_targets_defined}")
+  string(REPLACE ";" ", " _cmake_targets_not_defined_text "${_cmake_targets_not_defined}")
+  message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_cmake_targets_defined_text}\nTargets not yet defined: ${_cmake_targets_not_defined_text}\n")
+endif()
+unset(_cmake_targets_defined)
+unset(_cmake_targets_not_defined)
+unset(_cmake_expected_targets)
+
+# Create imported target TransitiveDep::TransitiveDep
+add_library(TransitiveDep::TransitiveDep INTERFACE IMPORTED)
+
+# Commands beyond this point should not need to know the version.
+set(CMAKE_IMPORT_FILE_VERSION)
+cmake_policy(POP)

+ 606 - 0
Help/guide/tutorial/Configuration and Cache Variables.rst

@@ -0,0 +1,606 @@
+Step 3: Configuration and Cache Variables
+=========================================
+
+CMake projects often have some project-specific configuration variables which
+users and packagers are interested in. CMake has many ways that an invoking
+user or process can communicate these configuration choices, but the most
+fundamental of them are :option:`-D <cmake -D>` flags.
+
+In this step we'll explore the ins and out of how to provide project
+configuration options from within a CML, and how to invoke CMake to take
+advantage of configuration options provided by both CMake and individual
+projects.
+
+Background
+^^^^^^^^^^
+
+If we had a CMake project for compression software which supported multiple
+compression algorithms, we might want to let the packager of the project decide
+which algorithms to enable when they build our software. We can do so by
+consuming variables set via :option:`-D <cmake -D>` flags.
+
+.. code-block:: cmake
+
+  if(COMPRESSION_SOFTWARE_USE_ZLIB)
+    message("I will use Zlib!")
+    # ...
+  endif()
+
+  if(COMPRESSION_SOFTWARE_USE_ZSTD)
+    message("I will use Zstd!")
+    # ...
+  endif()
+
+.. code-block:: console
+
+  $ cmake -B build \
+      -DCOMPRESSION_SOFTWARE_USE_ZLIB=ON \
+      -DCOMPRESSION_SOFTWARE_USE_ZSTD=OFF
+  ...
+  I will use Zlib!
+
+Of course, we will want to provide reasonable defaults for these configuration
+choices, and a way to communicate the purpose of a given option. This function
+is provided by the :command:`option` command.
+
+.. code-block:: cmake
+
+  option(COMPRESSION_SOFTWARE_USE_ZLIB "Support Zlib compression" ON)
+  option(COMPRESSION_SOFTWARE_USE_ZSTD "Support Zstd compression" ON)
+
+  if(COMPRESSION_SOFTWARE_USE_ZLIB)
+    # Same as before
+  # ...
+
+.. code-block:: console
+
+  $ cmake -B build \
+      -DCOMPRESSION_SOFTWARE_USE_ZLIB=OFF
+  ...
+  I will use Zstd!
+
+The names created by :option:`-D <cmake -D>` flags and :command:`option` are
+not normal variables, they are **cache** variables. Cache variables are globally
+visible variables which are *sticky*, their value is difficult to change after
+it is initially set. In fact they are so sticky that, in project mode, CMake
+will save and restore cache variables across multiple configurations. If a
+cache variable is set once, it will remain until another :option:`-D <cmake -D>`
+flag preempts the saved variable.
+
+.. note::
+  CMake itself has dozens of normal and cache variables used for configuration.
+  These are documented at :manual:`cmake-variables(7)` and operate in the same
+  manner as project-provided variables for configuration.
+
+:command:`set` can also be used to manipulate cache variables, but will not
+change a variable which has already been created.
+
+.. code-block:: cmake
+
+  set(StickyCacheVariable "I will not change" CACHE STRING "")
+  set(StickyCacheVariable "Overwrite StickyCache" CACHE STRING "")
+
+  message("StickyCacheVariable: ${StickyCacheVariable}")
+
+.. code-block:: console
+
+  $ cmake -P StickyCacheVariable.cmake
+  StickyCacheVariable: I will not change
+
+Because :option:`-D <cmake -D>` flags are processed before any other commands,
+they take precedence for setting the value of a cache variable.
+
+.. code-block:: console
+
+  $ cmake \
+    -DStickyCacheVariable="Commandline always wins" \
+    -P StickyCacheVariable.cmake
+  StickyCacheVariable: Commandline always wins
+
+While cache variables cannot ordinarily be changed, they can be *shadowed* by
+normal variables. We can observe this by :command:`set`'ing a variable to have
+the same name as a cache variable, and then using :command:`unset` to remove
+the normal variable.
+
+.. code-block:: cmake
+
+  set(ShadowVariable "In the shadows" CACHE STRING "")
+  set(ShadowVariable "Hiding the cache variable")
+  message("ShadowVariable: ${ShadowVariable}")
+
+  unset(ShadowVariable)
+  message("ShadowVariable: ${ShadowVariable}")
+
+.. code-block:: console
+
+  $ cmake -P ShadowVariable.cmake
+  ShadowVariable: Hiding the cache variable
+  ShadowVariable: In the shadows
+
+Exercise 1 - Using Options
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+We can imagine a scenario where consumers really want our ``MathFunctions``
+library, and the ``Tutorial`` utility is a "take it or leave it" add-on. In
+that case, we might want to add an option to allow consumers to disable
+building our ``Tutorial`` binary, building only the ``MathFunctions`` library.
+
+With our knowledge of options, conditionals, and cache variables we have all
+the pieces we need to make this configuration available.
+
+Goal
+----
+
+Add an option named ``TUTORIAL_BUILD_UTILITIES`` to control if the ``Tutorial``
+binary is configured and built.
+
+.. note::
+  CMake allows us to determine which targets are built after configuration. Our
+  users could ask for the ``MathFunctions`` library alone without ``Tutorial``.
+  CMake also has mechanisms to exclude targets from ``ALL``, the default target
+  which builds all the other available targets.
+
+  However, options which completely exclude targets from the configuration are
+  convenient and popular, especially if configuring those targets involves
+  heavy-weight steps which might take some time.
+
+  It also simplifies :command:`install()` logic, which we'll discuss in later
+  steps, if targets the packager is uninterested in are completely excluded.
+
+Helpful Resources
+-----------------
+
+* :command:`option`
+* :command:`if`
+
+Files to Edit
+-------------
+
+* ``CMakeLists.txt``
+
+Getting Started
+---------------
+
+The ``Help/guide/tutorial/Step3`` folder contains the complete, recommended
+solution to ``Step1`` and the relevant ``TODOs`` for this step. Take a minute
+to review and refamiliarize yourself with the ``Tutorial`` project.
+
+When you feel you have an understanding of the current code, start with
+``TODO 1`` and complete through ``TODO 2``.
+
+Build and Run
+-------------
+
+We can now reconfigure our project. However, this time we want to control the
+configuration via :option:`-D <cmake -D>` flags. We again start by navigating
+to ``Help/guide/tutorial/Step3`` and invoking CMake, but this time with our
+configuration options.
+
+.. code-block:: console
+
+  cmake -B build -DTUTORIAL_BUILD_UTILITIES=OFF
+
+We can now build as usual.
+
+.. code-block:: console
+
+  cmake --build build
+
+After the build we should observe no Tutorial executable is produced. Because
+cache variables are sticky even a reconfigure shouldn't change this, despite
+the default-``ON`` option.
+
+.. code-block:: console
+
+  cmake -B build
+  cmake --build build
+
+Will not produce the Tutorial executable, the cache variables are "locked in".
+To change this we have two options. First, we can edit the file which stores
+the cache variables between CMake configuration runs, the "CMake Cache". This
+file is ``build/CMakeCache.txt``, in it we can find the option cache variable.
+
+.. code-block:: cmake
+
+  //Build the Tutorial executable
+  TUTORIAL_BUILD_UTILITIES:BOOL=OFF
+
+We can change this from ``OFF`` to ``ON``, rerun the build, and we will get
+our ``Tutorial`` executable.
+
+.. note::
+  ``CMakeCache.txt`` entries are of the form ``<Name>:<Type>=<Value>``, however
+  the "type" is only a hint. All objects in CMake are strings, regardless of
+  what the cache says.
+
+Alternatively, we can change the value of the cache variable on the command
+line, because the command line runs before ``CMakeCache.txt`` is loaded its
+value take precedence over those in the cache file.
+
+.. code-block:: console
+
+  cmake -B build -DTUTORIAL_BUILD_UTILITIES=ON
+  cmake --build build
+
+Doing so we observe the value in ``CMakeCache.txt`` has flipped from ``OFF``
+to ``ON``, and that the ``Tutorial`` executable is built.
+
+Solution
+--------
+
+First we create our :command:`option` to provide our cache variable with a
+reasonable default value.
+
+.. raw:: html
+
+  <details><summary>TODO 1: Click to show/hide answer</summary>
+
+.. literalinclude:: Step4/CMakeLists.txt
+  :caption: TODO 1: CMakeLists.txt
+  :name: CMakeLists.txt-option-TUTORIAL_BUILD_UTILITIES
+  :language: cmake
+  :start-at: option(TUTORIAL_BUILD_UTILITIES
+  :end-at: option(TUTORIAL_BUILD_UTILITIES
+
+.. raw:: html
+
+  </details>
+
+Then we can check the cache variable to conditionally enable the ``Tutorial``
+executable (by way of adding its subdirectory).
+
+.. raw:: html
+
+  <details><summary>TODO 2: Click to show/hide answer</summary>
+
+.. literalinclude:: Step4/CMakeLists.txt
+  :caption: TODO 2: CMakeLists.txt
+  :name: CMakeLists.txt-if-TUTORIAL_BUILD_UTILITIES
+  :language: cmake
+  :start-at: if(TUTORIAL_BUILD_UTILITIES)
+  :end-at: endif()
+
+.. raw:: html
+
+  </details>
+
+Exercise 2 - ``CMAKE`` Variables
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+CMake has several important normal and cache variables provided to allow
+packagers to control the build. Decisions such as compilers, default flags,
+search locations for packages, and much more are all controlled by CMake's
+own configuration variables.
+
+Among the most important are language standards. As the language standard can
+have significant impact on the ABI presented by a given package. For example,
+it's quite common for libraries to use standard C++ templates on later
+standards, and provide polyfills on earlier standards. If a library is consumed
+under different standards then ABI incompatibilities between the standard
+templates and the polyfills can result in incomprehensible errors and runtime
+crashes.
+
+Ensuring all of our targets are built under the same language standard is
+achieved with the :variable:`CMAKE_<LANG>_STANDARD` cache variables. For C++,
+this is ``CMAKE_CXX_STANDARD``.
+
+.. note::
+  Because these variables are so important, it is equally important that
+  developers not override or shadow them in their CMLs. Shadowing
+  :variable:`CMAKE_<LANG>_STANDARD` in a CML because the library wants C++20,
+  when the packager has decided to build the rest of their libraries and
+  applications with C++23, can lead to the aforementioned terrible,
+  incomprehensible errors.
+
+  Do not :command:`set` ``CMAKE_`` globals without very strong reasons for
+  doing so. We'll discuss better methods for targets to communicate
+  requirements like definitions and minimum standards in later steps.
+
+In this exercise, we'll introduce some C++20 code into our library and
+executable and build them with C++20 by setting the appropriate cache variable.
+
+Goal
+----
+
+Use ``std::format`` to format printed strings instead of stream operators. To
+ensure availability of ``std::format``, configure CMake to use the C++20
+standard for C++ targets.
+
+Helpful Resources
+-----------------
+
+* :option:`cmake -D`
+* :variable:`CMAKE_<LANG>_STANDARD`
+* :variable:`CMAKE_CXX_STANDARD`
+* :prop_tgt:`CXX_STANDARD`
+* `cppreference \<format\> <https://en.cppreference.com/w/cpp/utility/format/format.html>`_
+
+Files to Edit
+-------------
+
+* ``Tutorial/Tutorial.cxx``
+* ``MathFunctions/MathFunctions.cxx``
+
+Getting Started
+---------------
+
+Continue to edit files from ``Step3``. Complete ``TODO 3`` through ``TODO 7``.
+We'll be modifying our prints to use ``std::format`` instead of stream
+operators.
+
+Ensure your cache variables are set such that the Tutorial executable will be
+built, using any of the methods discussed in the previous exercise.
+
+Build and Run
+-------------
+
+We need to reconfigure our project with the new standard, we can do this
+using the same method as our ``TUTORIAL_BUILD_UTILITIES`` cache variable.
+
+.. code-block:: console
+
+  cmake -B build -DCMAKE_CXX_STANDARD=20
+
+.. note::
+  Configuration variables are, by convention, prefixed with the provider of the
+  variable. CMake configuration variables are prefixed with ``CMAKE_``, while
+  projects should prefix their variables with ``<PROJECT>_``.
+
+  The tutorial configuration variables follow this convention, and are prefixed
+  with ``TUTORIAL_``.
+
+Now that we've configured with C++20, we can build as usual.
+
+.. code-block:: console
+
+  cmake --build build
+
+Solution
+--------
+
+We need to include ``<format>`` and then use it.
+
+.. raw:: html
+
+  <details><summary>TODO 3-5: Click to show/hide answer</summary>
+
+.. literalinclude:: Step4/Tutorial/Tutorial.cxx
+  :caption: TODO 3: Tutorial/Tutorial.cxx
+  :name: Tutorial/Tutorial.cxx-include-format
+  :language: c++
+  :start-at: #include <format>
+  :end-at: #include <string>
+
+.. literalinclude:: Step4/Tutorial/Tutorial.cxx
+  :caption: TODO 4: Tutorial/Tutorial.cxx
+  :name: Tutorial/Tutorial.cxx-format1
+  :language: c++
+  :start-at: if (argc < 2) {
+  :end-at: return 1;
+  :append: }
+  :dedent: 2
+
+.. literalinclude:: Step4/Tutorial/Tutorial.cxx
+  :caption: TODO 5: Tutorial/Tutorial.cxx
+  :name: Tutorial/Tutorial.cxx-format3
+  :language: c++
+  :start-at: // calculate square root
+  :end-at: outputValue);
+  :dedent: 2
+
+.. raw:: html
+
+  </details>
+
+And again for the ``MathFunctions`` library.
+
+.. raw:: html
+
+  <details><summary>TODO 6-7: Click to show/hide answer</summary>
+
+.. literalinclude:: Step4/MathFunctions/MathFunctions.cxx
+  :caption: TODO 6: MathFunctions.cxx
+  :name: MathFunctions/MathFunctions.cxx-include-format
+  :language: c++
+  :start-at: #include <format>
+  :end-at: #include <iostream>
+
+.. literalinclude:: Step4/MathFunctions/MathFunctions.cxx
+  :caption: TODO 7: MathFunctions.cxx
+  :name: MathFunctions/MathFunctions.cxx-format
+  :language: c++
+  :start-at: double delta
+  :end-at: std::format
+  :dedent: 4
+
+.. raw:: html
+
+  </details>
+
+Exercise 3 - CMakePresets.json
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Managing these configuration values can quickly become overwhelming. In CI
+systems it is appropriate to record these as part of a given CI step. For
+example in a Github Actions CI step we might see something akin to the
+following:
+
+.. code-block:: yaml
+
+  - name: Configure and Build
+    run: |
+      cmake \
+        -B build \
+        -DCMAKE_BUILD_TYPE=Release \
+        -DCMAKE_CXX_STANDARD=20 \
+        -DCMAKE_CXX_EXTENSIONS=ON \
+        -DTUTORIAL_BUILD_UTILITIES=OFF \
+        # Possibly many more options
+        # ...
+
+      cmake --build build
+
+When developing code locally, typing all these options even once might be error
+prone. If a fresh configuration is needed for any reason, doing so multiple
+times could be exhausting.
+
+There are many and varied solutions to this problem, and your choice is
+ultimately up to your preferences as a developer. CLI-oriented developers
+commonly use task runners to invoke CMake with their desired options for a
+project. Most IDEs also have a custom mechanism for controlling CMake
+configuration.
+
+It would be impossible to fully enumerate every possible configuration workflow
+here. Instead we will explore CMake's built-in solution, known as
+:manual:`CMake Presets <cmake-presets(7)>`. Presets give us a format to name
+and express collections of CMake configuration options.
+
+.. note::
+    Presets are capable of expressing entire CMake workflows, from
+    configuration, through building, all the way to installing the software
+    package.
+
+    They are far more flexible than can we have room for here. We'll limit
+    ourselves to using them for configuration.
+
+CMake Presets come in two standard files, ``CMakePresets.json``, which is
+intended to be a part of the project and tracked in source control; and
+``CMakeUserPresets.json``, which is intended for local user configuration
+and should not be tracked in source control.
+
+The simplest preset which would be of use to a developer does nothing more
+than configure variables.
+
+.. code-block:: json
+
+  {
+    "version": 4,
+    "configurePresets": [
+      {
+        "name": "example-preset",
+        "cacheVariables": {
+          "EXAMPLE_FOO": "Bar",
+          "EXAMPLE_QUX": "Baz"
+        }
+      }
+    ]
+  }
+
+When invoking CMake, where previously we would have done:
+
+.. code-block:: console
+
+  cmake -B build -DEXAMPLE_FOO=Bar -DEXAMPLE_QUX=Baz
+
+We can now use the preset:
+
+.. code-block:: console
+
+  cmake -B build --preset example-preset
+
+CMake will search for files named ``CMakePresets.json`` and
+``CMakeUserPresets.json``, and load the named configuration from them if
+available.
+
+.. note::
+  Command line flags can be mixed with presets. Command line flags have
+  precedence over values found in a preset.
+
+Presets also support limited macros, variables that can be brace-expanded
+inside the preset. The only one of interest to us is the ``${sourceDir}`` macro,
+which expands to the root directory of the project. We can use this to set our
+build directory, skipping the :option:`-B <cmake -B>` flag when configuring
+the project.
+
+.. code-block:: json
+
+  {
+    "name": "example-preset",
+    "binaryDir": "${sourceDir}/build"
+  }
+
+Goal
+----
+
+Configure and build the tutorial using a CMake Preset instead of command line
+flags.
+
+Helpful Resources
+-----------------
+
+* :manual:`cmake-presets(7)`
+
+Files to Edit
+-------------
+
+* ``CMakePresets.json``
+
+Getting Started
+---------------
+
+Continue to edit files from ``Step3``. Complete ``TODO 8`` and ``TODO 9``.
+
+.. note::
+  ``TODOs`` inside ``CMakePresets.json`` need to be *replaced*. There should
+  be no ``TODO`` keys left inside the file when you have completed the exercise.
+
+You can verify the preset is working correctly by deleting the existing build
+folder before you configure, this will ensure you're not reusing the existing
+CMake Cache for configuration.
+
+.. note::
+  On CMake 3.24 and newer, the same effect can be achieved by configuring with
+  :option:`cmake --fresh`.
+
+All future configuration changes will be via the ``CMakePresets.json`` file.
+
+Build and Run
+-------------
+
+We can now use the preset file to manage our configuration.
+
+.. code-block:: console
+
+  cmake --preset tutorial
+
+Presets are capable of running the build step for us, but for this tutorial
+we'll continue to run the build ourselves.
+
+.. code-block:: console
+
+  cmake --build build
+
+Solution
+--------
+
+There are two changes we need to make, first we want to set the build
+directory (also called the "binary directory") to the ``build`` subdirectory
+of our project folder, and second we need to set the ``CMAKE_CXX_STANDARD`` to
+``20``.
+
+.. raw:: html
+
+  <details><summary>TODO 8-9: Click to show/hide answer</summary>
+
+.. code-block:: json
+  :caption: TODO 8-9: CMakePresets.json
+  :name: CMakePresets.json-initial
+
+  {
+    "version": 4,
+    "configurePresets": [
+      {
+        "name": "tutorial",
+        "displayName": "Tutorial Preset",
+        "description": "Preset to use with the tutorial",
+        "binaryDir": "${sourceDir}/build",
+        "cacheVariables": {
+          "CMAKE_CXX_STANDARD": "20"
+        }
+      }
+    ]
+  }
+
+.. raw:: html
+
+  </details>

+ 279 - 0
Help/guide/tutorial/Custom Commands and Generated Files.rst

@@ -0,0 +1,279 @@
+Step 7: Custom Commands and Generated Files
+===========================================
+
+Code generation is a ubiquitous mechanism for extending programming languages
+beyond the bounds of their language model. CMake has first-class support for
+Qt's Meta-Object Compiler, but very few other code generators are notable
+enough to warrant that kind of effort.
+
+Instead, code generators tend to be bespoke and usage specific. CMake provides
+facilities for describing the usage of a code generator, so projects can
+add support for their individual needs.
+
+In this step, we will use :command:`add_custom_command` to add support for a
+code generator within the tutorial project.
+
+Background
+^^^^^^^^^^
+
+Any step in the build process can generally be described in terms of its inputs
+and outputs. CMake assumes that code generators and other custom processes
+operate on the same principle. In this way, the code generator acts identically
+to compilers, linkers, and other elements of the toolchain; when the inputs are
+newer than the outputs (or the outputs don't exist), a user-specified command
+will be run to update the outputs.
+
+.. note::
+  This model assumes the outputs of a process are known before it is run. CMake
+  lacks the ability to describe code generators where the name and location of
+  the outputs depends on the *content* of the input. Various hacks exist to
+  shim this functionality into CMake, but they are outside the scope of this
+  tutorial.
+
+Describing a code generator (or any custom process) is usually performed in
+two parts. First, the inputs and outputs are described independently of the
+CMake target model, concerned only with the generation process itself. Second,
+the outputs are associated with a CMake target to insert them into the CMake
+target model.
+
+For sources, this is as simple as adding the generated files to the source list
+of a ``STATIC``, ``SHARED``, or ``OBJECT`` library. For header-only generators,
+it's often necessary to use an intermediary target created via
+:command:`add_custom_target` to add the header file generation to the
+build stage (because ``INTERFACE`` libraries have no build step).
+
+Exercise 1 - Using a Code Generator
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The primary mechanism for describing a code generator is the
+:command:`add_custom_command` command. A "command", for the purpose of
+:command:`add_custom_command` is either an executable available in the build
+environment or a CMake executable target name.
+
+.. code-block:: cmake
+
+  add_executable(Tool)
+  # ...
+  add_custom_command(
+    OUTPUT Generated.cxx
+    COMMAND Tool -i input.txt -o Generated.cxx
+    DEPENDS Tool input.txt
+    VERBATIM
+  )
+  # ...
+  add_library(GeneratedObject OBJECT)
+  target_sources(GeneratedObject
+    PRIVATE
+      Generated.cxx
+  )
+
+Most of the keywords are self-explanatory, with the exception of ``VERBATIM``.
+This argument is effectively mandatory for legacy reasons that are uninteresting
+to explain in a modern context. The curious should consult the
+:command:`add_custom_command` documentation for additional details.
+
+The ``Tool`` executable target appears both in the ``COMMAND`` and ``DEPENDS``
+parameters. While ``COMMAND`` is sufficient for the code to build correctly,
+adding the ``Tool`` itself as a dependency of the custom command ensure that
+if ``Tool`` is updated, the custom command will be rerun.
+
+For header-only file generation, additional commands are necessary because the
+library itself has no build step. We can use :command:`add_custom_target` to
+create an "artificial" build step for the library. We then force the custom
+target to be run before any targets which link the library with the command
+:command:`add_dependencies`.
+
+.. code-block:: cmake
+
+  add_custom_target(RunGenerator DEPENDS Generated.h)
+
+  add_library(GeneratedLib INTERFACE)
+  target_sources(GeneratedLib
+    INTERFACE
+      FILE_SET HEADERS
+      BASE_DIRS
+        ${CMAKE_CURRENT_BINARY_DIR}
+      FILES
+        ${CMAKE_CURRENT_BINARY_DIR}/Generated.h
+  )
+
+  add_dependencies(GeneratedLib RunGenerator)
+
+.. note::
+  We add the :variable:`CMAKE_CURRENT_BINARY_DIR`, a variable which names the
+  current location in the build tree where our artifacts are being placed, to
+  the base directories because that's the working directory our code generator
+  will be run inside of. Listing the ``FILES`` is unnecessary for the build and
+  done so here only for clarity.
+
+Goal
+----
+
+Add a generated table of pre-computed square roots to the ``MathFunctions``
+library.
+
+Helpful Resources
+-----------------
+
+* :command:`add_executable`
+* :command:`add_library`
+* :command:`target_sources`
+* :command:`add_custom_command`
+* :command:`add_custom_target`
+* :command:`add_dependencies`
+
+Files to Edit
+-------------
+
+* ``MathFunctions/CMakeLists.txt``
+* ``MathFunctions/MakeTable/CMakeLists.txt``
+* ``MathFunctions/MathFunctions.cxx``
+
+Getting Started
+---------------
+
+The ``MathFunctions`` library has been edited to use a pre-computed table when
+given a number less than 10. However, the hardcoded table is not particularly
+accurate, containing only the nearest truncated integer value.
+
+The ``MakeTable.cxx`` source file describes a program which will generate a
+better table. It takes a single argument as input, the file name of the table
+to be generated.
+
+Complete ``TODO 1`` through ``TODO 10``.
+
+Build and Run
+-------------
+
+No special configuration is needed, configure and build as usual. Note that
+the ``MakeTable`` executable is sequenced before ``MathFunctions``.
+
+.. code-block:: console
+
+  cmake --preset tutorial
+  cmake --build build
+
+Verify the output of ``Tutorial`` now uses the pre-computed table for values
+less than 10.
+
+Solution
+--------
+
+First we add a new executable to generate the tables, adding the
+``MakeTable.cxx`` file as a source.
+
+.. raw:: html
+
+  <details><summary>TODO 1-2: Click to show/hide answer</summary>
+
+.. literalinclude:: Step8/MathFunctions/MakeTable/CMakeLists.txt
+  :caption: TODO 1-2: MathFunctions/MakeTable/CMakeLists.txt
+  :name: MathFunctions/MakeTable/CMakeLists.txt-add_executable
+  :language: cmake
+  :start-at: add_executable
+  :end-at: MakeTable.cxx
+  :append: )
+
+.. raw:: html
+
+  </details>
+
+Then we add a custom command which produces the table, and custom target which
+depends on the table.
+
+.. raw:: html
+
+  <details><summary>TODO 3-4: Click to show/hide answer</summary>
+
+.. literalinclude:: Step8/MathFunctions/MakeTable/CMakeLists.txt
+  :caption: TODO 3-4: MathFunctions/MakeTable/CMakeLists.txt
+  :name: MathFunctions/MakeTable/CMakeLists.txt-add_custom_command
+  :language: cmake
+  :start-at: add_custom_command
+  :end-at: add_custom_target
+
+.. raw:: html
+
+  </details>
+
+We need to add an interface library which describes the output which will
+appear in :variable:`CMAKE_CURRENT_BINARY_DIR`. The ``FILES`` parameter is
+optional.
+
+.. raw:: html
+
+  <details><summary>TODO 5-6: Click to show/hide answer</summary>
+
+.. literalinclude:: Step8/MathFunctions/MakeTable/CMakeLists.txt
+  :caption: TODO 5-6: MathFunctions/MakeTable/CMakeLists.txt
+  :name: MathFunctions/MakeTable/CMakeLists.txt-add_library
+  :language: cmake
+  :start-at: add_library
+  :end-at: SqrtTable.h
+  :append: )
+
+.. raw:: html
+
+  </details>
+
+Now that all the targets are described, we can force the custom target to run
+before any dependents of the interface library by associating them with
+:command:`add_dependencies`.
+
+.. raw:: html
+
+  <details><summary>TODO 7: Click to show/hide answer</summary>
+
+.. literalinclude:: Step8/MathFunctions/MakeTable/CMakeLists.txt
+  :caption: TODO 7: MathFunctions/MakeTable/CMakeLists.txt
+  :name: MathFunctions/MakeTable/CMakeLists.txt-add_dependencies
+  :language: cmake
+  :start-at: add_dependencies
+  :end-at: add_dependencies
+
+.. raw:: html
+
+  </details>
+
+We are ready to add the interface library to the linked libraries of
+``MathFunctions``, and add the entire ``MakeTable`` folder to the project.
+
+.. raw:: html
+
+  <details><summary>TODO 8-9: Click to show/hide answer</summary>
+
+.. literalinclude:: Step8/MathFunctions/CMakeLists.txt
+  :caption: TODO 8: MathFunctions/CMakeLists.txt
+  :name: MathFunctions/CMakeLists.txt-link-sqrttable
+  :language: cmake
+  :start-at: target_link_libraries(MathFunctions
+  :end-at: )
+
+.. literalinclude:: Step8/MathFunctions/CMakeLists.txt
+  :caption: TODO 9: MathFunctions/CMakeLists.txt
+  :name: MathFunctions/CMakeLists.txt-add-maketable
+  :language: cmake
+  :start-at: add_subdirectory(MakeTable
+  :end-at: add_subdirectory(MakeTable
+
+.. raw:: html
+
+  </details>
+
+Finally, we update the ``MathFunctions`` library itself to take advantage of
+the generated table.
+
+.. raw:: html
+
+  <details><summary>TODO 10: Click to show/hide answer</summary>
+
+.. literalinclude:: Step8/MathFunctions/MathFunctions.cxx
+  :caption: TODO 10: MathFunctions/MathFunctions.cxx
+  :name: MathFunctions/MathFunctions.cxx-include-sqrttable
+  :language: c++
+  :start-at: #include <SqrtTable.h>
+  :end-at: {
+
+.. raw:: html
+
+  </details>

+ 529 - 0
Help/guide/tutorial/Finding Dependencies.rst

@@ -0,0 +1,529 @@
+Step 10: Finding Dependencies
+=============================
+
+In C/C++ software development, managing build dependencies is consistently
+one of the highest ranked challenges facing modern developers. CMake provides
+an extensive toolset for discovering and validating dependencies of different
+kinds.
+
+However, for correctly packaged projects there is no need to use these advanced
+tools. Many popular library and utility projects today produce correct install
+trees, like the one we set up in ``Step 9``, which are easy is to integrate
+into CMake.
+
+In this best-case scenario, we only need the :command:`find_package` to
+import dependencies into our project.
+
+Background
+^^^^^^^^^^
+
+There are five principle commands used for discovering dependencies with
+CMake, the first four are:
+
+  :command:`find_file`
+    Finds and reports the full path to a named file, this tends to be the
+    most flexible of the ``find`` commands.
+
+  :command:`find_library`
+    Finds and reports the full path to a static archive or shared object
+    suitable for use with :command:`target_link_libraries`.
+
+  :command:`find_path`
+    Finds and reports the full path to a directory *containing* a file. This
+    is most commonly used for headers in combination with
+    :command:`target_include_directories`.
+
+  :command:`find_program`
+    Finds and reports and invocable name or path for a program. Often used in
+    combination with :command:`execute_process` or :command:`add_custom_command`.
+
+These commands should be considered "backup", used when the primary find command
+is unsuitable. The primary find command is :command:`find_package`. It uses
+comprehensive built-in heuristics and upstream-provided packaging files to
+provide the best interface to the requested dependency.
+
+Exercise 1 - Using ``find_package()``
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The search paths and behaviors used by :command:`find_package` are fully
+described in its documentation, but much too verbose to replicate here. Suffice
+to say it searches well known, lesser known, obscure, and user-provided
+locations attempting to find a package which meets the requirements given to it.
+
+.. code-block:: cmake
+
+  find_package(ForeignLibrary)
+
+The best way to use :command:`find_package` is to ensure all dependencies have
+been installed to a single install tree prior to the build, and then make the
+location of that install tree known to :command:`find_package` via the
+:variable:`CMAKE_PREFIX_PATH` variable.
+
+.. note::
+  Building and installing dependencies can itself be an immense amount of labor.
+  While this tutorial will do so for illustration purposes, it is **extremely**
+  recommended that a package manager be used for project-local dependency
+  management.
+
+:command:`find_package` accepts several parameters besides the package to be
+found. The most notable are:
+
+* A positional ``<version>`` argument, for describing a version to be checked
+  against the package's config version file. This should be used sparingly,
+  it is better to control the version of the dependency being installed via
+  a package manager than possibly break the build on otherwise innocuous
+  version updates.
+
+  If the package is known to rely on an older version of a dependency, it
+  may be appropriate to use a version requirement.
+
+* ``REQUIRED`` for non-optional dependencies which should abort the build
+  if not found.
+
+* ``QUIET`` for optional dependencies which should not report anything to
+  users when not found.
+
+:command:`find_package` reports its results via ``<PackageName>_FOUND``
+variables, which will be set to a true or false value for found and not found
+packages respectively.
+
+Goal
+----
+
+Integrate an externally installed test framework into the Tutorial project.
+
+Helpful Resources
+-----------------
+
+* :command:`find_package`
+* :command:`target_link_libraries`
+
+Files to Edit
+-------------
+
+* ``TutorialProject/CMakePresets.json``
+* ``TutorialProject/Tests/CMakeLists.txt``
+* ``TutorialProject/Tests/TestMathFunctions.cxx``
+
+Getting Started
+---------------
+
+The ``Step10`` folder is organized differently than previous steps. The tutorial
+project we need to edit is under ``Step10/TutorialProject``. Another project
+is now present, ``SimpleTest``, as well as a partially populated install tree
+which we will use in later exercises. You do not need to edit anything in these
+other directories for this exercise, all ``TODOs`` and solution steps are for
+``TutorialProject``.
+
+The ``SimpleTest`` package provides two useful constructs, the
+``SimpleTest::SimpleTest`` target to be linked into a test binary, and the
+``simpletest_discover_tests`` function for automatically adding tests to
+CTest.
+
+Similar to other test frameworks, ``simpletest_discover_tests`` only needs
+to be passed the name of the executable target containing the tests.
+
+.. code-block:: cmake
+
+  simpletest_discover_tests(MyTestExe)
+
+The ``TestMathFunctions.cxx`` file has been updated to use the ``SimpleTest``
+framework in the vein of GoogleTest or Catch2. Perform ``TODO 1`` through
+``TODO 5`` in order to use the new test framework.
+
+.. note::
+  It may go without saying, but ``SimpleTest`` is a very poor test framework
+  which only facially resembles a functional testing library. While much of
+  the CMake code in this tutorial could be used unaltered in other projects,
+  you should not use ``SimpleTest`` outside this tutorial, or try to learn from
+  the CMake code it provides.
+
+Build and Run
+-------------
+
+First we must install the ``SimpleTest`` framework. Navigate to the
+``Help/guide/Step10/SimpleTest`` directory and run the following commands
+
+.. code-block:: console
+
+  cmake --preset tutorial
+  cmake --install build
+
+.. note::
+  The ``SimpleTest`` preset sets up everything needed to install ``SimpleTest``
+  for the tutorial. For reasons that are beyond the scope of this tutorial,
+  there is no need to build or provide any other configuration for
+  ``SimpleTest``.
+
+We can observe that the ``Step10/install`` directory has now been populated by
+the ``SimpleTest`` header and package files.
+
+Now we can configure and build the Tutorial project as per usual, navigating to
+the ``Help/guide/Step10/TutorialProject`` and running:
+
+.. code-block:: console
+
+  cmake --preset tutorial
+  cmake --build build
+
+Verify that the ``SimpleTest`` framework has been consumed correctly by running
+the tests with CTest.
+
+Solution
+--------
+
+First we call :command:`find_package` to discover the ``SimpleTest`` package.
+We do this with ``REQUIRED`` because the tests cannot build without
+``SimpleTest``.
+
+.. raw:: html
+
+  <details><summary>TODO 1 Click to show/hide answer</summary>
+
+.. literalinclude:: Step11/TutorialProject/Tests/CMakeLists.txt
+  :caption: TODO 1: TutorialProject/Tests/CMakeLists.txt
+  :name: TutorialProject/Tests/CMakeLists.txt-find_package
+  :language: cmake
+  :start-at: find_package
+  :end-at: find_package
+
+.. raw:: html
+
+  </details>
+
+Next we add the ``SimpleTest::SimpleTest`` target to ``TestMathFunctions``
+
+.. raw:: html
+
+  <details><summary>TODO 2 Click to show/hide answer</summary>
+
+.. literalinclude:: Step11/TutorialProject/Tests/CMakeLists.txt
+  :caption: TODO 2: TutorialProject/Tests/CMakeLists.txt
+  :name: TutorialProject/Tests/CMakeLists.txt-link-simple-test
+  :language: cmake
+  :start-at: target_link_libraries(TestMathFunctions
+  :end-at: )
+
+.. raw:: html
+
+  </details>
+
+Now we can replace our test description code with a call to
+``simpletest_discover_tests``.
+
+.. raw:: html
+
+  <details><summary>TODO 3 Click to show/hide answer</summary>
+
+.. literalinclude:: Step11/TutorialProject/Tests/CMakeLists.txt
+  :caption: TODO 3: TutorialProject/Tests/CMakeLists.txt
+  :name: TutorialProject/Tests/CMakeLists.txt-simpletest_discover_tests
+  :language: cmake
+  :start-at: simpletest_discover_tests
+  :end-at: simpletest_discover_tests
+
+.. raw:: html
+
+  </details>
+
+We ensure :command:`find_package` can discover ``SimpleTest`` by
+adding the install tree to :variable:`CMAKE_PREFIX_PATH`.
+
+.. raw:: html
+
+  <details><summary>TODO 4 Click to show/hide answer</summary>
+
+.. literalinclude:: Step11/TutorialProject/CMakePresets.json
+  :caption: TODO 4: TutorialProject/CMakePresets.json
+  :name: TutorialProject/CMakePresets.json-CMAKE_PREFIX_PATH
+  :language: json
+  :start-at: cacheVariables
+  :end-at: TUTORIAL_ENABLE_IPO
+  :dedent: 6
+  :append: }
+
+.. raw:: html
+
+  </details>
+
+Finally, we update the tests to use the macros provided by ``SimpleTest`` by
+removing the placeholders and including the appropriate header.
+
+.. raw:: html
+
+  <details><summary>TODO 5 Click to show/hide answer</summary>
+
+.. literalinclude:: Step11/TutorialProject/Tests/TestMathFunctions.cxx
+  :caption: TODO 5: TutorialProject/Tests/TestMathFunctions.cxx
+  :name: TutorialProject/Tests/TestMathFunctions.cxx-simpletest
+  :language: c++
+  :start-at: #include <MathFunctions.h>
+  :end-at: {
+
+.. raw:: html
+
+  </details>
+
+Exercise 2 - Transitive Dependencies
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Libraries often build on one another. A multimedia application may depend on a
+library which provides support for various container formats, which may in turn
+rely on one or more other libraries for compression algorithms.
+
+We need to express these transitive requirements inside the package config
+files we place in the install tree. We do so with the
+:module:`CMakeFindDependencyMacro` module, which provides a safe mechanism for
+installed packages to recursively discover one another.
+
+.. code-block:: cmake
+
+  include(CMakeFindDependencyMacro)
+  find_dependency(zlib)
+
+:module:`find_dependency() <CMakeFindDependencyMacro>` also forwards arguments
+from the top-level :command:`find_package` call. If :command:`find_package` is
+called with ``QUIET`` or ``REQUIRED``,
+:module:`find_dependency() <CMakeFindDependencyMacro>` will also use ``QUIET``
+and/or ``REQUIRED``.
+
+Goal
+----
+
+Add a dependency to ``SimpleTest`` and ensure that packages which rely on
+``SimpleTest`` also discover this transitive dependency.
+
+Helpful Resources
+-----------------
+
+* :module:`CMakeFindDependencyMacro`
+* :command:`find_package`
+* :command:`target_link_libraries`
+
+Files to Edit
+-------------
+
+* ``SimpleTest/CMakeLists.txt``
+* ``SimpleTest/cmake/SimpleTestConfig.cmake``
+
+Getting Started
+---------------
+
+For this step we will only be editing the ``SimpleTest`` project. The transitive
+dependency, ``TransitiveDep``, is a dummy dependency which provides no behavior.
+However CMake doesn't know this and the ``TutorialProject`` tests will fail to
+configure and build if CMake cannot find all required dependencies.
+
+The ``TransitiveDep`` package has already been installed to the
+``Step10/install`` tree. We do not need to install it as we did with
+``SimpleTest``.
+
+Complete ``TODO 6`` through ``TODO 8``.
+
+Build and Run
+-------------
+
+We need to reinstall the SimpleTest framework. Navigate to the
+``Help/guide/Step10/SimpleTest`` directory and run the same commands as before.
+
+.. code-block:: console
+
+  cmake --preset tutorial
+  cmake --install build
+
+Now we can reconfigure and rebuild the ``TutorialProject``, navigate to
+``Help/guide/Step10/TutorialProject`` and perform the usual steps to do so.
+
+.. code-block:: console
+
+  cmake --preset tutorial
+  cmake --build build
+
+If the build passed we have likely successfully propagated the transitive
+dependency. Verify this by searching the ``CMakeCache.txt`` of
+``TutorialProject`` for an entry named ``TransitiveDep_DIR``. This demonstrates
+the ``TutorialProject`` searched for an found ``TransitiveDep`` even though it
+has no direct requirement for it.
+
+Solution
+--------
+
+First we call :command:`find_package` to discover the ``TransitiveDep`` package.
+We use ``REQUIRED`` to verify we have found ``TransitiveDep``.
+
+.. raw:: html
+
+  <details><summary>TODO 6 Click to show/hide answer</summary>
+
+.. literalinclude:: Step11/SimpleTest/CMakeLists.txt
+  :caption: TODO 6: SimpleTest/CMakeLists.txt
+  :name: SimpleTest/CMakeLists.txt-find_package
+  :language: cmake
+  :start-at: find_package
+  :end-at: find_package
+
+.. raw:: html
+
+  </details>
+
+Next we add the ``TransitiveDep::TransitiveDep`` target to ``SimpleTest``.
+
+.. raw:: html
+
+  <details><summary>TODO 7 Click to show/hide answer</summary>
+
+.. literalinclude:: Step11/SimpleTest/CMakeLists.txt
+  :caption: TODO 7: SimpleTest/CMakeLists.txt
+  :name: SimpleTest/CMakeLists.txt-link-transitive-dep
+  :language: cmake
+  :start-at: target_link_libraries(SimpleTest
+  :end-at: )
+
+.. raw:: html
+
+  </details>
+
+.. note::
+  If we built ``TutorialProject`` at this point, we would expect the
+  configuration to fail due to the ``TransitiveDep::TransitiveDep`` target
+  being unavailable inside that project.
+
+Finally, we include the :module:`CMakeFindDependencyMacro` and call
+:module:`find_dependency() <CMakeFindDependencyMacro>` inside the ``SimpleTest``
+package config file to propagate the transitive dependency.
+
+.. raw:: html
+
+  <details><summary>TODO 8 Click to show/hide answer</summary>
+
+.. literalinclude:: Step11/SimpleTest/cmake/SimpleTestConfig.cmake
+  :caption: TODO 8: SimpleTest/cmake/SimpleTestConfig.cmake
+  :name: SimpleTest/cmake/SimpleTestConfig.cmake-find_dependency
+  :language: cmake
+  :start-at: include
+  :end-at: find_dependency
+
+.. raw:: html
+
+  </details>
+
+  </details>
+
+Exercise 3 - Finding Other Kinds of Files
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In a perfect world every dependency we care about would be packaged correctly,
+or at least some other developer would have written a module that discovers it
+for us. We do no live in a perfect world, and sometimes we will have to get
+our hands dirty and discover build requirements manually.
+
+For this we have the other find commands enumerated earlier in the step, such
+as :command:`find_path`.
+
+.. code-block:: cmake
+
+  find_path(PackageIncludeFolder Package.h REQUIRED
+    PATH_SUFFIXES
+      Package
+  )
+  target_include_directories(MyApp
+    PRIVATE
+      ${PackageIncludeFolder}
+  )
+
+Goal
+----
+
+Add an unpackaged header to the ``Tutorial`` executable of the
+``TutorialProject``.
+
+Helpful Resources
+-----------------
+
+* :command:`find_path`
+* :command:`target_include_directories`
+
+Files to Edit
+-------------
+
+* ``TutorialProject/Tutorial/CMakeLists.txt``
+* ``TutorialProject/Tutorial/Tutorial.cxx``
+
+Getting Started
+---------------
+
+For this step we will only be editing the ``TutorialProject`` project. The
+unpackaged header, ``Unpackaged/Unpackaged.h`` has already been installed to the
+``Step10/install`` tree.
+
+Complete ``TODO 9`` through ``TODO 11``.
+
+Build and Run
+-------------
+
+There are no special build steps for this exercise, navigate to
+``Help/guide/Step10/TutorialProject`` and perform the usual build.
+
+.. code-block:: console
+
+  cmake --build build
+
+If the build passed we have successfully added the ``Unpackaged`` include
+directory to the project.
+
+Solution
+--------
+
+First we call :command:`find_path` to discover the ``Unpackaged`` include
+directory. We use ``REQUIRED`` because building ``Tutorial`` will fail if
+we cannot locate the ``Unpackaged.h`` header.
+
+.. raw:: html
+
+  <details><summary>TODO 9 Click to show/hide answer</summary>
+
+.. literalinclude:: Step11/TutorialProject/Tutorial/CMakeLists.txt
+  :caption: TODO 9: TutorialProject/Tutorial/CMakeLists.txt
+  :name: TutorialProject/Tutorial/CMakeLists.txt-find_path
+  :language: cmake
+  :start-at: find_path
+  :end-at: )
+
+.. raw:: html
+
+  </details>
+
+Next we add the discovered path to ``Tutorial`` using
+:command:`target_include_directories`.
+
+.. raw:: html
+
+  <details><summary>TODO 10 Click to show/hide answer</summary>
+
+.. literalinclude:: Step11/TutorialProject/Tutorial/CMakeLists.txt
+  :caption: TODO 10: TutorialProject/Tutorial/CMakeLists.txt
+  :name: TutorialProject/Tutorial/CMakeLists.txt-target_include_directories
+  :language: cmake
+  :start-at: target_include_directories
+  :end-at: )
+
+.. raw:: html
+
+  </details>
+
+Finally, we edit ``Tutorial.cxx`` to include the discovered header.
+
+.. raw:: html
+
+  <details><summary>TODO 11 Click to show/hide answer</summary>
+
+.. literalinclude:: Step11/TutorialProject/Tutorial/Tutorial.cxx
+  :caption: TODO 11: TutorialProject/Tutorial/Tutorial.cxx
+  :name: TutorialProject/Tutorial/Tutorial.cxx-include-unpackaged
+  :language: c++
+  :start-at: #include <MathFunctions.h>
+  :end-at: #include <Unpackaged.h>
+
+.. raw:: html
+
+  </details>

+ 805 - 0
Help/guide/tutorial/Getting Started with CMake.rst

@@ -0,0 +1,805 @@
+Step 1: Getting Started with CMake
+==================================
+
+This first step in the CMake tutorial is intended as a quick-start into writing
+useful builds for small projects with CMake. By the end, you will be able to
+describe executables, libraries, source and header files, and the linkage
+relationships between them using CMake.
+
+Each exercise in this step will start with a discussion of the concepts and
+commands needed for the exercise. Then, a goal and list of helpful resources are
+provided. Each file in the ``Files to Edit`` section is in the ``Step1``
+directory and contains one or more ``TODO`` comments. Each ``TODO`` represents
+a line or two of code to change or add. The ``TODOs`` are intended to be
+completed in numerical order, first complete  ``TODO 1`` then ``TODO 2``, etc.
+
+.. note::
+  Each step in the tutorial builds on the previous, but the steps are not
+  strictly contiguous. Code not relevant to learning CMake, such as C++
+  function implementations or CMake code outside the scope of the tutorial,
+  will sometimes be added between steps.
+
+The ``Getting Started`` section will give some helpful hints and guide you
+through the exercise. Then the ``Build and Run`` section will walk step-by-step
+through how to build and test the exercise. Finally, at the end of each exercise
+the intended solution is reviewed.
+
+Background
+^^^^^^^^^^
+
+Typical usage of CMake revolves around one or more files named
+``CMakeLists.txt``. This file is sometimes referred to as a "lists file" or
+"CML". Within a given software project, a ``CMakeLists.txt`` will exist within
+any directory where we want to provide instructions to CMake on how to handle
+files and operations local to that directory or subdirectories. Each consists of
+a set of commands which describe some information or actions relevant to
+building the software project.
+
+Not every directory in a software project needs a CML, but it's strongly
+recommended that the project root contains one. This will serve as the entry
+point for CMake for its initial setup during configuration. This *root* CML
+should always contain the same two commands at or near the top the file.
+
+.. code-block:: cmake
+
+  cmake_minimum_required(VERSION 3.23)
+
+  project(MyProjectName)
+
+The :command:`cmake_minimum_required` is a compatibility guarantee provided by
+CMake to the project developer. When called, it ensures that CMake will adopt
+the behavior of the listed version. If a later version of CMake is invoked on a
+CML containing the above code, it will act exactly as if it were CMake 3.23.
+
+The :command:`project` command is a conceptually simple command which provides a
+complex function. It informs CMake that what follows is the description of a
+distinct software project of a given name (as opposed to a shell-like script).
+When CMake sees the :command:`project` command it performs various checks to
+ensure the environment is suitable for building software; such as checking for
+compilers and other build tooling, and discovering properties like the
+endianness of the host and target machines.
+
+.. note::
+  While links to complete documentation are provided for every command, it is
+  not intended the reader understand the full semantics of each CMake command
+  they use. Effectively learning CMake, like any piece of software, is an
+  incremental process.
+
+The rest of this tutorial step will be chiefly concerned with the usage of four
+more commands. The :command:`add_executable` and :command:`add_library` commands
+for describing output artifacts the software project wants to produce, the
+:command:`target_sources` command for associating input files with their
+respective output artifacts, and the :command:`target_link_libraries` command
+for associating output artifacts with one another.
+
+These four commands are the backbone of most CMake usage. As we'll learn, they
+are sufficient for describing the majority of a typical project's requirements.
+
+Exercise 1 - Building an Executable
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The most basic CMake project is an executable built from a single source code
+file. For simple projects like this, a ``CMakeLists.txt`` file with only
+four commands is needed.
+
+.. note::
+  Although upper, lower and mixed case commands are supported by CMake,
+  lower case commands are preferred and will be used throughout the tutorial.
+
+The first two commands we have already introduced, :command:`cmake_minimum_required`
+and :command:`project`. There is no usage of CMake where the first command in a
+root CML will be anything other than :command:`cmake_minimum_required`. There
+are some advanced usages where :command:`project` might not be the second
+command in a CML, but for our purposes it always will be.
+
+The next command we need is :command:`add_executable`.
+This command creates a *target*. In CMake lingo, a target is a name the
+developer gives to a collection of properties.
+
+Some examples of properties a target might want to keep track of are:
+  - The artifact kind (executable, library, header collection, etc)
+  - Source files
+  - Include directories
+  - Output name of an executable or library
+  - Dependencies
+  - Compiler and linker flags
+
+The mechanisms of CMake are often best understood as describing and manipulating
+targets and their properties. There are many more properties than those listed
+here. Documentation of CMake commands will often discuss their function in terms
+of the target properties they operate on.
+
+Targets themselves are simply names, a handle to this collection of properties.
+Using the :command:`add_executable` command is as easy as specifying the name
+we want to use for the target.
+
+.. code-block:: cmake
+
+  add_executable(MyProgram)
+
+Now that we have a name for our target, we can start associating properties
+with it like source files we want to build and link. The primary command for
+this is :command:`target_sources`, which takes as arguments a target name
+followed by one or more collections of files.
+
+.. code-block:: cmake
+
+  target_sources(MyProgram
+    PRIVATE
+      main.cxx
+  )
+
+.. note::
+  Paths in CMake are generally either absolute, or relative to the
+  :variable:`CMAKE_CURRENT_SOURCE_DIR`. We haven't talked about variables like
+  that yet, so you can read this as "relative to the location of the current
+  CML".
+
+Each collection of files is prefixed by a :ref:`scope keyword <Target Command Scope>`.
+We'll discuss the complete semantics of these keywords when we talk about
+linking targets together, but the quick explanation is these describe how a
+property should be inherited by dependents of our target.
+
+Typically, nothing depends on an executable. Other programs and libraries don't
+need to link to an executable, or inherit headers, or anything of that nature.
+So the appropriate scope to use here is ``PRIVATE``, which informs CMake that
+this property only belongs to ``MyProgram`` and is not inheritable.
+
+.. note::
+  This rule is true almost everywhere. Outside advanced and esoteric usages,
+  the scope keyword for executables should *always* be ``PRIVATE``. The same
+  holds for implementation files generally, regardless of whether the target
+  is an executable or a library. The only target which needs to "see" the
+  ``.cxx`` files is the target building them.
+
+Goal
+----
+
+Understand how to create a simple CMake project with a single executable.
+
+Helpful Resources
+-----------------
+
+* :command:`project`
+* :command:`cmake_minimum_required`
+* :command:`add_executable`
+* :command:`target_sources`
+
+Files to Edit
+-------------
+
+* ``CMakeLists.txt``
+
+Getting Started
+----------------
+
+The source code for ``Tutorial.cxx`` is provided in the
+``Help/guide/tutorial/Step1/Tutorial`` directory and can be used to compute the
+square root of a number. This file does not need to be edited in this exercise.
+
+In the parent directory, ``Help/guide/tutorial/Step1``, is a ``CMakeLists.txt``
+file which you will complete. Start with ``TODO 1`` and work through ``TODO 4``.
+
+Build and Run
+-------------
+
+Once ``TODO 1`` through ``TODO 4`` have been completed, we are ready to build
+and run our project! First, 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.
+
+For example, from the command line we could navigate to the
+``Help/guide/tutorial/Step1`` directory and invoke CMake for configuration
+as follows:
+
+.. code-block:: console
+
+  cmake -B build
+
+The :option:`-B <cmake -B>` flag tells CMake to use the given relative
+path as the location to generate files and store artifacts during the build
+process. If it is omitted, the current working directory is used. It is
+generally considered bad practice to do "in-source" builds, placing these
+generated files in the source tree itself.
+
+Next, tell CMake to build the project with
+:option:`cmake --build <cmake --build>`, passing it the same relative path
+we did with the :option:`-B <cmake -B>` flag.
+
+.. code-block:: console
+
+  cmake --build build
+
+The ``Tutorial`` executable will be built into the ``build`` directory. For
+multi-config generators (e.g. Visual Studio), it might be placed in a
+subdirectory such as ``build/Debug``.
+
+Finally, try to use the newly built ``Tutorial``:
+
+.. code-block:: console
+
+  Tutorial 4294967296
+  Tutorial 10
+  Tutorial
+
+.. note::
+  Depending on the shell, the correct syntax may be ``Tutorial``,
+  ``./Tutorial``, ``.\Tutorial``, or even ``.\Tutorial.exe``. For simplicity,
+  the exercises will use ``Tutorial`` throughout.
+
+Solution
+--------
+
+As mentioned above, a four command ``CMakeLists.txt`` is all that we need to get
+up and running. The first line should be :command:`cmake_minimum_required`, to
+set the CMake version as follows:
+
+.. raw:: html
+
+  <details><summary>TODO 1: Click to show/hide answer</summary>
+
+.. literalinclude:: Step3/CMakeLists.txt
+  :caption: TODO 1: CMakeLists.txt
+  :name: CMakeLists.txt-cmake_minimum_required
+  :language: cmake
+  :start-at: cmake_minimum_required
+  :end-at: cmake_minimum_required
+
+.. raw:: html
+
+  </details>
+
+The next step to make a basic project is to use the :command:`project`
+command as follows to set the project name and inform CMake we intend to build
+software with this ``CMakeLists.txt``.
+
+.. raw:: html
+
+  <details><summary>TODO 2: Click to show/hide answer</summary>
+
+.. literalinclude:: Step3/CMakeLists.txt
+  :caption: TODO 2: CMakeLists.txt
+  :name: CMakeLists.txt-project
+  :language: cmake
+  :start-at: project
+  :end-at: project
+
+.. raw:: html
+
+  </details>
+
+Now we can setup our executable target for the Tutorial with :command:`add_executable`.
+
+.. raw:: html
+
+  <details><summary>TODO 3: Click to show/hide answer</summary>
+
+.. literalinclude:: Step3/Tutorial/CMakeLists.txt
+  :caption: TODO 3: CMakeLists.txt
+  :name: CMakeLists.txt-add_executable
+  :language: cmake
+  :start-at: add_executable
+  :end-at: add_executable
+
+.. raw:: html
+
+  </details>
+
+Finally, we can associate our source file with the Tutorial executable target
+using :command:`target_sources`.
+
+.. raw:: html
+
+  <details><summary>TODO 4: Click to show/hide answer</summary>
+
+.. code-block:: cmake
+  :caption: TODO 4: CMakeLists.txt
+  :name: CMakeLists.txt-target_sources
+
+  target_sources(Tutorial
+    PRIVATE
+      Tutorial/Tutorial.cxx
+  )
+
+
+.. raw:: html
+
+  </details>
+
+Exercise 2 - Building a Library
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+We only need to introduce one more command to build a library,
+:command:`add_library`. This works exactly like :command:`add_executable`, but
+for libraries.
+
+.. code-block:: cmake
+
+  add_library(MyLibrary)
+
+However, now is a good time to introduce header files. Header files are not
+directly built as translation units, which is to say they are not a *build*
+requirement. They are a *usage* requirement. We need to know about header files
+in order to build other parts of a given target.
+
+As such, header files are described slightly differently than implementation
+files like ``tutorial.cxx``. They're also going to need different
+:ref:`scope keywords <Target Command Scope>` than the ``PRIVATE`` keyword we
+have used so far.
+
+To describe a collection of header files, we're going to use what's known as a
+``FILE_SET``.
+
+.. code-block:: cmake
+
+  target_sources(MyLibrary
+    PRIVATE
+      library_implementation.cxx
+
+    PUBLIC
+      FILE_SET MyHeaders
+      TYPE HEADERS
+      BASE_DIRS
+        include
+      FILES
+        include/library_header.h
+  )
+
+This is a lot of complexity, but we'll go through it point by point. First,
+note that we have our implementation file as a ``PRIVATE`` source, same as
+with the executable previously. However, we now use ``PUBLIC`` for our
+header file. This allows consumers of our library to "see" the library's
+header files.
+
+.. note::
+  We're not quite ready to discuss the full semantics of scope keywords. We'll
+  cover them more completely in Exercise 3.
+
+Following the scope keyword is a ``FILE_SET``, a collection of files to be
+described as a single unit. A ``FILE_SET`` consists of the following parts:
+
+* ``FILE_SET <name>`` is the name of the ``FILE_SET``. This is a handle which
+  we can use to describe the collection in other contexts.
+
+* ``TYPE <type>`` is the kind of files we are describing. Most commonly this
+  will be headers, but newer versions of CMake support other types like C++20
+  modules.
+
+* ``BASE_DIRS`` is the "base" locations for the files. This can be most easily
+  understood as the locations that will be described to compilers for header
+  discovery via ``-I`` flags.
+
+* ``FILES`` is the list of files, same as with the implementation sources list
+  earlier.
+
+This is a lot of information to describe, so there are some useful shortcuts
+we can take. Notably, if the ``FILE_SET`` name is the same as the type, we
+don't need to provide the ``TYPE`` field.
+
+.. code-block:: cmake
+
+  target_sources(MyLibrary
+    PRIVATE
+      library_implementation.cxx
+
+    PUBLIC
+      FILE_SET HEADERS
+      BASE_DIRS
+        include
+      FILES
+        include/library_header.h
+  )
+
+There are other shortcuts we can take, but we'll discuss those more in later
+steps.
+
+Goal
+----
+
+Build a library.
+
+Helpful Resources
+-----------------
+
+* :command:`add_library`
+* :command:`target_sources`
+
+Files to Edit
+-------------
+
+* ``CMakeLists.txt``
+
+Getting Started
+---------------
+
+Continue editing files in the ``Step1`` directory. Start with ``TODO 5`` and
+complete through ``TODO 6``.
+
+Build and Run
+-------------
+
+Let's build our project again. Since we already created a build directory and
+ran CMake for Exercise 1, we can skip to the build step:
+
+.. code-block:: console
+
+  cmake --build build
+
+We should be able to see our library created alongside the Tutorial executable.
+
+Solution
+--------
+
+We start by adding the library target in the same manner as the the Tutorial
+executable.
+
+.. raw:: html
+
+  <details><summary>TODO 5: Click to show/hide answer</summary>
+
+.. literalinclude:: Step3/MathFunctions/CMakeLists.txt
+  :caption: TODO 5: CMakeLists.txt
+  :name: CMakeLists.txt-add_library
+  :language: cmake
+  :start-at: add_library
+  :end-at: add_library
+
+.. raw:: html
+
+  </details>
+
+Next we need to describe the source files. For the implementation file,
+``MathFunctions.cxx``, this is straight-forward; for the header file
+``MathFunctions.h`` we will need to use a ``FILE_SET``.
+
+We can either give this ``FILE_SET`` its own name, or use the shortcut of naming
+it ``HEADERS``. For this tutorial, we'll be using the shortcut, but either
+solution is valid.
+
+For ``BASE_DIRS`` we need to determine the directory which will allow for the
+desired ``#include <MathFunctions.h>`` directive. To achieve this, the
+``MathFunctions`` folder itself will be a base directory. We would make a
+different choice if the desired include directive were
+``#include <MathFunctions/MathFunctions.h>`` or similar.
+
+.. raw:: html
+
+  <details><summary>TODO 6: Click to show/hide answer</summary>
+
+.. code-block:: cmake
+  :caption: TODO 6: CMakeLists.txt
+  :name: CMakeLists.txt-library_sources
+
+  target_sources(MathFunctions
+    PRIVATE
+      MathFunctions/MathFunctions.cxx
+
+    PUBLIC
+      FILE_SET HEADERS
+      BASE_DIRS
+        MathFunctions
+      FILES
+        MathFunctions/MathFunctions.h
+  )
+
+.. raw:: html
+
+  </details>
+
+Exercise 3 - Linking Together Libraries and Executables
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+We're ready to combine our library with our executable, for this we must
+introduce a new command, :command:`target_link_libraries`. The name of this
+command can be somewhat misleading, as it does a great deal more than just
+invoke linkers. It describes relationships between targets generally.
+
+.. code-block:: cmake
+
+  target_link_libraries(MyProgram
+    PRIVATE
+      MyLibrary
+  )
+
+We're finally ready to discuss the :ref:`scope keywords <Target Command Scope>`.
+There are three of them, ``PRIVATE``, ``INTERFACE``, and ``PUBLIC``. These
+describe how properties are made available to targets.
+
+* A ``PRIVATE`` property (also called a "non-interface" property) is only
+  available to the target which owns it, for example ``PRIVATE`` headers will
+  only be visible to the target they're attached to.
+
+* An ``INTERFACE`` property is only available to targets *which link* the
+  owning target. The owning target does not have access to these properties. A
+  header-only library is an example of a collection of ``INTERFACE`` properties,
+  as header-only libraries do not build anything themselves and do not need to
+  access their own files.
+
+* ``PUBLIC`` is not a distinct kind of property, but rather is the union of the
+  ``PRIVATE`` and ``INTERFACE`` properties. Thus requirements described with
+  ``PUBLIC`` are available to both the owning target and consuming targets.
+
+Consider the following concrete example:
+
+.. code-block:: cmake
+
+  target_sources(MyLibrary
+    PRIVATE
+      FILE_SET InternalOnlyHeaders
+      TYPE HEADERS
+      FILES
+        InternalOnlyHeader.h
+
+    INTERFACE
+      FILE_SET ConsumerOnlyHeaders
+      TYPE HEADERS
+      FILES
+        ConsumerOnlyHeader.h
+
+    PUBLIC
+      FILE_SET PublicHeaders
+      TYPE HEADERS
+      FILES
+        PublicHeader.h
+  )
+
+.. note::
+  We excluded ``BASE_DIRS`` for each file set here, that's another shortcut.
+  When excluded, ``BASE_DIRS`` defaults to the current source directory.
+
+The ``MyLibrary`` target has several properties which will be modified by this
+call to :command:`target_sources`. Until now we've used the term "properties"
+generically, but properties are themselves named values we can reason about.
+Two specific properties which will be modified here are :prop_tgt:`HEADER_SETS`
+and :prop_tgt:`INTERFACE_HEADER_SETS`, which both contain lists of header file
+sets added via :command:`target_sources`.
+
+The value ``InternalOnlyHeaders`` will be added to :prop_tgt:`HEADER_SETS`,
+``ConsumerOnlyHeaders`` to :prop_tgt:`INTERFACE_HEADER_SETS`, and
+``PublicHeaders`` will be added to both.
+
+When a given target is being built, it will use its own *non-interface*
+properties (eg, :prop_tgt:`HEADER_SETS`), combined with the *interface*
+properties of any targets it links to (eg, :prop_tgt:`INTERFACE_HEADER_SETS`).
+
+.. note::
+  **It is not necessary to reason about CMake properties at this level of
+  detail.** The above is described for completeness. Most of the time you don't
+  need to be concerned with the specific properties a command is modifying.
+
+  Scope keywords have a simple intuition associated with them, when considering
+  a command from the point of view of the target it is being applied to:
+  **PRIVATE** is for me, **INTERFACE** is for others, **PUBLIC** is for all of
+  us.
+
+Goal
+----
+
+In the Tutorial executable, use the ``sqrt()`` function provided by the
+``MathFunctions`` library.
+
+Helpful Resources
+-----------------
+
+* :command:`target_link_libraries`
+
+Files to Edit
+-------------
+
+* ``CMakeLists.txt``
+* ``Tutorial/Tutorial.cxx``
+
+Getting Started
+---------------
+
+Continue to edit files from ``Step1``. Start on ``TODO 7`` and complete through
+``TODO 9``. In this exercise, we need to add the ``MathFunctions`` target to
+the ``Tutorial`` target's linked libraries using :command:`target_link_libraries`.
+
+After modifying the CML, update ``tutorial.cxx`` to use the
+``mathfunctions::sqrt()`` function instead of ``std::sqrt``.
+
+Build and Run
+-------------
+
+Let's build our project again. As before, we already created a build directory
+and ran CMake so we can skip to the build step:
+
+.. code-block:: console
+
+  cmake --build build
+
+Verify that the output matches what you would expect from the ``MathFunctions``
+library.
+
+Solution
+--------
+
+In this exercise, we are describing the ``Tutorial`` executable as a consumer
+of the ``MathFunctions`` target by adding ``MathFunctions`` to the linked
+libraries of the ``Tutorial``.
+
+To achieve this, we modify ``CMakeLists.txt`` file to use the
+:command:`target_link_libraries` command, using ``Tutorial`` as the target to
+be modified and ``MathFunctions`` as the library we want to add.
+
+.. raw:: html
+
+  <details><summary>TODO 7: Click to show/hide answer</summary>
+
+.. literalinclude:: Step3/Tutorial/CMakeLists.txt
+  :caption: TODO 7: CMakeLists.txt
+  :name: CMakeLists.txt-target_link_libraries
+  :language: cmake
+  :start-at: target_link_libraries(Tutorial
+  :end-at: )
+
+.. raw:: html
+
+  </details>
+
+.. note::
+  The order here is only loosely relevant. That we call
+  :command:`target_link_libraries` prior to defining ``MathFunctions`` with
+  :command:`add_library` doesn't matter to CMake. We are recording that
+  ``Tutorial`` has a dependency on something named ``MathFunctions``, but what
+  ``MathFunctions`` means isn't resolved at this stage.
+
+  The only target which needs to be defined when calling a CMake command like
+  :command:`target_sources` or :command:`target_link_libraries` is the target
+  being modified.
+
+Finally, all that's left to do is modify ``Tutorial.cxx`` to use the newly
+provided ``mathfunctions::sqrt`` function. That means adding the appropriate
+header file and modifying our ``sqrt()`` call.
+
+.. raw:: html
+
+  <details><summary>TODO 8-9: Click to show/hide answer</summary>
+
+.. literalinclude:: Step3/Tutorial/Tutorial.cxx
+  :caption: TODO 8: Tutorial/Tutorial.cxx
+  :name: Tutorial/Tutorial.cxx-MathFunctions-headers
+  :language: c++
+  :start-at: iostream
+  :end-at: MathFunctions.h
+
+.. literalinclude:: Step3/Tutorial/Tutorial.cxx
+  :caption: TODO 9: Tutorial/Tutorial.cxx
+  :name: Tutorial/Tutorial.cxx-MathFunctions-code
+  :language: c++
+  :start-at: calculate square root
+  :end-at: mathfunctions::sqrt
+  :dedent: 2
+
+.. raw:: html
+
+  </details>
+
+Exercise 4 - Subdirectories
+^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+As we move through the tutorial, we will be adding more commands to manipulate
+the ``Tutorial`` executable and the ``MathFunctions`` library. We want to make
+sure we keep commands local to the files they are dealing with. While not a
+major concern for a small project like this, it can be very useful for large
+projects with many targets and thousands of files.
+
+The :command:`add_subdirectory` command allows us to incorporate CMLs located
+in subdirectories of the project.
+
+.. code-block:: cmake
+
+  add_subdirectory(SubdirectoryName)
+
+When a ``CMakeLists.txt`` in a subdirectory is being processed by CMake all
+relative paths described in the subdirectory CML are relative to that
+subdirectory, not the top-level CML.
+
+Goal
+----
+
+Use :command:`add_subdirectory` to organize the project.
+
+Helpful Resources
+-----------------
+
+* :command:`add_subdirectory`
+
+Files to Edit
+-------------
+
+* ``CMakeLists.txt``
+* ``Tutorial/CMakeLists.txt``
+* ``MathFunctions/CMakeLists.txt``
+
+Getting Started
+---------------
+
+The ``TODOs`` for this step are spread across three ``CMakeLists.txt`` files.
+Be sure to pay attention to the path changes necessary when moving the
+:command:`target_sources` commands into subdirectories.
+
+.. note::
+  Previously we said that ``BASE_DIRS`` defaults to the current source
+  directory. As the desired include directory for ``MathFunctions`` will now be
+  the same directory as the CML calling :command:`target_sources`, we should
+  remove the ``BASE_DIRS`` keyword and argument entirely.
+
+Complete ``TODO 10`` through ``TODO 13``.
+
+Build and Run
+-------------
+
+Because of the reorganization, we'll need to clean the original build
+directory prior to rebuilding (otherwise our new ``Target`` build folder would
+conflict with our previously created ``Target`` executable). We can achieve
+this with the :option:`--clean-first <cmake--build --clean-first>` flag.
+
+There's no need for a reconfiguration. CMake will automatically
+re-configure itself due to the changes in the CMLs.
+
+.. code-block:: console
+
+  cmake --build build --clean-first
+
+.. note::
+  Our executable and library will be output to a new location in the build tree.
+  A subdirectory which mirrors where :command:`add_executable` and
+  :command:`add_library` were called in the source tree. You will need to
+  navigate to this subdirectory in the build tree to run the tutorial
+  executable in future steps.
+
+  You can verify this behavior by deleting the old ``Tutorial`` executable,
+  and observing that the new one is produced at ``Tutorial/Tutorial``.
+
+Solution
+--------
+
+We need to move all the commands concerning the ``Tutorial`` executable into
+``Tutorial/CMakeLists.txt``, and replace them with an
+:command:`add_subdirectory` command. We also need to update the path for
+``Tutorial.cxx``.
+
+.. raw:: html
+
+  <details><summary>TODO 10-11: Click to show/hide answer</summary>
+
+.. literalinclude:: Step3/Tutorial/CMakeLists.txt
+  :caption: TODO 10: Tutorial/CMakeLists.txt
+  :name: Tutorial/CMakeLists.txt-moved
+  :language: cmake
+
+.. code-block:: cmake
+  :caption: TODO 11: CMakeLists.txt
+  :name: CMakeLists.txt-add_subdirectory-Tutorial
+
+  add_subdirectory(Tutorial)
+
+.. raw:: html
+
+  </details>
+
+We need to do the same with the commands for ``MathFunctions``, changing the
+relative paths as appropriate and removing ``BASE_DIRS`` as it is no longer
+necessary, the default value will work.
+
+.. raw:: html
+
+  <details><summary>TODO 12-13: Click to show/hide answer</summary>
+
+.. literalinclude:: Step3/MathFunctions/CMakeLists.txt
+  :caption: TODO 12: MathFunctions/CMakeLists.txt
+  :name: MathFunctions/CMakeLists.txt-moved
+  :language: cmake
+
+.. literalinclude:: Step3/CMakeLists.txt
+  :caption: TODO 13: CMakeLists.txt
+  :name: CMakeLists.txt-add_subdirectory-MathFunctions
+  :language: cmake
+  :start-at: add_subdirectory(MathFunctions
+  :end-at: add_subdirectory(MathFunctions
+
+.. raw:: html
+
+  </details>

+ 446 - 0
Help/guide/tutorial/In-Depth CMake Library Concepts.rst

@@ -0,0 +1,446 @@
+Step 5: In-Depth CMake Library Concepts
+=======================================
+
+While executables are mostly one-size-fits-all, libraries come in many
+different forms. There are static archives, shared objects, modules,
+object libraries, header-only libraries, and libraries which describe advanced
+CMake properties to be inherited by other targets, just to name a few.
+
+In this step you will learn about some of the most common kinds of libraries
+that CMake can describe. This will cover most of the in-project uses of
+:command:`add_library`. Libraries which are imported from dependencies (or
+exported by the project to be consumed as a dependency) will be covered in
+later steps.
+
+Background
+^^^^^^^^^^
+
+As we learned in ``Step1``, the :command:`add_library` command accepts the name
+of the library target to be created as its first argument. The second
+argument is an optional ``<type>`` for which the following values are valid:
+
+  ``STATIC``
+    A :ref:`Static Library <Static Libraries>`:
+    an archive of object files for use when linking other targets.
+
+  ``SHARED``
+    A :ref:`Shared Library <Shared Libraries>`:
+    a dynamic library that may be linked by other targets and loaded
+    at runtime.
+
+  ``MODULE``
+    A :ref:`Module Library <Module Libraries>`:
+    a plugin that may not be linked by other targets, but may be
+    dynamically loaded at runtime using dlopen-like functionality.
+
+  ``OBJECT``
+    An :ref:`Object Library <Object Libraries>`:
+    a collection of object files which have not been archived or linked
+    into a library.
+
+  ``INTERFACE``
+    An :ref:`Interface Library <Interface Libraries>`:
+    a library target which specifies usage requirements for dependents but
+    does not compile sources and does not produce a library artifact on disk.
+
+In addition, there are ``IMPORTED`` libraries which describe library targets
+from foreign projects or modules, imported into the current project. We will
+cover these briefly in later steps.
+
+``MODULE`` libraries are most commonly found in plugin systems, or as extensions
+to runtime-loading languages like Python or Javascript. They act very similar to
+normal shared libraries, except they cannot be directly linked by other targets.
+They are sufficiently similar that we won't cover them in further depth here.
+
+Exercise 1 - Static and Shared
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+While the :command:`add_library` command supports explicitly setting ``STATIC``
+or ``SHARED``, and this is sometimes necessary, it is best to leave the second
+argument empty for most "normal" libraries which can operate as either.
+
+When not given a type, :command:`add_library` will create either a ``STATIC``
+or ``SHARED`` library depending on the value of :variable:`BUILD_SHARED_LIBS`.
+If :variable:`BUILD_SHARED_LIBS` is true, a ``SHARED`` library will be created,
+otherwise it will be ``STATIC``.
+
+.. code-block:: cmake
+
+  add_library(MyLib-static STATIC)
+  add_library(MyLib-shared SHARED)
+
+  # Depends on BUILD_SHARED_LIBRARY
+  add_library(MyLib)
+
+This is desirable behavior, as it allows packagers to determine what kind of
+library will be produced, and ensure dependents link to that version of the
+library without needing to modify their source code. In some contexts, fully
+static builds are appropriate, and in others shared libraries are desirable.
+
+.. note::
+  CMake does not define the :variable:`BUILD_SHARED_LIBS` variable by default,
+  meaning without project or user intervention :command:`add_library` will
+  produce ``STATIC`` libraries.
+
+By leaving the second argument to :command:`add_library()` blank, projects
+provide additional flexibility to their packagers and downstream dependents.
+
+Goal
+----
+
+Build ``MathFunctions`` as a shared library.
+
+.. note::
+  On Windows, you might see warnings about an empty DLL, as ``MathFunctions``
+  doesn't export any symbols.
+
+Helpful Resources
+-----------------
+
+* :variable:`BUILD_SHARED_LIBS`
+
+Files to Edit
+-------------
+
+There are no files to edit.
+
+Getting Started
+---------------
+
+The ``Help/guide/tutorial/Step5`` directory contains the complete, recommended
+solution to ``Step4``. This step is about building the ``MathFunctions``
+library, there are no ``TODOs`` necessary. You can proceed directly to the
+build step.
+
+Build and Run
+-------------
+
+We can configure using our preset, turning on :variable:`BUILD_SHARED_LIBS` with
+a :option:`-D <cmake -D>` flag.
+
+.. code-block:: console
+
+  cmake --preset tutorial -DBUILD_SHARED_LIBS=ON
+
+Then we can build only the ``MathFunctions`` library with
+:option:`-t <cmake--build -t>`.
+
+.. code-block:: console
+
+  cmake --build build -t MathFunctions
+
+Verify a shared library is produced for ``MathFunctions`` then reset
+:variable:`BUILD_SHARED_LIBS`, either by reconfiguring with
+``-DBUILD_SHARED_LIBS=OFF`` or deleting the ``CMakeCache.txt``.
+
+Solution
+--------
+
+There are no changes to the project for this exercise.
+
+Exercise 2 - Interface Libraries
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Interface libraries are those which only communicate usage requirements for
+other targets, they do not build or produce any artifacts of their own. As such
+all the properties of an interface library must themselves be interface
+properties, specified with the ``INTERFACE`` :ref:`scope keywords <Target Command Scope>`.
+
+.. code-block:: cmake
+
+  add_library(MyInterface INTERFACE)
+  target_compile_definitions(MyInterface INTERFACE MYINTERFACE_COMPILE_DEF)
+
+The most common kind of interface library in C++ development is a header-only
+library. Such libraries do not build anything, only providing the flags
+necessary to discover their headers.
+
+Goal
+----
+
+Add a header-only library to the tutorial project, and use it inside the
+``Tutorial`` executable.
+
+Helpful Resources
+-----------------
+
+* :command:`add_library`
+* :command:`target_sources`
+
+Files to Edit
+-------------
+
+* ``MathFunctions/MathLogger/CMakeLists.txt``
+* ``MathFunctions/CMakeLists.txt``
+* ``MathFunctions/MathFunctions.cxx``
+
+Getting Started
+---------------
+
+In our previous discussions of :command:`target_sources(FILE_SET)`, we noted
+we can omit the ``TYPE`` parameter if the file set's name is the same as the
+file set's type. We also said we can omit the ``BASE_DIRS`` parameter if
+we want to use the current source directory as the only base directory.
+
+We're ready to introduce a third shortcut, we only need to include the ``FILES``
+parameter if the headers are intended to be installed, such as public headers
+of a library.
+
+The ``MathLogger`` headers in this exercise are only used internally by the
+``MathFunctions`` implementation. They will not be installed. This should
+make for a very abbreviated call to :command:`target_sources(FILE_SET)`.
+
+.. note::
+  The headers will be discovered by the compiler's dependency scanner to ensure
+  correct incremental builds. It can be useful to list header files in these
+  contexts anyway, as the list can be used to generate metadata some IDEs
+  rely on.
+
+You can begin editing the ``Step5`` directory. Complete ``TODO 1`` through
+``TODO 7``.
+
+Build and Run
+-------------
+
+The preset has already been updated to use ``mathfunctions::sqrt`` instead of
+``std::sqrt``. We can build and configure as usual.
+
+.. code-block:: console
+
+  cmake --preset tutorial
+  cmake --build build
+
+Verify that the ``Tutorial`` output now uses the logging framework.
+
+Solution
+--------
+
+First we add a new ``INTERFACE`` library named ``MathLogger``.
+
+.. raw:: html
+
+  <details><summary>TODO 1: Click to show/hide answer</summary>
+
+.. literalinclude:: Step6/MathFunctions/MathLogger/CMakeLists.txt
+  :caption: TODO 1: MathFunctions/MathLogger/CMakeLists.txt
+  :name: MathFunctions/MathLogger/CMakeLists.txt-add_library
+  :language: cmake
+  :start-at: add_library
+  :end-at: add_library
+
+.. raw:: html
+
+  </details>
+
+Then we add the appropriate :command:`target_sources` call to capture the
+header information. We give this file set the name ``HEADERS`` so we can
+omit the ``TYPE``, we don't need ``BASE_DIRS`` as we will use the default
+of the current source directory, and we can exclude the ``FILES`` list because
+we don't intend to install the library.
+
+.. raw:: html
+
+  <details><summary>TODO 2: Click to show/hide answer</summary>
+
+.. literalinclude:: Step6/MathFunctions/MathLogger/CMakeLists.txt
+  :caption: TODO 2: MathFunctions/MathLogger/CMakeLists.txt
+  :name: MathFunctions/MathLogger/CMakeLists.txt-target_sources
+  :language: cmake
+  :start-at: target_sources(
+  :end-at: )
+
+.. raw:: html
+
+  </details>
+
+Now we can add the ``MathLogger`` library to the ``MathFunctions`` linked
+libraries, and at the ``MathLogger`` folder to the project.
+
+.. raw:: html
+
+  <details><summary>TODO 3-4: Click to show/hide answer</summary>
+
+.. literalinclude:: Step6/MathFunctions/CMakeLists.txt
+  :caption: TODO 3: MathFunctions/CMakeLists.txt
+  :name: MathFunctions/CMakeLists.txt-link-mathlogger
+  :language: cmake
+  :start-at: target_link_libraries(
+  :end-at: MathLogger
+  :append: )
+
+.. literalinclude:: Step6/MathFunctions/CMakeLists.txt
+  :caption: TODO 4: MathFunctions/CMakeLists.txt
+  :name: MathFunctions/CMakeLists.txt-add-mathlogger
+  :language: cmake
+  :start-at: add_subdirectory(MathLogger
+  :end-at: add_subdirectory(MathLogger
+
+.. raw:: html
+
+  </details>
+
+Finally we can update ``MathFunctions.cxx`` to take advantage of the new logger.
+
+.. raw:: html
+
+  <details><summary>TODO 5-7: Click to show/hide answer</summary>
+
+.. literalinclude:: Step6/MathFunctions/MathFunctions.cxx
+  :caption: TODO 5: MathFunctions/MathFunctions.cxx
+  :name: MathFunctions/MathFunctions.cxx-mathlogger-header
+  :language: c++
+  :start-at: cmath
+  :end-at: MathLogger
+
+.. literalinclude:: Step6/MathFunctions/MathFunctions.cxx
+  :caption: TODO 6: MathFunctions/MathFunctions.cxx
+  :name: MathFunctions/MathFunctions.cxx-mathlogger-logger
+  :language: c++
+  :start-at: mathlogger::Logger Logger
+  :end-at: mathlogger::Logger Logger
+
+.. literalinclude:: Step6/MathFunctions/MathFunctions.cxx
+  :caption: TODO 7: MathFunctions/MathFunctions.cxx
+  :name: MathFunctions/MathFunctions.cxx-mathlogger-code
+  :language: c++
+  :start-at: Logger.Log(std::format("Computing sqrt of {} to be {}\n"
+  :end-at: std::format
+  :dedent: 4
+
+.. raw:: html
+
+  </details>
+
+Exercise 3 - Object Libraries
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Object libraries have several advanced uses, but also tricky nuances which
+are difficult to fully enumerate in the scope of this tutorial.
+
+.. code-block:: cmake
+
+  add_library(MyObjects OBJECT)
+
+The most obvious drawback to object libraries is the objects themselves cannot
+be transitively linked. If an object library appears in the
+:prop_tgt:`INTERFACE_LINK_LIBRARIES` of a target, the dependents which link that
+target will not "see" the objects. The object library will act like an
+``INTERFACE`` library in such contexts. In the general case, object libraries
+are only suitable for ``PRIVATE`` or ``PUBLIC`` consumption via
+:command:`target_link_libraries`.
+
+A common use case for object libraries is coalescing several library targets
+into a single archive or shared library object. Even within a single project
+libraries may be maintained as different targets for a variety of reasons, such
+as belonging to different teams within an organization. However, it may be
+desirable to distribute these as a single consumer-facing binary. Object
+libraries make this possible.
+
+Goal
+----
+
+Add several object libraries to the ``MathFunctions`` library.
+
+Helpful Resources
+-----------------
+
+* :command:`target_link_libraries`
+* :command:`add_subdirectory`
+
+Files to Edit
+-------------
+
+* ``MathFunctions/CMakeLists.txt``
+* ``MathFunctions/MathFunctions.h``
+* ``Tutorial/Tutorial.cxx``
+
+Getting Started
+---------------
+
+Several extensions for our ``MathFunctions`` library have been made available
+(we can imagine these coming from other teams in our organization). Take
+a minute to look at the targets made available in ``MathFunctions/MathExtensions``.
+Then complete ``TODO 8`` through ``TODO 11``.
+
+Build and Run
+-------------
+
+There's no reconfiguration needed, we can build as usual.
+
+.. code-block:: console
+
+  cmake --build build
+
+Verify the output of ``Tutorial`` now includes the verification message. Also
+take a minute to inspect the build directory under
+``build/MathFunctions/MathExtensions``. You should find that, unlike
+``MathFunctions``, no archives are produced for any of the object libraries.
+
+Solution
+--------
+
+First we will add links for all the object libraries to ``MathFunctions``.
+These are ``PUBLIC``, because we want the objects to be added to the
+``MathFunctions`` library as part of its own build step, and we want the
+headers to be available to consumers of the library.
+
+Then we add the ``MathExtensions`` subdirectoy to the project.
+
+.. raw:: html
+
+  <details><summary>TODO 8-9: Click to show/hide answer</summary>
+
+.. literalinclude:: Step6/MathFunctions/CMakeLists.txt
+  :caption: TODO 8: MathFunctions/CMakeLists.txt
+  :name: MathFunctions/CMakeLists.txt-link-objects
+  :language: cmake
+  :start-at: target_link_libraries(
+  :end-at: )
+
+.. literalinclude:: Step6/MathFunctions/CMakeLists.txt
+  :caption: TODO 9: MathFunctions/CMakeLists.txt
+  :name: MathFunctions/CMakeLists.txt-add-objs
+  :language: cmake
+  :start-at: add_subdirectory(MathExtensions
+  :end-at: add_subdirectory(MathExtensions
+
+.. raw:: html
+
+  </details>
+
+
+To make the extensions available to consumers, we include their headers in the
+``MathFunctions.h`` header.
+
+.. raw:: html
+
+  <details><summary>TODO 10: Click to show/hide answer</summary>
+
+.. literalinclude:: Step6/MathFunctions/MathFunctions.h
+  :caption: TODO 10: MathFunctions/MathFunctions.h
+  :name: MathFunctions/MathFunctions.h-include-objects
+  :language: c++
+  :start-at: OpAdd
+  :end-at: OpSub
+
+.. raw:: html
+
+  </details>
+
+Finally we can take advantage of the extensions in the ``Tutorial`` program.
+
+.. raw:: html
+
+  <details><summary>TODO 11: Click to show/hide answer</summary>
+
+.. literalinclude:: Step6/Tutorial/Tutorial.cxx
+  :caption: TODO 11: Tutorial/Tutorial.cxx
+  :name: Tutorial/Tutorial.cxx-use-objects
+  :language: c++
+  :start-at: OpMul
+  :end-at: checkValue);
+  :dedent: 2
+
+.. raw:: html
+
+  </details>

+ 532 - 0
Help/guide/tutorial/In-Depth CMake Target Commands.rst

@@ -0,0 +1,532 @@
+Step 4: In-Depth CMake Target Commands
+======================================
+
+There are several target commands within CMake we can use to describe
+requirements. As a reminder, a target command is one which modifies the
+properties of the target it is applied to. These properties describe
+requirements needed to build the software, such as sources, compile flags,
+and output names; or properties necessary to consume the target, such as header
+includes, library directories, and linkage rules.
+
+.. note::
+  As discussed in ``Step1``, properties required to build a target should be
+  described with the ``PRIVATE`` :ref:`scope keyword <Target Command Scope>`,
+  those required to consume the target with ``INTERFACE``, and properties needed
+  for both are described with ``PUBLIC``.
+
+In this step we will go over all the available target commands in CMake. Not all
+target commands are created equal. We have already discussed the two most
+important target commands, :command:`target_sources` and
+:command:`target_link_libraries`. Of the remaining commands, some are almost
+as common as these two, others have more advanced applications, and a couple
+should only be used as a last resort when other options are not available.
+
+Background
+^^^^^^^^^^
+
+Before going any further, let's name all of the CMake target commands. We'll
+split these into three groups: the recommended and generally useful commands,
+the advanced and cautionary commands, and the "footgun" commands which should
+be avoided unless necessary.
+
++-----------------------------------------+--------------------------------------+---------------------------------------+
+| Common/Recommended                      | Advanced/Caution                     | Esoteric/Footguns                     |
++=========================================+======================================+=======================================+
+| :command:`target_compile_definitions`   | :command:`get_target_property`       | :command:`target_include_directories` |
+| :command:`target_compile_features`      | :command:`set_target_properties`     | :command:`target_link_directories`    |
+| :command:`target_link_libraries`        | :command:`target_compile_options`    |                                       |
+| :command:`target_sources`               | :command:`target_link_options`       |                                       |
+|                                         | :command:`target_precompile_headers` |                                       |
++-----------------------------------------+--------------------------------------+---------------------------------------+
+
+.. note::
+    There's no such thing as a "bad" CMake target command. They all have valid
+    use cases. This categorization is provided to give newcomers a simple
+    intuition about which commands they should consider first when tackling
+    a problem.
+
+We'll demonstrate most of these in the following exercises. The three we won't
+be using are :command:`get_target_property`, :command:`set_target_properties`
+and :command:`target_precompile_headers`, so we will briefly discuss their
+purpose here.
+
+The :command:`get_target_property` and :command:`set_target_properties` commands
+give direct access to a target's properties by name. They can even be used
+to attach arbitrary property names to a target.
+
+.. code-block:: cmake
+
+  add_library(Example)
+  set_target_properties(Example
+    PROPERTIES
+      Key Value
+      Hello World
+  )
+
+  get_target_property(KeyVar Example Key)
+  get_target_property(HelloVar Example Hello)
+
+  message("Key: ${KeyVar}")
+  message("Hello: ${HelloVar}")
+
+.. code-block:: console
+
+  $ cmake -B build
+  ...
+  Key: Value
+  Hello: World
+
+The full list of target properties which are semantically meaningful to CMake
+are documented at :manual:`cmake-properties(7)`, however most of these should
+be modified with their dedicated commands. For example, it is unnecessary to
+directly manipulate ``LINK_LIBRARIES`` and ``INTERFACE_LINK_LIBRARIES``, as
+these are handled by :command:`target_link_libraries`.
+
+Conversely, some lesser-used properties are only accessible via these commands.
+The :prop_tgt:`DEPRECATION` property, used to attach deprecation notices to
+targets, can only be set via :command:`set_target_properties`; as can the
+:prop_tgt:`ADDITIONAL_CLEAN_FILES`, for describing additional files to be
+removed by CMake's ``clean`` target; and other properties of this sort.
+
+The :command:`target_precompile_headers` command takes a list of header files,
+similar to :command:`target_sources`, and creates a precompiled header from
+them. This precompiled header is then force included into all translation
+units in the target. This can be useful for build performance.
+
+Exercise 1 - Features and Definitions
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+In earlier steps we cautioned against globally setting
+:variable:`CMAKE_<LANG>_STANDARD` and overriding packagers' decision concerning
+which language standard to use. On the other hand, many libraries have a
+minimum required feature set they need in order to build, and for these it
+is appropriate to use the :command:`target_compile_features` command to
+communicate those requirements.
+
+.. code-block:: cmake
+
+  target_compile_features(MyApp PRIVATE cxx_std_20)
+
+The :command:`target_compile_features` command describes a minimum language
+standard as a target property. If the :variable:`CMAKE_<LANG>_STANDARD` is above
+this version, or the compiler default already provides this language standard,
+no action is taken. If additional flags are necessary to enable the standard,
+these will be added by CMake.
+
+.. note::
+  :command:`target_compile_features` manipulates the same style of interface and
+  non-interface properties as the other target commands. This means it is
+  possible to *inherit* a language standard requirement specified with
+  ``INTERFACE`` or ``PUBLIC`` scope keywords.
+
+  If language features are used only in implementation files, then the
+  respective compile features should be ``PRIVATE``. If the target's headers
+  use the features, then ``PUBLIC`` or ``INTERFACE`` should be used.
+
+For C++, the compile features are of the form ``cxx_std_YY`` where ``YY`` is
+the standardization year, e.g. ``14``, ``17``, ``20``, etc.
+
+The :command:`target_compile_definitions` command describes compile definitions
+as target properties. It is the most common mechanism for communicating build
+configuration information to the source code itself. As with all properties,
+the scope keywords apply as we have discussed.
+
+.. code-block:: cmake
+
+  target_compile_definitions(MyLibrary
+    PRIVATE
+      MYLIBRARY_USE_EXPERIMENTAL_IMPLEMENTATION
+
+    PUBLIC
+      MYLIBRARY_EXCLUDE_DEPRECATED_FUNCTIONS
+  )
+
+It is neither required nor desired that we attach ``-D`` prefixes to compile
+definitions described with :command:`target_compile_definitions`. CMake will
+determine the correct flag for the current compiler.
+
+Goal
+----
+
+Use :command:`target_compile_features` and :command:`target_compile_definitions`
+to communicate language standard and compile definition requirements.
+
+Helpful Resources
+-----------------
+
+* :command:`target_compile_features`
+* :command:`target_compile_definitions`
+* :command:`option`
+* :command:`if`
+
+Files to Edit
+-------------
+
+* ``Tutorial/CMakeLists.txt``
+* ``MathFunctions/CMakeLists.txt``
+* ``MathFunctions/MathFunctions.cxx``
+* ``CMakePresets.json``
+
+Getting Started
+---------------
+
+The ``Help/guide/tutorial/Step4`` directory contains the complete, recommended
+solution to ``Step3`` and relevant ``TODOs`` for this step. Complete ``TODO 1``
+through ``TODO 8``.
+
+Build and Run
+-------------
+
+We can run CMake using our ``tutorial`` preset, and then build as usual.
+
+.. code-block:: console
+
+  cmake --preset tutorial
+  cmake --build build
+
+Verify that the output of ``Tutorial`` is what we would expect for ``std::sqrt``.
+
+Solution
+--------
+
+First we add a new option to the top-level CML.
+
+.. raw:: html
+
+  <details><summary>TODO 1: Click to show/hide answer</summary>
+
+.. literalinclude:: Step5/CMakeLists.txt
+  :caption: TODO 1: CMakeLists.txt
+  :name: CMakeLists.txt-TUTORIAL_USE_STD_SQRT
+  :language: cmake
+  :start-at: option(TUTORIAL_BUILD_UTILITIES
+  :end-at: option(TUTORIAL_USE_STD_SQRT
+
+.. raw:: html
+
+  </details>
+
+Then we add the compile feature and definitions to ``MathFunctions``.
+
+.. raw:: html
+
+  <details><summary>TODO 2-3: Click to show/hide answer</summary>
+
+.. literalinclude:: Step5/MathFunctions/CMakeLists.txt
+  :caption: TODO 2-3: MathFunctions/CMakeLists.txt
+  :name: MathFunctions/CMakeLists.txt-target_compile_features
+  :language: cmake
+  :start-at: target_compile_features
+  :end-at: endif()
+
+.. raw:: html
+
+  </details>
+
+And the compile feature for ``Tutorial``.
+
+.. raw:: html
+
+  <details><summary>TODO 4: Click to show/hide answer</summary>
+
+.. literalinclude:: Step5/Tutorial/CMakeLists.txt
+  :caption: TODO 4: Tutorial/CMakeLists.txt
+  :name: Tutorial/CMakeLists.txt-target_compile_features
+  :language: cmake
+  :start-at: target_compile_features
+  :end-at: target_compile_features
+
+.. raw:: html
+
+  </details>
+
+Now we can modify ``MathFunctions`` to take advantage of the new definition.
+
+.. raw:: html
+
+  <details><summary>TODO 5-6: Click to show/hide answer</summary>
+
+.. literalinclude:: Step5/MathFunctions/MathFunctions.cxx
+  :caption: TODO 5: MathFunctions/MathFunctions.cxx
+  :name: MathFunctions/MathFunctions.cxx-cmath
+  :language: c++
+  :start-at: cmath
+  :end-at: format
+  :append: #include <iostream>
+
+.. literalinclude:: Step5/MathFunctions/MathFunctions.cxx
+  :caption: TODO 6: MathFunctions/MathFunctions.cxx
+  :name: MathFunctions/MathFunctions.cxx-std-sqrt
+  :language: c++
+  :start-at: double sqrt(double x)
+  :end-at: }
+
+.. raw:: html
+
+  </details>
+
+Finally we can update our ``CMakePresets.json``. We don't need to set
+``CMAKE_CXX_STANDARD`` anymore, but we do want to try out our new
+compile definition.
+
+.. raw:: html
+
+  <details><summary>TODO 7-8: Click to show/hide answer</summary>
+
+.. code-block:: json
+  :caption: TODO 7-8: CMakePresets.json
+  :name: CMakePresets.json-std-sqrt
+
+  "cacheVariables": {
+    "TUTORIAL_USE_STD_SQRT": "ON"
+  }
+
+.. raw:: html
+
+  </details>
+
+Exercise 2 - Compile and Link Options
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Sometimes, we need to exercise specific control over the exact options being
+passed on the compile and link line. These situations are addressed by
+:command:`target_compile_options` and :command:`target_link_options`.
+
+.. code:: c++
+
+  target_compile_options(MyApp PRIVATE -Wall -Werror)
+  target_link_options(MyApp PRIVATE -T LinksScript.ld)
+
+There are several problems with unconditionally calling
+:command:`target_compile_options` or :command:`target_link_options`. The primary
+problem is compiler flags are specific to the compiler frontend being used. In
+order to ensure that our project supports multiple compiler frontends, we must
+only pass compatible flags to the compiler.
+
+We can achieve this by checking the :variable:`CMAKE_<LANG>_COMPILER_FRONTEND_VARIANT`
+variable which tells us the style of flags supported by the compiler frontend.
+
+.. note::
+  Prior to CMake 3.26, :variable:`CMAKE_<LANG>_COMPILER_FRONTEND_VARIANT` was
+  only set for compilers with multiple frontend variants. In versions after
+  CMake 3.26 checking this variable alone is sufficient.
+
+  However this tutorial targets CMake 3.23. As such, the logic is more
+  complicated than we have time for here. This tutorial step already includes
+  correct logic for checking the compiler variant for MSVC, GCC, Clang, and
+  AppleClang on CMake 3.23.
+
+Even if a compiler accepts the flags we pass, the semantics of compiler flags
+change over time. This is especially true with regards to warnings. Projects
+should not turn warnings-as-error flags by default, as this can break their
+build on otherwise innocuous compiler warnings included in later releases.
+
+.. note::
+  For errors and warnings, consider placing flags in :variable:`CMAKE_<LANG>_FLAGS`
+  for local development builds and during CI runs (via preset or
+  :option:`-D <cmake -D>` flags). We know exactly which compiler and
+  toolchain are being used in these contexts, so we can customize the behavior
+  precisely without risking build breakages on other platforms.
+
+Goal
+----
+
+Add appropriate warning flags to the ``Tutorial`` executable for MSVC-style and
+GNU-style compiler frontends.
+
+Helpful Resources
+-----------------
+
+* :command:`target_compile_options`
+
+Files to Edit
+-------------
+
+* ``Tutorial/CMakeLists.txt``
+
+Getting Started
+---------------
+
+Continue editing files in the ``Step4`` directory. The conditional for checking
+the frontend variant has already been written. Complete ``TODO 9`` and
+``TODO 10`` to add warning flags to ``Tutorial``.
+
+Build and Run
+-------------
+
+Since we have already configured for this step, we can build with the usual
+command.
+
+.. code-block:: cmake
+
+  cmake --build build
+
+This should reveal a simple warning in the build. You can go ahead and fix it.
+
+Solution
+--------
+
+We need to add two compile options to ``Tutorial``, one MSVC-style flag and
+one GNU-style flag.
+
+.. raw:: html
+
+  <details><summary>TODO 9-10: Click to show/hide answer</summary>
+
+.. literalinclude:: Step5/Tutorial/CMakeLists.txt
+  :caption: TODO 9-10: Tutorial/CMakeLists.txt
+  :name: Tutorial/CMakeLists.txt-target_compile_options
+  :language: cmake
+  :start-at: if(
+  :end-at: endif()
+
+.. raw:: html
+
+  </details>
+
+Exercise 3 - Include and Link Directories
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. note::
+  This exercise requires building an archive using a compiler directly on the
+  command line. It is not used in later steps. It is included only to
+  demonstrate a use case for :command:`target_include_directories` and
+  :command:`target_link_directories`.
+
+  If you cannot complete this exercise for whatever reason feel free to treat
+  it as informational-only, or skip it entirely.
+
+It is generally unnecessary to directly describe include and link directories,
+as these requirements are inherited when linking together targets generated
+within CMake, or from external dependencies imported into CMake with commands
+we will cover in later steps.
+
+If we happen to have some libraries or header files which are not described
+by a CMake target which we need to bring into the build, perhaps pre-compiled
+binaries provided by a vendor, we can incorporate with the
+:command:`target_link_directories` and :command:`target_include_directories`
+commands.
+
+.. code-block:: cmake
+
+  target_link_directories(MyApp PRIVATE Vendor/lib)
+  target_include_directories(MyApp PRIVATE Vendor/include)
+
+
+These commands use properties which map to the ``-L`` and ``-I`` compiler flags
+(or whatever flags the compiler uses for link and include directories).
+
+Of course, passing a link directory doesn't tell the compiler to link anything
+into the build. For that we need :command:`target_link_libraries`. When
+:command:`target_link_libraries` is given an argument which does not map to
+a target name, it will add the string directly to the link line as a library
+to be linked into the build (prepending any appropriate flags, such a ``-l``).
+
+Goal
+----
+
+Describe a pre-compiled, vendored, static library and its headers inside a
+project using :command:`target_link_directories` and
+:command:`target_include_directories`.
+
+Helpful Resources
+-----------------
+
+* :command:`target_link_directories`
+* :command:`target_include_directories`
+* :command:`target_link_libraries`
+
+Files to Edit
+-------------
+
+* ``Vendor/CMakeLists.txt``
+* ``Tutorial/CMakeLists.txt``
+
+Getting Started
+---------------
+
+You will need to build the vendor library into a static archive to complete this
+exercise. Navigate to the ``Help/guide/tutorial/Step4/Vendor/lib`` directory
+and build the code as appropriate for your platform. On Unix-like operating
+systems the appropriate commands are usually:
+
+.. code-block:: console
+
+  g++ -c Vendors.cxx
+  ar rvs libVendor.a Vendor.o
+
+Then complete ``TODO 11`` through ``TODO 14``.
+
+.. note::
+  ``VendorLib`` is an ``INTERFACE`` library, meaning it has no build requirements
+  (because it has already been built). All of its properties should also be
+  interface properties.
+
+  We'll discuss ``INTERFACE`` libraries in greater depth during the next step.
+
+
+Build and Run
+-------------
+
+If you have successfully built ``libVendor``, you can rebuild ``Tutorial``
+using the normal command.
+
+.. code-block:: console
+
+  cmake --build build
+
+Running ``Tutorial`` should now output a message about the acceptability of the
+result to the vendor.
+
+Solution
+--------
+
+We need to use the target link and include commands to describe the archive
+and its headers as ``INTERFACE`` requirements of ``VendorLib``.
+
+.. raw:: html
+
+  <details><summary>TODO 11-13: Click to show/hide answer</summary>
+
+.. code-block:: cmake
+  :caption: TODO 11-13: Vendor/CMakeLists.txt
+  :name: Vendor/CMakeLists.txt
+
+  target_include_directories(VendorLib
+    INTERFACE
+      include
+  )
+
+  target_link_directories(VendorLib
+    INTERFACE
+      lib
+  )
+
+  target_link_libraries(VendorLib
+    INTERFACE
+      Vendor
+  )
+
+.. raw:: html
+
+  </details>
+
+Then we can add ``VendorLib`` to ``Tutorial``'s linked libraries.
+
+.. raw:: html
+
+  <details><summary>TODO 14: Click to show/hide answer</summary>
+
+.. code-block:: cmake
+  :caption: TODO 14: Tutorial/CMakeLists.txt
+  :name: Tutorial/CMakeLists.txt-VendorLib
+
+  target_link_libraries(Tutorial
+    PRIVATE
+      MathFunctions
+      VendorLib
+  )
+
+.. raw:: html
+
+  </details>

+ 418 - 0
Help/guide/tutorial/In-Depth System Introspection.rst

@@ -0,0 +1,418 @@
+Step 6: In-Depth System Introspection
+=====================================
+
+In order to discover information about the system environment and the toolchain,
+CMake will often compile small test programs to verify the availability of
+compiler flags, headers, and builtins or other language constructs.
+
+In this step, we will take advantage of the same test program mechanisms that
+CMake uses in our own project code.
+
+Background
+^^^^^^^^^^
+
+An old trick going back to the oldest days of configuration and build systems
+is to verify the availability of some feature by compiling a small program
+which uses that feature.
+
+CMake makes this unnecessary for many contexts. As we will address in later
+steps, if CMake can find a library dependency, we can rely on it having all
+the facilities (headers, code generators, test utilities, etc) we expect it to
+have. Conversely, if CMake can't find a dependency, attempting to use the
+dependency anyway will almost certainly fail.
+
+However, there are other kinds of information about the toolchain which CMake
+doesn't communicate readily. For these advanced cases, we can write our own
+test programs and compile commands to check for availability.
+
+CMake provides modules to simplify these checks. These are documented at
+:manual:`cmake-modules(7)`. Any module that begins with ``Check`` is a system
+introspection module we can use to interrogate the toolchain and system
+environment. Some notable ones include:
+
+  ``CheckIncludeFiles``
+    Check one or more C/C++ header files.
+
+  ``CheckCompilerFlag``
+    Check whether the compiler supports a given flag.
+
+  ``CheckSourceCompiles``
+    Checks whether source code can be built for a given language.
+
+  ``CheckIPOSupported``
+    Check whether the compiler supports interprocedural optimization (IPO/LTO).
+
+
+Exercise 1 - Check Include File
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+A fast and easy check to perform is if a given header file is available on
+a certain platform, for which CMake provides :module:`CheckIncludeFiles`. This
+is most appropriate for system and intrinsic headers, which may not be provided
+by a specific package by are expected to be available in many build environments.
+
+.. code-block:: cmake
+
+  include(CheckIncludeFiles)
+  check_include_files(sys/socket.h HAVE_SYS_SOCKET_H LANGUAGE CXX)
+
+.. note::
+  These functions are not immediately available in CMake, they must be added via
+  :command:`include`'ing their associated module (aka, a CMakeLang file). Many
+  modules live inside CMake's own ``Modules`` folder. This built-in ``Modules``
+  folder is one of the places CMake searches when evaluating an :command:`include`
+  command. You can think of these modules like standard library headers, they're
+  expected to be available.
+
+Once a header file is known to exist, we can communicate that to our code using
+the same mechanisms of conditionals and target commands already covered.
+
+Goal
+----
+
+Check if the x86 SSE2 intrinsic header is available, and if so use it to
+improve ``mathfunctions::sqrt``.
+
+Helpful Resources
+-----------------
+
+* :module:`CheckIncludeFiles`
+* :command:`target_compile_definitions`
+
+Files to Edit
+-------------
+
+* ``MathFunctions/CMakeLists.txt``
+* ``MathFunctions/MathFunctions.cxx``
+
+Getting Started
+---------------
+
+The ``Help/guide/tutorial/Step6`` directory contains the complete, recommended
+solution to ``Step5`` and relevant ``TODOs`` for this step. It also contains
+specialized implementations of the ``sqrt`` function for various conditions,
+which you will find in ``MathFunctions/MathFunctions.cxx``.
+
+Complete ``TODO 1`` through ``TODO 3``. Note that some ``#ifdef`` directives
+have already been added to the library, which will change its operation as we
+work through the step.
+
+Build and Run
+-------------
+
+We can use our usual commands to configure.
+
+.. code-block:: console
+
+  cmake --preset tutorial
+  cmake --build build
+
+In the output of the configuration step we should observe CMake checking for
+the ``emmintrin.h`` header.
+
+.. code-block:: console
+
+  -- Looking for include file emmintrin.h
+  -- Looking for include file emmintrin.h - found
+
+If the header is available on your system, verify the ``Tutorial`` output
+contains the message about using SSE2. Conversely, if the header is not
+available you should see the usual behavior from ``Tutorial``.
+
+Solution
+--------
+
+First we include and use the ``CheckIncludeFiles`` module, verifying the
+``emmintrin.h`` header is available.
+
+.. raw:: html
+
+  <details><summary>TODO 1: Click to show/hide answer</summary>
+
+.. literalinclude:: Step7/MathFunctions/CMakeLists.txt
+  :caption: TODO 1: MathFunctions/CMakeLists.txt
+  :name: MathFunctions/CMakeLists.txt-check-include-files
+  :language: cmake
+  :start-at: include(CheckIncludeFiles
+  :end-at: check_include_files(
+
+.. raw:: html
+
+  </details>
+
+Then we use the result of the check to conditionally set a compile definition
+on ``MathFunctions``.
+
+.. raw:: html
+
+  <details><summary>TODO 2: Click to show/hide answer</summary>
+
+.. literalinclude:: Step7/MathFunctions/CMakeLists.txt
+  :caption: TODO 2: MathFunctions/CMakeLists.txt
+  :name: MathFunctions/CMakeLists.txt-define-use-sse2
+  :language: cmake
+  :start-at: if(HAS_EMMINTRIN)
+  :end-at: endif()
+
+.. raw:: html
+
+  </details>
+
+Finally we can conditionally include the header in the ``MathFunctions`` library.
+
+.. raw:: html
+
+  <details><summary>TODO 3: Click to show/hide answer</summary>
+
+.. literalinclude:: Step7/MathFunctions/MathFunctions.cxx
+  :caption: TODO 3: MathFunctions/MathFunctions.cxx
+  :name: MathFunctions/MathFunctions.cxx-include-sse2
+  :language: c++
+  :start-at: #ifdef TUTORIAL_USE_SSE2
+  :end-at: #endif
+
+.. raw:: html
+
+  </details>
+
+
+Exercise 2 - Check Source Compiles
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Sometimes it is insufficient to merely check for a header. This is especially
+true when no header is available to check, such is the case with
+compiler-builtins. For these scenarios we have :module:`CheckSourceCompiles`.
+
+.. code-block:: cmake
+
+  include(CheckSourceCompiles)
+  check_source_compiles(CXX
+    "
+      int main() {
+        int a, b, c;
+        __builtin_add_overflow(a, b, &c);
+      }
+    "
+    HAS_CHECKED_ADDITION
+  )
+
+.. note::
+  By default :module:`CheckSourceCompiles` builds and links an executable. The
+  code to be check must provide a valid ``int main()`` in order to succeed.
+
+After performing the check, this system introspection can be applied identically
+to how we discussed with header files.
+
+Goal
+----
+
+Check if the GNU SSE2 builtins are available, and if so use them to improve
+``mathfunctions::sqrt``.
+
+Helpful Resources
+-----------------
+
+* :module:`CheckSourceCompiles`
+* :command:`target_compile_definitions`
+
+Files to Edit
+-------------
+
+* ``MathFunctions/CMakeLists.txt``
+
+Getting Started
+---------------
+
+Complete ``TODO 4`` and ``TODO 5``. No code changes to the ``MathFunctions``
+implementation are necessary, as these have already been provided.
+
+Build and Run
+-------------
+
+We need only rebuild the tutorial.
+
+.. code-block:: console
+
+  cmake --build build
+
+.. note::
+  If a check fails and you think it should succeed, you will need to clear the
+  CMake Cache by deleting the ``CMakeCache.txt`` file. CMake will not rerun
+  compile checks on subsequent runs if it has a cached result.
+
+In the output of the configuration step we should observe CMake checking if the
+provided source code compiles, which will be reported under the variable name
+we provided to ``check_source_compiles()``.
+
+.. code-block:: console
+
+  -- Performing Test HAS_GNU_BUILTIN
+  -- Performing Test HAS_GNU_BUILTIN - Success
+
+If the builtins are available on your compiler, verify the ``Tutorial`` output
+contains the message about using GNU-builting. Conversely, if the builtins are
+not available you should see the previous behavior from ``Tutorial``.
+
+Solution
+--------
+
+First we include and use the ``CheckSourceCompiles`` module, verifying the
+provided source code can be built.
+
+..
+  pygments doesn't like the [=[ <string> ]=] literals in the following
+  literalinclude, so use :language: none
+
+.. raw:: html
+
+  <details><summary>TODO 4: Click to show/hide answer</summary>
+
+.. literalinclude:: Step7/MathFunctions/CMakeLists.txt
+  :caption: TODO 4: MathFunctions/CMakeLists.txt
+  :name: MathFunctions/CMakeLists.txt-check-source-compiles
+  :language: none
+  :start-at: include(CheckSourceCompiles
+  :end-at: HAS_GNU_BUILTIN
+  :append: )
+
+.. raw:: html
+
+  </details>
+
+Then we use the result of the check to conditionally set a compile definition
+on ``MathFunctions``.
+
+.. raw:: html
+
+  <details><summary>TODO 5: Click to show/hide answer</summary>
+
+.. literalinclude:: Step7/MathFunctions/CMakeLists.txt
+  :caption: TODO 5: MathFunctions/CMakeLists.txt
+  :name: MathFunctions/CMakeLists.txt-define-use-gnu-builtin
+  :language: cmake
+  :start-at: if(HAS_GNU_BUILTIN)
+  :end-at: endif()
+
+.. raw:: html
+
+  </details>
+
+Exercise 3 - Check Interprocedural Optimization
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Interprocedural and link time optimizations can provide significant performance
+improvements to some software. CMake has the capacity to check for the
+availability of IPO flags via :module:`CheckIPOSupported`.
+
+.. code-block:: cmake
+
+  include(CheckIPOSupported)
+  check_ipo_supported() # fatal error if IPO is not supported
+  set_target_properties(MyApp
+    PROPERTIES
+      INTERPROCEDURAL_OPTIMIZATION TRUE
+  )
+
+.. note::
+  There a couple important caveats with regard to in-project IPO configuration:
+
+  * CMake does not know about every IPO/LTO flag on every compiler, better
+    results can often be achieved with individual tuning for a known toolchain.
+  * Setting the :prop_tgt:`INTERPROCEDURAL_OPTIMIZATION` property on a target
+    does not alter any of the targets it links to, or dependencies from other
+    projects. IPO can only "see" into other targets which are also compiled
+    appropriately.
+
+  For these reasons, serious consideration should be given to manually setting
+  up IPO/LTO flags across all projects in the dependency tree via external
+  mechanisms (presets, :option:`-D <cmake -D>` flags,
+  :manual:`toolchain files <cmake-toolchains(7)>`, etc) instead of in-project
+  control.
+
+However, especially for extremely large projects, it can be useful to have
+an in-project mechanism to use IPO whenever it is available.
+
+Goal
+----
+
+Enable IPO for the entire tutorial project when it is available from the
+toolchain.
+
+Helpful Resources
+-----------------
+
+* :module:`CheckIPOSupported`
+* :variable:`CMAKE_INTERPROCEDURAL_OPTIMIZATION`
+
+Files to Edit
+-------------
+
+* ``CMakeLists.txt``
+
+Getting Started
+---------------
+
+Continue editing the files in ``Step6``. Complete ``TODO 6`` and ``TODO 7``.
+
+Build and Run
+-------------
+
+We need only rebuild the tutorial.
+
+.. code-block:: console
+
+  cmake --build build
+
+If IPO is unavailable, we will see an error message during configuration.
+Otherwise nothing will change.
+
+.. note::
+  Regardless of the result of the IPO check, we shouldn't expect any change
+  in behavior from ``Tutorial`` or ``MathFunctions``.
+
+Solution
+--------
+
+The first ``TODO`` is easy, we add another option to our project.
+
+.. raw:: html
+
+  <details><summary>TODO 6: Click to show/hide answer</summary>
+
+.. literalinclude:: Step7/CMakeLists.txt
+  :caption: TODO 6: MathFunctions/CMakeLists.txt
+  :name: CMakeLists.txt-enable-ipo
+  :language: cmake
+  :start-at: option(TUTORIAL_ENABLE_IPO
+  :end-at: option(TUTORIAL_ENABLE_IPO
+
+.. raw:: html
+
+  </details>
+
+The next step is involved, however the documentation for :module:`CheckIPOSupported`
+has an almost complete example of what we need to do. The only difference is
+we are going to enable IPO project-wide instead of for a single target.
+
+.. raw:: html
+
+  <details><summary>TODO 7: Click to show/hide answer</summary>
+
+.. literalinclude:: Step7/CMakeLists.txt
+  :caption: TODO 7: CMakeLists.txt
+  :name: CMakeLists.txt-check-ipo
+  :language: cmake
+  :start-at: if(TUTORIAL_ENABLE_IPO)
+  :end-at: endif()
+  :append: endif()
+
+.. raw:: html
+
+  </details>
+
+.. note::
+  Normally we have discouraged setting ``CMAKE_`` variables inside the project.
+  Here, we are controlling that behavior with an :command:`option()`. This
+  allows packagers to opt-out of our override. This is an imperfect, but
+  acceptable solution to situations where we want to provide options to control
+  project-wide behavior controlled by ``CMAKE_`` variables.

+ 596 - 0
Help/guide/tutorial/Installation Commands and Concepts.rst

@@ -0,0 +1,596 @@
+Step 9: Installation Commands and Concepts
+==========================================
+
+Projects need to do more than build and test their code, they need to make it
+available to consumers. The layout of files in the build tree is unsuitable
+for consumption by other projects, binaries are in unexpected places, header
+files are located far away in the source tree, and there's no clear way
+to discover what targets are provided or how to use them.
+
+This translation, moving artifacts from the source and build trees into a final
+layout suitable for consumption, is known as installation. CMake supports a
+complete installation workflow as part of the project description, controlling
+both the layout of artifacts in the install tree, and reconstructing targets
+for other CMake projects which want to consume the libraries provided by the
+install tree.
+
+Background
+^^^^^^^^^^
+
+All CMake installation goes through a single command, :command:`install`, which
+is split into many subcommands responsible for various aspects of the
+installation process. For target-based CMake workflows, it is mostly sufficient
+to rely on installing targets themselves with :command:`install(TARGETS)`
+instead of resorting to manually moving files with :command:`install(FILES)`
+or :command:`install(DIRECTORY)`.
+
+.. note::
+  This is why we need to add ``FILES`` to header sets which are intended to be
+  installed. CMake needs to be able to locate the files when their associated
+  target is installed.
+
+CMake divides target-based installation into various artifact kinds. The
+available artifact kinds (in CMake 3.23) are:
+
+  ``ARCHIVE``
+    Static libraries (``.a`` / ``.lib``), DLL import libraries (``.lib``), and
+    a handful of other "archive-like" objects.
+
+  ``LIBRARY``
+    Shared libraries (``.so``), modules, and other dynamically loadable
+    objects. **Not** Window's DLL files (``.dll``) or MacOS frameworks.
+
+  ``RUNTIME``
+    Executables of all kinds except MacOS bundles; and Window's DLLs (``.dll``).
+
+  ``OBJECT``
+    Objects from ``OBJECT`` libraries.
+
+  ``FRAMEWORK``
+    Both static and shared MacOS frameworks
+
+  ``BUNDLE``
+    MacOS bundle executables
+
+  ``PUBLIC_HEADER`` / ``PRIVATE_HEADER`` / ``RESOURCE``
+    Files described by the :prop_tgt:`PUBLIC_HEADER`, :prop_tgt:`PRIVATE_HEADER`
+    and :prop_tgt:`RESOURCE` target properties, typically used with MacOS
+    frameworks
+
+  ``FILE_SET <set-name>``
+    A file set associated with the target. This is how headers are typically
+    installed.
+
+Most important artifact kinds have known destinations which CMake will default
+to unless instructed to do otherwise. For example, ``RUNTIME`` will be installed
+to the location named by :module:`CMAKE_INSTALL_BINDIR <GNUInstallDirs>`, if
+the variable is available, otherwise they default to ``bin``.
+
+The full list of artifact kind default destinations is described in the
+following table.
+
+=============================== =============================== ======================
+    Target Type                              Variable           Built-In Default
+=============================== =============================== ======================
+``RUNTIME``                     ``${CMAKE_INSTALL_BINDIR}``     ``bin``
+``LIBRARY``                     ``${CMAKE_INSTALL_LIBDIR}``     ``lib``
+``ARCHIVE``                     ``${CMAKE_INSTALL_LIBDIR}``     ``lib``
+``PRIVATE_HEADER``              ``${CMAKE_INSTALL_INCLUDEDIR}`` ``include``
+``PUBLIC_HEADER``               ``${CMAKE_INSTALL_INCLUDEDIR}`` ``include``
+``FILE_SET`` (type ``HEADERS``) ``${CMAKE_INSTALL_INCLUDEDIR}`` ``include``
+=============================== =============================== ======================
+
+For the most part, projects should leave the defaults alone unless they need to
+install to a specific subdirectory of a default location.
+
+CMake does not define the ``CMAKE_INSTALL_<dir>`` variables by default. If a
+project wishes to dictate installing to a subdirectory of one of these
+locations, it is necessary to include the :module:`GNUInstallDirs` module, which
+will provide values for all ``CMAKE_INSTALL_<dir>`` variables that have not
+already been defined.
+
+Exercise 1 - Installing Artifacts
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+For modern, target-based CMake projects installation of artifacts is trivial
+and consists of a single call to :command:`install(targets)`.
+
+.. code-block:: cmake
+
+  install(
+    TARGETS MyApp MyLib
+
+    FILE_SET HEADERS
+    FILE_SET AnotherHeaderFileSet
+  )
+
+Most artifact kinds are installed by default and do not need to be listed in
+the :command:`install` command. However, ``FILE_SET``s must be named to let
+CMake know you want to install. In the above example we install two file
+sets, one named ``HEADERS`` and another named ``AnotherHeaderFileSet``.
+
+When named, an artifact kind can be given various options, such as a destination.
+
+.. code-block:: cmake
+
+  include(GNUInstallDirs)
+
+  install(
+    TARGETS MyApp MyLib
+
+    RUNTIME
+      DESTINATION ${CMAKE_INSTALL_BINDIR}/Subfolder
+
+    FILE_SET HEADERS
+  )
+
+This will install the ``MyApp`` target to ``bin/Subfolder`` (if the packager
+hasn't changed :module:`CMAKE_INSTALL_BINDIR <GNUInstallDirs>`).
+
+Importantly, if the ``OBJECT`` artifact kind is never given a destination, it
+will act like an ``INTERFACE`` library, only installing its headers.
+
+Goal
+----
+
+Install the artifacts for the libraries and executables (except tests) described
+in the tutorial project.
+
+Helpful Resources
+-----------------
+
+* :command:`install`
+
+Files to Edit
+-------------
+
+* ``CMakeLists.txt``
+
+Getting Started
+---------------
+
+The ``Help/guide/tutorial/Step9`` directory contains the complete, recommended
+solution to ``Step8``. Complete ``TODO 1`` and ``TODO 2``.
+
+Build and Run
+-------------
+
+No special configuration is needed, configure and build as usual.
+
+.. code-block:: console
+
+  cmake --preset tutorial
+  cmake --build build
+
+We can verify the installation is correct with :option:`cmake --install`.
+
+.. code-block:: console
+
+  cmake --install build --prefix install
+
+The ``install`` folder should be populated correctly for our artifacts.
+
+Solution
+--------
+
+First we add an :command:`install(TARGETS)` for the conditionally built,
+thus conditionally installed, ``Tutorial`` executable.
+
+.. raw:: html
+
+  <details><summary>TODO 1 Click to show/hide answer</summary>
+
+.. code-block:: cmake
+  :caption: TODO 1: CMakeLists.txt
+  :name: CMakeLists.txt-install-tutorial
+
+  if(TUTORIAL_BUILD_UTILITIES)
+    add_subdirectory(Tutorial)
+    install(
+      TARGETS Tutorial
+    )
+  endif()
+
+.. raw:: html
+
+  </details>
+
+Then we can install the rest of the targets.
+
+.. raw:: html
+
+  <details><summary>TODO 2 Click to show/hide answer</summary>
+
+.. code-block:: cmake
+  :caption: TODO 2: CMakeLists.txt
+  :name: CMakeLists.txt-install-libs
+
+  install(
+    TARGETS MathFunctions OpAdd OpMul OpSub MathLogger SqrtTable
+    FILE_SET HEADERS
+  )
+
+.. raw:: html
+
+  </details>
+
+.. note::
+  We could add :command:`install(TARGETS)` commands locally to each subfolder
+  where the targets are defined. This would be typical in very large projects
+  where keeping track of all the installable targets is difficult.
+
+It might seem unnecessary to install the ``SqrtTable`` and ``MathLogger``,
+and it is at this stage. Due to how CMake models target relationships, when we
+reconstruct the target model in the next exercise we will need these targets to
+be available.
+
+Exercise 2 - Exporting Targets
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This raw collection of installed files is a good start, but we lose the CMake
+target model. These are effectively no better than the pre-compiled vendored
+libraries we discussed in ``Step 4``. We need some way for other projects to
+reconstruct our targets from what we have provided in the install tree.
+
+The mechanism CMake provides to solve this is a CMakeLang file known as a
+"target export file". It is created by the :command:`install(EXPORT)`
+command.
+
+.. code-block:: cmake
+
+  install(
+    TARGETS MyApp MyLib
+    EXPORT MyProjectTargets
+  )
+
+  include(GNUInstallDirs)
+
+  install(
+    EXPORT MyProjectTargets
+    DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MyProject
+    NAMESPACE MyProject::
+  )
+
+There are several parts to the above example. Firstly the
+:command:`install(TARGETS)` command takes an export name, basically a list to
+add the installed targets to.
+
+Later, the :command:`install(EXPORT)` command consumes this list of targets
+to generate the target export file. This will be a file named
+``<ExportName>.cmake`` located in the provided ``DESTINATION``. The
+``DESTINATION`` provided in this example is the conventional one, but any
+location searched by the :command:`find_package` command is valid.
+
+Finally, the targets created by the target export file will be prefixed with the
+``NAMESPACE`` string, ie they will be of the form ``<NAMESPACE><TargetName>``.
+It is conventional for this to be the project name followed by two colons.
+
+For reasons that will become more obvious in future steps, we typically don't
+consume this file directly. Instead we have a file named
+``<ProjectName>Config.cmake`` consume it via :command:`include()`.
+
+.. code-block:: cmake
+
+  include(${CMAKE_CURRENT_LIST_DIR}/MyProjectTargets.cmake)
+
+.. note::
+  The :variable:`CMAKE_CURRENT_LIST_DIR` variable names the directory that the
+  currently running CMake Language file is inside of, regardless of how that
+  file was included or launched.
+
+Then this file is installed alongside the target export with
+:command:`install(FILES)`.
+
+.. code-block:: cmake
+
+  install(
+    FILES
+      cmake/MyProjectConfig.cmake
+    DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MyProject
+  )
+
+.. note::
+  The name of this file and its location are dictated by the discovery
+  semantics of the :command:`find_package` command, which we will discuss more
+  in the next step.
+
+Goal
+----
+
+Export the Tutorial project targets so other projects may consume them.
+
+Helpful Resources
+-----------------
+
+* :command:`install`
+* :module:`GNUInstallDirs`
+* :variable:`CMAKE_CURRENT_LIST_DIR`
+
+Files to Edit
+-------------
+
+* ``CMakeLists.txt``
+* ``cmake/TutorialConfig.cmake``
+
+Getting Started
+---------------
+
+Continue editing the files in the ``Help/guide/tutorial/Step9`` directory.
+Complete ``TODO 3`` through ``TODO 8``.
+
+Build and Run
+-------------
+
+The build command is sufficient to reconfigure the project.
+
+.. code-block:: console
+
+  cmake --build build
+
+We can verify the installation is correct with :option:`cmake --install`.
+
+.. note::
+
+  As with CTest, when using multi-config generator, eg Visual Studio, it will be
+  necessary to specify a configuration with
+  ``cmake --install --config <config> <remaining flags>``, where
+  ``<config>`` is a value like ``Debug`` or ``Release``. This is true whenever
+  using a multi-config generator, and won't be called out specifically in
+  future commands.
+
+.. code-block:: console
+
+  cmake --install build --prefix install
+
+.. note::
+  CMake won't update files which have not changed, only installing new or
+  updated files from the build and source trees.
+
+The ``install`` folder should be populated correctly for our artifacts and
+export files. We'll demonstrate how to use these files in the next step.
+
+Solution
+--------
+
+First we add the ``Tutorial`` target to the ``TutorialTargets`` export.
+
+.. raw:: html
+
+  <details><summary>TODO 3 Click to show/hide answer</summary>
+
+.. literalinclude:: Step10/TutorialProject/CMakeLists.txt
+  :caption: TODO 3: CMakeLists.txt
+  :name: CMakeLists.txt-install-tutorial-export
+  :language: cmake
+  :start-at: install(
+  :end-at: )
+
+.. raw:: html
+
+  </details>
+
+Soon we will need access to the ``CMAKE_INSTALL_<dir>`` variables, so next
+we include the :module:`GNUInstallDirs` module.
+
+.. raw:: html
+
+  <details><summary>TODO 4 Click to show/hide answer</summary>
+
+.. literalinclude:: Step10/TutorialProject/CMakeLists.txt
+  :caption: TODO 4: CMakeLists.txt
+  :name: CMakeLists.txt-gnuinstalldirss
+  :language: cmake
+  :start-at: include(GNUInstallDirs)
+  :end-at: include(GNUInstallDirs)
+
+.. raw:: html
+
+  </details>
+
+Now we add the rest of our targets to the ``TutorialTargets`` export.
+
+.. raw:: html
+
+  <details><summary>TODO 5 Click to show/hide answer</summary>
+
+.. literalinclude:: Step10/TutorialProject/CMakeLists.txt
+  :caption: TODO 5: CMakeLists.txt
+  :name: CMakeLists.txt-install-libs-export
+  :language: cmake
+  :start-at: TARGETS MathFunctions
+  :end-at: )
+  :prepend: install(
+
+.. raw:: html
+
+  </details>
+
+Next we install the export itself, to generate our target export file.
+
+.. raw:: html
+
+  <details><summary>TODO 6 Click to show/hide answer</summary>
+
+.. code-block:: cmake
+  :caption: TODO 6: CMakeLists.txt
+  :name: CMakeLists.txt-install-export
+
+  install(
+    EXPORT TutorialTargets
+    DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Tutorial
+    NAMESPACE Tutorial::
+  )
+
+.. raw:: html
+
+  </details>
+
+And then we install our "config" file, which we will use to include our target
+export file.
+
+.. raw:: html
+
+  <details><summary>TODO 7 Click to show/hide answer</summary>
+
+.. code-block:: cmake
+  :caption: TODO 7: CMakeLists.txt
+  :name: CMakeLists.txt-install-config
+
+  install(
+    FILES
+      cmake/TutorialConfig.cmake
+    DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Tutorial
+  )
+
+.. raw:: html
+
+  </details>
+
+Finally we can add the necessary :command:`include` command to the config file.
+
+.. raw:: html
+
+  <details><summary>TODO 8 Click to show/hide answer</summary>
+
+.. literalinclude:: Step10/TutorialProject/cmake/TutorialConfig.cmake
+  :caption: TODO 8: cmake/TutorialConfig.cmake
+  :name: cmake/TutorialConfig.cmake
+  :language: cmake
+  :start-at: include
+  :end-at: include
+
+.. raw:: html
+
+  </details>
+
+Exercise 3 - Exporting a Version File
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+When importing CMake targets from a target export file, there is no way to
+"bail out" or "undo" the operation. If it turns out a package is a wrong or
+incompatible version for the one we requested, we'll be stuck with any
+side-effects incurred while we learned that version information.
+
+The answer CMake provides for this problem is a light-weight version file which
+only describes this version compatibility information, which can be checked
+before CMake commits to fully importing the file.
+
+CMake provides helper modules and scripts for generating these version files,
+namely the :module:`CMakePackageConfigHelpers` module.
+
+.. code-block:: cmake
+
+  include(CMakePackageConfigHelpers)
+
+  write_basic_package_version_file(
+    ${CMAKE_CURRENT_BINARY_DIR}/MyProjectConfigVersion.cmake
+    COMPATIBILITY ExactVersion
+  )
+
+The available versions are:
+
+* ``AnyNewerVersion``
+* ``SameMajorVersion``
+* ``SameMinorVersion``
+* ``ExactVersion``
+
+Additionally packages can mark themselves as ``ARCH_INDEPENDENT``, intended for
+packages which ship no binaries which would tie them to a specific machine
+architecture.
+
+By default, the ``VERSION`` used by ``write_basic_package_version_file()`` is
+the ``VERSION`` number given to the :command:`project` command.
+
+Goal
+----
+
+Export a version file for the Tutorial project.
+
+Helpful Resources
+-----------------
+
+* :command:`project`
+* :command:`install`
+* :module:`CMakePackageConfigHelpers`
+* :variable:`PROJECT_VERSION`
+
+Files to Edit
+-------------
+
+* ``CMakeLists.txt``
+
+Getting Started
+---------------
+
+Continue editing the files in the ``Help/guide/tutorial/Step9`` directory.
+Complete ``TODO 9`` through ``TODO 12``.
+
+Build and Run
+-------------
+
+Rebuild and install as done previously.
+
+.. code-block:: console
+
+  cmake --build build
+  cmake --install build --prefix install
+
+The ``install`` folder should be populated correctly with our newly generated
+and installed version file.
+
+Solution
+--------
+
+First we add a ``VERSION`` parameter to the :command:`project` command.
+
+.. raw:: html
+
+  <details><summary>TODO 9 Click to show/hide answer</summary>
+
+.. literalinclude:: Step10/TutorialProject/CMakeLists.txt
+  :caption: TODO 9: CMakeLists.txt
+  :name: CMakeLists.txt-project-version
+  :language: cmake
+  :start-at: project(
+  :end-at: )
+
+.. raw:: html
+
+  </details>
+
+Next we include the :module:`CMakePackageConfigHelpers` modules and use it
+to generate the config version file.
+
+.. raw:: html
+
+  <details><summary>TODO 10-11 Click to show/hide answer</summary>
+
+.. literalinclude:: Step10/TutorialProject/CMakeLists.txt
+  :caption: TODO 10-11: CMakeLists.txt
+  :name: CMakeLists.txt-write_basic_package_version_file
+  :language: cmake
+  :start-at: include(CMakePackageConfigHelpers
+  :end-at: COMPATIBILITY ExactVersion
+  :append: )
+
+.. raw:: html
+
+  </details>
+
+Finally we add the config version file to the list of files to be installed.
+
+.. raw:: html
+
+  <details><summary>TODO 12 Click to show/hide answer</summary>
+
+.. literalinclude:: Step10/TutorialProject/CMakeLists.txt
+  :caption: TODO 12: CMakeLists.txt
+  :name: CMakeLists.txt-install-version-config
+  :language: cmake
+  :start-at: FILES
+  :end-at: )
+  :prepend: install(
+
+.. raw:: html
+
+  </details>

+ 0 - 311
Help/guide/tutorial/Installing and Testing.rst

@@ -1,311 +0,0 @@
-Step 5: Installing and Testing
-==============================
-
-Exercise 1 - Install Rules
-^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-Often, it is not enough to only build an executable, it should also be
-installable. With CMake, we can specify install rules using the
-:command:`install` command. Supporting local installations for your builds in
-CMake is often as simple as specifying an install location and the targets and
-files to be installed.
-
-Goal
-----
-
-Install the ``Tutorial`` executable and the ``MathFunctions`` library.
-
-Helpful Materials
------------------
-
-* :command:`install`
-
-Files to Edit
--------------
-
-* ``MathFunctions/CMakeLists.txt``
-* ``CMakeLists.txt``
-
-Getting Started
----------------
-
-The starting code is provided in the ``Step5`` directory. In this
-exercise, complete ``TODO 1`` through ``TODO 4``.
-
-First, update ``MathFunctions/CMakeLists.txt`` to install the
-``MathFunctions`` and ``tutorial_compiler_flags`` libraries to the ``lib``
-directory. In that same file, specify the install rules needed to install
-``MathFunctions.h`` to the ``include`` directory.
-
-Then, update the top level ``CMakeLists.txt`` to install
-the ``Tutorial`` executable to the ``bin`` directory. Lastly, any header files
-should be installed to the ``include`` directory. Remember that
-``TutorialConfig.h`` is in the :variable:`PROJECT_BINARY_DIR`.
-
-Build and Run
--------------
-
-Make a new directory called ``Step5_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.
-
-Then, run the install step by using the :option:`--install <cmake --install>`
-option of the :manual:`cmake  <cmake(1)>` command (introduced in 3.15, older
-versions of CMake must use ``make install``) from the command line. This step
-will install the appropriate header files, libraries, and executables.
-For example:
-
-.. code-block:: console
-
-  cmake --install .
-
-For multi-configuration tools, don't forget to use the
-:option:`--config <cmake--build --config>` argument to specify the configuration.
-
-.. code-block:: console
-
-  cmake --install . --config Release
-
-If using an IDE, simply build the ``INSTALL`` target. You can build the same
-install target from the command line like the following:
-
-.. code-block:: console
-
-  cmake --build . --target install --config Debug
-
-The CMake variable :variable:`CMAKE_INSTALL_PREFIX` is used to determine the
-root of where the files will be installed. If using the :option:`cmake --install`
-command, the installation prefix can be overridden via the
-:option:`--prefix <cmake--install --prefix>` argument. For example:
-
-.. code-block:: console
-
-  cmake --install . --prefix "/home/myuser/installdir"
-
-Navigate to the install directory and verify that the installed ``Tutorial``
-runs.
-
-Solution
---------
-
-The install rules for our project are fairly simple:
-
-* For ``MathFunctions``, we want to install the libraries and header file to
-  the ``lib`` and ``include`` directories respectively.
-
-* For the ``Tutorial`` executable, we want to install the executable and
-  configured header file to the ``bin`` and ``include`` directories
-  respectively.
-
-So to the end of ``MathFunctions/CMakeLists.txt`` we add:
-
-.. raw:: html
-
-  <details><summary>TODO 1: Click to show/hide answer</summary>
-
-.. literalinclude:: Step6/MathFunctions/CMakeLists.txt
-  :caption: TODO 1: MathFunctions/CMakeLists.txt
-  :name: MathFunctions/CMakeLists.txt-install-TARGETS
-  :language: cmake
-  :start-after: # install libs
-  :end-before: # install include headers
-
-.. raw:: html
-
-  </details>
-
-and
-
-.. raw:: html
-
-  <details><summary>TODO 2: Click to show/hide answer</summary>
-
-.. literalinclude:: Step6/MathFunctions/CMakeLists.txt
-  :caption: TODO 2: MathFunctions/CMakeLists.txt
-  :name: MathFunctions/CMakeLists.txt-install-headers
-  :language: cmake
-  :start-after: # install include headers
-
-.. raw:: html
-
-  </details>
-
-The install rules for the ``Tutorial`` executable and configured header file
-are similar. To the end of the top-level ``CMakeLists.txt`` we add:
-
-.. raw:: html
-
-  <details><summary>TODO 3,4: Click to show/hide answer</summary>
-
-.. literalinclude:: Step6/CMakeLists.txt
-  :caption: CMakeLists.txt
-  :name: TODO 3,4: CMakeLists.txt-install-TARGETS
-  :language: cmake
-  :start-after: # add the install targets
-  :end-before: # TODO 1: Replace enable_testing() with include(CTest)
-
-.. raw:: html
-
-  </details>
-
-That is all that is needed to create a basic local
-install of the tutorial.
-
-.. _`Tutorial Testing Support`:
-
-Exercise 2 - Testing Support
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-CTest offers a way to easily manage tests for your project. Tests can be
-added through the :command:`add_test` command. Although it is not
-explicitly covered in this tutorial, there is a lot of compatibility
-between CTest and other testing frameworks such as :module:`GoogleTest`.
-
-Goal
-----
-
-Create unit tests for our executable using CTest.
-
-Helpful Materials
------------------
-
-* :command:`enable_testing`
-* :command:`add_test`
-* :command:`function`
-* :command:`set_tests_properties`
-* :manual:`ctest <ctest(1)>`
-
-Files to Edit
--------------
-
-* ``CMakeLists.txt``
-
-Getting Started
----------------
-
-The starting source code is provided in the ``Step5`` directory. In this
-exercise, complete ``TODO 5`` through ``TODO 9``.
-
-First, we need to enable testing. Next, begin adding tests to our project
-using :command:`add_test`. We will work through adding 3 simple tests and
-then you can add additional testing as you see fit.
-
-Build and Run
--------------
-
-Navigate to the build directory and rebuild the application. Then, run the
-:program:`ctest` executable: :option:`ctest -N` and :option:`ctest -VV`. For
-multi-config generators (e.g. Visual Studio), the configuration type must be
-specified with the :option:`-C \<mode\> <ctest -C>` flag.  For example, to run tests in Debug
-mode use ``ctest -C Debug -VV`` from the build directory
-(not the Debug subdirectory!). Release mode would be executed from the same
-location but with a ``-C Release``. Alternatively, build the ``RUN_TESTS``
-target from the IDE.
-
-Solution
---------
-
-Let's test our application. At the end of the top-level ``CMakeLists.txt``
-file we first need to enable testing with the
-:command:`enable_testing` command.
-
-.. raw:: html
-
-  <details><summary>TODO 5: Click to show/hide answer</summary>
-
-.. literalinclude:: Step6/CMakeLists.txt
-  :caption: TODO 5: CMakeLists.txt
-  :name: CMakeLists.txt-enable_testing
-  :language: cmake
-  :start-after: # enable testing
-  :end-before: # does the application run
-
-.. raw:: html
-
-  </details>
-
-With testing enabled, we will add a number of basic tests to verify
-that the application is working correctly. First, we create a test using
-:command:`add_test` which runs the ``Tutorial`` executable with the
-parameter 25 passed in. For this test, we are not going to check the
-executable's computed answer. This test will verify that
-application runs, does not segfault or otherwise crash, and has a zero
-return value. This is the basic form of a CTest test.
-
-.. raw:: html
-
-  <details><summary>TODO 6: Click to show/hide answer</summary>
-
-.. literalinclude:: Step6/CMakeLists.txt
-  :caption: TODO 6: CMakeLists.txt
-  :name: CMakeLists.txt-test-runs
-  :language: cmake
-  :start-after: # does the application run
-  :end-before: # does the usage message work
-
-.. raw:: html
-
-  </details>
-
-Next, let's use the :prop_test:`PASS_REGULAR_EXPRESSION` test property to
-verify that the output of the test contains certain strings. In this case,
-verifying that the usage message is printed when an incorrect number of
-arguments are provided.
-
-.. raw:: html
-
-  <details><summary>TODO 7: Click to show/hide answer</summary>
-
-.. literalinclude:: Step6/CMakeLists.txt
-  :caption: TODO 7: CMakeLists.txt
-  :name: CMakeLists.txt-test-usage
-  :language: cmake
-  :start-after: # does the usage message work?
-  :end-before: # define a function to simplify adding tests
-
-.. raw:: html
-
-  </details>
-
-The next test we will add verifies the computed value is truly the
-square root.
-
-.. raw:: html
-
-  <details><summary>TODO 8: Click to show/hide answer</summary>
-
-.. code-block:: cmake
-  :caption: TODO 8: CMakeLists.txt
-  :name: CMakeLists.txt-test-standard
-
-  add_test(NAME StandardUse COMMAND Tutorial 4)
-  set_tests_properties(StandardUse
-    PROPERTIES PASS_REGULAR_EXPRESSION "4 is 2"
-    )
-
-.. raw:: html
-
-  </details>
-
-This one test is not enough to give us confidence that it will
-work for all values passed in. We should add more tests to verify this.
-To easily add more tests, we make a function called ``do_test`` that runs the
-application and verifies that the computed square root is correct for
-given input. For each invocation of ``do_test``, another test is added to
-the project with a name, input, and expected results based on the passed
-arguments.
-
-.. raw:: html
-
-  <details><summary>TODO 9: Click to show/hide answer</summary>
-
-.. literalinclude:: Step6/CMakeLists.txt
-  :caption: TODO 9: CMakeLists.txt
-  :name: CMakeLists.txt-generalized-tests
-  :language: cmake
-  :start-after: # define a function to simplify adding tests
-
-.. raw:: html
-
-  </details>

+ 188 - 0
Help/guide/tutorial/Miscellaneous Features.rst

@@ -0,0 +1,188 @@
+Step 11: Miscellaneous Features
+===============================
+
+Some features don't fit well or aren't important enough to receive attention
+in the main tutorial, but deserve mention. These exercises collect some of those
+features. They should be considered "bonuses".
+
+There are many CMake features that are not covered by the tutorial, some of
+which are considered essential to the projects which use them. Others are
+in common use by packagers but see little discussion among software developers
+producing local builds.
+
+This list is not an exhaustive discussion of what remains of CMake's
+capabilities. It may grow or shrink with time and relevance.
+
+Exercise 1: Target Aliases
+^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+This tutorial focuses on installing dependencies and consuming them from an
+install tree. It also recommends the use of package managers to facilitate
+this process. However, for a variety of reasons both historical and
+contemporary this is not always how CMake projects are consumed.
+
+It is possible to vendor a dependency's source code entirely in a parent project
+and consume it with :command:`add_subdirectory`. When performed, the target
+names exposed are those used within the project, not those exported via
+:command:`install(EXPORT)`. The target names will not have the namespace string
+that command prefixes to targets.
+
+Some projects wish to support this workflow with an interface consistent with
+the one presented to :command:`find_package` consumers. CMake supports this via
+:command:`add_library(ALIAS)` and :command:`add_executable(ALIAS)`.
+
+.. code-block:: cmake
+
+  add_library(MyLib INTERFACE)
+  add_library(MyProject::MyLib ALIAS MyLib)
+
+Goal
+----
+
+Add a library alias for the ``MathFunctions`` library.
+
+Helpful Resources
+-----------------
+
+* :command:`add_library`
+
+Files to Edit
+-------------
+
+* ``TutorialProject/MathFunctions/CMakeLists.txt``
+
+Getting Started
+---------------
+
+For this step we will only be editing the ``TutorialProject`` project in the
+``Step11`` folder. Complete ``TODO 1``.
+
+Build and Run
+-------------
+
+To build the project we first need configure and install ``SimpleTest``.
+Navigate to ``Help/guide/Step11/SimpleTest`` and run the appropriate commands.
+
+.. code-block:: console
+
+  cmake --preset tutorial
+  cmake --install build
+
+Then navigate to ``Help/guide/Step11/TutorialProject`` and perform the usual build.
+
+.. code-block:: console
+
+  cmake --preset tutorial
+  cmake --build build
+
+There should be no observable change in behavior from adding the alias.
+
+Solution
+--------
+
+We add a single line to the ``MathFunctions`` CML.
+
+.. raw:: html
+
+  <details><summary>TODO 1 Click to show/hide answer</summary>
+
+.. literalinclude:: Complete/TutorialProject/MathFunctions/CMakeLists.txt
+  :caption: TODO 1: TutorialProject/MathFunctions/CMakeLists.txt
+  :name: TutorialProject/MathFunctions/CMakeLists.txt-alias
+  :language: cmake
+  :start-at: ALIAS
+  :end-at: ALIAS
+
+.. raw:: html
+
+  </details>
+
+Exercise 2: Generator Expressions
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+:manual:`Generator expressions <cmake-generator-expressions(7)>` are a
+complicated domain-specific language supported in some contexts within CMake.
+They are most easily understood as deferred-evaluation conditionals, they
+express requirements where the inputs to determine the correct behavior are not
+known during the CMake configuration stage.
+
+.. note::
+  This is where generator expressions get their name, they are evaluated when
+  the underlying build system is being generated.
+
+Generator expressions were commonly used in combination with
+:command:`target_include_directories` to express include directory requirements
+across the build and install tree, but file sets have superseded this use case.
+Their most common applications now are in multi-config generators and
+intricate dependency injection systems.
+
+.. code-block:: cmake
+
+  target_compile_definitions(MyApp PRIVATE "MYAPP_BUILD_CONFIG=$<CONFIG>")
+
+Goal
+----
+
+Add a generator expression to ``SimpleTest`` that checks the build configuration
+inside a compile definition.
+
+Helpful Resources
+-----------------
+
+* :command:`target_compile_definitions`
+* :manual:`cmake-generator-expressions(7)`
+
+Files to Edit
+-------------
+
+* ``SimpleTest/CMakeLists.txt``
+
+Getting Started
+---------------
+
+For this step we will only be editing the ``SimpleTest`` project in the
+``Step11`` folder. Complete ``TODO 2``.
+
+Build and Run
+-------------
+
+To build the project we first need configure and install ``SimpleTest``.
+Navigate to ``Help/guide/Step11/SimpleTest`` and run the appropriate commands.
+
+.. code-block:: console
+
+  cmake --preset tutorial
+  cmake --install build
+
+Then navigate to ``Help/guide/Step11/TutorialProject`` and perform the usual build.
+
+.. code-block:: console
+
+  cmake --preset tutorial
+  cmake --build build
+
+When running the ``TestMathFunctions`` binary directly, we should a message
+naming the build configuration used to build the executable (not necessarily the
+same as configuration used to configure ``SimpleTest``). On single configuration
+generators, the build configuration can be changed by setting
+:variable:`CMAKE_BUILD_TYPE`.
+
+Solution
+--------
+
+We add a single line to the ``SimpleTest`` CML.
+
+.. raw:: html
+
+  <details><summary>TODO 2 Click to show/hide answer</summary>
+
+.. literalinclude:: Complete/SimpleTest/CMakeLists.txt
+  :caption: TODO 2: SimpleTest/CMakeLists.txt
+  :name: SimpleTest/CMakeLists.txt-target_compile_definitions
+  :language: cmake
+  :start-at: target_compile_definitions
+  :end-at: target_compile_definitions
+
+.. raw:: html
+
+  </details>

+ 0 - 86
Help/guide/tutorial/Packaging Debug and Release.rst

@@ -1,86 +0,0 @@
-Step 12: Packaging Debug and Release
-====================================
-
-**Note:** This example is valid for single-configuration generators and will
-not work for multi-configuration generators (e.g. Visual Studio).
-
-By default, CMake's model is that a build directory only contains a single
-configuration, be it Debug, Release, MinSizeRel, or RelWithDebInfo. It is
-possible, however, to setup CPack to bundle multiple build directories and
-construct a package that contains multiple configurations of the same project.
-
-First, we want to ensure that the debug and release builds use different names
-for the libraries that will be installed. Let's use ``d`` as the
-postfix for the debug libraries.
-
-Set :variable:`CMAKE_DEBUG_POSTFIX` near the beginning of the top-level
-``CMakeLists.txt`` file:
-
-.. literalinclude:: Complete/CMakeLists.txt
-  :caption: CMakeLists.txt
-  :name: CMakeLists.txt-CMAKE_DEBUG_POSTFIX-variable
-  :language: cmake
-  :start-after: project(Tutorial VERSION 1.0)
-  :end-before: target_compile_features(tutorial_compiler_flags
-
-And the :prop_tgt:`DEBUG_POSTFIX` property on the tutorial executable:
-
-.. literalinclude:: Complete/CMakeLists.txt
-  :caption: CMakeLists.txt
-  :name: CMakeLists.txt-DEBUG_POSTFIX-property
-  :language: cmake
-  :start-after: # add the executable
-  :end-before: # add the binary tree to the search path for include files
-
-Let's also add version numbering to the ``MathFunctions`` library. In
-``MathFunctions/CMakeLists.txt``, set the :prop_tgt:`VERSION` and
-:prop_tgt:`SOVERSION` properties:
-
-.. literalinclude:: Complete/MathFunctions/CMakeLists.txt
-  :caption: MathFunctions/CMakeLists.txt
-  :name: MathFunctions/CMakeLists.txt-VERSION-properties
-  :language: cmake
-  :start-after: # setup the version numbering
-  :end-before: # install libs
-
-From the ``Step12`` directory, create ``debug`` and ``release``
-subdirectories. The layout will look like:
-
-.. code-block:: none
-
-  - Step12
-     - debug
-     - release
-
-Now we need to setup debug and release builds. We can use
-:variable:`CMAKE_BUILD_TYPE` to set the configuration type:
-
-.. code-block:: console
-
-  cd debug
-  cmake -DCMAKE_BUILD_TYPE=Debug ..
-  cmake --build .
-  cd ../release
-  cmake -DCMAKE_BUILD_TYPE=Release ..
-  cmake --build .
-
-Now that both the debug and release builds are complete, we can use a custom
-configuration file to package both builds into a single release. In the
-``Step12`` directory, create a file called ``MultiCPackConfig.cmake``. In this
-file, first include the default configuration file that was created by the
-:manual:`cmake  <cmake(1)>` executable.
-
-Next, use the ``CPACK_INSTALL_CMAKE_PROJECTS`` variable to specify which
-projects to install. In this case, we want to install both debug and release.
-
-.. literalinclude:: Complete/MultiCPackConfig.cmake
-  :caption: MultiCPackConfig.cmake
-  :name: MultiCPackConfig.cmake
-  :language: cmake
-
-From the ``Step12`` directory, run :manual:`cpack <cpack(1)>` specifying our
-custom configuration file with the ``config`` option:
-
-.. code-block:: console
-
-  cpack --config MultiCPackConfig.cmake

+ 0 - 64
Help/guide/tutorial/Packaging an Installer.rst

@@ -1,64 +0,0 @@
-Step 9: Packaging an Installer
-==============================
-
-Next suppose that we want to distribute our project to other people so that
-they can use it. We want to provide both binary and source distributions on a
-variety of platforms. This is a little different from the install we did
-previously in :guide:`tutorial/Installing and Testing`, where we were
-installing the binaries that we had built from the source code. In this
-example we will be building installation packages that support binary
-installations and package management features. To accomplish this we will use
-CPack to create platform specific installers. Specifically we need to add a
-few lines to the bottom of our top-level ``CMakeLists.txt`` file.
-
-.. literalinclude:: Step10/CMakeLists.txt
-  :caption: CMakeLists.txt
-  :name: CMakeLists.txt-include-CPack
-  :language: cmake
-  :start-after: # setup installer
-
-That is all there is to it. We start by including
-:module:`InstallRequiredSystemLibraries`. This module will include any runtime
-libraries that are needed by the project for the current platform. Next we set
-some CPack variables to where we have stored the license and version
-information for this project. The version information was set earlier in this
-tutorial and the ``License.txt`` has been included in the top-level source
-directory for this step.  The :variable:`CPACK_GENERATOR` and
-:variable:`CPACK_SOURCE_GENERATOR` variables select the generators used for
-binary and source installations, respectively.
-
-Finally we include the :module:`CPack module <CPack>` which will use these
-variables and some other properties of the current system to setup an
-installer.
-
-The next step is to build the project in the usual manner and then run the
-:manual:`cpack <cpack(1)>` executable. To build a binary distribution, from the
-binary directory run:
-
-.. code-block:: console
-
-  cpack
-
-To specify the binary generator, use the :option:`-G <cpack -G>` option. For
-multi-config builds, use :option:`-C <cpack -C>` to specify the configuration.
-For example:
-
-.. code-block:: console
-
-  cpack -G ZIP -C Debug
-
-For a list of available generators, see :manual:`cpack-generators(7)` or call
-:option:`cpack --help`. An :cpack_gen:`archive generator <CPack Archive Generator>`
-like ZIP creates a compressed archive of all *installed* files.
-
-To create an archive of the *full* source tree you would type:
-
-.. code-block:: console
-
-  cpack --config CPackSourceConfig.cmake
-
-Alternatively, run ``make package`` or right click the ``Package`` target and
-``Build Project`` from an IDE.
-
-Run the installer found in the binary directory. Then run the installed
-executable and verify that it works.

+ 0 - 61
Help/guide/tutorial/Selecting Static or Shared Libraries.rst

@@ -1,61 +0,0 @@
-Step 10: Selecting Static or Shared Libraries
-=============================================
-
-In this section we will show how the :variable:`BUILD_SHARED_LIBS` variable can
-be used to control the default behavior of :command:`add_library`,
-and allow control over how libraries without an explicit type (``STATIC``,
-``SHARED``, ``MODULE`` or ``OBJECT``) are built.
-
-To accomplish this we need to add :variable:`BUILD_SHARED_LIBS` to the
-top-level ``CMakeLists.txt``. We use the :command:`option` command as it allows
-users to optionally select if the value should be ``ON`` or ``OFF``.
-
-.. literalinclude:: Step11/CMakeLists.txt
-  :caption: CMakeLists.txt
-  :name: CMakeLists.txt-option-BUILD_SHARED_LIBS
-  :language: cmake
-  :start-after: set(CMAKE_RUNTIME_OUTPUT_DIRECTORY
-  :end-before: # configure a header file to pass the version number only
-
-Next, we need to specify output directories for our static and shared
-libraries.
-
-.. literalinclude:: Step11/CMakeLists.txt
-  :caption: CMakeLists.txt
-  :name: CMakeLists.txt-cmake-output-directories
-  :language: cmake
-  :start-after: # we don't need to tinker with the path to run the executable
-  :end-before: # configure a header file to pass the version number only
-
-Finally, update ``MathFunctions/MathFunctions.h`` to use dll export defines:
-
-.. literalinclude:: Step11/MathFunctions/MathFunctions.h
-  :caption: MathFunctions/MathFunctions.h
-  :name: MathFunctions/MathFunctions.h
-  :language: c++
-
-At this point, if you build everything, you may notice that linking fails
-as we are combining a static library without position independent code with a
-library that has position independent code. The solution to this is to
-explicitly set the :prop_tgt:`POSITION_INDEPENDENT_CODE` target property of
-SqrtLibrary to be ``True`` when building shared libraries.
-
-.. literalinclude:: Step11/MathFunctions/CMakeLists.txt
-  :caption: MathFunctions/CMakeLists.txt
-  :name: MathFunctions/CMakeLists.txt-POSITION_INDEPENDENT_CODE
-  :language: cmake
-  :start-at: # state that SqrtLibrary need PIC when the default is shared libraries
-  :end-at:  )
-
-Define ``EXPORTING_MYMATH`` stating we are using ``declspec(dllexport)`` when
-building on Windows.
-
-.. literalinclude:: Step11/MathFunctions/CMakeLists.txt
-  :caption: MathFunctions/CMakeLists.txt
-  :name: MathFunctions/CMakeLists.txt-dll-export
-  :language: cmake
-  :start-at: # define the symbol stating we are using the declspec(dllexport) when
-  :end-at: target_compile_definitions(MathFunctions PRIVATE "EXPORTING_MYMATH")
-
-**Exercise**: We modified ``MathFunctions.h`` to use dll export defines.
-Using CMake documentation can you find a helper module to simplify this?

+ 15 - 10
Help/guide/tutorial/Step1/CMakeLists.txt

@@ -1,16 +1,21 @@
-# TODO 1: Set the minimum required version of CMake to be 3.10
+# TODO1: Set the minimum required version of CMake to be 3.23
 
-# TODO 2: Create a project named Tutorial
+# TODO2: Create a project named Tutorial
 
-# TODO 7: Set the project version number as 1.0 in the above project command
+# TODO3: Add an executable target called Tutorial to the project
 
-# TODO 6: Set the variable CMAKE_CXX_STANDARD to 11
-#         and the variable CMAKE_CXX_STANDARD_REQUIRED to True
+# TODO4: Add the Tutorial/Tutorial.cxx source file to the Tutorial target
 
-# TODO 8: Use configure_file to configure and copy TutorialConfig.h.in to
-#         TutorialConfig.h
+# TODO7: Add the MathFunctions library as a linked dependency
+#        to the Tutorial target
 
-# TODO 3: Add an executable called Tutorial to the project
-# Hint: Be sure to specify the source file as tutorial.cxx
+# TODO11: Add the Tutorial subdirectory to the project
 
-# TODO 9: Use target_include_directories to include ${PROJECT_BINARY_DIR}
+# TODO5: Add a library target called MathFunctions to the project
+
+# TODO6: Add the source and header file located in Step1/MathFunctions to the
+#        MathFunctions target, note that the intended way to include the
+#        MathFunctions header is:
+#          #include <MathFunctions.h>
+
+# TODO13: Add the MathFunctions subdirectory to the project

+ 2 - 0
Help/guide/tutorial/Step1/MathFunctions/CMakeLists.txt

@@ -0,0 +1,2 @@
+# TODO12: Move all the MathFunctions target commands to this CMakeLists.txt.
+#         Ensure that all paths are updated to be relative to this new location.

+ 7 - 4
Help/guide/tutorial/Step2/MathFunctions/mysqrt.cxx → Help/guide/tutorial/Step1/MathFunctions/MathFunctions.cxx

@@ -1,9 +1,6 @@
-#include "mysqrt.h"
-
 #include <iostream>
 
-namespace mathfunctions {
-namespace detail {
+namespace {
 // a hack square root calculation using simple operations
 double mysqrt(double x)
 {
@@ -25,4 +22,10 @@ double mysqrt(double x)
   return result;
 }
 }
+
+namespace mathfunctions {
+double sqrt(double x)
+{
+  return mysqrt(x);
+}
 }

+ 0 - 0
Help/guide/tutorial/Step2/MathFunctions/MathFunctions.h → Help/guide/tutorial/Step1/MathFunctions/MathFunctions.h


+ 2 - 0
Help/guide/tutorial/Step1/Tutorial/CMakeLists.txt

@@ -0,0 +1,2 @@
+# TODO10: Move all the Tutorial target commands to this CMakeLists.txt. Ensure
+#          that all paths are updated to be relative to this new location.

+ 4 - 8
Help/guide/tutorial/Step4/tutorial.cxx → Help/guide/tutorial/Step1/Tutorial/Tutorial.cxx

@@ -3,15 +3,11 @@
 #include <iostream>
 #include <string>
 
-#include "MathFunctions.h"
-#include "TutorialConfig.h"
+// TODO8: Include the MathFunctions header
 
 int main(int argc, char* argv[])
 {
   if (argc < 2) {
-    // report version
-    std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
-              << Tutorial_VERSION_MINOR << std::endl;
     std::cout << "Usage: " << argv[0] << " number" << std::endl;
     return 1;
   }
@@ -19,9 +15,9 @@ int main(int argc, char* argv[])
   // convert input to double
   double const inputValue = std::stod(argv[1]);
 
-  double const outputValue = mathfunctions::sqrt(inputValue);
-
+  // TODO9: Use the mathfunctions::sqrt function
+  // calculate square root
+  double const outputValue = std::sqrt(inputValue);
   std::cout << "The square root of " << inputValue << " is " << outputValue
             << std::endl;
-  return 0;
 }

+ 0 - 2
Help/guide/tutorial/Step1/TutorialConfig.h.in

@@ -1,2 +0,0 @@
-// the configured options and settings for Tutorial
-// TODO 10: Define Tutorial_VERSION_MAJOR and Tutorial_VERSION_MINOR

+ 0 - 27
Help/guide/tutorial/Step1/tutorial.cxx

@@ -1,27 +0,0 @@
-// A simple program that computes the square root of a number
-#include <cmath>
-#include <cstdlib> // TODO 5: Remove this line
-#include <iostream>
-#include <string>
-
-// TODO 11: Include TutorialConfig.h
-
-int main(int argc, char* argv[])
-{
-  if (argc < 2) {
-    // TODO 12: Create a print statement using Tutorial_VERSION_MAJOR
-    //          and Tutorial_VERSION_MINOR
-    std::cout << "Usage: " << argv[0] << " number" << std::endl;
-    return 1;
-  }
-
-  // convert input to double
-  // TODO 4: Replace atof(argv[1]) with std::stod(argv[1])
-  double const inputValue = atof(argv[1]);
-
-  // calculate square root
-  double const outputValue = sqrt(inputValue);
-  std::cout << "The square root of " << inputValue << " is " << outputValue
-            << std::endl;
-  return 0;
-}

+ 0 - 77
Help/guide/tutorial/Step10/CMakeLists.txt

@@ -1,77 +0,0 @@
-cmake_minimum_required(VERSION 3.15)
-
-# set the project name and version
-project(Tutorial VERSION 1.0)
-
-# specify the C++ standard
-add_library(tutorial_compiler_flags INTERFACE)
-target_compile_features(tutorial_compiler_flags INTERFACE cxx_std_11)
-
-# add compiler warning flags just when building this project via
-# the BUILD_INTERFACE genex
-set(gcc_like_cxx "$<COMPILE_LANG_AND_ID:CXX,ARMClang,AppleClang,Clang,GNU,LCC>")
-set(msvc_cxx "$<COMPILE_LANG_AND_ID:CXX,MSVC>")
-target_compile_options(tutorial_compiler_flags INTERFACE
-  "$<${gcc_like_cxx}:$<BUILD_INTERFACE:-Wall;-Wextra;-Wshadow;-Wformat=2;-Wunused>>"
-  "$<${msvc_cxx}:$<BUILD_INTERFACE:-W3>>"
-)
-
-# configure a header file to pass the version number only
-configure_file(TutorialConfig.h.in TutorialConfig.h)
-
-# add the MathFunctions library
-add_subdirectory(MathFunctions)
-
-# add the executable
-add_executable(Tutorial tutorial.cxx)
-target_link_libraries(Tutorial PUBLIC MathFunctions tutorial_compiler_flags)
-
-# add the binary tree to the search path for include files
-# so that we will find TutorialConfig.h
-target_include_directories(Tutorial PUBLIC
-                           "${PROJECT_BINARY_DIR}"
-                           )
-
-# add the install targets
-install(TARGETS Tutorial DESTINATION bin)
-install(FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h"
-  DESTINATION include
-  )
-
-# enable testing
-include(CTest)
-
-# does the application run
-add_test(NAME Runs COMMAND Tutorial 25)
-
-# does the usage message work?
-add_test(NAME Usage COMMAND Tutorial)
-set_tests_properties(Usage
-  PROPERTIES PASS_REGULAR_EXPRESSION "Usage:.*number"
-  )
-
-# define a function to simplify adding tests
-function(do_test target arg result)
-  add_test(NAME Comp${arg} COMMAND ${target} ${arg})
-  set_tests_properties(Comp${arg}
-    PROPERTIES PASS_REGULAR_EXPRESSION ${result}
-    )
-endfunction()
-
-# do a bunch of result based tests
-do_test(Tutorial 4 "4 is 2")
-do_test(Tutorial 9 "9 is 3")
-do_test(Tutorial 5 "5 is 2.236")
-do_test(Tutorial 7 "7 is 2.645")
-do_test(Tutorial 25 "25 is 5")
-do_test(Tutorial -25 "-25 is (-nan|nan|0)")
-do_test(Tutorial 0.0001 "0.0001 is 0.01")
-
-# setup installer
-include(InstallRequiredSystemLibraries)
-set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/License.txt")
-set(CPACK_PACKAGE_VERSION_MAJOR "${Tutorial_VERSION_MAJOR}")
-set(CPACK_PACKAGE_VERSION_MINOR "${Tutorial_VERSION_MINOR}")
-set(CPACK_GENERATOR "TGZ")
-set(CPACK_SOURCE_GENERATOR "TGZ")
-include(CPack)

+ 0 - 3
Help/guide/tutorial/Step10/CTestConfig.cmake

@@ -1,3 +0,0 @@
-set(CTEST_NIGHTLY_START_TIME "00:00:00 EST")
-
-set(CTEST_SUBMIT_URL "https://my.cdash.org/submit.php?project=CMakeTutorial")

+ 0 - 2
Help/guide/tutorial/Step10/License.txt

@@ -1,2 +0,0 @@
-This is the open source License.txt file introduced in
-CMake/Tutorial/Step9...

+ 0 - 45
Help/guide/tutorial/Step10/MathFunctions/CMakeLists.txt

@@ -1,45 +0,0 @@
-# add the library that runs
-add_library(MathFunctions MathFunctions.cxx)
-
-# state that anybody linking to us needs to include the current source dir
-# to find MathFunctions.h, while we don't.
-target_include_directories(MathFunctions
-                           INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
-                           )
-
-# should we use our own math functions
-option(USE_MYMATH "Use tutorial provided math implementation" ON)
-if(USE_MYMATH)
-
-  target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH")
-
-  include(MakeTable.cmake) # generates Table.h
-
-  # library that just does sqrt
-  add_library(SqrtLibrary STATIC
-              mysqrt.cxx
-              ${CMAKE_CURRENT_BINARY_DIR}/Table.h
-              )
-
-  # state that we depend on our binary dir to find Table.h
-  target_include_directories(SqrtLibrary PRIVATE
-                             ${CMAKE_CURRENT_BINARY_DIR}
-                             )
-
-  # link SqrtLibrary to tutorial_compiler_flags
-  target_link_libraries(SqrtLibrary PUBLIC tutorial_compiler_flags)
-
-  target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
-endif()
-
-# link MathFunctions to tutorial_compiler_flags
-target_link_libraries(MathFunctions PUBLIC tutorial_compiler_flags)
-
-# install libs
-set(installable_libs MathFunctions tutorial_compiler_flags)
-if(TARGET SqrtLibrary)
-  list(APPEND installable_libs SqrtLibrary)
-endif()
-install(TARGETS ${installable_libs} DESTINATION lib)
-# install include headers
-install(FILES MathFunctions.h DESTINATION include)

+ 0 - 10
Help/guide/tutorial/Step10/MathFunctions/MakeTable.cmake

@@ -1,10 +0,0 @@
-# first we add the executable that generates the table
-add_executable(MakeTable MakeTable.cxx)
-target_link_libraries(MakeTable PRIVATE tutorial_compiler_flags)
-
-# add the command to generate the source code
-add_custom_command(
-  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h
-  COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h
-  DEPENDS MakeTable
-  )

+ 0 - 20
Help/guide/tutorial/Step10/MathFunctions/MathFunctions.cxx

@@ -1,20 +0,0 @@
-
-#include "MathFunctions.h"
-
-#include <cmath>
-
-#ifdef USE_MYMATH
-#  include "mysqrt.h"
-#endif
-
-namespace mathfunctions {
-double sqrt(double x)
-{
-// which square root function should we use?
-#ifdef USE_MYMATH
-  return detail::mysqrt(x);
-#else
-  return std::sqrt(x);
-#endif
-}
-}

+ 0 - 3
Help/guide/tutorial/Step10/MathFunctions/MathFunctions.h

@@ -1,3 +0,0 @@
-namespace mathfunctions {
-double sqrt(double x);
-}

+ 0 - 37
Help/guide/tutorial/Step10/MathFunctions/mysqrt.cxx

@@ -1,37 +0,0 @@
-#include <iostream>
-
-#include "MathFunctions.h"
-
-// include the generated table
-#include "Table.h"
-
-namespace mathfunctions {
-namespace detail {
-// a hack square root calculation using simple operations
-double mysqrt(double x)
-{
-  if (x <= 0) {
-    return 0;
-  }
-
-  // use the table to help find an initial value
-  double result = x;
-  if (x >= 1 && x < 10) {
-    std::cout << "Use the table to help find an initial value " << std::endl;
-    result = sqrtTable[static_cast<int>(x)];
-  }
-
-  // do ten iterations
-  for (int i = 0; i < 10; ++i) {
-    if (result <= 0) {
-      result = 0.1;
-    }
-    double delta = x - (result * result);
-    result = result + 0.5 * delta / result;
-    std::cout << "Computing sqrt of " << x << " to be " << result << std::endl;
-  }
-
-  return result;
-}
-}
-}

+ 0 - 6
Help/guide/tutorial/Step10/MathFunctions/mysqrt.h

@@ -1,6 +0,0 @@
-
-namespace mathfunctions {
-namespace detail {
-double mysqrt(double x);
-}
-}

+ 52 - 0
Help/guide/tutorial/Step10/SimpleTest/CMakeLists.txt

@@ -0,0 +1,52 @@
+# A very simple test framework for demonstrating how dependencies work
+cmake_minimum_required(VERSION 3.23)
+
+project(SimpleTest
+  VERSION 0.0.1
+)
+
+add_library(SimpleTest INTERFACE)
+target_sources(SimpleTest
+  INTERFACE
+    FILE_SET HEADERS
+    FILES
+      SimpleTest.h
+)
+target_compile_features(SimpleTest INTERFACE cxx_std_20)
+
+# TODO6: Find the TransitiveDep package with find_package. The SimpleTest
+#        build should fail if TransitiveDep cannot be found.
+
+# TODO7: Add the TransitiveDep::TransitiveDep target to the SimpleTest interface
+#        library's links. Remember that interface libraries can only have
+#        interface properties.
+
+include(GNUInstallDirs)
+include(CMakePackageConfigHelpers)
+
+install(
+  TARGETS SimpleTest
+  EXPORT SimpleTestTargets
+  FILE_SET HEADERS
+)
+
+install(
+  EXPORT SimpleTestTargets
+  DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/SimpleTest
+  NAMESPACE SimpleTest::
+)
+
+write_basic_package_version_file(
+  ${CMAKE_CURRENT_BINARY_DIR}/SimpleTestConfigVersion.cmake
+  COMPATIBILITY ExactVersion
+  ARCH_INDEPENDENT
+)
+
+install(
+  FILES
+    cmake/simpletest_discover_impl.cmake
+    cmake/simpletest_discover_tests.cmake
+    cmake/SimpleTestConfig.cmake
+    ${CMAKE_CURRENT_BINARY_DIR}/SimpleTestConfigVersion.cmake
+  DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/SimpleTest
+)

+ 16 - 0
Help/guide/tutorial/Step10/SimpleTest/CMakePresets.json

@@ -0,0 +1,16 @@
+{
+  "version": 4,
+  "configurePresets": [
+    {
+      "name": "tutorial",
+      "displayName": "SimpleTest Preset",
+      "description": "Preset to use with the tutorial's SimpleTest library",
+      "binaryDir": "${sourceDir}/build",
+      "installDir": "${sourceParentDir}/install",
+      "cacheVariables": {
+        "CMAKE_CXX_STANDARD": "20",
+        "CMAKE_PREFIX_PATH": "${sourceParentDir}/install"
+      }
+    }
+  ]
+}

+ 151 - 0
Help/guide/tutorial/Step10/SimpleTest/SimpleTest.h

@@ -0,0 +1,151 @@
+#pragma once
+
+#include <cstdio>
+#include <map>
+#include <string_view>
+
+namespace SimpleTest {
+
+using TestFunc = void (*)();
+
+using Registry = std::map<std::string_view, TestFunc, std::less<>>;
+inline Registry g_registry;
+
+inline Registry& registry()
+{
+  return g_registry;
+}
+
+struct failure
+{
+  char const* file;
+  int line;
+  char const* expr;
+};
+
+struct Registrar
+{
+  template <std::size_t N>
+  Registrar(char const (&name)[N], TestFunc f)
+  {
+    auto [it, inserted] =
+      registry().emplace(std::string_view{ name, N ? (N - 1) : 0 }, f);
+    if (!inserted) {
+      std::printf("[  WARN    ] duplicate test name: %.*s\n",
+                  int(it->first.size()), it->first.data());
+    }
+  }
+};
+
+inline Registry const& all()
+{
+  return registry();
+}
+inline TestFunc find(std::string_view name)
+{
+  auto it = registry().find(name);
+  return it == registry().end() ? nullptr : it->second;
+}
+
+}
+
+#define SIMPLETEST_CONCAT_(a, b) a##b
+#define SIMPLETEST_CONCAT(a, b) SIMPLETEST_CONCAT_(a, b)
+
+#define TEST(name_literal)                                                    \
+  static void SIMPLETEST_CONCAT(_simpletest_fn_, __LINE__)();                 \
+  static ::SimpleTest::Registrar SIMPLETEST_CONCAT(_simpletest_reg_,          \
+                                                   __LINE__)(                 \
+    name_literal, &SIMPLETEST_CONCAT(_simpletest_fn_, __LINE__));             \
+  static void SIMPLETEST_CONCAT(_simpletest_fn_, __LINE__)()
+
+// Minimal assertion
+#define REQUIRE(expr)                                                         \
+  do {                                                                        \
+    if (!(expr))                                                              \
+      throw ::SimpleTest::failure{ __FILE__, __LINE__, #expr };               \
+  } while (0)
+
+int main(int argc, char** argv)
+{
+  using namespace ::SimpleTest;
+
+  std::string_view arg1 =
+    (argc >= 2) ? std::string_view{ argv[1] } : std::string_view{};
+
+  if (arg1 == "--list") {
+    bool first = true;
+    for (auto const& [name, _] : registry()) {
+      if (!first)
+        std::printf(",");
+      std::printf("%.*s", int(name.size()), name.data());
+      first = false;
+    }
+    std::printf("\n");
+    return 0;
+  }
+
+  if (arg1 == "--test") {
+    if (argc < 3) {
+      std::printf("usage: %s [--list] [--test <name>]\n", argv[0]);
+      return 2;
+    }
+
+#ifdef SIMPLETEST_CONFIG
+    std::printf("SimpleTest built with config: %s\n", SIMPLETEST_CONFIG);
+#endif
+
+    std::string_view name{ argv[2] };
+    auto it = registry().find(name);
+    if (it == registry().end()) {
+      std::printf("[ NOTFOUND ] %s\n", argv[2]);
+      return 2;
+    }
+
+    int failed = 0;
+    std::printf("[ RUN      ] %.*s\n", int(it->first.size()),
+                it->first.data());
+    try {
+      it->second();
+      std::printf("[       OK] %.*s\n", int(it->first.size()),
+                  it->first.data());
+    } catch (failure const& f) {
+      std::printf("[  FAILED  ] %.*s at %s:%d : %s\n", int(it->first.size()),
+                  it->first.data(), f.file, f.line, f.expr);
+      failed = 1;
+    } catch (...) {
+      std::printf("[  FAILED  ] %.*s : unknown exception\n",
+                  int(it->first.size()), it->first.data());
+      failed = 1;
+    }
+    return failed;
+  }
+
+  if (argc > 1) {
+    std::printf("usage: %s [--list] [--test <name>]\n", argv[0]);
+    return 2;
+  }
+
+#ifdef SIMPLETEST_CONFIG
+  std::printf("SimpleTest built with config: %s\n", SIMPLETEST_CONFIG);
+#endif
+
+  // Default: run all tests.
+  int failed = 0;
+  for (auto const& [name, func] : all()) {
+    std::printf("[ RUN      ] %.*s\n", int(name.size()), name.data());
+    try {
+      func();
+      std::printf("[       OK ] %.*s\n", int(name.size()), name.data());
+    } catch (failure const& f) {
+      std::printf("[  FAILED  ] %.*s at %s:%d : %s\n", int(name.size()),
+                  name.data(), f.file, f.line, f.expr);
+      failed = 1;
+    } catch (...) {
+      std::printf("[  FAILED  ] %.*s : unknown exception\n", int(name.size()),
+                  name.data());
+      failed = 1;
+    }
+  }
+  return failed;
+}

+ 6 - 0
Help/guide/tutorial/Step10/SimpleTest/cmake/SimpleTestConfig.cmake

@@ -0,0 +1,6 @@
+# TODO8: Include the CMakeFindDependencyMacro and use find_dependency to find
+#        the TransitiveDep package.
+
+
+include(${CMAKE_CURRENT_LIST_DIR}/SimpleTestTargets.cmake)
+include(${CMAKE_CURRENT_LIST_DIR}/simpletest_discover_tests.cmake)

+ 32 - 0
Help/guide/tutorial/Step10/SimpleTest/cmake/simpletest_discover_impl.cmake

@@ -0,0 +1,32 @@
+if(NOT DEFINED TEST_EXE OR NOT DEFINED OUT_FILE)
+# noqa: spellcheck off
+  message(FATAL_ERROR "simpletest_discover: need -DTEST_EXE and -DOUT_FILE")
+# noqa: spellcheck on
+endif()
+
+execute_process(
+  COMMAND ${TEST_EXE} --list
+  RESULT_VARIABLE _rc
+  OUTPUT_VARIABLE _out
+  ERROR_VARIABLE _err
+  OUTPUT_STRIP_TRAILING_WHITESPACE
+)
+
+if(NOT _rc EQUAL 0)
+  file(WRITE ${OUT_FILE} "# simpletest: --list failed (rc=${_rc})\n")
+  message(FATAL_ERROR "simpletest_discover: '${TEST_EXE} --list' failed (${_rc})\n${_err}")
+endif()
+
+if(_out STREQUAL "")
+  file(WRITE ${OUT_FILE} "# simpletest: no tests\n")
+  return()
+endif()
+
+string(REPLACE "," ";" _names "${_out}")
+
+file(WRITE ${OUT_FILE} "# Auto-generated by simpletest_discover_impl.cmake\n")
+foreach(_name IN LISTS _names)
+  file(APPEND ${OUT_FILE}
+    "add_test([=[${_name}]=] \"${TEST_EXE}\" \"--test\" \"${_name}\")\n"
+  )
+endforeach()

+ 27 - 0
Help/guide/tutorial/Step10/SimpleTest/cmake/simpletest_discover_tests.cmake

@@ -0,0 +1,27 @@
+set(_simpletest_impl_script ${CMAKE_CURRENT_LIST_DIR}/simpletest_discover_impl.cmake)
+
+function(simpletest_discover_tests target)
+  if(NOT TARGET ${target})
+    message(FATAL_ERROR "simpletest_discover_tests: no such target '${target}'")
+  endif()
+
+  set(_out ${CMAKE_CURRENT_BINARY_DIR}/${target}_ctests.cmake)
+
+  if(NOT EXISTS ${_out})
+    file(WRITE ${_out} "# Populated after building ${target}\n")
+  endif()
+
+# noqa: spellcheck off
+  add_custom_command(TARGET ${target} POST_BUILD
+    COMMAND ${CMAKE_COMMAND}
+      -DTEST_EXE=$<TARGET_FILE:${target}>
+      -DOUT_FILE=${_out}
+      -P ${_simpletest_impl_script}
+    BYPRODUCTS ${_out}
+    COMMENT "SimpleTest: Discovering tests in ${target}"
+    VERBATIM
+  )
+# noqa: spellcheck on
+
+  set_property(DIRECTORY APPEND PROPERTY TEST_INCLUDE_FILES ${_out})
+endfunction()

+ 0 - 3
Help/guide/tutorial/Step10/TutorialConfig.h.in

@@ -1,3 +0,0 @@
-// the configured options and settings for Tutorial
-#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
-#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@

+ 63 - 0
Help/guide/tutorial/Step10/TutorialProject/CMakeLists.txt

@@ -0,0 +1,63 @@
+cmake_minimum_required(VERSION 3.23)
+
+project(Tutorial
+  VERSION 1.0.0
+)
+
+option(TUTORIAL_BUILD_UTILITIES "Build the Tutorial executable" ON)
+option(TUTORIAL_USE_STD_SQRT "Use std::sqrt" OFF)
+option(TUTORIAL_ENABLE_IPO "Check for and use IPO support" ON)
+option(BUILD_TESTING "Enable testing and build tests" ON)
+
+if(TUTORIAL_ENABLE_IPO)
+  include(CheckIPOSupported)
+  check_ipo_supported(RESULT result OUTPUT output)
+  if(result)
+    set(CMAKE_INTERPROCEDURAL_OPTIMIZATION ON)
+  else()
+    message(WARNING "IPO is not supported ${message}")
+  endif()
+endif()
+
+if(TUTORIAL_BUILD_UTILITIES)
+  add_subdirectory(Tutorial)
+  install(
+    TARGETS Tutorial
+    EXPORT TutorialTargets
+  )
+endif()
+
+if(BUILD_TESTING)
+  enable_testing()
+  add_subdirectory(Tests)
+endif()
+
+add_subdirectory(MathFunctions)
+
+include(GNUInstallDirs)
+
+install(
+  TARGETS MathFunctions OpAdd OpMul OpSub MathLogger SqrtTable
+  EXPORT TutorialTargets
+  FILE_SET HEADERS
+)
+
+install(
+  EXPORT TutorialTargets
+  DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Tutorial
+  NAMESPACE Tutorial::
+)
+
+include(CMakePackageConfigHelpers)
+
+write_basic_package_version_file(
+  ${CMAKE_CURRENT_BINARY_DIR}/TutorialConfigVersion.cmake
+  COMPATIBILITY ExactVersion
+)
+
+install(
+  FILES
+    cmake/TutorialConfig.cmake
+    ${CMAKE_CURRENT_BINARY_DIR}/TutorialConfigVersion.cmake
+  DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Tutorial
+)

+ 16 - 0
Help/guide/tutorial/Step10/TutorialProject/CMakePresets.json

@@ -0,0 +1,16 @@
+{
+  "version": 4,
+  "configurePresets": [
+    {
+      "name": "tutorial",
+      "displayName": "Tutorial Preset",
+      "description": "Preset to use with the tutorial",
+      "binaryDir": "${sourceDir}/build",
+      "cacheVariables": {
+        "TODO4": "Add ${sourceParentDir}/install to CMAKE_PREFIX_PATH",
+        "TUTORIAL_USE_STD_SQRT": "OFF",
+        "TUTORIAL_ENABLE_IPO": "OFF"
+      }
+    }
+  ]
+}

+ 54 - 0
Help/guide/tutorial/Step10/TutorialProject/MathFunctions/CMakeLists.txt

@@ -0,0 +1,54 @@
+add_library(MathFunctions)
+
+target_sources(MathFunctions
+  PRIVATE
+    MathFunctions.cxx
+
+  PUBLIC
+    FILE_SET HEADERS
+    FILES
+      MathFunctions.h
+)
+
+target_link_libraries(MathFunctions
+  PRIVATE
+    MathLogger
+    SqrtTable
+
+  PUBLIC
+    OpAdd
+    OpMul
+    OpSub
+)
+
+target_compile_features(MathFunctions PRIVATE cxx_std_20)
+
+if(TUTORIAL_USE_STD_SQRT)
+  target_compile_definitions(MathFunctions PRIVATE TUTORIAL_USE_STD_SQRT)
+endif()
+
+include(CheckIncludeFiles)
+check_include_files(emmintrin.h HAS_EMMINTRIN LANGUAGE CXX)
+
+if(HAS_EMMINTRIN)
+  target_compile_definitions(MathFunctions PRIVATE TUTORIAL_USE_SSE2)
+endif()
+
+include(CheckSourceCompiles)
+check_source_compiles(CXX
+  [=[
+    typedef double v2df __attribute__((vector_size(16)));
+    int main() {
+      __builtin_ia32_sqrtsd(v2df{});
+    }
+  ]=]
+  HAS_GNU_BUILTIN
+)
+
+if(HAS_GNU_BUILTIN)
+  target_compile_definitions(MathFunctions PRIVATE TUTORIAL_USE_GNU_BUILTIN)
+endif()
+
+add_subdirectory(MathLogger)
+add_subdirectory(MathExtensions)
+add_subdirectory(MakeTable)

+ 28 - 0
Help/guide/tutorial/Step10/TutorialProject/MathFunctions/MakeTable/CMakeLists.txt

@@ -0,0 +1,28 @@
+add_executable(MakeTable)
+
+target_sources(MakeTable
+  PRIVATE
+    MakeTable.cxx
+)
+
+add_custom_command(
+  OUTPUT SqrtTable.h
+  COMMAND MakeTable SqrtTable.h
+  DEPENDS MakeTable
+  VERBATIM
+)
+
+add_custom_target(RunMakeTable DEPENDS SqrtTable.h)
+
+add_library(SqrtTable INTERFACE)
+
+target_sources(SqrtTable
+  INTERFACE
+    FILE_SET HEADERS
+    BASE_DIRS
+      ${CMAKE_CURRENT_BINARY_DIR}
+    FILES
+      ${CMAKE_CURRENT_BINARY_DIR}/SqrtTable.h
+)
+
+add_dependencies(SqrtTable RunMakeTable)

+ 0 - 0
Help/guide/tutorial/Step10/MathFunctions/MakeTable.cxx → Help/guide/tutorial/Step10/TutorialProject/MathFunctions/MakeTable/MakeTable.cxx


+ 3 - 0
Help/guide/tutorial/Step10/TutorialProject/MathFunctions/MathExtensions/CMakeLists.txt

@@ -0,0 +1,3 @@
+add_subdirectory(OpAdd)
+add_subdirectory(OpMul)
+add_subdirectory(OpSub)

+ 11 - 0
Help/guide/tutorial/Step10/TutorialProject/MathFunctions/MathExtensions/OpAdd/CMakeLists.txt

@@ -0,0 +1,11 @@
+add_library(OpAdd OBJECT)
+
+target_sources(OpAdd
+  PRIVATE
+    OpAdd.cxx
+
+  INTERFACE
+    FILE_SET HEADERS
+    FILES
+      OpAdd.h
+)

+ 6 - 0
Help/guide/tutorial/Step10/TutorialProject/MathFunctions/MathExtensions/OpAdd/OpAdd.cxx

@@ -0,0 +1,6 @@
+namespace mathfunctions {
+double OpAdd(double a, double b)
+{
+  return a + b;
+}
+}

Některé soubory nejsou zobrazeny, neboť je v těchto rozdílových datech změněno mnoho souborů