Tutorial: Add links to relevant CMake documentation

Add links for commands, properties and variables.
This commit is contained in:
Betsy McPhail
2019-12-04 13:13:09 -05:00
parent d4d11b1707
commit 3a510a47b0
+144 -125
View File
@@ -45,7 +45,8 @@ 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 version number. While we could do this exclusively in the source code, using
``CMakeLists.txt`` provides more flexibility. ``CMakeLists.txt`` provides more flexibility.
First, modify the ``CMakeLists.txt`` file to set the version number. First, modify the ``CMakeLists.txt`` file to use the :command:`project` command
to set the project name and version number.
.. literalinclude:: Step2/CMakeLists.txt .. literalinclude:: Step2/CMakeLists.txt
:language: cmake :language: cmake
@@ -102,9 +103,10 @@ Next let's add some C++11 features to our project by replacing ``atof`` with
We will need to explicitly state in the CMake code that it should use the 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 correct flags. The easiest way to enable support for a specific C++ standard
in CMake is by using the ``CMAKE_CXX_STANDARD`` variable. For this tutorial, in CMake is by using the :variable:`CMAKE_CXX_STANDARD` variable. For this
set the ``CMAKE_CXX_STANDARD`` variable in the ``CMakeLists.txt`` file to 11 tutorial, set the :variable:`CMAKE_CXX_STANDARD` variable in the
and ``CMAKE_CXX_STANDARD_REQUIRED`` to True: ``CMakeLists.txt`` file to 11 and :variable:`CMAKE_CXX_STANDARD_REQUIRED` to
True:
.. literalinclude:: Step2/CMakeLists.txt .. literalinclude:: Step2/CMakeLists.txt
:language: cmake :language: cmake
@@ -113,7 +115,8 @@ and ``CMAKE_CXX_STANDARD_REQUIRED`` to True:
Build and Test Build and Test
-------------- --------------
Run **cmake** or **cmake-gui** to configure the project and then build it 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. with your chosen build tool.
For example, from the command line we could navigate to the For example, from the command line we could navigate to the
@@ -156,11 +159,11 @@ directory:
.. literalinclude:: Step3/MathFunctions/CMakeLists.txt .. literalinclude:: Step3/MathFunctions/CMakeLists.txt
:language: cmake :language: cmake
To make use of the new library we will add an ``add_subdirectory`` call in the To make use of the new library we will add an :command:`add_subdirectory`
top-level ``CMakeLists.txt`` file so that the library will get built. We add call in the top-level ``CMakeLists.txt`` file so that the library will get
the new library to the executable, and add ``MathFunctions`` as an include built. We add the new library to the executable, and add ``MathFunctions`` as
directory so that the ``mqsqrt.h`` header file can be found. The last few lines an include directory so that the ``mqsqrt.h`` header file can be found. The
of the top-level ``CMakeLists.txt`` file should now look like: last few lines of the top-level ``CMakeLists.txt`` file should now look like:
.. code-block:: cmake .. code-block:: cmake
@@ -189,10 +192,11 @@ occurrence. The first step is to add an option to the top-level
:start-after: # should we use our own math functions :start-after: # should we use our own math functions
:end-before: # add the MathFunctions library :end-before: # add the MathFunctions library
This option will be displayed in the CMake GUI and ccmake with a default This option will be displayed in the :manual:`cmake-gui <cmake-gui(1)>` and
value of ON that can be changed by the user. This setting will be stored in :manual:`ccmake <ccmake(1)>`
the cache so that the user does not need to set the value each time they run with a default value of ON that can be changed by the user. This setting will
CMake on a build directory. 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 The next change is to make building and linking the MathFunctions library
conditional. To do this we change the end of the top-level ``CMakeLists.txt`` conditional. To do this we change the end of the top-level ``CMakeLists.txt``
@@ -234,11 +238,13 @@ Since the source code now requires ``USE_MYMATH`` we can add it to
**Exercise**: Why is it important that we configure ``TutorialConfig.h.in`` **Exercise**: Why is it important that we configure ``TutorialConfig.h.in``
after the option for ``USE_MYMATH``? What would happen if we inverted the two? after the option for ``USE_MYMATH``? What would happen if we inverted the two?
Run **cmake** or **cmake-gui** to configure the project and then build it 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. with your chosen build tool. Then run the built Tutorial executable.
Use ccmake or the CMake GUI to update the value of ``USE_MYMATH``. Rebuild and Use the :manual:`ccmake <ccmake(1)>` executable or the :manual:`cmake-gui <cmake-gui(1)>`
run the tutorial again. Which function gives better results, sqrt or mysqrt? to update the value of ``USE_MYMATH``. Rebuild and run the tutorial again.
Which function gives better results, sqrt or mysqrt?
Adding Usage Requirements for Library (Step 3) Adding Usage Requirements for Library (Step 3)
============================================== ==============================================
@@ -248,19 +254,20 @@ link and include line while also giving more control over the transitive
property of targets inside CMake. The primary commands that leverage usage property of targets inside CMake. The primary commands that leverage usage
requirements are: requirements are:
- ``target_compile_definitions`` - :command:`target_compile_definitions`
- ``target_compile_options`` - :command:`target_compile_options`
- ``target_include_directories`` - :command:`target_include_directories`
- ``target_link_libraries`` - :command:`target_link_libraries`
Let's refactor our code from `Adding a Library (Step 2)`_ to use the modern Let's refactor our code from `Adding a Library (Step 2)`_ to use the modern
CMake approach of usage requirements. We first state that anybody linking to CMake approach of usage requirements. We first state that anybody linking to
MathFunctions needs to include the current source directory, while MathFunctions needs to include the current source directory, while
MathFunctions itself doesn't. So this can become an ``INTERFACE`` usage MathFunctions itself doesn't. So this can become an ``INTERFACE`` usage
requirement. requirement.
Remember ``INTERFACE`` means things that consumers require but the producer Remember ``INTERFACE`` means things that consumers require but the producer
doesn't. Add the following lines to the end of ``MathFunctions/CMakeLists.txt``: doesn't. Add the following lines to the end of
``MathFunctions/CMakeLists.txt``:
.. literalinclude:: Step4/MathFunctions/CMakeLists.txt .. literalinclude:: Step4/MathFunctions/CMakeLists.txt
:language: cmake :language: cmake
@@ -281,9 +288,10 @@ And here:
:language: cmake :language: cmake
:start-after: # so that we will find TutorialConfig.h :start-after: # so that we will find TutorialConfig.h
Once this is done, run **cmake** or **cmake-gui** to configure the project Once this is done, run the :manual:`cmake <cmake(1)>` executable or the
and then build it with your chosen build tool or by using ``cmake --build .`` :manual:`cmake-gui <cmake-gui(1)>` to configure the project and then build it
from the build directory. with your chosen build tool or by using ``cmake --build .`` from the build
directory.
Installing and Testing (Step 4) Installing and Testing (Step 4)
=============================== ===============================
@@ -312,16 +320,17 @@ And to the end of the top-level ``CMakeLists.txt`` we add:
That is all that is needed to create a basic local install of the tutorial. That is all that is needed to create a basic local install of the tutorial.
Run **cmake** or **cmake-gui** to configure the project and then build it Run the :manual:`cmake <cmake(1)>` executable or the
with your chosen build tool. Run the install step by typing :manual:`cmake-gui <cmake-gui(1)>` to configure the project and then build it
``cmake --install .`` (introduced in 3.15, older versions of CMake must use with your chosen build tool. Run the install step by using the ``install``
``make install``) from the command line, or build the ``INSTALL`` target from option of the :manual:`cmake <cmake(1)>` command (introduced in 3.15, older
an IDE. This will install the appropriate header files, libraries, and versions of CMake must use ``make install``) from the command line, or build
executables. the ``INSTALL`` target from an IDE. This will install the appropriate header
files, libraries, and executables.
The CMake variable ``CMAKE_INSTALL_PREFIX`` is used to determine the root of The CMake variable :variable:`CMAKE_INSTALL_PREFIX` is used to determine the
where the files will be installed. If using ``cmake --install`` a custom root of where the files will be installed. If using ``cmake --install`` a
installation directory can be given via ``--prefix`` argument. For custom installation directory can be given via the ``--prefix`` argument. For
multi-configuration tools, use the ``--config`` argument to specify the multi-configuration tools, use the ``--config`` argument to specify the
configuration. configuration.
@@ -339,25 +348,25 @@ the application is working correctly.
:start-after: # enable testing :start-after: # enable testing
The first test simply verifies that the application runs, does not segfault or 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 otherwise crash, and has a zero return value. This is the basic form of a
test. CTest test.
The next test makes use of the ``PASS_REGULAR_EXPRESSION`` test property to The next test makes use of the :prop_test:`PASS_REGULAR_EXPRESSION` test
verify that the output of the test contains certain strings. In this case, property to verify that the output of the test contains certain strings. In
verifying that the usage message is printed when an incorrect number of this case, verifying that the usage message is printed when an incorrect number
arguments are provided. of arguments are provided.
Lastly, we have a function called ``do_test`` that runs the application and 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 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, invocation of ``do_test``, another test is added to the project with a name,
input, and expected results based on the passed arguments. input, and expected results based on the passed arguments.
Rebuild the application and then cd to the binary directory and run Rebuild the application and then cd to the binary directory and run the
``ctest -N`` and ``ctest -VV``. For multi-config generators (e.g. Visual :manual:`ctest <ctest(1)>` executable: ``ctest -N`` and ``ctest -VV``. For
Studio), the configuration type must be specified. To run tests in Debug mode, multi-config generators (e.g. Visual Studio), the configuration type must be
for example, use ``ctest -C Debug -VV`` from the build directory (not the specified. To run tests in Debug mode, for example, use ``ctest -C Debug -VV``
Debug subdirectory!). Alternatively, build the ``RUN_TESTS`` target from the from the build directory (not the Debug subdirectory!). Alternatively, build
IDE. the ``RUN_TESTS`` target from the IDE.
Adding System Introspection (Step 5) Adding System Introspection (Step 5)
==================================== ====================================
@@ -370,7 +379,7 @@ tutorial assume that they are not common.
If the platform has ``log`` and ``exp`` then we will use them to compute the If the platform has ``log`` and ``exp`` then we will use them to compute the
square root in the ``mysqrt`` function. We first test for the availability of square root in the ``mysqrt`` function. We first test for the availability of
these functions using the ``CheckSymbolExists`` module in the top-level these functions using the :module:`CheckSymbolExists` module in the top-level
``CMakeLists.txt``. We're going to use the new defines in ``CMakeLists.txt``. We're going to use the new defines in
``TutorialConfig.h.in``, so be sure to set them before that file is configured. ``TutorialConfig.h.in``, so be sure to set them before that file is configured.
@@ -398,12 +407,13 @@ code (don't forget the ``#endif`` before returning the result!):
:start-after: // if we have both log and exp then use them :start-after: // if we have both log and exp then use them
:end-before: // do ten iterations :end-before: // do ten iterations
Run **cmake** or **cmake-gui** to configure the project and then build it Run the :manual:`cmake <cmake(1)>` executable or the
:manual:`cmake-gui <cmake-gui(1)>` to configure the project and then build it
with your chosen build tool and run the Tutorial executable. with your chosen build tool and run the Tutorial executable.
You will notice that we're not using ``log`` and ``exp``, even if we think they You will notice that we're not using ``log`` and ``exp``, even if we think they
should be available. We should realize quickly that we have forgotten to include should be available. We should realize quickly that we have forgotten to
``TutorialConfig.h`` in ``mysqrt.cxx``. include ``TutorialConfig.h`` in ``mysqrt.cxx``.
We will also need to update ``MathFunctions/CMakeLists.txt`` so ``mysqrt.cxx`` We will also need to update ``MathFunctions/CMakeLists.txt`` so ``mysqrt.cxx``
knows where this file is located: knows where this file is located:
@@ -415,10 +425,10 @@ knows where this file is located:
PRIVATE ${CMAKE_BINARY_DIR} PRIVATE ${CMAKE_BINARY_DIR}
) )
After making this update, go ahead and build the project again and run the built After making this update, go ahead and build the project again and run the
Tutorial executable. If ``log`` and ``exp`` are still not being used, open the built Tutorial executable. If ``log`` and ``exp`` are still not being used,
generated ``TutorialConfig.h`` file from the build directory. Maybe they aren't open the generated ``TutorialConfig.h`` file from the build directory. Maybe
available on the current system? they aren't available on the current system?
Which function gives better results now, sqrt or mysqrt? Which function gives better results now, sqrt or mysqrt?
@@ -427,7 +437,7 @@ Specify Compile Definition
Is there a better place for us to save the ``HAVE_LOG`` and ``HAVE_EXP`` values Is there a better place for us to save the ``HAVE_LOG`` and ``HAVE_EXP`` values
other than in ``TutorialConfig.h``? Let's try to use other than in ``TutorialConfig.h``? Let's try to use
``target_compile_definitions``. :command:`target_compile_definitions`.
First, remove the defines from ``TutorialConfig.h.in``. We no longer need to First, remove the defines from ``TutorialConfig.h.in``. We no longer need to
include ``TutorialConfig.h`` from ``mysqrt.cxx`` or the extra include in include ``TutorialConfig.h`` from ``mysqrt.cxx`` or the extra include in
@@ -460,8 +470,8 @@ First, let's remove the check for the ``log`` and ``exp`` functions in
``HAVE_EXP`` from ``mysqrt.cxx``. At the same time, we can remove ``HAVE_EXP`` from ``mysqrt.cxx``. At the same time, we can remove
:code:`#include <cmath>`. :code:`#include <cmath>`.
In the ``MathFunctions`` subdirectory, a new source file named ``MakeTable.cxx`` In the ``MathFunctions`` subdirectory, a new source file named
has been provided to generate the table. ``MakeTable.cxx`` has been provided to generate the table.
After reviewing the file, we can see that the table is produced as valid C++ After reviewing the file, we can see that the table is produced as valid C++
code and that the output filename is passed in as an argument. code and that the output filename is passed in as an argument.
@@ -510,7 +520,8 @@ Now let's use the generated table. First, modify ``mysqrt.cxx`` to include
:language: c++ :language: c++
:start-after: // a hack square root calculation using simple operations :start-after: // a hack square root calculation using simple operations
Run **cmake** or **cmake-gui** to configure the project and then build it 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. with your chosen build tool.
When this project is built it will first build the ``MakeTable`` executable. When this project is built it will first build the ``MakeTable`` executable.
@@ -530,26 +541,28 @@ previously in `Installing and Testing (Step 4)`_ , where we were
installing the binaries that we had built from the source code. In this installing the binaries that we had built from the source code. In this
example we will be building installation packages that support binary example we will be building installation packages that support binary
installations and package management features. To accomplish this we will use installations and package management features. To accomplish this we will use
CPack to create platform specific installers. Specifically we need to add CPack to create platform specific installers. Specifically we need to add a
a few lines to the bottom of our top-level ``CMakeLists.txt`` file. few lines to the bottom of our top-level ``CMakeLists.txt`` file.
.. literalinclude:: Step8/CMakeLists.txt .. literalinclude:: Step8/CMakeLists.txt
:language: cmake :language: cmake
:start-after: # setup installer :start-after: # setup installer
That is all there is to it. We start by including That is all there is to it. We start by including
``InstallRequiredSystemLibraries``. This module will include any runtime :module:`InstallRequiredSystemLibraries`. This module will include any runtime
libraries that are needed by the project for the current platform. Next we libraries that are needed by the project for the current platform. Next we set
set some CPack variables to where we have stored the license and version some CPack variables to where we have stored the license and version
information for this project. The version information was set earlier in this information for this project. The version information was set earlier in this
tutorial and the ``license.txt`` has been included in the top-level source tutorial and the ``license.txt`` has been included in the top-level source
directory for this step. directory for this step.
Finally we include the CPack module which will use these variables and some Finally we include the :module:`CPack module <CPack>` which will use these
other properties of the current system to setup an installer. variables and some other properties of the current system to setup an
installer.
The next step is to build the project in the usual manner and then run The next step is to build the project in the usual manner and then run the
CPack on it. To build a binary distribution, from the binary directory run: :manual:`cpack <cpack(1)>` executable. To build a binary distribution, from the
binary directory run:
.. code-block:: console .. code-block:: console
@@ -571,16 +584,17 @@ To create a source distribution you would type:
Alternatively, run ``make package`` or right click the ``Package`` target and Alternatively, run ``make package`` or right click the ``Package`` target and
``Build Project`` from an IDE. ``Build Project`` from an IDE.
Run the installer found in the binary directory. Then run the Run the installer found in the binary directory. Then run the installed
installed executable and verify that it works. executable and verify that it works.
Adding Support for a Dashboard (Step 8) Adding Support for a Dashboard (Step 8)
======================================= =======================================
Adding support for submitting our test results to a dashboard is very easy. We Adding support for submitting our test results to a dashboard is simple. We
already defined a number of tests for our project in `Testing Support`_. Now we already defined a number of tests for our project in `Testing Support`_. Now we
just have to run those tests and submit them to a dashboard. To include support just have to run those tests and submit them to a dashboard. To include support
for dashboards we include the CTest module in our top-level ``CMakeLists.txt``. for dashboards we include the :module:`CTest` module in our top-level
``CMakeLists.txt``.
Replace: Replace:
@@ -596,8 +610,8 @@ With:
# enable dashboard scripting # enable dashboard scripting
include(CTest) include(CTest)
The CTest module will automatically call ``enable_testing()``, so The :module:`CTest` module will automatically call ``enable_testing()``, so we
we can remove it from our CMake files. can remove it from our CMake files.
We will also need to create a ``CTestConfig.cmake`` file in the top-level We will also need to create a ``CTestConfig.cmake`` file in the top-level
directory where we can specify the name of the project and where to submit the directory where we can specify the name of the project and where to submit the
@@ -606,9 +620,11 @@ dashboard.
.. literalinclude:: Step9/CTestConfig.cmake .. literalinclude:: Step9/CTestConfig.cmake
:language: cmake :language: cmake
CTest will read in this file when it runs. To create a simple dashboard you can The :manual:`ctest <ctest(1)>` executable will read in this file when it runs.
run **cmake** or **cmake-gui** to configure the project, but do not build it To create a simple dashboard you can run the :manual:`cmake <cmake(1)>`
yet. Instead, change directory to the binary tree, and then run:: executable or the :manual:`cmake-gui <cmake-gui(1)>` to configure the project,
but do not build it yet. Instead, change directory to the binary tree, and then
run:
ctest [-VV] -D Experimental ctest [-VV] -D Experimental
@@ -619,26 +635,26 @@ type must be specified::
Or, from an IDE, build the ``Experimental`` target. Or, from an IDE, build the ``Experimental`` target.
``ctest`` will build and test the project and submit the results to the Kitware The :manual:`ctest <ctest(1)>` executable will build and test the project and
public dashboard. The results of your dashboard will be uploaded to Kitware's submit the results to Kitware's public dashboard:
public dashboard here: https://my.cdash.org/index.php?project=CMakeTutorial. https://my.cdash.org/index.php?project=CMakeTutorial.
Mixing Static and Shared (Step 9) Mixing Static and Shared (Step 9)
================================= =================================
In this section we will show how by using the ``BUILD_SHARED_LIBS`` variable In this section we will show how the :variable:`BUILD_SHARED_LIBS` variable can
we can control the default behavior of ``add_library``, and allow control be used to control the default behavior of :command:`add_library`,
over how libraries without an explicit type (``STATIC``, ``SHARED``, ``MODULE`` and allow control over how libraries without an explicit type (``STATIC``,
or ``OBJECT``) are built. ``SHARED``, ``MODULE`` or ``OBJECT``) are built.
To accomplish this we need to add ``BUILD_SHARED_LIBS`` to the top-level To accomplish this we need to add :variable:`BUILD_SHARED_LIBS` to the
``CMakeLists.txt``. We use the ``option`` command as it allows users to top-level ``CMakeLists.txt``. We use the :command:`option` command as it allows
optionally select if the value should be On or Off. users to optionally select if the value should be ON or OFF.
Next we are going to refactor MathFunctions to become a real library that Next we are going to refactor MathFunctions to become a real library that
encapsulates using ``mysqrt`` or ``sqrt``, instead of requiring the calling encapsulates using ``mysqrt`` or ``sqrt``, instead of requiring the calling
code to do this logic. This will also mean that ``USE_MYMATH`` will not control code to do this logic. This will also mean that ``USE_MYMATH`` will not control
building MathFuctions, but instead will control the behavior of this library. building MathFunctions, but instead will control the behavior of this library.
The first step is to update the starting section of the top-level The first step is to update the starting section of the top-level
``CMakeLists.txt`` to look like: ``CMakeLists.txt`` to look like:
@@ -680,8 +696,8 @@ Finally, update ``MathFunctions/MathFunctions.h`` to use dll export defines:
At this point, if you build everything, you will notice that linking fails At this point, if you build everything, you will notice that linking fails
as we are combining a static library without position independent code with a as we are combining a static library without position independent code with a
library that has position independent code. The solution to this is to library that has position independent code. The solution to this is to
explicitly set the ``POSITION_INDEPENDENT_CODE`` target property of SqrtLibrary explicitly set the :prop_tgt:`POSITION_INDEPENDENT_CODE` target property of
to be True no matter the build type. SqrtLibrary to be True no matter the build type.
.. literalinclude:: Step10/MathFunctions/CMakeLists.txt .. literalinclude:: Step10/MathFunctions/CMakeLists.txt
:language: cmake :language: cmake
@@ -694,35 +710,39 @@ Using CMake documentation can you find a helper module to simplify this?
Adding Generator Expressions (Step 10) Adding Generator Expressions (Step 10)
====================================== ======================================
Generator expressions are evaluated during build system generation to produce :manual:`Generator expressions <cmake-generator-expressions(7)>` are evaluated
information specific to each build configuration. during build system generation to produce information specific to each build
configuration.
Generator expressions are allowed in the context of many target properties, :manual:`Generator expressions <cmake-generator-expressions(7)>` are allowed in
such as ``LINK_LIBRARIES``, ``INCLUDE_DIRECTORIES``, ``COMPILE_DEFINITIONS`` the context of many target properties, such as :prop_tgt:`LINK_LIBRARIES`,
and others. They may also be used when using commands to populate those :prop_tgt:`INCLUDE_DIRECTORIES`, :prop_tgt:`COMPILE_DEFINITIONS` and others.
properties, such as ``target_link_libraries()``, They may also be used when using commands to populate those properties, such as
``target_include_directories()``, :command:`target_link_libraries`, :command:`target_include_directories`,
``target_compile_definitions()`` and others. :command:`target_compile_definitions` and others.
Generator expressions may be used to enable conditional linking, conditional :manual:`Generator expressions <cmake-generator-expressions(7)>` may be used
definitions used when compiling, conditional include directories and more. to enable conditional linking, conditional definitions used when compiling,
The conditions may be based on the build configuration, target properties, conditional include directories and more. The conditions may be based on the
platform information or any other queryable information. build configuration, target properties, platform information or any other
queryable information.
There are different types of generator expressions including Logical, There are different types of
Informational, and Output expressions. :manual:`generator expressions <cmake-generator-expressions(7)>` including
Logical, Informational, and Output expressions.
Logical expressions are used to create conditional output. The basic Logical expressions are used to create conditional output. The basic
expressions are the 0 and 1 expressions. A ``$<0:...>`` results in the empty 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 string, and ``<1:...>`` results in the content of "...". They can also be
nested. nested.
A common usage of generator expressions is to conditionally add compiler A common usage of
flags, such as those for language levels or warnings. A nice pattern is :manual:`generator expressions <cmake-generator-expressions(7)>` is to
to associate this information to an ``INTERFACE`` target allowing this conditionally add compiler flags, such as those for language levels or
information to propagate. Lets start by constructing an ``INTERFACE`` warnings. A nice pattern is to associate this information to an ``INTERFACE``
target and specifying the required C++ standard level of ``11`` instead target allowing this information to propagate. Lets start by constructing an
of using ``CMAKE_CXX_STANDARD``. ``INTERFACE`` target and specifying the required C++ standard level of ``11``
instead of using :variable:`CMAKE_CXX_STANDARD`.
So the following code: So the following code:
@@ -739,11 +759,10 @@ Would be replaced with:
:end-before: # add compiler warning flags just when building this project via :end-before: # add compiler warning flags just when building this project via
Next we add the desired compiler warning flags that we want for our Next we add the desired compiler warning flags that we want for our project. As
project. As warning flags vary based on the compiler we use warning flags vary based on the compiler we use the ``COMPILE_LANG_AND_ID``
the ``COMPILE_LANG_AND_ID`` generator expression to control which generator expression to control which flags to apply given a language and a set
flags to apply given a language and a set of compiler ids as seen of compiler ids as seen below:
below:
.. literalinclude:: Step11/CMakeLists.txt .. literalinclude:: Step11/CMakeLists.txt
:language: cmake :language: cmake
@@ -755,8 +774,8 @@ Looking at this we see that the warning flags are encapsulated inside a
project will not inherit our warning flags. project will not inherit our warning flags.
**Exercise**: Modify ``MathFunctions/CMakeLists.txt`` so that **Exercise**: Modify ``MathFunctions/CMakeLists.txt`` so that all targets have
all targets have a ``target_link_libraries()`` call to ``tutorial_compiler_flags``. a :command:`target_link_libraries` call to ``tutorial_compiler_flags``.
Adding Export Configuration (Step 11) Adding Export Configuration (Step 11)
@@ -771,12 +790,12 @@ The next step is to add the necessary information so that other CMake projects
can use our project, be it from a build directory, a local install or when can use our project, be it from a build directory, a local install or when
packaged. packaged.
The first step is to update our ``install(TARGETS)`` commands to not only The first step is to update our :command:`install(TARGETS)` commands to not
specify a ``DESTINATION`` but also an ``EXPORT``. The ``EXPORT`` keyword only specify a ``DESTINATION`` but also an ``EXPORT``. The ``EXPORT`` keyword
generates and installs a CMake file containing code to import all targets generates and installs a CMake file containing code to import all targets
listed in the install command from the installation tree. So let's go ahead listed in the install command from the installation tree. So let's go ahead and
and explicitly ``EXPORT`` the MathFunctions library by updating the explicitly ``EXPORT`` the MathFunctions library by updating the ``install``
``install`` command in ``MathFunctions/CMakeLists.txt`` to look like: command in ``MathFunctions/CMakeLists.txt`` to look like:
.. literalinclude:: Complete/MathFunctions/CMakeLists.txt .. literalinclude:: Complete/MathFunctions/CMakeLists.txt
:language: cmake :language: cmake
@@ -806,10 +825,10 @@ you will see that CMake will generate an error that looks like:
What CMake is trying to say is that during generating the export information What CMake is trying to say is that during generating the export information
it will export a path that is intrinsically tied to the current machine and it will export a path that is intrinsically tied to the current machine and
will not be valid on other machines. The solution to this is to update the will not be valid on other machines. The solution to this is to update the
MathFunctions ``target_include_directories`` to understand that it needs MathFunctions :command:`target_include_directories` to understand that it needs
different ``INTERFACE`` locations when being used from within the build different ``INTERFACE`` locations when being used from within the build
directory and from an install / package. This means converting the directory and from an install / package. This means converting the
``target_include_directories`` call for MathFunctions to look like: :command:`target_include_directories` call for MathFunctions to look like:
.. literalinclude:: Complete/MathFunctions/CMakeLists.txt .. literalinclude:: Complete/MathFunctions/CMakeLists.txt
:language: cmake :language: cmake
@@ -821,7 +840,7 @@ warn anymore.
At this point, we have CMake properly packaging the target information that is At this point, we have CMake properly packaging the target information that is
required but we will still need to generate a ``MathFunctionsConfig.cmake`` so required but we will still need to generate a ``MathFunctionsConfig.cmake`` so
that the CMake ``find_package`` command can find our project. So let's go that the CMake :command:`find_package` command can find our project. So let's go
ahead and add a new file to the top-level of the project called ahead and add a new file to the top-level of the project called
``Config.cmake.in`` with the following contents: ``Config.cmake.in`` with the following contents: