diff options
Diffstat (limited to 'Help/guide')
65 files changed, 1879 insertions, 720 deletions
diff --git a/Help/guide/ide-integration/index.rst b/Help/guide/ide-integration/index.rst index 8473481..e198789 100644 --- a/Help/guide/ide-integration/index.rst +++ b/Help/guide/ide-integration/index.rst @@ -47,8 +47,9 @@ does, and present the user with the presets listed in the file. Users should be able to see (and possibly edit) the CMake cache variables, environment variables, and command line options that are defined for a given preset. The IDE should then construct the list of appropriate :manual:`cmake(1)` command -line arguments based on these settings, rather than using the ``--preset=`` -option directly. The ``--preset=`` option is intended only as a convenient +line arguments based on these settings, rather than using the +:option:`--preset= <cmake --preset>` option directly. The +:option:`--preset= <cmake --preset>` option is intended only as a convenient frontend for command line users, and should not be used by the IDE. For example, if a preset named ``ninja`` specifies ``Ninja`` as the generator @@ -66,10 +67,9 @@ run: cmake -S /path/to/source -B /path/to/source/build -G Ninja In cases where a preset contains lots of cache variables, and passing all of -them as ``-D`` flags would cause the command line length limit of the platform -to be exceeded, the IDE should instead construct a temporary cache script and -pass it with the ``-C`` flag. See :ref:`CMake Options` for details on how the -``-C`` flag is used. +them as :option:`-D <cmake -D>` flags would cause the command line length limit +of the platform to be exceeded, the IDE should instead construct a temporary +cache script and pass it with the :option:`-C <cmake -C>` flag. While reading, parsing, and evaluating the contents of ``CMakePresets.json`` is straightforward, it is not trivial. In addition to the documentation, IDE @@ -110,8 +110,9 @@ Building If a Makefile or Ninja generator is used to generate the build tree, it is not recommended to invoke ``make`` or ``ninja`` directly. Instead, it is -recommended that the IDE invoke :manual:`cmake(1)` with the ``--build`` -argument, which will in turn invoke the appropriate build tool. +recommended that the IDE invoke :manual:`cmake(1)` with the +:option:`--build <cmake --build>` argument, which will in turn invoke the +appropriate build tool. If an IDE project generator is used, such as :generator:`Xcode` or one of the Visual Studio generators, and the IDE understands the project format used, the diff --git a/Help/guide/tutorial/A Basic Starting Point.rst b/Help/guide/tutorial/A Basic Starting Point.rst index cf1ec01..3dac68a 100644 --- a/Help/guide/tutorial/A Basic Starting Point.rst +++ b/Help/guide/tutorial/A Basic Starting Point.rst @@ -1,34 +1,81 @@ Step 1: A Basic Starting Point ============================== -The most basic project is an executable built from source code files. -For simple projects, a three line ``CMakeLists.txt`` file is all that is -required. This will be the starting point for our tutorial. Create a -``CMakeLists.txt`` file in the ``Step1`` directory that looks like: - -.. code-block:: cmake - :caption: CMakeLists.txt - :name: CMakeLists.txt-start - - cmake_minimum_required(VERSION 3.10) +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 next. So, 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 +------------- - # set the project name - project(Tutorial) +* ``CMakeLists.txt`` - # add the executable - add_executable(Tutorial tutorial.cxx) +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. -Note that this example uses lower case commands in the ``CMakeLists.txt`` file. -Upper, lower, and mixed case commands are supported by CMake. The source -code for ``tutorial.cxx`` is provided in the ``Step1`` directory and can be -used to compute the square root of a number. +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 ------------- -That's all that is needed - we can build and run our project now! First, run -the :manual:`cmake <cmake(1)>` executable or the +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. @@ -40,8 +87,9 @@ build directory: mkdir Step1_build -Next, navigate to the build directory and run CMake to configure the project -and generate a native build system: +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 @@ -62,114 +110,352 @@ Finally, try to use the newly built ``Tutorial`` with these commands: Tutorial 10 Tutorial +Solution +-------- -Adding a Version Number and Configured Header File --------------------------------------------------- +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: -The first feature we will add is to provide our executable and project with a -version number. While we could do this exclusively in the source code, using -``CMakeLists.txt`` provides more flexibility. +.. raw:: html -First, modify the ``CMakeLists.txt`` file to use the :command:`project` command -to set the project name and version number. + <details><summary>TODO 1: Click to show/hide answer</summary> .. literalinclude:: Step2/CMakeLists.txt - :caption: CMakeLists.txt - :name: CMakeLists.txt-project-VERSION + :caption: TODO 1: CMakeLists.txt + :name: CMakeLists.txt-cmake_minimum_required :language: cmake - :end-before: # specify the C++ standard + :end-before: # set the project name and version -Then, configure a header file to pass the version number to the source -code: +.. raw:: html -.. literalinclude:: Step2/CMakeLists.txt - :caption: CMakeLists.txt - :name: CMakeLists.txt-configure_file - :language: cmake - :start-after: # to the source code - :end-before: # add the executable + </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 -Since the configured file will be written into the binary tree, we -must add that directory to the list of paths to search for include -files. Add the following lines to the end of the ``CMakeLists.txt`` file: + </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: CMakeLists.txt - :name: CMakeLists.txt-target_include_directories + :caption: TODO 3: CMakeLists.txt + :name: CMakeLists.txt-add_executable :language: cmake - :start-after: # so that we will find TutorialConfig.h + :start-after: # add the executable + :end-before: # TODO 9: -Using your favorite editor, create ``TutorialConfig.h.in`` in the source -directory with the following contents: +.. raw:: html -.. literalinclude:: Step2/TutorialConfig.h.in - :caption: TutorialConfig.h.in - :name: TutorialConfig.h.in - :language: c++ + </details> -When CMake configures this header file the values for -``@Tutorial_VERSION_MAJOR@`` and ``@Tutorial_VERSION_MINOR@`` will be -replaced. +Exercise 2 - Specifying the C++ Standard +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Next modify ``tutorial.cxx`` to include the configured header file, -``TutorialConfig.h``. +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. -Finally, let's print out the executable name and version number by updating -``tutorial.cxx`` as follows: +Goal +---- -.. literalinclude:: Step2/tutorial.cxx - :caption: tutorial.cxx - :name: tutorial.cxx-print-version - :language: c++ - :start-after: { - :end-before: // convert input to double +Add a feature that requires C++11. + +Helpful Resources +----------------- + +* :variable:`CMAKE_CXX_STANDARD` +* :variable:`CMAKE_CXX_STANDARD_REQUIRED` +* :command:`set` + +Files to Edit +------------- -Specify the C++ Standard -------------------------- +* ``CMakeLists.txt`` +* ``tutorial.cxx`` -Next let's add some C++11 features to our project by replacing ``atof`` with -``std::stod`` in ``tutorial.cxx``. At the same time, remove -``#include <cstdlib>``. +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: tutorial.cxx + :caption: TODO 4: tutorial.cxx :name: tutorial.cxx-cxx11 :language: c++ :start-after: // convert input to double - :end-before: // calculate square root + :end-before: // TODO 12: + +.. 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. The easiest 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 ``CMAKE_CXX_STANDARD`` declarations above the -call to ``add_executable``. +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: CMakeLists.txt + :caption: TODO 6: CMakeLists.txt :name: CMakeLists.txt-CXX_STANDARD :language: cmake - :end-before: # configure a header file to pass some of the CMake settings + :start-after: # specify the C++ standard + :end-before: # TODO 7: + +.. raw:: html -Rebuild -------- + </details> -Let's build our project again. We already created a build directory and ran -CMake, so we can skip to the build step: +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`` + +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 . -Now we can try to use the newly built ``Tutorial`` with same commands as before: +Verify that the version number is now reported when running the executable +without any arguments. -.. code-block:: console +Solution +-------- - Tutorial 4294967296 - Tutorial 10 - Tutorial +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 8: + +.. 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++ + :end-before: // TODO 13: + +.. 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 -Check that the version number is now reported when running the executable without -any arguments. + </details> diff --git a/Help/guide/tutorial/Adding Export Configuration.rst b/Help/guide/tutorial/Adding Export Configuration.rst index 3bd6d64..eb14f42 100644 --- a/Help/guide/tutorial/Adding Export Configuration.rst +++ b/Help/guide/tutorial/Adding Export Configuration.rst @@ -21,7 +21,7 @@ in ``MathFunctions/CMakeLists.txt`` to look like: :caption: MathFunctions/CMakeLists.txt :name: MathFunctions/CMakeLists.txt-install-TARGETS-EXPORT :language: cmake - :start-after: # install rules + :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 diff --git a/Help/guide/tutorial/Adding Generator Expressions.rst b/Help/guide/tutorial/Adding Generator Expressions.rst index 7fcc97f..6f9714e 100644 --- a/Help/guide/tutorial/Adding Generator Expressions.rst +++ b/Help/guide/tutorial/Adding Generator Expressions.rst @@ -1,4 +1,4 @@ -Step 10: Adding Generator Expressions +Step 4: Adding Generator Expressions ===================================== :manual:`Generator expressions <cmake-generator-expressions(7)>` are evaluated @@ -27,58 +27,280 @@ expressions are the ``0`` and ``1`` expressions. A ``$<0:...>`` results in the empty string, and ``<1:...>`` results in the content of ``...``. They can also be nested. +Exercise 1 - Setting the C++ Standard with Interface Libraries +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Before we use :manual:`generator expressions <cmake-generator-expressions(7)>` +let's refactor our existing code to use an ``INTERFACE`` library. We will +use that library in the next step to demonstrate a common use for +:manual:`generator expressions <cmake-generator-expressions(7)>`. + +Goal +---- + +Add an ``INTERFACE`` library target to specify the required C++ standard. + +Helpful Resources +----------------- + +* :command:`add_library` +* :command:`target_compile_features` +* :command:`target_link_libraries` + +Files to Edit +------------- + +* ``CMakeLists.txt`` +* ``MathFunctions/CMakeLists.txt`` + +Getting Started +--------------- + +In this exercise, we will refactor our code to use an ``INTERFACE`` library to +specify the C++ standard. + +The starting source code is provided in the ``Step4`` directory. In this +exercise, complete ``TODO 1`` through ``TODO 3``. + +Start by editing the top level ``CMakeLists.txt`` file. Construct an +``INTERFACE`` library target called ``tutorial_compiler_flags`` and +specify ``cxx_std_11`` as a target compiler feature. + +Modify ``CMakeLists.txt`` and ``MathFunctions/CMakeLists.txt`` so that all +targets have a :command:`target_link_libraries` call to +``tutorial_compiler_flags``. + +Build and Run +------------- + +Make a new directory called ``Step4_build``, run the :manual:`cmake <cmake(1)>` +executable or the :manual:`cmake-gui <cmake-gui(1)>` to configure the project +and then build it with your chosen build tool or by using ``cmake --build .`` +from the build directory. + +Here's a refresher of what that looks like from the command line: + +.. code-block:: console + + mkdir Step4_build + cd Step4_build + cmake ../Step4 + cmake --build . + +Next, use the newly built ``Tutorial`` and verify that it is working as +expected. + +Solution +-------- + +Let's update our code from the previous step to use interface libraries +to set our C++ requirements. + +To start, we need to remove the two :command:`set` calls on the variables +:variable:`CMAKE_CXX_STANDARD` and :variable:`CMAKE_CXX_STANDARD_REQUIRED`. +The specific lines to remove are as follows: + +.. literalinclude:: Step4/CMakeLists.txt + :caption: CMakeLists.txt + :name: CMakeLists.txt-CXX_STANDARD-variable-remove + :language: cmake + :start-after: # specify the C++ standard + :end-before: # TODO 5: Create helper variables + +Next, we need to create an interface library, ``tutorial_compiler_flags``. And +then use :command:`target_compile_features` to add the compiler feature +``cxx_std_11``. + + +.. raw:: html + + <details><summary>TODO 1: Click to show/hide answer</summary> + +.. literalinclude:: Step5/CMakeLists.txt + :caption: TODO 1: CMakeLists.txt + :name: CMakeLists.txt-cxx_std-feature + :language: cmake + :start-after: # specify the C++ standard + :end-before: # add compiler warning flags just + +.. raw:: html + + </details> + +Finally, with our interface library set up, we need to link our +executable ``Target`` and our ``MathFunctions`` library to our new +``tutorial_compiler_flags`` library. Respectively, the code will look like +this: + +.. raw:: html + + <details><summary>TODO 2: Click to show/hide answer</summary> + +.. literalinclude:: Step5/CMakeLists.txt + :caption: TODO 2: CMakeLists.txt + :name: CMakeLists.txt-target_link_libraries-step4 + :language: cmake + :start-after: add_executable(Tutorial tutorial.cxx) + :end-before: # add the binary tree to the search path for include file + +.. raw:: html + + </details> + +and this: + +.. raw:: html + + <details><summary>TODO 3: Click to show/hide answer</summary> + +.. literalinclude:: Step5/MathFunctions/CMakeLists.txt + :caption: TODO 3: MathFunctions/CMakeLists.txt + :name: MathFunctions-CMakeLists.txt-target_link_libraries-step4 + :language: cmake + :start-after: # link our compiler flags interface library + :end-before: # TODO 1 + +.. raw:: html + + </details> + +With this, all of our code still requires C++ 11 to build. Notice +though that with this method, it gives us the ability to be specific about +which targets get specific requirements. In addition, we create a single +source of truth in our interface library. + +Exercise 2 - Adding Compiler Warning Flags with Generator Expressions +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + A common usage of :manual:`generator expressions <cmake-generator-expressions(7)>` is to conditionally add compiler flags, such as those for language levels or warnings. A nice pattern is to associate this information to an ``INTERFACE`` -target allowing this information to propagate. Let's start by constructing an -``INTERFACE`` target and specifying the required C++ standard level of ``11`` -instead of using :variable:`CMAKE_CXX_STANDARD`. +target allowing this information to propagate. -So the following code: +Goal +---- -.. literalinclude:: Step10/CMakeLists.txt - :caption: CMakeLists.txt - :name: CMakeLists.txt-CXX_STANDARD-variable-remove +Add compiler warning flags when building but not for installed versions. + +Helpful Resources +----------------- + +* :manual:`cmake-generator-expressions(7)` +* :command:`cmake_minimum_required` +* :command:`set` +* :command:`target_compile_options` + +Files to Edit +------------- + +* ``CMakeLists.txt`` + +Getting Started +--------------- + +Start with the resulting files from Exercise 1. Complete ``TODO 4`` through +``TODO 7``. + +First, in the top level ``CMakeLists.txt`` file, we need to set the +:command:`cmake_minimum_required` to ``3.15``. In this exercise we are going +to use a generator expression which was introduced in CMake 3.15. + +Next we add the desired compiler warning flags that we want for our project. +As warning flags vary based on the compiler, we use the +``COMPILE_LANG_AND_ID`` generator expression to control which flags to apply +given a language and a set of compiler ids. + +Build and Run +------------- + +Since we have our build directory already configured from Exercise 1, simply +rebuild our code by calling the following: + +.. code-block:: console + + cd Step4_build + cmake --build . + +Solution +-------- + +Update the :command:`cmake_minimum_required` to require at least CMake +version ``3.15``: + +.. raw:: html + + <details><summary>TODO 4: Click to show/hide answer</summary> + +.. literalinclude:: Step5/CMakeLists.txt + :caption: TODO 4: CMakeLists.txt + :name: MathFunctions-CMakeLists.txt-minimum-required-step4 :language: cmake - :start-after: project(Tutorial VERSION 1.0) - :end-before: # control where the static and shared libraries are built so that on windows + :end-before: # set the project name and version -Would be replaced with: +.. raw:: html -.. literalinclude:: Step11/CMakeLists.txt - :caption: CMakeLists.txt - :name: CMakeLists.txt-cxx_std-feature + </details> + +Next we determine which compiler our system is currently using to build +since warning flags vary based on the compiler we use. This is done with +the ``COMPILE_LANG_AND_ID`` generator expression. We set the result in the +variables ``gcc_like_cxx`` and ``msvc_cxx`` as follows: + +.. raw:: html + + <details><summary>TODO 5: Click to show/hide answer</summary> + +.. literalinclude:: Step5/CMakeLists.txt + :caption: TODO 5: CMakeLists.txt + :name: CMakeLists.txt-compile_lang_and_id :language: cmake - :start-after: project(Tutorial VERSION 1.0) - :end-before: # add compiler warning flags just when building this project via + :start-after: # the BUILD_INTERFACE genex + :end-before: target_compile_options(tutorial_compiler_flags INTERFACE -**Note**: This upcoming section will require a change to the -:command:`cmake_minimum_required` usage in the code. The Generator Expression -that is about to be used was introduced in `3.15`. Update the call to require -that more recent version: +.. raw:: html + + </details> + +Next we add the desired compiler warning flags that we want for our project. +Using our variables ``gcc_like_cxx`` and ``msvc_cxx``, we can use another +generator expression to apply the respective flags only when the variables are +true. We use :command:`target_compile_options` to apply these flags to our +interface library. + +.. raw:: html + + <details><summary>TODO 6: Click to show/hide answer</summary> .. code-block:: cmake - :caption: CMakeLists.txt - :name: CMakeLists.txt-version-update + :caption: TODO 6: CMakeLists.txt + :name: CMakeLists.txt-compile_flags - cmake_minimum_required(VERSION 3.15) + target_compile_options(tutorial_compiler_flags INTERFACE + "$<${gcc_like_cxx}:-Wall;-Wextra;-Wshadow;-Wformat=2;-Wunused>" + "$<${msvc_cxx}:-W3>" + ) -Next we add the desired compiler warning flags that we want for our project. As -warning flags vary based on the compiler we use the ``COMPILE_LANG_AND_ID`` -generator expression to control which flags to apply given a language and a set -of compiler ids as seen below: +.. raw:: html -.. literalinclude:: Step11/CMakeLists.txt - :caption: CMakeLists.txt + </details> + +Lastly, we only want these warning flags to be used during builds. Consumers +of our installed project should not inherit our warning flags. To specify +this, we wrap our flags in a generator expression using the ``BUILD_INTERFACE`` +condition. The resulting full code looks like the following: + +.. raw:: html + + <details><summary>TODO 7: Click to show/hide answer</summary> + +.. literalinclude:: Step5/CMakeLists.txt + :caption: TODO 7: CMakeLists.txt :name: CMakeLists.txt-target_compile_options-genex :language: cmake - :start-after: # the BUILD_INTERFACE genex - :end-before: # control where the static and shared libraries are built so that on windows + :start-after: set(msvc_cxx "$<COMPILE_LANG_AND_ID:CXX,MSVC>") + :end-before: # should we use our own math functions -Looking at this we see that the warning flags are encapsulated inside a -``BUILD_INTERFACE`` condition. This is done so that consumers of our installed -project will not inherit our warning flags. +.. raw:: html -**Exercise**: Modify ``MathFunctions/CMakeLists.txt`` so that all targets have -a :command:`target_link_libraries` call to ``tutorial_compiler_flags``. + </details> diff --git a/Help/guide/tutorial/Adding Support for a Testing Dashboard.rst b/Help/guide/tutorial/Adding Support for a Testing Dashboard.rst index c6e0fd0..45d5976 100644 --- a/Help/guide/tutorial/Adding Support for a Testing Dashboard.rst +++ b/Help/guide/tutorial/Adding Support for a Testing Dashboard.rst @@ -1,4 +1,4 @@ -Step 8: Adding Support for a Testing Dashboard +Step 6: Adding Support for a Testing Dashboard ============================================== Adding support for submitting our test results to a dashboard is simple. We @@ -9,21 +9,21 @@ we include the :module:`CTest` module in our top-level ``CMakeLists.txt``. Replace: -.. code-block:: cmake +.. literalinclude:: Step6/CMakeLists.txt :caption: CMakeLists.txt :name: CMakeLists.txt-enable_testing-remove - - # enable testing - enable_testing() + :language: cmake + :start-after: # enable testing + :end-before: # does the application run With: -.. code-block:: cmake +.. literalinclude:: Step7/CMakeLists.txt :caption: CMakeLists.txt :name: CMakeLists.txt-include-CTest - - # enable dashboard scripting - include(CTest) + :language: cmake + :start-after: # enable testing + :end-before: # does the application run The :module:`CTest` module will automatically call ``enable_testing()``, so we can remove it from our CMake files. @@ -46,7 +46,7 @@ downloaded from the ``Settings`` page of the project on the CDash instance that will host and display the test results. Once downloaded from CDash, the file should not be modified locally. -.. literalinclude:: Step9/CTestConfig.cmake +.. literalinclude:: Step7/CTestConfig.cmake :caption: CTestConfig.cmake :name: CTestConfig.cmake :language: cmake diff --git a/Help/guide/tutorial/Adding System Introspection.rst b/Help/guide/tutorial/Adding System Introspection.rst index 8db0cb8..ba91df4 100644 --- a/Help/guide/tutorial/Adding System Introspection.rst +++ b/Help/guide/tutorial/Adding System Introspection.rst @@ -1,4 +1,4 @@ -Step 5: Adding System Introspection +Step 7: Adding System Introspection =================================== Let us consider adding some code to our project that depends on features the @@ -15,7 +15,7 @@ these functions using the :module:`CheckCXXSourceCompiles` module in Add the checks for ``log`` and ``exp`` to ``MathFunctions/CMakeLists.txt``, after the call to :command:`target_include_directories`: -.. literalinclude:: Step6/MathFunctions/CMakeLists.txt +.. literalinclude:: Step8/MathFunctions/CMakeLists.txt :caption: MathFunctions/CMakeLists.txt :name: MathFunctions/CMakeLists.txt-check_cxx_source_compiles :language: cmake @@ -25,19 +25,19 @@ after the call to :command:`target_include_directories`: If available, use :command:`target_compile_definitions` to specify ``HAVE_LOG`` and ``HAVE_EXP`` as ``PRIVATE`` compile definitions. -.. literalinclude:: Step6/MathFunctions/CMakeLists.txt +.. literalinclude:: Step8/MathFunctions/CMakeLists.txt :caption: MathFunctions/CMakeLists.txt :name: MathFunctions/CMakeLists.txt-target_compile_definitions :language: cmake :start-after: # add compile definitions - :end-before: # install rules + :end-before: # install libs If ``log`` and ``exp`` are available on the system, then we will use them to compute the square root in the ``mysqrt`` function. Add the following code to the ``mysqrt`` function in ``MathFunctions/mysqrt.cxx`` (don't forget the ``#endif`` before returning the result!): -.. literalinclude:: Step6/MathFunctions/mysqrt.cxx +.. literalinclude:: Step8/MathFunctions/mysqrt.cxx :caption: MathFunctions/mysqrt.cxx :name: MathFunctions/mysqrt.cxx-ifdef :language: c++ @@ -46,7 +46,7 @@ the ``mysqrt`` function in ``MathFunctions/mysqrt.cxx`` (don't forget the We will also need to modify ``mysqrt.cxx`` to include ``cmath``. -.. literalinclude:: Step6/MathFunctions/mysqrt.cxx +.. literalinclude:: Step8/MathFunctions/mysqrt.cxx :caption: MathFunctions/mysqrt.cxx :name: MathFunctions/mysqrt.cxx-include-cmath :language: c++ diff --git a/Help/guide/tutorial/Adding Usage Requirements for a Library.rst b/Help/guide/tutorial/Adding Usage Requirements for a Library.rst index a8e914e..4aef050 100644 --- a/Help/guide/tutorial/Adding Usage Requirements for a Library.rst +++ b/Help/guide/tutorial/Adding Usage Requirements for a Library.rst @@ -1,52 +1,147 @@ Step 3: Adding Usage Requirements for a Library =============================================== -Usage requirements 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_libraries` - -Let's refactor our code from :guide:`tutorial/Adding a Library` to use the -modern CMake approach of usage requirements. We first state that anybody -linking to ``MathFunctions`` needs to include the current source directory, -while ``MathFunctions`` itself doesn't. So this can become an ``INTERFACE`` -usage requirement. - -Remember ``INTERFACE`` means things that consumers require but the producer -doesn't. Add the following lines to the end of -``MathFunctions/CMakeLists.txt``: +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: 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: # TODO 3: Link to + +.. 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 +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``, here: +.. raw:: html + + <details><summary>TODO 2: Click to show/hide answer</summary> + .. literalinclude:: Step4/CMakeLists.txt - :caption: CMakeLists.txt + :caption: TODO 2: CMakeLists.txt :name: CMakeLists.txt-remove-EXTRA_INCLUDES :language: cmake :start-after: # add the MathFunctions library :end-before: # add the executable +.. raw:: html + + </details> + And here: +.. raw:: html + + <details><summary>TODO 3: Click to show/hide answer</summary> + .. literalinclude:: Step4/CMakeLists.txt - :caption: 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 -Once this is done, 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. +.. 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. diff --git a/Help/guide/tutorial/Adding a Custom Command and Generated File.rst b/Help/guide/tutorial/Adding a Custom Command and Generated File.rst index 70c6695..b1f9840 100644 --- a/Help/guide/tutorial/Adding a Custom Command and Generated File.rst +++ b/Help/guide/tutorial/Adding a Custom Command and Generated File.rst @@ -1,4 +1,4 @@ -Step 6: Adding a Custom Command and Generated File +Step 8: Adding a Custom Command and Generated File ================================================== Suppose, for the purpose of this tutorial, we decide that we never want to use @@ -26,7 +26,7 @@ accomplish this. First, at the top of ``MathFunctions/CMakeLists.txt``, the executable for ``MakeTable`` is added as any other executable would be added. -.. literalinclude:: Step7/MathFunctions/CMakeLists.txt +.. literalinclude:: Step9/MathFunctions/CMakeLists.txt :caption: MathFunctions/CMakeLists.txt :name: MathFunctions/CMakeLists.txt-add_executable-MakeTable :language: cmake @@ -36,7 +36,7 @@ First, at the top of ``MathFunctions/CMakeLists.txt``, the executable for Then we add a custom command that specifies how to produce ``Table.h`` by running MakeTable. -.. literalinclude:: Step7/MathFunctions/CMakeLists.txt +.. literalinclude:: Step9/MathFunctions/CMakeLists.txt :caption: MathFunctions/CMakeLists.txt :name: MathFunctions/CMakeLists.txt-add_custom_command-Table.h :language: cmake @@ -47,7 +47,7 @@ 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 MathFunctions. -.. literalinclude:: Step7/MathFunctions/CMakeLists.txt +.. literalinclude:: Step9/MathFunctions/CMakeLists.txt :caption: MathFunctions/CMakeLists.txt :name: MathFunctions/CMakeLists.txt-add_library-Table.h :language: cmake @@ -57,17 +57,17 @@ of sources for the library MathFunctions. 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:: Step7/MathFunctions/CMakeLists.txt +.. 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: # install rules + :end-before: # install libs 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:: Step7/MathFunctions/mysqrt.cxx +.. literalinclude:: Step9/MathFunctions/mysqrt.cxx :caption: MathFunctions/mysqrt.cxx :name: MathFunctions/mysqrt.cxx :language: c++ diff --git a/Help/guide/tutorial/Adding a Library.rst b/Help/guide/tutorial/Adding a Library.rst index 71755be..a56c327 100644 --- a/Help/guide/tutorial/Adding a Library.rst +++ b/Help/guide/tutorial/Adding a Library.rst @@ -1,136 +1,459 @@ Step 2: Adding a Library ======================== -Now we will add a library to our project. This library will contain our own +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 a header file, -``MathFunctions.h``, and a source file ``mysqrt.cxx``. The source file has one -function called ``mysqrt`` that provides similar functionality to the -compiler's ``sqrt`` function. +For this tutorial we will put the library into a subdirectory called +``MathFunctions``. This directory already contains a header file, +``MathFunctions.h``, and a source file ``mysqrt.cxx``. We will not need to +modify either of these files. The source file has one function called +``mysqrt`` that provides similar functionality to the compiler's ``sqrt`` +function. + +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 file for the library is passed as an argument to +:command:`add_library`. This looks like the following line: -Add the following one line ``CMakeLists.txt`` file to the ``MathFunctions`` -directory: +.. raw:: html + + <details><summary>TODO 1: Click to show/hide answer</summary> .. literalinclude:: Step3/MathFunctions/CMakeLists.txt - :caption: MathFunctions/CMakeLists.txt - :name: MathFunctions/CMakeLists.txt + :caption: TODO 1: MathFunctions/CMakeLists.txt + :name: MathFunctions/CMakeLists.txt-add_library :language: cmake + :end-before: # TODO 1 + +.. 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. We add the new library to the executable, and add ``MathFunctions`` as -an include directory so that the ``MathFunctions.h`` header file can be found. -The last few lines of the top-level ``CMakeLists.txt`` file should now look -like: +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 +:command:`target_include_directories` 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: CMakeLists.txt - :name: CMakeLists.txt-add_subdirectory + :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> - # add the MathFunctions library - add_subdirectory(MathFunctions) +.. code-block:: c++ + :caption: TODO 5 : tutorial.cxx + :name: tutorial.cxx-include_MathFunctions.h - # add the executable - add_executable(Tutorial tutorial.cxx) + #include "MathFunctions.h" - target_link_libraries(Tutorial PUBLIC MathFunctions) +.. raw:: html - # 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}" - "${PROJECT_SOURCE_DIR}/MathFunctions" - ) + </details> -Now let us make the ``MathFunctions`` library optional. While for the tutorial +Lastly, replace ``sqrt`` with our library function ``mysqrt``. + +.. raw:: html + + <details><summary>TODO 6: Click to show/hide answer</summary> + +.. code-block:: c++ + :caption: TODO 6 : tutorial.cxx + :name: tutorial.cxx-call_mysqrt + + const double outputValue = mysqrt(inputValue); + +.. raw:: html + + </details> + +Exercise 2 - Making Our Library Optional +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Now let us make the MathFunctions library optional. While for the tutorial there really isn't any need to do so, for larger projects this is a common -occurrence. The first step is to add an option to the top-level -``CMakeLists.txt`` file. +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:`list` +* :command:`option` +* :command:`cmakedefine <configure_file>` + +Files to Edit +------------- + +* ``CMakeLists.txt`` +* ``tutorial.cxx`` +* ``TutorialConfig.h.in`` + +Getting Started +--------------- + +Start with the resulting files from Exercise 1. Complete ``TODO 7`` through +``TODO 13``. + +First create a variable ``USE_MYMATH`` using the :command:`option` command +in the top-level ``CMakeLists.txt`` file. In that same file, use that option +to determine whether to build and use the ``MathFunctions`` library. + +Then, update ``tutorial.cxx`` and ``TutorialConfig.h.in`` to use +``USE_MYMATH``. + +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 the top-level ``CMakeLists.txt`` file. +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/CMakeLists.txt - :caption: CMakeLists.txt + :caption: TODO 7: CMakeLists.txt :name: CMakeLists.txt-option :language: cmake :start-after: # should we use our own math functions - :end-before: # add the MathFunctions library + :end-before: # configure a header file to pass some of the CMake settings -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. 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. - -The next change is to make building and linking the ``MathFunctions`` library -conditional. To do this, we will create an ``if`` statement which checks the -value of the option. Inside the ``if`` block, put the -:command:`add_subdirectory` command from above with some additional list -commands to store information needed to link to the library and add the -subdirectory as an include directory in the ``Tutorial`` target. -The end of the top-level ``CMakeLists.txt`` file will now look like the -following: +.. raw:: html + + </details> + +Next, make building and linking the ``MathFunctions`` library +conditional. + +Start by creating a :command:`list` of the optional library targets for our +project. At the moment, it is just ``MathFunctions``. Let's name our list +``EXTRA_LIBS``. + +Similarly, we need to make a :command:`list` for the optional includes which +we will call ``EXTRA_INCLUDES``. In this list, we will ``APPEND`` the path of +the header file needed for our library. + +Next, create an :command:`if` statement which checks the value of +``USE_MYMATH``. Inside the :command:`if` block, put the +:command:`add_subdirectory` command from Exercise 1 with the additional +:command:`list` commands. + +When ``USE_MYMATH`` is ``ON``, the lists will be generated and will be added to +our project. When ``USE_MYMATH`` is ``OFF``, the lists stay empty. With this +strategy, we allow users to toggle ``USE_MYMATH`` to manipulate what library is +used in the build. + +The top-level CMakeLists.txt file will now look like the following: + +.. raw:: html + + <details><summary>TODO 8: Click to show/hide answer</summary> .. literalinclude:: Step3/CMakeLists.txt - :caption: CMakeLists.txt - :name: CMakeLists.txt-target_link_libraries-EXTRA_LIBS + :caption: TODO 8: CMakeLists.txt + :name: CMakeLists.txt-USE_MYMATH :language: cmake :start-after: # add the MathFunctions library + :end-before: # add the executable + +.. raw:: html + + </details> -Note the use of the variable ``EXTRA_LIBS`` to collect up any optional -libraries to later be linked into the executable. The variable -``EXTRA_INCLUDES`` is used similarly for optional header files. This is a -classic approach when dealing with many optional components, we will cover -the modern approach in the next step. +Now that we have these two lists, we need to update +:command:`target_link_libraries` and :command:`target_include_directories` to +use them. Changing them is fairly straightforward. + +For :command:`target_link_libraries`, we replace the written out +library names with ``EXTRA_LIBS``. This looks like the following: + +.. raw:: html + + <details><summary>TODO 9: Click to show/hide answer</summary> + +.. literalinclude:: Step3/CMakeLists.txt + :caption: TODO 9: CMakeLists.txt + :name: CMakeLists.txt-target_link_libraries-EXTRA_LIBS + :language: cmake + :start-after: add_executable(Tutorial tutorial.cxx) + :end-before: # TODO 3 + +.. raw:: html + + </details> + +Then, we do the same thing with :command:`target_include_directories` and +``EXTRA_INCLUDES``. + +.. raw:: html + + <details><summary>TODO 10: Click to show/hide answer</summary> + +.. literalinclude:: Step3/CMakeLists.txt + :caption: TODO 10 : CMakeLists.txt + :name: CMakeLists.txt-target_link_libraries-EXTRA_INCLUDES + :language: cmake + :start-after: # so that we will find TutorialConfig.h + +.. raw:: html + + </details> + +Note that this is a classic approach when dealing with many components. We +will cover the modern approach in the Step 3 of the tutorial. The corresponding changes to the source code are fairly straightforward. -First, in ``tutorial.cxx``, include the ``MathFunctions.h`` header if we -need it: +First, in ``tutorial.cxx``, we include the ``MathFunctions.h`` header if +``USE_MYMATH`` is defined. + +.. raw:: html + + <details><summary>TODO 11: Click to show/hide answer</summary> .. literalinclude:: Step3/tutorial.cxx - :caption: tutorial.cxx + :caption: TODO 11 : tutorial.cxx :name: tutorial.cxx-ifdef-include :language: c++ :start-after: // should we include the MathFunctions header :end-before: int main -Then, in the same file, make ``USE_MYMATH`` control which square root +.. raw:: html + + </details> + +Then, in the same file, we make ``USE_MYMATH`` control which square root function is used: +.. raw:: html + + <details><summary>TODO 12: Click to show/hide answer</summary> + .. literalinclude:: Step3/tutorial.cxx - :caption: tutorial.cxx + :caption: TODO 12 : tutorial.cxx :name: tutorial.cxx-ifdef-const :language: c++ :start-after: // which square root function should we use? :end-before: std::cout << "The square root of +.. raw:: html + + </details> + Since the source code now requires ``USE_MYMATH`` we can add it to ``TutorialConfig.h.in`` with the following line: +.. raw:: html + + <details><summary>TODO 13: Click to show/hide answer</summary> + .. literalinclude:: Step3/TutorialConfig.h.in - :caption: TutorialConfig.h.in + :caption: TODO 13 : TutorialConfig.h.in :name: TutorialConfig.h.in-cmakedefine :language: c++ :lines: 4 -**Exercise**: Why is it important that we configure ``TutorialConfig.h.in`` +.. raw:: html + + </details> + +With these changes, our library is now completely optional to whoever is +building and using it. + +Bonus Question +-------------- + +Why is it important that we configure ``TutorialConfig.h.in`` after the option for ``USE_MYMATH``? What would happen if we inverted the two? -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 built Tutorial executable. +Answer +------ -Now let's update the value of ``USE_MYMATH``. 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: +.. raw:: html -.. code-block:: console + <details><summary>Click to show/hide answer</summary> - cmake ../Step2 -DUSE_MYMATH=OFF +We configure after because ``TutorialConfig.h.in`` uses the value of +``USE_MYMATH``. If we configure the file before +calling :command:`option`, we won't be using the expected value of +``USE_MYMATH``. -Rebuild and run the tutorial again. +.. raw:: html -Which function gives better results, ``sqrt`` or ``mysqrt``? + </details> diff --git a/Help/guide/tutorial/Complete/CMakeLists.txt b/Help/guide/tutorial/Complete/CMakeLists.txt index 41baf64..3cdaaae 100644 --- a/Help/guide/tutorial/Complete/CMakeLists.txt +++ b/Help/guide/tutorial/Complete/CMakeLists.txt @@ -41,7 +41,7 @@ add_subdirectory(MathFunctions) add_executable(Tutorial tutorial.cxx) set_target_properties(Tutorial PROPERTIES DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) -target_link_libraries(Tutorial PUBLIC MathFunctions) +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 @@ -84,6 +84,7 @@ 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}") diff --git a/Help/guide/tutorial/Complete/License.txt b/Help/guide/tutorial/Complete/License.txt index c62d00b..85760e5 100644 --- a/Help/guide/tutorial/Complete/License.txt +++ b/Help/guide/tutorial/Complete/License.txt @@ -1,2 +1,2 @@ This is the open source License.txt file introduced in -CMake/Tutorial/Step7... +CMake/Tutorial/Step9... diff --git a/Help/guide/tutorial/Complete/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Complete/MathFunctions/CMakeLists.txt index 40b9fd2..d256db2 100644 --- a/Help/guide/tutorial/Complete/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Complete/MathFunctions/CMakeLists.txt @@ -56,7 +56,7 @@ target_compile_definitions(MathFunctions PRIVATE "EXPORTING_MYMATH") set_property(TARGET MathFunctions PROPERTY VERSION "1.0.0") set_property(TARGET MathFunctions PROPERTY SOVERSION "1") -# install rules +# install libs set(installable_libs MathFunctions tutorial_compiler_flags) if(TARGET SqrtLibrary) list(APPEND installable_libs SqrtLibrary) @@ -64,4 +64,5 @@ endif() install(TARGETS ${installable_libs} EXPORT MathFunctionsTargets DESTINATION lib) +# install include headers install(FILES MathFunctions.h DESTINATION include) diff --git a/Help/guide/tutorial/Installing and Testing.rst b/Help/guide/tutorial/Installing and Testing.rst index 394c986..fa13040 100644 --- a/Help/guide/tutorial/Installing and Testing.rst +++ b/Help/guide/tutorial/Installing and Testing.rst @@ -1,95 +1,311 @@ -Step 4: Installing and Testing +Step 5: Installing and Testing ============================== -Now we can start adding install rules and testing support to our project. +.. _`Tutorial Testing Support`: + +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` -Install Rules +Files to Edit ------------- -The install rules are fairly simple: for ``MathFunctions`` we want to install -the library and header file and for the application we want to install the -executable and configured header. +* ``MathFunctions/CMakeLists.txt`` +* ``CMakeLists.txt`` -So to the end of ``MathFunctions/CMakeLists.txt`` we add: +Getting Started +--------------- -.. literalinclude:: Step5/MathFunctions/CMakeLists.txt - :caption: MathFunctions/CMakeLists.txt - :name: MathFunctions/CMakeLists.txt-install-TARGETS - :language: cmake - :start-after: # install rules +The starting code is provided in the ``Step5`` directory. In this +exercise, complete ``TODO 1`` through ``TODO 4``. -And to the end of the top-level ``CMakeLists.txt`` we add: +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. -.. literalinclude:: Step5/CMakeLists.txt - :caption: CMakeLists.txt - :name: CMakeLists.txt-install-TARGETS - :language: cmake - :start-after: # add the install targets - :end-before: # enable testing +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`. -That is all that is needed to create a basic local install of the tutorial. +Build and Run +------------- -Now run the :manual:`cmake <cmake(1)>` executable or the +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 ``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. For -multi-configuration tools, don't forget to use the ``--config`` argument to -specify the configuration. If using an IDE, simply build the ``INSTALL`` -target. This step will install the appropriate header files, libraries, and -executables. For example: +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 ``cmake --install`` -command, the installation prefix can be overridden via the ``--prefix`` -argument. For example: +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. +Navigate to the install directory and verify that the installed ``Tutorial`` +runs. -.. _`Tutorial Testing Support`: +Solution +-------- -Testing Support ---------------- +The install rules for our project are fairly simple: -Next let's test our application. At the end of the top-level ``CMakeLists.txt`` -file we can enable testing and then add a number of basic tests to verify that -the application is working correctly. +* For ``MathFunctions``, we want to install the libraries and header file to + the ``lib`` and ``include`` directories respectively. -.. literalinclude:: Step5/CMakeLists.txt +* 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: CMakeLists.txt-enable_testing + :name: TODO 3,4: CMakeLists.txt-install-TARGETS :language: cmake - :start-after: # enable testing + :start-after: # add the install targets + :end-before: # enable testing + +.. raw:: html + + </details> -The first test simply verifies that the application runs, does not segfault or -otherwise crash, and has a zero return value. This is the basic form of a -CTest test. +That is all that is needed to create a basic local +install of the tutorial. -The next test makes use of 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. +Exercise 2 - Testing Support +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Lastly, we have 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. +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`. -Rebuild the application and then cd to the binary directory and run the -:manual:`ctest <ctest(1)>` executable: ``ctest -N`` and ``ctest -VV``. For +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 +``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 ``-C <mode>`` flag. For example, to run tests in Debug -mode use ``ctest -C Debug -VV`` from the binary directory +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`` +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> diff --git a/Help/guide/tutorial/Packaging Debug and Release.rst b/Help/guide/tutorial/Packaging Debug and Release.rst index 91b46a7..8c660a3 100644 --- a/Help/guide/tutorial/Packaging Debug and Release.rst +++ b/Help/guide/tutorial/Packaging Debug and Release.rst @@ -10,8 +10,8 @@ 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 executables and libraries that will be installed. Let's use `d` as the -postfix for the debug executable and libraries. +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: @@ -41,10 +41,10 @@ Let's also add version numbering to the ``MathFunctions`` library. In :name: MathFunctions/CMakeLists.txt-VERSION-properties :language: cmake :start-after: # setup the version numbering - :end-before: # install rules + :end-before: # install libs From the ``Step12`` directory, create ``debug`` and ``release`` -subbdirectories. The layout will look like: +subdirectories. The layout will look like: .. code-block:: none diff --git a/Help/guide/tutorial/Packaging an Installer.rst b/Help/guide/tutorial/Packaging an Installer.rst index 0ee5db2..11a1952 100644 --- a/Help/guide/tutorial/Packaging an Installer.rst +++ b/Help/guide/tutorial/Packaging an Installer.rst @@ -1,4 +1,4 @@ -Step 7: Packaging an Installer +Step 9: Packaging an Installer ============================== Next suppose that we want to distribute our project to other people so that @@ -11,7 +11,7 @@ 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:: Step8/CMakeLists.txt +.. literalinclude:: Step10/CMakeLists.txt :caption: CMakeLists.txt :name: CMakeLists.txt-include-CPack :language: cmake @@ -38,15 +38,15 @@ binary directory run: cpack -To specify the generator, use the ``-G`` option. For multi-config builds, use -``-C`` to specify the configuration. For example: +To specify the 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 -``cpack --help``. An :cpack_gen:`archive generator <CPack Archive Generator>` +: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: diff --git a/Help/guide/tutorial/Selecting Static or Shared Libraries.rst b/Help/guide/tutorial/Selecting Static or Shared Libraries.rst index 2d5f70e..1c49c23 100644 --- a/Help/guide/tutorial/Selecting Static or Shared Libraries.rst +++ b/Help/guide/tutorial/Selecting Static or Shared Libraries.rst @@ -1,5 +1,5 @@ -Step 9: Selecting Static or Shared Libraries -============================================ +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`, @@ -19,7 +19,7 @@ library. The first step is to update the starting section of the top-level ``CMakeLists.txt`` to look like: -.. literalinclude:: Step10/CMakeLists.txt +.. literalinclude:: Step11/CMakeLists.txt :caption: CMakeLists.txt :name: CMakeLists.txt-option-BUILD_SHARED_LIBS :language: cmake @@ -33,7 +33,7 @@ explicitly require that SqrtLibrary is built statically. The end result is that ``MathFunctions/CMakeLists.txt`` should look like: -.. literalinclude:: Step10/MathFunctions/CMakeLists.txt +.. literalinclude:: Step11/MathFunctions/CMakeLists.txt :caption: MathFunctions/CMakeLists.txt :name: MathFunctions/CMakeLists.txt-add_library-STATIC :language: cmake @@ -42,7 +42,7 @@ The end result is that ``MathFunctions/CMakeLists.txt`` should look like: Next, update ``MathFunctions/mysqrt.cxx`` to use the ``mathfunctions`` and ``detail`` namespaces: -.. literalinclude:: Step10/MathFunctions/mysqrt.cxx +.. literalinclude:: Step11/MathFunctions/mysqrt.cxx :caption: MathFunctions/mysqrt.cxx :name: MathFunctions/mysqrt.cxx-namespace :language: c++ @@ -56,7 +56,7 @@ uses ``USE_MYMATH``: Finally, update ``MathFunctions/MathFunctions.h`` to use dll export defines: -.. literalinclude:: Step10/MathFunctions/MathFunctions.h +.. literalinclude:: Step11/MathFunctions/MathFunctions.h :caption: MathFunctions/MathFunctions.h :name: MathFunctions/MathFunctions.h :language: c++ @@ -67,7 +67,7 @@ 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`` no matter the build type. -.. literalinclude:: Step10/MathFunctions/CMakeLists.txt +.. literalinclude:: Step11/MathFunctions/CMakeLists.txt :caption: MathFunctions/CMakeLists.txt :name: MathFunctions/CMakeLists.txt-POSITION_INDEPENDENT_CODE :language: cmake diff --git a/Help/guide/tutorial/Step1/CMakeLists.txt b/Help/guide/tutorial/Step1/CMakeLists.txt new file mode 100644 index 0000000..6fcce90 --- /dev/null +++ b/Help/guide/tutorial/Step1/CMakeLists.txt @@ -0,0 +1,16 @@ +# TODO 1: Set the minimum required version of CMake to be 3.10 + +# TODO 2: Create a project named Tutorial + +# TODO 7: Set the project version number as 1.0 in the above project command + +# TODO 6: Set the variable CMAKE_CXX_STANDARD to 11 +# and the variable CMAKE_CXX_STANDARD_REQUIRED to True + +# TODO 8: Use configure_file to configure and copy TutorialConfig.h.in to +# TutorialConfig.h + +# TODO 3: Add an executable called Tutorial to the project +# Hint: Be sure to specify the source file as tutorial.cxx + +# TODO 9: Use target_include_directories to include ${PROJECT_BINARY_DIR} diff --git a/Help/guide/tutorial/Step1/TutorialConfig.h.in b/Help/guide/tutorial/Step1/TutorialConfig.h.in new file mode 100644 index 0000000..990bfbd --- /dev/null +++ b/Help/guide/tutorial/Step1/TutorialConfig.h.in @@ -0,0 +1,2 @@ +// the configured options and settings for Tutorial +// TODO 10: Define Tutorial_VERSION_MAJOR and Tutorial_VERSION_MINOR diff --git a/Help/guide/tutorial/Step1/tutorial.cxx b/Help/guide/tutorial/Step1/tutorial.cxx index 08323bf..64d0916 100644 --- a/Help/guide/tutorial/Step1/tutorial.cxx +++ b/Help/guide/tutorial/Step1/tutorial.cxx @@ -1,17 +1,22 @@ // A simple program that computes the square root of a number #include <cmath> -#include <cstdlib> +#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]) const double inputValue = atof(argv[1]); // calculate square root diff --git a/Help/guide/tutorial/Step10/CMakeLists.txt b/Help/guide/tutorial/Step10/CMakeLists.txt index 55dc409..5c661aa 100644 --- a/Help/guide/tutorial/Step10/CMakeLists.txt +++ b/Help/guide/tutorial/Step10/CMakeLists.txt @@ -1,29 +1,37 @@ -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.15) # set the project name and version project(Tutorial VERSION 1.0) # specify the C++ standard -set(CMAKE_CXX_STANDARD 11) -set(CMAKE_CXX_STANDARD_REQUIRED True) +add_library(tutorial_compiler_flags INTERFACE) +target_compile_features(tutorial_compiler_flags INTERFACE cxx_std_11) -# 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}") +# 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>>" +) -option(BUILD_SHARED_LIBS "Build using shared libraries" ON) +# should we use our own math functions +option(USE_MYMATH "Use tutorial provided math implementation" ON) -# configure a header file to pass the version number only +# configure a header file to pass some of the CMake settings +# to the source code configure_file(TutorialConfig.h.in TutorialConfig.h) # add the MathFunctions library -add_subdirectory(MathFunctions) +if(USE_MYMATH) + add_subdirectory(MathFunctions) + list(APPEND EXTRA_LIBS MathFunctions) +endif() # add the executable add_executable(Tutorial tutorial.cxx) -target_link_libraries(Tutorial PUBLIC MathFunctions) +target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS} tutorial_compiler_flags) # add the binary tree to the search path for include files # so that we will find TutorialConfig.h @@ -66,6 +74,7 @@ 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}") diff --git a/Help/guide/tutorial/Step10/License.txt b/Help/guide/tutorial/Step10/License.txt index c62d00b..85760e5 100644 --- a/Help/guide/tutorial/Step10/License.txt +++ b/Help/guide/tutorial/Step10/License.txt @@ -1,2 +1,2 @@ This is the open source License.txt file introduced in -CMake/Tutorial/Step7... +CMake/Tutorial/Step9... diff --git a/Help/guide/tutorial/Step10/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step10/MathFunctions/CMakeLists.txt index 0bfe20c..fa73321 100644 --- a/Help/guide/tutorial/Step10/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Step10/MathFunctions/CMakeLists.txt @@ -1,55 +1,32 @@ -# add the library that runs -add_library(MathFunctions MathFunctions.cxx) +# first we add the executable that generates the table +add_executable(MakeTable MakeTable.cxx) + +# 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 + ) + +# add the main library +add_library(MathFunctions + mysqrt.cxx + ${CMAKE_CURRENT_BINARY_DIR}/Table.h + ) # state that anybody linking to us needs to include the current source dir # to find MathFunctions.h, while we don't. +# state that we depend on our binary dir to find Table.h target_include_directories(MathFunctions - INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} - ) + INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} + PRIVATE ${CMAKE_CURRENT_BINARY_DIR} + ) -# should we use our own math functions -option(USE_MYMATH "Use tutorial provided math implementation" ON) -if(USE_MYMATH) +# link our compiler flags interface library +target_link_libraries(MathFunctions tutorial_compiler_flags) - target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH") - - # first we add the executable that generates the table - add_executable(MakeTable MakeTable.cxx) - - # 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 - ) - - # 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} - ) - - target_link_libraries(MathFunctions PRIVATE SqrtLibrary) -endif() - -# define the symbol stating we are using the declspec(dllexport) when -# building on windows -target_compile_definitions(MathFunctions PRIVATE "EXPORTING_MYMATH") - -# install rules -set(installable_libs MathFunctions) -if(TARGET SqrtLibrary) - list(APPEND installable_libs SqrtLibrary) -endif() +# install libs +set(installable_libs MathFunctions tutorial_compiler_flags) install(TARGETS ${installable_libs} DESTINATION lib) +# install include headers install(FILES MathFunctions.h DESTINATION include) diff --git a/Help/guide/tutorial/Step10/MathFunctions/MathFunctions.h b/Help/guide/tutorial/Step10/MathFunctions/MathFunctions.h index 3fb547b..cd36bcc 100644 --- a/Help/guide/tutorial/Step10/MathFunctions/MathFunctions.h +++ b/Help/guide/tutorial/Step10/MathFunctions/MathFunctions.h @@ -1,14 +1 @@ - -#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); -} +double mysqrt(double x); diff --git a/Help/guide/tutorial/Step10/MathFunctions/mysqrt.cxx b/Help/guide/tutorial/Step10/MathFunctions/mysqrt.cxx index 8153f18..7d80ee9 100644 --- a/Help/guide/tutorial/Step10/MathFunctions/mysqrt.cxx +++ b/Help/guide/tutorial/Step10/MathFunctions/mysqrt.cxx @@ -5,8 +5,6 @@ // include the generated table #include "Table.h" -namespace mathfunctions { -namespace detail { // a hack square root calculation using simple operations double mysqrt(double x) { @@ -33,5 +31,3 @@ double mysqrt(double x) return result; } -} -} diff --git a/Help/guide/tutorial/Step10/TutorialConfig.h.in b/Help/guide/tutorial/Step10/TutorialConfig.h.in index 7e4d7fa..e23f521 100644 --- a/Help/guide/tutorial/Step10/TutorialConfig.h.in +++ b/Help/guide/tutorial/Step10/TutorialConfig.h.in @@ -1,3 +1,4 @@ // the configured options and settings for Tutorial #define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@ #define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@ +#cmakedefine USE_MYMATH diff --git a/Help/guide/tutorial/Step10/tutorial.cxx b/Help/guide/tutorial/Step10/tutorial.cxx index 37a0333..b3c6a4f 100644 --- a/Help/guide/tutorial/Step10/tutorial.cxx +++ b/Help/guide/tutorial/Step10/tutorial.cxx @@ -1,11 +1,15 @@ // A simple program that computes the square root of a number +#include <cmath> #include <iostream> -#include <sstream> #include <string> -#include "MathFunctions.h" #include "TutorialConfig.h" +// should we include the MathFunctions header? +#ifdef USE_MYMATH +# include "MathFunctions.h" +#endif + int main(int argc, char* argv[]) { if (argc < 2) { @@ -19,7 +23,12 @@ int main(int argc, char* argv[]) // convert input to double const double inputValue = std::stod(argv[1]); - const double outputValue = mathfunctions::sqrt(inputValue); + // which square root function should we use? +#ifdef USE_MYMATH + const double outputValue = mysqrt(inputValue); +#else + const double outputValue = sqrt(inputValue); +#endif std::cout << "The square root of " << inputValue << " is " << outputValue << std::endl; diff --git a/Help/guide/tutorial/Step11/CMakeLists.txt b/Help/guide/tutorial/Step11/CMakeLists.txt index 1044748..046bfc9 100644 --- a/Help/guide/tutorial/Step11/CMakeLists.txt +++ b/Help/guide/tutorial/Step11/CMakeLists.txt @@ -3,6 +3,7 @@ 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) @@ -31,7 +32,7 @@ add_subdirectory(MathFunctions) # add the executable add_executable(Tutorial tutorial.cxx) -target_link_libraries(Tutorial PUBLIC MathFunctions) +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 @@ -46,7 +47,7 @@ install(FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h" ) # enable testing -enable_testing() +include(CTest) # does the application run add_test(NAME Runs COMMAND Tutorial 25) @@ -74,6 +75,7 @@ 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}") diff --git a/Help/guide/tutorial/Step11/License.txt b/Help/guide/tutorial/Step11/License.txt index c62d00b..85760e5 100644 --- a/Help/guide/tutorial/Step11/License.txt +++ b/Help/guide/tutorial/Step11/License.txt @@ -1,2 +1,2 @@ This is the open source License.txt file introduced in -CMake/Tutorial/Step7... +CMake/Tutorial/Step9... diff --git a/Help/guide/tutorial/Step11/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step11/MathFunctions/CMakeLists.txt index 0d287ca..a60fb63 100644 --- a/Help/guide/tutorial/Step11/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Step11/MathFunctions/CMakeLists.txt @@ -47,13 +47,14 @@ endif() target_link_libraries(MathFunctions PUBLIC tutorial_compiler_flags) # define the symbol stating we are using the declspec(dllexport) when -#building on windows +# building on windows target_compile_definitions(MathFunctions PRIVATE "EXPORTING_MYMATH") -# install rules +# 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) diff --git a/Help/guide/tutorial/Step11/tutorial.cxx b/Help/guide/tutorial/Step11/tutorial.cxx index a4f44d5..37a0333 100644 --- a/Help/guide/tutorial/Step11/tutorial.cxx +++ b/Help/guide/tutorial/Step11/tutorial.cxx @@ -1,5 +1,6 @@ // A simple program that computes the square root of a number #include <iostream> +#include <sstream> #include <string> #include "MathFunctions.h" diff --git a/Help/guide/tutorial/Step12/CMakeLists.txt b/Help/guide/tutorial/Step12/CMakeLists.txt index 63f9643..220ed4b 100644 --- a/Help/guide/tutorial/Step12/CMakeLists.txt +++ b/Help/guide/tutorial/Step12/CMakeLists.txt @@ -37,7 +37,7 @@ add_subdirectory(MathFunctions) # add the executable add_executable(Tutorial tutorial.cxx) -target_link_libraries(Tutorial PUBLIC MathFunctions) +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 @@ -80,6 +80,7 @@ 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}") diff --git a/Help/guide/tutorial/Step12/License.txt b/Help/guide/tutorial/Step12/License.txt index c62d00b..85760e5 100644 --- a/Help/guide/tutorial/Step12/License.txt +++ b/Help/guide/tutorial/Step12/License.txt @@ -1,2 +1,2 @@ This is the open source License.txt file introduced in -CMake/Tutorial/Step7... +CMake/Tutorial/Step9... diff --git a/Help/guide/tutorial/Step12/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step12/MathFunctions/CMakeLists.txt index d5961da..a85f3cb 100644 --- a/Help/guide/tutorial/Step12/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Step12/MathFunctions/CMakeLists.txt @@ -52,7 +52,7 @@ target_link_libraries(MathFunctions PUBLIC tutorial_compiler_flags) # building on windows target_compile_definitions(MathFunctions PRIVATE "EXPORTING_MYMATH") -# install rules +# install libs set(installable_libs MathFunctions tutorial_compiler_flags) if(TARGET SqrtLibrary) list(APPEND installable_libs SqrtLibrary) @@ -60,4 +60,5 @@ endif() install(TARGETS ${installable_libs} EXPORT MathFunctionsTargets DESTINATION lib) +# install include headers install(FILES MathFunctions.h DESTINATION include) diff --git a/Help/guide/tutorial/Step2/CMakeLists.txt b/Help/guide/tutorial/Step2/CMakeLists.txt index 7aa59e9..2b96128 100644 --- a/Help/guide/tutorial/Step2/CMakeLists.txt +++ b/Help/guide/tutorial/Step2/CMakeLists.txt @@ -7,13 +7,36 @@ project(Tutorial VERSION 1.0) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED True) +# TODO 7: Create a variable USE_MYMATH using option and set default to ON + # configure a header file to pass some of the CMake settings # to the source code configure_file(TutorialConfig.h.in TutorialConfig.h) +# TODO 8: Use list() and APPEND to create a list of optional libraries +# called EXTRA_LIBS and a list of optional include directories called +# EXTRA_INCLUDES. Add the MathFunctions library and source directory to +# the appropriate lists. +# +# Only call add_subdirectory and only add MathFunctions specific values +# to EXTRA_LIBS and EXTRA_INCLUDES if USE_MYMATH is true. + +# TODO 2: Use add_subdirectory() to add MathFunctions to this project + # add the executable add_executable(Tutorial tutorial.cxx) +# TODO 9: Use EXTRA_LIBS instead of the MathFunctions specific values +# in target_link_libraries. + +# TODO 3: Use target_link_libraries to link the library to our executable + +# TODO 4: Add MathFunctions to Tutorial's target_include_directories() +# Hint: ${PROJECT_SOURCE_DIR} is a path to the project source. AKA This folder! + +# TODO 10: Use EXTRA_INCLUDES instead of the MathFunctions specific values +# in target_include_directories. + # add the binary tree to the search path for include files # so that we will find TutorialConfig.h target_include_directories(Tutorial PUBLIC diff --git a/Help/guide/tutorial/Step2/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step2/MathFunctions/CMakeLists.txt new file mode 100644 index 0000000..b7779b7 --- /dev/null +++ b/Help/guide/tutorial/Step2/MathFunctions/CMakeLists.txt @@ -0,0 +1,2 @@ +# TODO 1: Add a library called MathFunctions +# Hint: You will need the add_library command diff --git a/Help/guide/tutorial/Step2/TutorialConfig.h.in b/Help/guide/tutorial/Step2/TutorialConfig.h.in index 7e4d7fa..6c09e1a 100644 --- a/Help/guide/tutorial/Step2/TutorialConfig.h.in +++ b/Help/guide/tutorial/Step2/TutorialConfig.h.in @@ -1,3 +1,5 @@ // the configured options and settings for Tutorial #define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@ #define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@ + +// TODO 13: use cmakedefine to define USE_MYMATH diff --git a/Help/guide/tutorial/Step2/tutorial.cxx b/Help/guide/tutorial/Step2/tutorial.cxx index 53b0810..87f5e0f 100644 --- a/Help/guide/tutorial/Step2/tutorial.cxx +++ b/Help/guide/tutorial/Step2/tutorial.cxx @@ -5,6 +5,10 @@ #include "TutorialConfig.h" +// TODO 11: Only include MathFunctions if USE_MYMATH is defined + +// TODO 5: Include MathFunctions.h + int main(int argc, char* argv[]) { if (argc < 2) { @@ -18,6 +22,10 @@ int main(int argc, char* argv[]) // convert input to double const double inputValue = std::stod(argv[1]); + // TODO 12: Use mysqrt if USE_MYMATH is defined and sqrt otherwise + + // TODO 6: Replace sqrt with mysqrt + // calculate square root const double outputValue = sqrt(inputValue); std::cout << "The square root of " << inputValue << " is " << outputValue diff --git a/Help/guide/tutorial/Step3/CMakeLists.txt b/Help/guide/tutorial/Step3/CMakeLists.txt index 1c12816..007770a 100644 --- a/Help/guide/tutorial/Step3/CMakeLists.txt +++ b/Help/guide/tutorial/Step3/CMakeLists.txt @@ -14,6 +14,8 @@ option(USE_MYMATH "Use tutorial provided math implementation" ON) # to the source code configure_file(TutorialConfig.h.in TutorialConfig.h) +# TODO 2: Remove EXTRA_INCLUDES list + # add the MathFunctions library if(USE_MYMATH) add_subdirectory(MathFunctions) @@ -26,6 +28,8 @@ add_executable(Tutorial tutorial.cxx) target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS}) +# TODO 3: Remove use of EXTRA_INCLUDES + # add the binary tree to the search path for include files # so that we will find TutorialConfig.h target_include_directories(Tutorial PUBLIC diff --git a/Help/guide/tutorial/Step3/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step3/MathFunctions/CMakeLists.txt index 8b443a6..7bf05e0 100644 --- a/Help/guide/tutorial/Step3/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Step3/MathFunctions/CMakeLists.txt @@ -1 +1,5 @@ add_library(MathFunctions mysqrt.cxx) + +# TODO 1: State that anybody linking to MathFunctions needs to include the +# current source directory, while MathFunctions itself doesn't. +# Hint: Use target_include_directories with the INTERFACE keyword diff --git a/Help/guide/tutorial/Step4/CMakeLists.txt b/Help/guide/tutorial/Step4/CMakeLists.txt index 38e9b1f..fa4aab2 100644 --- a/Help/guide/tutorial/Step4/CMakeLists.txt +++ b/Help/guide/tutorial/Step4/CMakeLists.txt @@ -1,12 +1,36 @@ +# TODO 4: Update the minimum required version to 3.15 + cmake_minimum_required(VERSION 3.10) # set the project name and version project(Tutorial VERSION 1.0) +# TODO 1: Replace the following code by: +# * Creating an interface library called tutorial_compiler_flags +# Hint: use add_library() with the INTERFACE signature +# * Add compiler feature cxx_std_11 to tutorial_compiler_flags +# Hint: Use target_compile_features() + # specify the C++ standard set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED True) +# TODO 5: Create helper variables to determine which compiler we are using: +# * Create a new variable gcc_like_cxx that is true if we are using CXX and +# any of the following compilers: ARMClang, AppleClang, Clang, GNU, LCC +# * Create a new variable msvc_cxx that is true if we are using CXX and MSVC +# Hint: Use set() and COMPILE_LANG_AND_ID + +# TODO 6: Add warning flag compile options to the interface library +# tutorial_compiler_flags. +# * For gcc_like_cxx, add flags -Wall;-Wextra;-Wshadow;-Wformat=2;-Wunused +# * For msvc_cxx, add flags -W3 +# Hint: Use target_compile_options() + +# TODO 7: With nested generator expressions, only use the flags for the +# build-tree +# Hint: Use BUILD_INTERFACE + # should we use our own math functions option(USE_MYMATH "Use tutorial provided math implementation" ON) @@ -23,6 +47,8 @@ endif() # add the executable add_executable(Tutorial tutorial.cxx) +# TODO 2: Link to tutorial_compiler_flags + target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS}) # add the binary tree to the search path for include files diff --git a/Help/guide/tutorial/Step4/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step4/MathFunctions/CMakeLists.txt index 0515852..5f7369c 100644 --- a/Help/guide/tutorial/Step4/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Step4/MathFunctions/CMakeLists.txt @@ -5,3 +5,5 @@ add_library(MathFunctions mysqrt.cxx) target_include_directories(MathFunctions INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} ) + +# TODO 3: Link to tutorial_compiler_flags diff --git a/Help/guide/tutorial/Step5/CMakeLists.txt b/Help/guide/tutorial/Step5/CMakeLists.txt index 82d00c8..a8f241a 100644 --- a/Help/guide/tutorial/Step5/CMakeLists.txt +++ b/Help/guide/tutorial/Step5/CMakeLists.txt @@ -1,11 +1,20 @@ -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.15) # set the project name and version project(Tutorial VERSION 1.0) # specify the C++ standard -set(CMAKE_CXX_STANDARD 11) -set(CMAKE_CXX_STANDARD_REQUIRED True) +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>>" +) # should we use our own math functions option(USE_MYMATH "Use tutorial provided math implementation" ON) @@ -22,7 +31,7 @@ endif() # add the executable add_executable(Tutorial tutorial.cxx) -target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS}) +target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS} tutorial_compiler_flags) # add the binary tree to the search path for include files # so that we will find TutorialConfig.h @@ -30,37 +39,26 @@ 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 - ) +# TODO 3: Install Tutorial in the bin directory +# Hint: Use the TARGETS and DESTINATION parameters + +# TODO 4: Install Tutorial.h to the include directory +# Hint: Use the FILES and DESTINATION parameters -# enable testing -enable_testing() +# TODO 5: Enable testing -# does the application run -add_test(NAME Runs COMMAND Tutorial 25) +# TODO 6: Add a test called Runs which runs the following command: +# $ Tutorial 25 -# does the usage message work? -add_test(NAME Usage COMMAND Tutorial) -set_tests_properties(Usage - PROPERTIES PASS_REGULAR_EXPRESSION "Usage:.*number" - ) +# TODO 7: Add a test called Usage which runs the following command: +# $ Tutorial +# Make sure the expected output is displayed. +# Hint: Use the PASS_REGULAR_EXPRESSION property with "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() +# TODO 8: Add a test which runs the following command: +# $ Tutorial 4 +# Make sure the result is correct. +# Hint: Use the PASS_REGULAR_EXPRESSION property with "4 is 2" -# 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") +# TODO 9: Add more tests. Create a function called do_test to avoid copy + +# paste. Test the following values: 4, 9, 5, 7, 25, -25 and 0.00001. diff --git a/Help/guide/tutorial/Step5/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step5/MathFunctions/CMakeLists.txt index b12f27d..6cd88d7 100644 --- a/Help/guide/tutorial/Step5/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Step5/MathFunctions/CMakeLists.txt @@ -6,6 +6,13 @@ target_include_directories(MathFunctions INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} ) -# install rules -install(TARGETS MathFunctions DESTINATION lib) -install(FILES MathFunctions.h DESTINATION include) +# link our compiler flags interface library +target_link_libraries(MathFunctions tutorial_compiler_flags) + +# TODO 1: Create a variable called installable_libs that is a list of all +# libraries we want to install (e.g. MathFunctions and tutorial_compiler_flags) +# Then install the installable libraries to the lib folder. +# Hint: Use the TARGETS and DESTINATION parameters + +# TODO 2: Install the library headers to the include folder. +# Hint: Use the FILES and DESTINATION parameters diff --git a/Help/guide/tutorial/Step6/CMakeLists.txt b/Help/guide/tutorial/Step6/CMakeLists.txt index 82d00c8..da9e852 100644 --- a/Help/guide/tutorial/Step6/CMakeLists.txt +++ b/Help/guide/tutorial/Step6/CMakeLists.txt @@ -1,11 +1,20 @@ -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.15) # set the project name and version project(Tutorial VERSION 1.0) # specify the C++ standard -set(CMAKE_CXX_STANDARD 11) -set(CMAKE_CXX_STANDARD_REQUIRED True) +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>>" +) # should we use our own math functions option(USE_MYMATH "Use tutorial provided math implementation" ON) @@ -22,7 +31,7 @@ endif() # add the executable add_executable(Tutorial tutorial.cxx) -target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS}) +target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS} tutorial_compiler_flags) # add the binary tree to the search path for include files # so that we will find TutorialConfig.h diff --git a/Help/guide/tutorial/Step6/CTestConfig.cmake b/Help/guide/tutorial/Step6/CTestConfig.cmake new file mode 100644 index 0000000..73efdb1 --- /dev/null +++ b/Help/guide/tutorial/Step6/CTestConfig.cmake @@ -0,0 +1,7 @@ +set(CTEST_PROJECT_NAME "CMakeTutorial") +set(CTEST_NIGHTLY_START_TIME "00:00:00 EST") + +set(CTEST_DROP_METHOD "http") +set(CTEST_DROP_SITE "my.cdash.org") +set(CTEST_DROP_LOCATION "/submit.php?project=CMakeTutorial") +set(CTEST_DROP_SITE_CDASH TRUE) diff --git a/Help/guide/tutorial/Step6/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step6/MathFunctions/CMakeLists.txt index 42e098a..b4724c4 100644 --- a/Help/guide/tutorial/Step6/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Step6/MathFunctions/CMakeLists.txt @@ -6,29 +6,11 @@ target_include_directories(MathFunctions INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} ) -# does this system provide the log and exp functions? -include(CheckCXXSourceCompiles) -check_cxx_source_compiles(" - #include <cmath> - int main() { - std::log(1.0); - return 0; - } -" HAVE_LOG) -check_cxx_source_compiles(" - #include <cmath> - int main() { - std::exp(1.0); - return 0; - } -" HAVE_EXP) +# link our compiler flags interface library +target_link_libraries(MathFunctions tutorial_compiler_flags) -# add compile definitions -if(HAVE_LOG AND HAVE_EXP) - target_compile_definitions(MathFunctions - PRIVATE "HAVE_LOG" "HAVE_EXP") -endif() - -# install rules -install(TARGETS MathFunctions DESTINATION lib) +# install libs +set(installable_libs MathFunctions tutorial_compiler_flags) +install(TARGETS ${installable_libs} DESTINATION lib) +# install include headers install(FILES MathFunctions.h DESTINATION include) diff --git a/Help/guide/tutorial/Step6/MathFunctions/MakeTable.cxx b/Help/guide/tutorial/Step6/MathFunctions/MakeTable.cxx deleted file mode 100644 index ee58556..0000000 --- a/Help/guide/tutorial/Step6/MathFunctions/MakeTable.cxx +++ /dev/null @@ -1,25 +0,0 @@ -// A simple program that builds a sqrt table -#include <cmath> -#include <fstream> -#include <iostream> - -int main(int argc, char* argv[]) -{ - // make sure we have enough arguments - if (argc < 2) { - return 1; - } - - std::ofstream fout(argv[1], std::ios_base::out); - const bool fileOpen = fout.is_open(); - if (fileOpen) { - fout << "double sqrtTable[] = {" << std::endl; - for (int i = 0; i < 10; ++i) { - fout << sqrt(static_cast<double>(i)) << "," << std::endl; - } - // close the table with a zero - fout << "0};" << std::endl; - fout.close(); - } - return fileOpen ? 0 : 1; // return 0 if wrote the file -} diff --git a/Help/guide/tutorial/Step6/MathFunctions/mysqrt.cxx b/Help/guide/tutorial/Step6/MathFunctions/mysqrt.cxx index 7eecd26..abe767d 100644 --- a/Help/guide/tutorial/Step6/MathFunctions/mysqrt.cxx +++ b/Help/guide/tutorial/Step6/MathFunctions/mysqrt.cxx @@ -1,4 +1,3 @@ -#include <cmath> #include <iostream> #include "MathFunctions.h" @@ -10,12 +9,6 @@ double mysqrt(double x) return 0; } - // if we have both log and exp then use them -#if defined(HAVE_LOG) && defined(HAVE_EXP) - double result = std::exp(std::log(x) * 0.5); - std::cout << "Computing sqrt of " << x << " to be " << result - << " using log and exp" << std::endl; -#else double result = x; // do ten iterations @@ -27,6 +20,5 @@ double mysqrt(double x) result = result + 0.5 * delta / result; std::cout << "Computing sqrt of " << x << " to be " << result << std::endl; } -#endif return result; } diff --git a/Help/guide/tutorial/Step7/CMakeLists.txt b/Help/guide/tutorial/Step7/CMakeLists.txt index 82d00c8..d26a90c 100644 --- a/Help/guide/tutorial/Step7/CMakeLists.txt +++ b/Help/guide/tutorial/Step7/CMakeLists.txt @@ -1,11 +1,20 @@ -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.15) # set the project name and version project(Tutorial VERSION 1.0) # specify the C++ standard -set(CMAKE_CXX_STANDARD 11) -set(CMAKE_CXX_STANDARD_REQUIRED True) +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>>" +) # should we use our own math functions option(USE_MYMATH "Use tutorial provided math implementation" ON) @@ -22,7 +31,7 @@ endif() # add the executable add_executable(Tutorial tutorial.cxx) -target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS}) +target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS} tutorial_compiler_flags) # add the binary tree to the search path for include files # so that we will find TutorialConfig.h @@ -37,7 +46,7 @@ install(FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h" ) # enable testing -enable_testing() +include(CTest) # does the application run add_test(NAME Runs COMMAND Tutorial 25) diff --git a/Help/guide/tutorial/Step7/CTestConfig.cmake b/Help/guide/tutorial/Step7/CTestConfig.cmake new file mode 100644 index 0000000..73efdb1 --- /dev/null +++ b/Help/guide/tutorial/Step7/CTestConfig.cmake @@ -0,0 +1,7 @@ +set(CTEST_PROJECT_NAME "CMakeTutorial") +set(CTEST_NIGHTLY_START_TIME "00:00:00 EST") + +set(CTEST_DROP_METHOD "http") +set(CTEST_DROP_SITE "my.cdash.org") +set(CTEST_DROP_LOCATION "/submit.php?project=CMakeTutorial") +set(CTEST_DROP_SITE_CDASH TRUE) diff --git a/Help/guide/tutorial/Step7/License.txt b/Help/guide/tutorial/Step7/License.txt deleted file mode 100644 index c62d00b..0000000 --- a/Help/guide/tutorial/Step7/License.txt +++ /dev/null @@ -1,2 +0,0 @@ -This is the open source License.txt file introduced in -CMake/Tutorial/Step7... diff --git a/Help/guide/tutorial/Step7/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step7/MathFunctions/CMakeLists.txt index 9ede4b3..b4724c4 100644 --- a/Help/guide/tutorial/Step7/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Step7/MathFunctions/CMakeLists.txt @@ -1,29 +1,16 @@ -# first we add the executable that generates the table -add_executable(MakeTable MakeTable.cxx) - -# 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 - ) - -# add the main library -add_library(MathFunctions - mysqrt.cxx - ${CMAKE_CURRENT_BINARY_DIR}/Table.h - ) +add_library(MathFunctions mysqrt.cxx) # state that anybody linking to us needs to include the current source dir # to find MathFunctions.h, while we don't. -# state that we depend on Tutorial_BINARY_DIR but consumers don't, as the -# TutorialConfig.h include is an implementation detail -# state that we depend on our binary dir to find Table.h target_include_directories(MathFunctions INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} - PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ) -# install rules -install(TARGETS MathFunctions DESTINATION lib) +# link our compiler flags interface library +target_link_libraries(MathFunctions tutorial_compiler_flags) + +# install libs +set(installable_libs MathFunctions tutorial_compiler_flags) +install(TARGETS ${installable_libs} DESTINATION lib) +# install include headers install(FILES MathFunctions.h DESTINATION include) diff --git a/Help/guide/tutorial/Step7/MathFunctions/MakeTable.cxx b/Help/guide/tutorial/Step7/MathFunctions/MakeTable.cxx deleted file mode 100644 index ee58556..0000000 --- a/Help/guide/tutorial/Step7/MathFunctions/MakeTable.cxx +++ /dev/null @@ -1,25 +0,0 @@ -// A simple program that builds a sqrt table -#include <cmath> -#include <fstream> -#include <iostream> - -int main(int argc, char* argv[]) -{ - // make sure we have enough arguments - if (argc < 2) { - return 1; - } - - std::ofstream fout(argv[1], std::ios_base::out); - const bool fileOpen = fout.is_open(); - if (fileOpen) { - fout << "double sqrtTable[] = {" << std::endl; - for (int i = 0; i < 10; ++i) { - fout << sqrt(static_cast<double>(i)) << "," << std::endl; - } - // close the table with a zero - fout << "0};" << std::endl; - fout.close(); - } - return fileOpen ? 0 : 1; // return 0 if wrote the file -} diff --git a/Help/guide/tutorial/Step7/MathFunctions/mysqrt.cxx b/Help/guide/tutorial/Step7/MathFunctions/mysqrt.cxx index 7d80ee9..abe767d 100644 --- a/Help/guide/tutorial/Step7/MathFunctions/mysqrt.cxx +++ b/Help/guide/tutorial/Step7/MathFunctions/mysqrt.cxx @@ -2,9 +2,6 @@ #include "MathFunctions.h" -// include the generated table -#include "Table.h" - // a hack square root calculation using simple operations double mysqrt(double x) { @@ -12,12 +9,7 @@ double mysqrt(double x) 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) { @@ -28,6 +20,5 @@ double mysqrt(double x) result = result + 0.5 * delta / result; std::cout << "Computing sqrt of " << x << " to be " << result << std::endl; } - return result; } diff --git a/Help/guide/tutorial/Step8/CMakeLists.txt b/Help/guide/tutorial/Step8/CMakeLists.txt index 4c78b94..cb87281 100644 --- a/Help/guide/tutorial/Step8/CMakeLists.txt +++ b/Help/guide/tutorial/Step8/CMakeLists.txt @@ -1,11 +1,21 @@ -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.15) # set the project name and version project(Tutorial VERSION 1.0) # specify the C++ standard -set(CMAKE_CXX_STANDARD 11) -set(CMAKE_CXX_STANDARD_REQUIRED True) +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>>" +) + # should we use our own math functions option(USE_MYMATH "Use tutorial provided math implementation" ON) @@ -22,7 +32,7 @@ endif() # add the executable add_executable(Tutorial tutorial.cxx) -target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS}) +target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS} tutorial_compiler_flags) # add the binary tree to the search path for include files # so that we will find TutorialConfig.h @@ -37,7 +47,7 @@ install(FILES "${PROJECT_BINARY_DIR}/TutorialConfig.h" ) # enable testing -enable_testing() +include(CTest) # does the application run add_test(NAME Runs COMMAND Tutorial 25) @@ -64,11 +74,3 @@ 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_SOURCE_GENERATOR "TGZ") -include(CPack) diff --git a/Help/guide/tutorial/Step8/License.txt b/Help/guide/tutorial/Step8/License.txt deleted file mode 100644 index c62d00b..0000000 --- a/Help/guide/tutorial/Step8/License.txt +++ /dev/null @@ -1,2 +0,0 @@ -This is the open source License.txt file introduced in -CMake/Tutorial/Step7... diff --git a/Help/guide/tutorial/Step8/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step8/MathFunctions/CMakeLists.txt index 9ede4b3..f81b563 100644 --- a/Help/guide/tutorial/Step8/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Step8/MathFunctions/CMakeLists.txt @@ -1,29 +1,39 @@ -# first we add the executable that generates the table -add_executable(MakeTable MakeTable.cxx) - -# 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 - ) - -# add the main library -add_library(MathFunctions - mysqrt.cxx - ${CMAKE_CURRENT_BINARY_DIR}/Table.h - ) +add_library(MathFunctions mysqrt.cxx) # state that anybody linking to us needs to include the current source dir # to find MathFunctions.h, while we don't. -# state that we depend on Tutorial_BINARY_DIR but consumers don't, as the -# TutorialConfig.h include is an implementation detail -# state that we depend on our binary dir to find Table.h target_include_directories(MathFunctions INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} - PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ) -# install rules -install(TARGETS MathFunctions DESTINATION lib) +# link our compiler flags interface library +target_link_libraries(MathFunctions tutorial_compiler_flags) + +# does this system provide the log and exp functions? +include(CheckCXXSourceCompiles) +check_cxx_source_compiles(" + #include <cmath> + int main() { + std::log(1.0); + return 0; + } +" HAVE_LOG) +check_cxx_source_compiles(" + #include <cmath> + int main() { + std::exp(1.0); + return 0; + } +" HAVE_EXP) + +# add compile definitions +if(HAVE_LOG AND HAVE_EXP) + target_compile_definitions(MathFunctions + PRIVATE "HAVE_LOG" "HAVE_EXP") +endif() + +# install libs +set(installable_libs MathFunctions tutorial_compiler_flags) +install(TARGETS ${installable_libs} DESTINATION lib) +# install include headers install(FILES MathFunctions.h DESTINATION include) diff --git a/Help/guide/tutorial/Step8/MathFunctions/mysqrt.cxx b/Help/guide/tutorial/Step8/MathFunctions/mysqrt.cxx index 7d80ee9..7eecd26 100644 --- a/Help/guide/tutorial/Step8/MathFunctions/mysqrt.cxx +++ b/Help/guide/tutorial/Step8/MathFunctions/mysqrt.cxx @@ -1,10 +1,8 @@ +#include <cmath> #include <iostream> #include "MathFunctions.h" -// include the generated table -#include "Table.h" - // a hack square root calculation using simple operations double mysqrt(double x) { @@ -12,12 +10,13 @@ double mysqrt(double x) return 0; } - // use the table to help find an initial value + // if we have both log and exp then use them +#if defined(HAVE_LOG) && defined(HAVE_EXP) + double result = std::exp(std::log(x) * 0.5); + std::cout << "Computing sqrt of " << x << " to be " << result + << " using log and exp" << std::endl; +#else 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) { @@ -28,6 +27,6 @@ double mysqrt(double x) result = result + 0.5 * delta / result; std::cout << "Computing sqrt of " << x << " to be " << result << std::endl; } - +#endif return result; } diff --git a/Help/guide/tutorial/Step9/CMakeLists.txt b/Help/guide/tutorial/Step9/CMakeLists.txt index 6bae26e..d26a90c 100644 --- a/Help/guide/tutorial/Step9/CMakeLists.txt +++ b/Help/guide/tutorial/Step9/CMakeLists.txt @@ -1,11 +1,20 @@ -cmake_minimum_required(VERSION 3.10) +cmake_minimum_required(VERSION 3.15) # set the project name and version project(Tutorial VERSION 1.0) # specify the C++ standard -set(CMAKE_CXX_STANDARD 11) -set(CMAKE_CXX_STANDARD_REQUIRED True) +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>>" +) # should we use our own math functions option(USE_MYMATH "Use tutorial provided math implementation" ON) @@ -22,7 +31,7 @@ endif() # add the executable add_executable(Tutorial tutorial.cxx) -target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS}) +target_link_libraries(Tutorial PUBLIC ${EXTRA_LIBS} tutorial_compiler_flags) # add the binary tree to the search path for include files # so that we will find TutorialConfig.h @@ -64,10 +73,3 @@ 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") - -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_SOURCE_GENERATOR "TGZ") -include(CPack) diff --git a/Help/guide/tutorial/Step9/License.txt b/Help/guide/tutorial/Step9/License.txt index c62d00b..85760e5 100644 --- a/Help/guide/tutorial/Step9/License.txt +++ b/Help/guide/tutorial/Step9/License.txt @@ -1,2 +1,2 @@ This is the open source License.txt file introduced in -CMake/Tutorial/Step7... +CMake/Tutorial/Step9... diff --git a/Help/guide/tutorial/Step9/MathFunctions/CMakeLists.txt b/Help/guide/tutorial/Step9/MathFunctions/CMakeLists.txt index 50f0701..8e04f97 100644 --- a/Help/guide/tutorial/Step9/MathFunctions/CMakeLists.txt +++ b/Help/guide/tutorial/Step9/MathFunctions/CMakeLists.txt @@ -16,12 +16,19 @@ add_library(MathFunctions # state that anybody linking to us needs to include the current source dir # to find MathFunctions.h, while we don't. +# state that we depend on Tutorial_BINARY_DIR but consumers don't, as the +# TutorialConfig.h include is an implementation detail # state that we depend on our binary dir to find Table.h target_include_directories(MathFunctions INTERFACE ${CMAKE_CURRENT_SOURCE_DIR} PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ) -# install rules -install(TARGETS MathFunctions DESTINATION lib) +# link our compiler flags interface library +target_link_libraries(MathFunctions tutorial_compiler_flags) + +# install libs +set(installable_libs MathFunctions tutorial_compiler_flags) +install(TARGETS ${installable_libs} DESTINATION lib) +# install include headers install(FILES MathFunctions.h DESTINATION include) diff --git a/Help/guide/tutorial/Step9/MathFunctions/MathFunctions.cxx b/Help/guide/tutorial/Step9/MathFunctions/MathFunctions.cxx deleted file mode 100644 index 0145300..0000000 --- a/Help/guide/tutorial/Step9/MathFunctions/MathFunctions.cxx +++ /dev/null @@ -1,19 +0,0 @@ - -#include "MathFunctions.h" - -#include <cmath> - -#ifdef USE_MYMATH -# include "mysqrt.h" -#endif - -namespace mathfunctions { -double sqrt(double x) -{ -#ifdef USE_MYMATH - return detail::mysqrt(x); -#else - return std::sqrt(x); -#endif -} -} diff --git a/Help/guide/tutorial/Step9/MathFunctions/mysqrt.h b/Help/guide/tutorial/Step9/MathFunctions/mysqrt.h deleted file mode 100644 index e1c42ef..0000000 --- a/Help/guide/tutorial/Step9/MathFunctions/mysqrt.h +++ /dev/null @@ -1,6 +0,0 @@ - -namespace mathfunctions { -namespace detail { -double mysqrt(double x); -} -} diff --git a/Help/guide/tutorial/index.rst b/Help/guide/tutorial/index.rst index 09553cb..1ab0009 100644 --- a/Help/guide/tutorial/index.rst +++ b/Help/guide/tutorial/index.rst @@ -24,13 +24,13 @@ provides the complete solution for the previous step. A Basic Starting Point Adding a Library Adding Usage Requirements for a Library + Adding Generator Expressions Installing and Testing + Adding Support for a Testing Dashboard Adding System Introspection Adding a Custom Command and Generated File Packaging an Installer - Adding Support for a Testing Dashboard Selecting Static or Shared Libraries - Adding Generator Expressions Adding Export Configuration Packaging Debug and Release diff --git a/Help/guide/user-interaction/index.rst b/Help/guide/user-interaction/index.rst index ba8196b..3355992 100644 --- a/Help/guide/user-interaction/index.rst +++ b/Help/guide/user-interaction/index.rst @@ -71,8 +71,8 @@ The CMake tooling may report warnings which are intended for the provider of the software, not intended for the consumer of the software. Such warnings end with "This warning is for project developers". Users may disable -such warnings by passing the ``-Wno-dev`` flag to -:manual:`cmake(1)`. +such warnings by passing the :option:`-Wno-dev <cmake -Wno-dev>` +flag to :manual:`cmake(1)`. cmake-gui tool -------------- @@ -153,13 +153,13 @@ platform. Usually, the default generator is sufficient to allow the user to proceed to build the software. The user may override the default generator with -the ``-G`` option: +the :option:`-G <cmake -G>` option: .. code-block:: console $ cmake .. -G Ninja -The output of ``cmake --help`` includes a list of +The output of :option:`cmake --help` includes a list of :manual:`generators <cmake-generators(7)>` available for the user to choose from. Note that generator names are case sensitive. @@ -196,7 +196,8 @@ VisualC++ compiler, or a combination of the two: $ cmake .. -G "Visual Studio 16 2019" Visual Studio generators can target different architectures. -One can specify the target architecture using the `-A` option: +One can specify the target architecture using the +:option:`-A <cmake -A>` option: .. code-block:: console @@ -214,8 +215,8 @@ generator to use, typically a choice between a ``Makefile`` or a ``Ninja`` based generator. Note that it is not possible to change the generator -with ``-G`` after the first invocation of CMake. To -change the generator, the build directory must be +with :option:`-G <cmake -G>` after the first invocation of CMake. +To change the generator, the build directory must be deleted and the build must be started from scratch. When generating Visual Studio project and solutions @@ -223,7 +224,7 @@ files several other options are available to use when initially running :manual:`cmake(1)`. The Visual Studio toolset can be specified with the -``-T`` option: +:option:`cmake -T` option: .. code-block:: console @@ -232,9 +233,9 @@ The Visual Studio toolset can be specified with the $ # Build targeting Windows XP $ cmake.exe .. -G "Visual Studio 16 2019" -A x64 -T v120_xp -Whereas the ``-A`` option specifies the _target_ -architecture, the ``-T`` option can be used to specify -details of the toolchain used. For example, `-Thost=x64` +Whereas the :option:`-A <cmake -A>` option specifies the _target_ +architecture, the :option:`-T <cmake -T>` option can be used to specify +details of the toolchain used. For example, ``-Thost=x64`` can be given to select the 64-bit version of the host tools. The following demonstrates how to use 64-bit tools and also build for a 64-bit target architecture: @@ -337,7 +338,7 @@ or later on a subsequent invocation of $ cd build $ cmake . -DCMAKE_BUILD_TYPE=Debug -The ``-U`` flag may be used to unset variables +The :option:`-U <cmake -U>` flag may be used to unset variables on the :manual:`cmake(1)` command line: .. code-block:: console @@ -351,7 +352,7 @@ on the command line can be modified using the The :manual:`cmake(1)` tool allows specifying a file to use to populate the initial cache using -the ``-C`` option. This can be useful to simplify +the :option:`-C <cmake -C>` option. This can be useful to simplify commands and scripts which repeatedly require the same cache entries. @@ -427,10 +428,10 @@ Using presets on the command-line --------------------------------- When using the :manual:`cmake(1)` command line tool, a -preset can be invoked by using the ``--preset`` option. If -``--preset`` is specified, the generator and build -directory are not required, but can be specified to -override them. For example, if you have the following +preset can be invoked by using the :option:`--preset <cmake --preset>` +option. If :option:`--preset <cmake --preset>` is specified, +the generator and build directory are not required, but can be +specified to override them. For example, if you have the following ``CMakePresets.json`` file: .. code-block:: json @@ -502,23 +503,25 @@ command may be invoked in the build directory: $ cmake --build . -The ``--build`` flag enables a particular mode of -operation for the :manual:`cmake(1)` tool. It invokes -the :variable:`CMAKE_MAKE_PROGRAM` command associated -with the :manual:`generator <cmake-generators(7)>`, or +The :option:`--build <cmake --build>` flag enables a +particular mode of operation for the :manual:`cmake(1)` +tool. It invokes the :variable:`CMAKE_MAKE_PROGRAM` +command associated with the +:manual:`generator <cmake-generators(7)>`, or the build tool configured by the user. -The ``--build`` mode also accepts the parameter -``--target`` to specify a particular target to build, -for example a particular library, executable or -custom target, or a particular special target like -``install``: +The :option:`--build <cmake --build>` mode also accepts +the parameter :option:`--target <cmake--build --target>` to +specify a particular target to build, for example a +particular library, executable or custom target, or a +particular special target like ``install``: .. code-block:: console $ cmake --build . --target myexe -The ``--build`` mode also accepts a ``--config`` parameter +The :option:`--build <cmake --build>` mode also accepts a +:option:`--config <cmake--build --config>` parameter in the case of multi-config generators to specify which particular configuration to build: @@ -526,23 +529,23 @@ particular configuration to build: $ cmake --build . --target myexe --config Release -The ``--config`` option has no effect if the generator -generates a buildsystem specific to a configuration which -is chosen when invoking cmake with the -:variable:`CMAKE_BUILD_TYPE` variable. +The :option:`--config <cmake--build --config>` option has no +effect if the generator generates a buildsystem specific +to a configuration which is chosen when invoking cmake +with the :variable:`CMAKE_BUILD_TYPE` variable. Some buildsystems omit details of command lines invoked -during the build. The ``--verbose`` flag can be used to -cause those command lines to be shown: +during the build. The :option:`--verbose <cmake--build --verbose>` +flag can be used to cause those command lines to be shown: .. code-block:: console $ cmake --build . --target myexe --verbose -The ``--build`` mode can also pass particular command -line options to the underlying build tool by listing -them after ``--``. This can be useful to specify -options to the build tool, such as to continue the +The :option:`--build <cmake --build>` mode can also pass +particular command line options to the underlying build +tool by listing them after ``--``. This can be useful +to specify options to the build tool, such as to continue the build after a failed job, where CMake does not provide a high-level user interface. @@ -638,9 +641,9 @@ building the ``foo.i`` target will preprocess both files. Specifying a Build Program -------------------------- -The program invoked by the ``--build`` mode is determined -by the :variable:`CMAKE_MAKE_PROGRAM` variable. For most -generators, the particular program does not need to be +The program invoked by the :option:`--build <cmake --build>` +mode is determined by the :variable:`CMAKE_MAKE_PROGRAM` variable. +For most generators, the particular program does not need to be configured. ===================== =========================== =========================== @@ -661,7 +664,8 @@ The ``jom`` tool is capable of reading makefiles of the ``NMake`` flavor and building in parallel, while the ``nmake`` tool always builds serially. After generating with the :generator:`NMake Makefiles` generator a user -can run ``jom`` instead of ``nmake``. The ``--build`` +can run ``jom`` instead of ``nmake``. The +:option:`--build <cmake --build>` mode would also use ``jom`` if the :variable:`CMAKE_MAKE_PROGRAM` was set to ``jom`` while using the :generator:`NMake Makefiles` generator, and @@ -671,7 +675,7 @@ and use it as the :variable:`CMAKE_MAKE_PROGRAM`. For completeness, ``nmake`` is an alternative tool which can process the output of the :generator:`NMake Makefiles JOM` generator, but doing -so would be a pessimisation. +so would be a pessimization. Software Installation ===================== @@ -745,8 +749,8 @@ run only tests without ``Qt`` in their name: $ ctest -E Qt -Tests can be run in parallel by passing ``-j`` arguments -to :manual:`ctest(1)`: +Tests can be run in parallel by passing :option:`-j <ctest -j>` +arguments to :manual:`ctest(1)`: .. code-block:: console @@ -754,14 +758,15 @@ to :manual:`ctest(1)`: The environment variable :envvar:`CTEST_PARALLEL_LEVEL` can alternatively be set to avoid the need to pass -``-j``. +:option:`-j <ctest -j>`. By default :manual:`ctest(1)` does not print the output -from the tests. The command line argument ``-V`` (or -``--verbose``) enables verbose mode to print the +from the tests. The command line argument :option:`-V <ctest -V>` +(or ``--verbose``) enables verbose mode to print the output from all tests. -The ``--output-on-failure`` option prints the test -output for failing tests only. The environment variable -:envvar:`CTEST_OUTPUT_ON_FAILURE` +The :option:`--output-on-failure <ctest --output-on-failure>` +option prints the test output for failing tests only. +The environment variable :envvar:`CTEST_OUTPUT_ON_FAILURE` can be set to ``1`` as an alternative to passing the -``--output-on-failure`` option to :manual:`ctest(1)`. +:option:`--output-on-failure <ctest --output-on-failure>` +option to :manual:`ctest(1)`. |