index.rst 33.8 KB
Newer Older
1 2
CMake Tutorial
**************
3

4 5 6 7
.. only:: html

   .. contents::

Betsy McPhail's avatar
Betsy McPhail committed
8
The CMake tutorial provides a step-by-step guide that covers common build
9
system issues that CMake helps address. Seeing how various topics all
Betsy McPhail's avatar
Betsy McPhail committed
10 11 12 13 14
work together in an example project can be very helpful. The tutorial
documentation and source code for examples can be found in the
``Help/guide/tutorial`` directory of the CMake source code tree. Each step has
its own subdirectory containing code that may be used as a starting point. The
tutorial examples are progressive so that each step provides the complete
15 16
solution for the previous step.

17 18 19
A Basic Starting Point (Step 1)
===============================

20
The most basic project is an executable built from source code files.
21 22 23
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:
Betsy McPhail's avatar
Betsy McPhail committed
24 25 26 27 28 29 30 31 32 33

.. code-block:: cmake

  cmake_minimum_required(VERSION 3.10)

  # set the project name
  project(Tutorial)

  # add the executable
  add_executable(Tutorial tutorial.cxx)
34 35


36
Note that this example uses lower case commands in the ``CMakeLists.txt`` file.
37
Upper, lower, and mixed case commands are supported by CMake. The source
Betsy McPhail's avatar
Betsy McPhail committed
38 39
code for ``tutorial.cxx`` is provided in the ``Step1`` directory and can be
used to compute the square root of a number.
40

41 42 43 44 45
Adding a Version Number and Configured Header File
--------------------------------------------------

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
46
``CMakeLists.txt`` provides more flexibility.
47

48
First, modify the ``CMakeLists.txt`` file to set the version number.
Betsy McPhail's avatar
Betsy McPhail committed
49 50 51 52 53 54 55

.. literalinclude:: Step2/CMakeLists.txt
  :language: cmake
  :end-before: # specify the C++ standard

Then, configure a header file to pass the version number to the source
code:
56 57 58

.. literalinclude:: Step2/CMakeLists.txt
  :language: cmake
Betsy McPhail's avatar
Betsy McPhail committed
59 60
  :start-after: # to the source code
  :end-before: # add the executable
61

62 63
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
64
files. Add the following lines to the end of the ``CMakeLists.txt`` file:
65 66 67 68 69

.. literalinclude:: Step2/CMakeLists.txt
  :language: cmake
  :start-after: # so that we will find TutorialConfig.h

Betsy McPhail's avatar
Betsy McPhail committed
70 71
Using your favorite editor, create ``TutorialConfig.h.in`` in the source
directory with the following contents:
72

Betsy McPhail's avatar
Betsy McPhail committed
73
.. literalinclude:: Step2/TutorialConfig.h.in
74 75 76 77
  :language: cmake

When CMake configures this header file the values for
``@Tutorial_VERSION_MAJOR@`` and ``@Tutorial_VERSION_MINOR@`` will be
Betsy McPhail's avatar
Betsy McPhail committed
78 79 80 81 82 83 84
replaced.

Next modify ``tutorial.cxx`` to include the configured header file,
``TutorialConfig.h``.

Finally, let's print out the version number by updating ``tutorial.cxx`` as
follows:
85 86 87

.. literalinclude:: Step2/tutorial.cxx
  :language: c++
Betsy McPhail's avatar
Betsy McPhail committed
88 89
  :start-after: {
  :end-before: // convert input to double
90 91 92 93

Specify the C++ Standard
-------------------------

Betsy McPhail's avatar
Betsy McPhail committed
94 95 96
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>``.
97

Betsy McPhail's avatar
Betsy McPhail committed
98 99 100 101
.. literalinclude:: Step2/tutorial.cxx
  :language: c++
  :start-after: // convert input to double
  :end-before: // calculate square root
102

Betsy McPhail's avatar
Betsy McPhail committed
103 104 105
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 ``CMAKE_CXX_STANDARD`` variable. For this tutorial,
106 107
set the ``CMAKE_CXX_STANDARD`` variable in the ``CMakeLists.txt`` file to 11
and ``CMAKE_CXX_STANDARD_REQUIRED`` to True:
108

Betsy McPhail's avatar
Betsy McPhail committed
109 110 111
.. literalinclude:: Step2/CMakeLists.txt
  :language: cmake
  :end-before: # configure a header file to pass some of the CMake settings
112 113 114 115 116 117 118

Build and Test
--------------

Run **cmake** or **cmake-gui** to configure the project and then build it
with your chosen build tool.

Betsy McPhail's avatar
Betsy McPhail committed
119 120 121 122 123 124 125 126 127 128 129 130 131
For example, from the command line we could navigate to the
``Help/guide/tutorial`` directory of the CMake source code tree and run the
following commands:

.. code-block:: console

  mkdir Step1_build
  cd Step1_build
  cmake ../Step1
  cmake --build .

Navigate to the directory where Tutorial was built (likely the make directory
or a Debug or Release build configuration subdirectory) and run these commands:
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147

.. code-block:: console

  Tutorial 4294967296
  Tutorial 10
  Tutorial

Adding a Library (Step 2)
=========================

Now we will add a library to our project. This library will contain 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
148
called ``MathFunctions``. This directory already contains a header file,
Betsy McPhail's avatar
Betsy McPhail committed
149 150 151
``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.
152

153
Add the following one line ``CMakeLists.txt`` file to the ``MathFunctions``
Betsy McPhail's avatar
Betsy McPhail committed
154 155 156
directory:

.. literalinclude:: Step3/MathFunctions/CMakeLists.txt
157 158
  :language: cmake

Betsy McPhail's avatar
Betsy McPhail committed
159
To make use of the new library we will add an ``add_subdirectory`` call in the
160 161 162 163
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 ``mqsqrt.h`` header file can be found. The last few lines
of the top-level ``CMakeLists.txt`` file should now look like:
164 165 166 167 168 169 170 171 172

.. code-block:: cmake

        # add the MathFunctions library
        add_subdirectory(MathFunctions)

        # add the executable
        add_executable(Tutorial tutorial.cxx)

Betsy McPhail's avatar
Betsy McPhail committed
173
        target_link_libraries(Tutorial PUBLIC MathFunctions)
174 175 176 177 178 179 180 181 182 183

        # 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"
                                  )

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
184 185
occurrence. The first step is to add an option to the top-level
``CMakeLists.txt`` file.
186 187 188 189

.. literalinclude:: Step3/CMakeLists.txt
  :language: cmake
  :start-after: # should we use our own math functions
Betsy McPhail's avatar
Betsy McPhail committed
190
  :end-before: # add the MathFunctions library
191

Betsy McPhail's avatar
Betsy McPhail committed
192 193 194 195
This option will be displayed in the CMake GUI and ccmake 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.
196 197

The next change is to make building and linking the MathFunctions library
198 199
conditional. To do this we change the end of the top-level ``CMakeLists.txt``
file to look like the following:
200 201 202

.. literalinclude:: Step3/CMakeLists.txt
  :language: cmake
Betsy McPhail's avatar
Betsy McPhail committed
203
  :start-after: # add the MathFunctions library
204

Betsy McPhail's avatar
Betsy McPhail committed
205 206 207 208 209
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.
210 211

The corresponding changes to the source code are fairly straightforward. First,
212
in ``tutorial.cxx``, include the ``MathFunctions.h`` header if we need it:
213 214 215 216 217 218

.. literalinclude:: Step3/tutorial.cxx
  :language: c++
  :start-after: // should we include the MathFunctions header
  :end-before: int main

219 220
Then, in the same file, make ``USE_MYMATH`` control which square root
function is used:
221 222 223 224 225 226 227 228 229 230 231 232 233

.. literalinclude:: Step3/tutorial.cxx
  :language: c++
  :start-after: // which square root function should we use?
  :end-before: std::cout << "The square root of

Since the source code now requires ``USE_MYMATH`` we can add it to
``TutorialConfig.h.in`` with the following line:

.. literalinclude:: Step3/TutorialConfig.h.in
  :language: c
  :lines: 4

Betsy McPhail's avatar
Betsy McPhail committed
234 235 236
**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?

237 238 239
Run **cmake** or **cmake-gui** to configure the project and then build it
with your chosen build tool. Then run the built Tutorial executable.

Betsy McPhail's avatar
Betsy McPhail committed
240 241
Use ccmake or the CMake GUI to update the value of ``USE_MYMATH``. Rebuild and
run the tutorial again. Which function gives better results, sqrt or mysqrt?
242 243 244 245 246 247 248 249 250 251 252 253 254 255

Adding Usage Requirements for Library (Step 3)
==============================================

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:

  - ``target_compile_definitions``
  - ``target_compile_options``
  - ``target_include_directories``
  - ``target_link_libraries``

Betsy McPhail's avatar
Betsy McPhail committed
256 257 258 259 260
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
MathFunctions needs to include the current source directory, while
MathFunctions itself doesn't. So  this can become an ``INTERFACE`` usage
requirement.
261 262

Remember ``INTERFACE`` means things that consumers require but the producer
Betsy McPhail's avatar
Betsy McPhail committed
263
doesn't. Add the following lines to the end of ``MathFunctions/CMakeLists.txt``:
264 265 266 267 268 269 270

.. literalinclude:: Step4/MathFunctions/CMakeLists.txt
  :language: cmake
  :start-after: # to find MathFunctions.h

Now that we've specified usage requirements for MathFunctions we can safely
remove our uses of the ``EXTRA_INCLUDES`` variable from the top-level
271
``CMakeLists.txt``, here:
Betsy McPhail's avatar
Betsy McPhail committed
272 273 274 275 276 277 278 279 280 281 282

.. literalinclude:: Step4/CMakeLists.txt
  :language: cmake
  :start-after: # add the MathFunctions library
  :end-before: # add the executable

And here:

.. literalinclude:: Step4/CMakeLists.txt
  :language: cmake
  :start-after: # so that we will find TutorialConfig.h
283 284

Once this is done, run **cmake** or **cmake-gui** to configure the project
285 286
and then build it with your chosen build tool or by using ``cmake --build .``
from the build directory.
287 288 289 290 291 292 293 294 295

Installing and Testing (Step 4)
===============================

Now we can start adding install rules and testing support to our project.

Install Rules
-------------

Betsy McPhail's avatar
Betsy McPhail committed
296
The install rules are fairly simple: for MathFunctions we want to install the
297 298 299
library and header file and for the application we want to install the
executable and configured header.

Betsy McPhail's avatar
Betsy McPhail committed
300
So to the end of ``MathFunctions/CMakeLists.txt`` we add:
301 302 303 304 305

.. literalinclude:: Step5/MathFunctions/CMakeLists.txt
  :language: cmake
  :start-after: # install rules

Betsy McPhail's avatar
Betsy McPhail committed
306
And to the end of the top-level ``CMakeLists.txt`` we add:
307 308 309 310 311 312 313 314 315

.. literalinclude:: Step5/CMakeLists.txt
  :language: cmake
  :start-after: # add the install targets
  :end-before: # enable testing

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
316
with your chosen build tool. Run the install step by typing
Betsy McPhail's avatar
Betsy McPhail committed
317 318 319 320
``cmake --install .`` (introduced in 3.15, older versions of CMake must use
``make install``) from the command line, or build the ``INSTALL`` target from
an IDE. This will install the appropriate header files, libraries, and
executables.
321

Betsy McPhail's avatar
Betsy McPhail committed
322 323 324 325 326 327 328
The CMake variable ``CMAKE_INSTALL_PREFIX`` is used to determine the root of
where the files will be installed. If using ``cmake --install`` a custom
installation directory can be given via ``--prefix`` argument. For
multi-configuration tools, use the ``--config`` argument to specify the
configuration.

Verify that the installed Tutorial runs.
329 330 331 332

Testing Support
---------------

333 334 335
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.
336 337 338 339 340 341 342 343 344 345

.. literalinclude:: Step5/CMakeLists.txt
  :language: cmake
  :start-after: # enable testing

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.

The next test makes use of the ``PASS_REGULAR_EXPRESSION`` test property to
Betsy McPhail's avatar
Betsy McPhail committed
346
verify that the output of the test contains certain strings. In this case,
347
verifying that the usage message is printed when an incorrect number of
348 349 350 351 352 353 354 355
arguments are provided.

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.

Rebuild the application and then cd to the binary directory and run
Betsy McPhail's avatar
Betsy McPhail committed
356 357 358 359 360
``ctest -N`` and ``ctest -VV``. For multi-config generators (e.g. Visual
Studio), the configuration type must be specified. To run tests in Debug mode,
for example, use ``ctest -C Debug -VV`` from the build directory (not the
Debug subdirectory!). Alternatively, build the ``RUN_TESTS`` target from the
IDE.
361 362 363 364 365 366 367 368 369 370 371 372

Adding System Introspection (Step 5)
====================================

Let us consider adding some code to our project that depends on features the
target platform may not have. For this example, we will add some code that
depends on whether or not the target platform has the ``log`` and ``exp``
functions. Of course almost every platform has these functions but for this
tutorial assume that they are not common.

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
373 374 375
these functions using the ``CheckSymbolExists`` module in the top-level
``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.
376

Betsy McPhail's avatar
Betsy McPhail committed
377
.. literalinclude:: Step6/MathFunctions/CMakeLists.txt
378 379
  :language: cmake
  :start-after: # does this system provide the log and exp functions?
Betsy McPhail's avatar
Betsy McPhail committed
380
  :end-before: if(HAVE_LOG AND HAVE_EXP)
381 382 383 384

Now let's add these defines to ``TutorialConfig.h.in`` so that we can use them
from ``mysqrt.cxx``:

Betsy McPhail's avatar
Betsy McPhail committed
385
.. code-block:: console
386

Betsy McPhail's avatar
Betsy McPhail committed
387 388 389 390 391 392 393 394
  // does the platform provide exp and log functions?
  #cmakedefine HAVE_LOG
  #cmakedefine HAVE_EXP

Modify ``mysqrt.cxx`` to include cmath. Next, in that same file in the
``mysqrt`` function we can provide an alternate implementation based on
``log`` and ``exp`` if they are available on the system using the following
code (don't forget the ``#endif`` before returning the result!):
395 396 397 398

.. literalinclude:: Step6/MathFunctions/mysqrt.cxx
  :language: c++
  :start-after: // if we have both log and exp then use them
Betsy McPhail's avatar
Betsy McPhail committed
399
  :end-before: // do ten iterations
400 401

Run **cmake** or **cmake-gui** to configure the project and then build it
Betsy McPhail's avatar
Betsy McPhail committed
402
with your chosen build tool and run the Tutorial executable.
403

Betsy McPhail's avatar
Betsy McPhail committed
404 405 406 407
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
``TutorialConfig.h`` in ``mysqrt.cxx``.

408 409
We will also need to update ``MathFunctions/CMakeLists.txt`` so ``mysqrt.cxx``
knows where this file is located:
Betsy McPhail's avatar
Betsy McPhail committed
410 411

.. code-block:: cmake
412

Betsy McPhail's avatar
Betsy McPhail committed
413 414 415 416
  target_include_directories(MathFunctions
            INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
            PRIVATE ${CMAKE_BINARY_DIR}
            )
417

Betsy McPhail's avatar
Betsy McPhail committed
418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
After making this update, go ahead and build the project again and run the built
Tutorial executable. If ``log`` and ``exp`` are still not being used, open the
generated ``TutorialConfig.h`` file from the build directory. Maybe they aren't
available on the current system?

Which function gives better results now, sqrt or mysqrt?

Specify Compile Definition
--------------------------

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
``target_compile_definitions``.

First, remove the defines from ``TutorialConfig.h.in``. We no longer need to
include ``TutorialConfig.h`` from ``mysqrt.cxx`` or the extra include in
434
``MathFunctions/CMakeLists.txt``.
Betsy McPhail's avatar
Betsy McPhail committed
435 436

Next, we can move the check for ``HAVE_LOG`` and ``HAVE_EXP`` to
437
``MathFunctions/CMakeLists.txt`` and then specify those values as ``PRIVATE``
Betsy McPhail's avatar
Betsy McPhail committed
438 439 440 441 442 443
compile definitions.

.. literalinclude:: Step6/MathFunctions/CMakeLists.txt
  :language: cmake
  :start-after: # does this system provide the log and exp functions?
  :end-before: # install rules
444

Betsy McPhail's avatar
Betsy McPhail committed
445
After making these updates, go ahead and build the project again. Run the
446
built Tutorial executable and verify that the results are same as earlier in
Betsy McPhail's avatar
Betsy McPhail committed
447
this step.
448 449 450 451

Adding a Custom Command and Generated File (Step 6)
===================================================

Betsy McPhail's avatar
Betsy McPhail committed
452 453 454 455 456
Suppose, for the purpose of this tutorial, we decide that we never want to use
the platform ``log`` and ``exp`` functions and instead would like to
generate a table of precomputed values to use in the ``mysqrt`` function.
In this section, we will create the table as part of the build process,
and then compile that table into our application.
457

Betsy McPhail's avatar
Betsy McPhail committed
458
First, let's remove the check for the ``log`` and ``exp`` functions in
459
``MathFunctions/CMakeLists.txt``. Then remove the check for ``HAVE_LOG`` and
Betsy McPhail's avatar
Betsy McPhail committed
460 461
``HAVE_EXP`` from ``mysqrt.cxx``. At the same time, we can remove
:code:`#include <cmath>`.
462

463
In the ``MathFunctions`` subdirectory, a new source file named ``MakeTable.cxx``
Betsy McPhail's avatar
Betsy McPhail committed
464
has been provided to generate the table.
465

Betsy McPhail's avatar
Betsy McPhail committed
466 467
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.
468

469 470 471 472
The next step is to add the appropriate commands to the
``MathFunctions/CMakeLists.txt`` file to build the MakeTable executable and
then run it as part of the build process. A few commands are needed to
accomplish this.
473

474 475
First, at the top of ``MathFunctions/CMakeLists.txt``, the executable for
``MakeTable`` is added as any other executable would be added.
476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513

.. literalinclude:: Step7/MathFunctions/CMakeLists.txt
  :language: cmake
  :start-after: # first we add the executable that generates the table
  :end-before: # add the command to generate the source code

Then we add a custom command that specifies how to produce ``Table.h``
by running MakeTable.

.. literalinclude:: Step7/MathFunctions/CMakeLists.txt
  :language: cmake
  :start-after: # add the command to generate the source code
  :end-before: # add the main library

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
  :language: cmake
  :start-after: # add the main library
  :end-before: # state that anybody linking

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
  :start-after: # state that we depend on our bin
  :end-before: # install rules

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
  :language: c++
  :start-after: // a hack square root calculation using simple operations

Run **cmake** or **cmake-gui** to configure the project and then build it
Betsy McPhail's avatar
Betsy McPhail committed
514 515 516 517 518 519 520 521
with your chosen build tool.

When this project is built it will first build the ``MakeTable`` executable.
It will then run ``MakeTable`` to produce ``Table.h``. Finally, it will
compile ``mysqrt.cxx`` which includes ``Table.h`` to produce the MathFunctions
library.

Run the Tutorial executable and verify that it is using the table.
522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543

Building an Installer (Step 7)
==============================

Next suppose that we want to distribute our project to other people so that
they can use it. We want to provide both binary and source distributions on a
variety of platforms. This is a little different from the install we did
previously in `Installing and Testing (Step 4)`_ , where we were
installing the binaries that we had built from the source code. In this
example we will be building installation packages that support binary
installations and package management features. To accomplish this we will use
CPack to create platform specific installers. Specifically we need to add
a few lines to the bottom of our top-level ``CMakeLists.txt`` file.

.. literalinclude:: Step8/CMakeLists.txt
  :language: cmake
  :start-after: # setup installer

That is all there is to it. We start by including
``InstallRequiredSystemLibraries``. This module will include any runtime
libraries that are needed by the project for the current platform. Next we
set some CPack variables to where we have stored the license and version
Betsy McPhail's avatar
Betsy McPhail committed
544 545 546 547 548 549
information for this project. The version information was set earlier in this
tutorial and the ``license.txt`` has been included in the top-level source
directory for this step.

Finally we include the CPack module which will use these variables and some
other properties of the current system to setup an installer.
550 551

The next step is to build the project in the usual manner and then run
Betsy McPhail's avatar
Betsy McPhail committed
552
CPack on it. To build a binary distribution, from the binary directory run:
553 554 555 556 557

.. code-block:: console

  cpack

Betsy McPhail's avatar
Betsy McPhail committed
558 559 560 561 562 563 564
To specify the generator, use the ``-G`` option. For multi-config builds, use
``-C`` to specify the configuration. For example:

.. code-block:: console

  cpack -G ZIP -C Debug

565 566 567 568
To create a source distribution you would type:

.. code-block:: console

Betsy McPhail's avatar
Betsy McPhail committed
569
  cpack --config CPackSourceConfig.cmake
570 571 572 573

Alternatively, run ``make package`` or right click the ``Package`` target and
``Build Project`` from an IDE.

Betsy McPhail's avatar
Betsy McPhail committed
574
Run the installer found in the binary directory. Then run the
575 576 577 578 579 580
installed executable and verify that it works.

Adding Support for a Dashboard (Step 8)
=======================================

Adding support for submitting our test results to a dashboard is very easy. We
Betsy McPhail's avatar
Betsy McPhail committed
581 582 583
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
for dashboards we include the CTest module in our top-level ``CMakeLists.txt``.
584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601

Replace:

.. code-block:: cmake

  # enable testing
  enable_testing()

With:

.. code-block:: cmake

  # enable dashboard scripting
  include(CTest)

The CTest module will automatically call ``enable_testing()``, so
we can remove it from our CMake files.

Betsy McPhail's avatar
Betsy McPhail committed
602 603 604
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
dashboard.
605 606 607 608 609 610

.. literalinclude:: Step9/CTestConfig.cmake
  :language: cmake

CTest will read in this file when it runs. To create a simple dashboard you can
run **cmake** or **cmake-gui** to configure the project, but do not build it
Betsy McPhail's avatar
Betsy McPhail committed
611
yet. Instead, change directory to the binary tree, and then run::
612

Betsy McPhail's avatar
Betsy McPhail committed
613 614 615 616
  ctest [-VV] –D Experimental

Remember, for multi-config generators (e.g. Visual Studio), the configuration
type must be specified::
617

Betsy McPhail's avatar
Betsy McPhail committed
618
  ctest [-VV] -C Debug –D Experimental
619

Betsy McPhail's avatar
Betsy McPhail committed
620
Or, from an IDE, build the ``Experimental`` target.
621

622
``ctest`` will build and test the project and submit the results to the Kitware
623 624 625 626 627 628 629 630
public dashboard. The results of your dashboard will be uploaded to Kitware's
public dashboard here: https://my.cdash.org/index.php?project=CMakeTutorial.

Mixing Static and Shared (Step 9)
=================================

In this section we will show how by using the ``BUILD_SHARED_LIBS`` variable
we can control the default behavior of ``add_library``, and allow control
631 632
over how libraries without an explicit type (``STATIC``, ``SHARED``, ``MODULE``
or ``OBJECT``) are built.
633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659

To accomplish this we need to add ``BUILD_SHARED_LIBS`` to the top-level
``CMakeLists.txt``. We use the ``option`` command as it allows 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
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
building MathFuctions, but instead will control the behavior of this library.

The first step is to update the starting section of the top-level
``CMakeLists.txt`` to look like:

.. literalinclude:: Step10/CMakeLists.txt
  :language: cmake
  :end-before: # add the binary tree

Now that we have made MathFunctions always be used, we will need to update
the logic of that library. So, in ``MathFunctions/CMakeLists.txt`` we need to
create a SqrtLibrary that will conditionally be built when ``USE_MYMATH`` is
enabled. Now, since this is a tutorial, we are going to explicitly require
that SqrtLibrary is built statically.

The end result is that ``MathFunctions/CMakeLists.txt`` should look like:

.. literalinclude:: Step10/MathFunctions/CMakeLists.txt
  :language: cmake
Betsy McPhail's avatar
Betsy McPhail committed
660
  :lines: 1-36,42-
661 662 663 664 665 666 667 668 669 670 671 672

Next, update ``MathFunctions/mysqrt.cxx`` to use the ``mathfunctions`` and
``detail`` namespaces:

.. literalinclude:: Step10/MathFunctions/mysqrt.cxx
  :language: c++

We also need to make some changes in ``tutorial.cxx``, so that it no longer
uses ``USE_MYMATH``:

#. Always include ``MathFunctions.h``
#. Always use ``mathfunctions::sqrt``
Betsy McPhail's avatar
Betsy McPhail committed
673
#. Don't include cmath
674 675 676 677 678 679 680

Finally, update ``MathFunctions/MathFunctions.h`` to use dll export defines:

.. literalinclude:: Step10/MathFunctions/MathFunctions.h
  :language: c++

At this point, if you build everything, you will notice that linking fails
681 682 683 684
as we are combining a static library without position independent code with a
library that has position independent code. The solution to this is to
explicitly set the ``POSITION_INDEPENDENT_CODE`` target property of SqrtLibrary
to be True no matter the build type.
685

Betsy McPhail's avatar
Betsy McPhail committed
686 687 688 689
.. literalinclude:: Step10/MathFunctions/CMakeLists.txt
  :language: cmake
  :lines: 37-42

690 691 692
**Exercise**: We modified ``MathFunctions.h`` to use dll export defines.
Using CMake documentation can you find a helper module to simplify this?

Betsy McPhail's avatar
Betsy McPhail committed
693

694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719
Adding Generator Expressions (Step 10)
======================================

Generator expressions are evaluated during build system generation to produce
information specific to each build configuration.

Generator expressions are allowed in the context of many target properties,
such as ``LINK_LIBRARIES``, ``INCLUDE_DIRECTORIES``, ``COMPILE_DEFINITIONS``
and others. They may also be used when using commands to populate those
properties, such as ``target_link_libraries()``,
``target_include_directories()``,
``target_compile_definitions()`` and others.

Generator expressions may be used to enable conditional linking, conditional
definitions used when compiling, conditional include directories and more.
The conditions may be based on the build configuration, target properties,
platform information or any other queryable information.

There are different types of generator expressions including Logical,
Informational, and Output expressions.

Logical expressions are used to create conditional output. The basic
expressions are the 0 and 1 expressions. A ``$<0:...>`` results in the empty
string, and ``<1:...>`` results in the content of "...".  They can also be
nested.

720
A common usage of generator expressions is to conditionally add compiler
721
flags, such as those for language levels or warnings. A nice pattern is
722 723 724 725
to associate this information to an ``INTERFACE`` target allowing this
information to propagate. Lets start by constructing an ``INTERFACE``
target and specifying the required C++ standard level of ``11`` instead
of using ``CMAKE_CXX_STANDARD``.
726

727 728 729 730
So the following code:

.. literalinclude:: Step10/CMakeLists.txt
  :language: cmake
Betsy McPhail's avatar
Betsy McPhail committed
731 732
  :start-after: project(Tutorial VERSION 1.0)
  :end-before: # control where the static and shared libraries are built so that on windows
733

734
Would be replaced with:
735

736 737
.. literalinclude:: Step11/CMakeLists.txt
  :language: cmake
Betsy McPhail's avatar
Betsy McPhail committed
738
  :start-after: project(Tutorial VERSION 1.0)
739 740 741 742 743 744 745 746 747 748 749 750
  :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
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:

.. literalinclude:: Step11/CMakeLists.txt
  :language: cmake
  :start-after: # the BUILD_INTERFACE genex
Betsy McPhail's avatar
Betsy McPhail committed
751
  :end-before: # control where the static and shared libraries are built so that on windows
752 753 754 755

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.
756 757


758 759
**Exercise**: Modify ``MathFunctions/CMakeLists.txt`` so that
all targets have a ``target_link_libraries()`` call to ``tutorial_compiler_flags``.
760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818


Adding Export Configuration (Step 11)
=====================================

During `Installing and Testing (Step 4)`_ of the tutorial we added the ability
for CMake to install the library and headers of the project. During
`Building an Installer (Step 7)`_ we added the ability to package up this
information so it could be distributed to other people.

The next step is to add the necessary information so that other CMake projects
can use our project, be it from a build directory, a local install or when
packaged.

The first step is to update our ``install(TARGETS)`` commands to not only
specify a ``DESTINATION`` but also an ``EXPORT``. The ``EXPORT`` keyword
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
and explicitly ``EXPORT`` the MathFunctions library by updating the
``install`` command in ``MathFunctions/CMakeLists.txt`` to look like:

.. literalinclude:: Complete/MathFunctions/CMakeLists.txt
  :language: cmake
  :start-after: # install rules

Now that we have MathFunctions being exported, we also need to explicitly
install the generated ``MathFunctionsTargets.cmake`` file. This is done by
adding the following to the bottom of the top-level ``CMakeLists.txt``:

.. literalinclude:: Complete/CMakeLists.txt
  :language: cmake
  :start-after: # install the configuration targets
  :end-before: include(CMakePackageConfigHelpers)

At this point you should try and run CMake. If everything is setup properly
you will see that CMake will generate an error that looks like:

.. code-block:: console

  Target "MathFunctions" INTERFACE_INCLUDE_DIRECTORIES property contains
  path:

    "/Users/robert/Documents/CMakeClass/Tutorial/Step11/MathFunctions"

  which is prefixed in the source directory.

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
will not be valid on other machines. The solution to this is to update the
MathFunctions ``target_include_directories`` to understand that it needs
different ``INTERFACE`` locations when being used from within the build
directory and from an install / package. This means converting the
``target_include_directories`` call for MathFunctions to look like:

.. literalinclude:: Complete/MathFunctions/CMakeLists.txt
  :language: cmake
  :start-after: # to find MathFunctions.h, while we don't.
  :end-before: # should we use our own math functions

819
Once this has been updated, we can re-run CMake and verify that it doesn't
820 821 822 823
warn anymore.

At this point, we have CMake properly packaging the target information that is
required but we will still need to generate a ``MathFunctionsConfig.cmake`` so
824
that the CMake ``find_package`` command can find our project. So let's go
825 826 827 828 829 830
ahead and add a new file to the top-level of the project called
``Config.cmake.in`` with the following contents:

.. literalinclude:: Complete/Config.cmake.in

Then, to properly configure and install that file, add the following to the
831
bottom of the top-level ``CMakeLists.txt``:
832 833 834 835 836 837 838 839 840

.. literalinclude:: Complete/CMakeLists.txt
  :language: cmake
  :start-after: # install the configuration targets
  :end-before: # generate the export

At this point, we have generated a relocatable CMake Configuration for our
project that can be used after the project has been installed or packaged. If
we want our project to also be used from a build directory we only have to add
841
the following to the bottom of the top level ``CMakeLists.txt``:
842 843 844 845 846 847 848 849 850 851 852 853

.. literalinclude:: Complete/CMakeLists.txt
  :language: cmake
  :start-after: # needs to be after the install(TARGETS ) command

With this export call we now generate a ``Targets.cmake``, allowing the
configured ``MathFunctionsConfig.cmake`` in the build directory to be used by
other projects, without needing it to be installed.

Import a CMake Project (Consumer)
=================================

854
This example shows how a project can find other CMake packages that
855 856 857 858 859 860 861 862
generate ``Config.cmake`` files.

It also shows how to state a project's external dependencies when generating
a ``Config.cmake``.

Packaging Debug and Release (MultiPackage)
==========================================

863
By default CMake's model is that a build directory only contains a single
864 865 866 867 868 869
configuration, be it Debug, Release, MinSizeRel, or RelWithDebInfo.

But it is possible to setup CPack to bundle multiple build directories at the
same time to build a package that contains multiple configurations of the
same project.

870
First we need to construct a directory called ``multi_config``, which
871 872 873 874 875
will contain all the builds that we want to package together.

Second create a ``debug`` and ``release`` directory underneath
``multi_config``. At the end you should have a layout that looks like:

876 877 878 879 880
.. code-block:: none

  ─ multi_config
      ├── debug
      └── release
881 882 883 884 885 886 887 888 889 890 891 892 893 894 895

Now we need to setup debug and release builds, which would roughly entail
the following:

.. code-block:: console

  cd debug
  cmake -DCMAKE_BUILD_TYPE=Debug ../../MultiPackage/
  cmake --build .
  cd ../release
  cmake -DCMAKE_BUILD_TYPE=Release ../../MultiPackage/
  cmake --build .
  cd ..


896 897 898
Now that both the debug and release builds are complete, we can use
a custom ``MultiCPackConfig.cmake`` file to package both builds into a single
release.
899 900 901 902

.. code-block:: console

  cpack --config ../../MultiPackage/MultiCPackConfig.cmake