code:
<!DOCTYPE html>

    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />

  <title>Importing and Exporting Guide — CMake 3.29.0-rc3 Documentation</title>

    <link rel="stylesheet" type="text/css" href="../../_static/pygments.css" />
    <link rel="stylesheet" type="text/css" href="../../_static/cmake.css" />

    <link rel="icon" href="../../_static/cmake-favicon.ico"/>
    <link rel="index" title="Index" href="../../genindex.html" />
    <link rel="search" title="Search" href="../../search.html" />
    <link rel="next" title="IDE Integration Guide" href="../ide-integration/index.html" />
    <link rel="prev" title="Using Dependencies Guide" href="../using-dependencies/index.html" />

Navigation

          index

          next |

          previous |

    CMake »

    3.29.0-rc3 Documentation »

Importing and Exporting Guide

Importing and Exporting Guide¶

Contents

Importing and Exporting Guide

Introduction

Importing Targets

Importing Executables

Importing Libraries

Exporting Targets

Creating Packages

Creating a Package Configuration File

Creating a Package Version File

Exporting Targets from the Build Tree

Building and Installing a Package

Creating Relocatable Packages

Using the Package Configuration File

Adding Components

Introduction¶

In this guide, we will present the concept of IMPORTED targets
and demonstrate how to import existing executable or library files from disk
into a CMake project. We will then show how CMake supports exporting targets
from one CMake-based project and importing them into another. Finally, we
will demonstrate how to package a project with a configuration file to allow
for easy integration into other CMake projects. This guide and the complete
example source code can be found in the Help/guide/importing-exporting
directory of the CMake source code tree.

Importing Targets¶

IMPORTED targets are used to convert files outside of a CMake
project into logical targets inside of the project. IMPORTED
targets are created using the IMPORTED option of the
add_executable() and add_library() commands. No build
files are generated for IMPORTED targets. Once imported,
IMPORTED targets may be referenced like any other target within
the project and provide a convenient, flexible reference to outside
executables and libraries.

By default, the IMPORTED target name has scope in the directory in
which it is created and below. We can use the GLOBAL option to extended
visibility so that the target is accessible globally in the build system.

Details about the IMPORTED target are specified by setting
properties whose names begin in IMPORTED_ and INTERFACE_. For example,
IMPORTED_LOCATION contains the full path to the target on
disk.

Importing Executables¶

To start, we will walk through a simple example that creates an
IMPORTED executable target and then references it from the
add_custom_command() command.

We'll need to do some setup to get started. We want to create an executable
that when run creates a basic main.cc file in the current directory. The
details of this project are not important. Navigate to
Help/guide/importing-exporting/MyExe, create a build directory, run
cmake and build and install the project.

$ cd Help/guide/importing-exporting/MyExe
$ mkdir build
$ cd build
$ cmake ..
$ cmake --build .
$ cmake --install . --prefix <install location>
$ <install location>/myexe
$ ls
[...] main.cc [...]

Now we can import this executable into another CMake project. The source code
for this section is available in Help/guide/importing-exporting/Importing.
In the CMakeLists file, use the add_executable() command to create a
new target called myexe. Use the IMPORTED option to tell CMake that
this target references an executable file located outside of the project. No
rules will be generated to build it and the IMPORTED target
property will be set  to true.

add_executable(myexe IMPORTED)

Next, set the IMPORTED_LOCATION property of the target using
the set_property() command. This will tell CMake the location of the
target on disk. The location may need to be adjusted to the
<install location> specified in the previous step.

set_property(TARGET myexe PROPERTY
             IMPORTED_LOCATION "../InstallMyExe/bin/myexe")

We can now reference this IMPORTED target just like any target
built within the project. In this instance, let's imagine that we want to use
the generated source file in our project. Use the IMPORTED
target in the add_custom_command() command:

add_custom_command(OUTPUT main.cc COMMAND myexe)

As COMMAND specifies an executable target name, it will automatically be
replaced by the location of the executable given by the
IMPORTED_LOCATION property above.

Finally, use the output from add_custom_command():

add_executable(mynewexe main.cc)

Importing Libraries¶

In a similar manner, libraries from other projects may be accessed through
IMPORTED targets.

Note: The full source code for the examples in this section is not provided
and is left as an exercise for the reader.

In the CMakeLists file, add an IMPORTED library and specify its
location on disk:

add_library(foo STATIC IMPORTED)
set_property(TARGET foo PROPERTY
             IMPORTED_LOCATION "/path/to/libfoo.a")

Then use the IMPORTED library inside of our project:

add_executable(myexe src1.c src2.c)
target_link_libraries(myexe PRIVATE foo)

On Windows, a .dll and its .lib import library may be imported together:

add_library(bar SHARED IMPORTED)
set_property(TARGET bar PROPERTY
             IMPORTED_LOCATION "c:/path/to/bar.dll")
set_property(TARGET bar PROPERTY
             IMPORTED_IMPLIB "c:/path/to/bar.lib")
add_executable(myexe src1.c src2.c)
target_link_libraries(myexe PRIVATE bar)

A library with multiple configurations may be imported with a single target:

find_library(math_REL NAMES m)
find_library(math_DBG NAMES md)
add_library(math STATIC IMPORTED GLOBAL)
set_target_properties(math PROPERTIES
  IMPORTED_LOCATION "${math_REL}"
  IMPORTED_LOCATION_DEBUG "${math_DBG}"
  IMPORTED_CONFIGURATIONS "RELEASE;DEBUG"
)
add_executable(myexe src1.c src2.c)
target_link_libraries(myexe PRIVATE math)

The generated build system will link myexe to m.lib when built in the
release configuration, and md.lib when built in the debug configuration.

Exporting Targets¶

While IMPORTED targets on their own are useful, they still
require that the project that imports them knows the locations of the target
files on disk. The real power of IMPORTED  targets is when the
project providing the target files also provides a CMake file to help import
them. A project can be setup to produce the necessary information so that it
can easily be used by other CMake projects be it from a build directory, a
local install or when packaged.

In the remaining sections, we will walk through a set of example projects
step-by-step. The first project will create and install a library and
corresponding CMake configuration and package files. The second project will
use the generated package.

Let's start by looking at the MathFunctions project in the
Help/guide/importing-exporting/MathFunctions directory. Here we have a
header file MathFunctions.h that declares a sqrt function:

#pragma once

namespace MathFunctions {
double sqrt(double x);
}

And a corresponding source file MathFunctions.cxx:

#include "MathFunctions.h"

#include <cmath>

namespace MathFunctions {
double sqrt(double x)
{
  return std::sqrt(x);
}
}

Don't worry too much about the specifics of the C++ files, they are just meant
to be a simple example that will compile and run on many build systems.

Now we can create a CMakeLists.txt file for the MathFunctions
project. Start by specifying the cmake_minimum_required() version and
project() name:

cmake_minimum_required(VERSION 3.15)
project(MathFunctions)

# make cache variables for install destinations
include(GNUInstallDirs)

# specify the C++ standard
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

The GNUInstallDirs module is included in order to provide the
project with the flexibility to install into different platform layouts by
making the directories available as cache variables.

Create a library called MathFunctions with the add_library()
command:

add_library(MathFunctions STATIC MathFunctions.cxx)

And then use the target_include_directories() command to specify the
include directories for the target:

target_include_directories(MathFunctions
                           PUBLIC
                           "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>"
                           "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
)

We need to tell CMake that we want to use different include directories
depending on if we're building the library or using it from an installed
location. If we don't do this, when CMake creates the export information it
will export a path that is specific to the current build directory
and will not be valid for other projects. We can use
generator expressions to specify
that if we're building the library include the current source directory.
Otherwise, when installed, include the include directory. See the Creating
Relocatable Packages section for more details.

The install(TARGETS) and install(EXPORT) commands
work together to install both targets (a library in our case) and a CMake
file designed to make it easy to import the targets into another CMake project.

First, in the install(TARGETS) command we will specify the target,
the EXPORT name and the destinations that tell CMake where to install the
targets.

install(TARGETS MathFunctions
        EXPORT MathFunctionsTargets
        LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
        ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
        RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
        INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)

Here, the EXPORT option tells CMake to create an export called
MathFunctionsTargets. The generated IMPORTED targets have
appropriate properties set to define their
usage requirements, such as
INTERFACE_INCLUDE_DIRECTORIES,
INTERFACE_COMPILE_DEFINITIONS and other relevant built-in
INTERFACE_ properties.  The INTERFACE variant of user-defined
properties listed in COMPATIBLE_INTERFACE_STRING and other
Compatible Interface Properties are also propagated to the
generated IMPORTED targets. For example, in this case, the
IMPORTED target will have its
INTERFACE_INCLUDE_DIRECTORIES property populated with
the directory specified by the INCLUDES DESTINATION property. As a
relative path was given, it is treated as relative to the
CMAKE_INSTALL_PREFIX.

Note, we have not asked CMake to install the export yet.

We don't want to forget to install the MathFunctions.h header file with the
install(FILES) command. The header file should be installed to the
include directory, as specified by the
target_include_directories() command above.

install(FILES MathFunctions.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})

Now that the MathFunctions library and header file are installed, we also
need to explicitly install the MathFunctionsTargets  export details. Use
the install(EXPORT) command to export the targets in
MathFunctionsTargets, as defined by the  install(TARGETS)
command.

install(EXPORT MathFunctionsTargets
        FILE MathFunctionsTargets.cmake
        NAMESPACE MathFunctions::
        DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MathFunctions
)

This command generates the MathFunctionsTargets.cmake file and arranges
to install it to ${CMAKE_INSTALL_LIBDIR}/cmake/MathFunctions. The file
contains code suitable for use by downstreams to import all targets listed in
the install command from the installation tree.

The NAMESPACE option will prepend MathFunctions:: to  the target names
as they are written to the export file. This convention of double-colons
gives CMake a hint that the name is an  IMPORTED target when it
is used by downstream projects. This way, CMake can issue a diagnostic
message if the package providing it was not found.

The generated export file contains code that creates an IMPORTED library.

# Create imported target MathFunctions::MathFunctions
add_library(MathFunctions::MathFunctions STATIC IMPORTED)

set_target_properties(MathFunctions::MathFunctions PROPERTIES
  INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/include"
)

This code is very similar to the example we created by hand in the
Importing Libraries section. Note that ${_IMPORT_PREFIX} is computed
relative to the file location.

An outside project may load this file with the include() command and
reference the MathFunctions library from the installation tree as if it
were built in its own tree. For example:

1 include(GNUInstallDirs)
2 include(${INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/cmake/MathFunctions/MathFunctionTargets.cmake)
3 add_executable(myexe src1.c src2.c )
4 target_link_libraries(myexe PRIVATE MathFunctions::MathFunctions)

Line 2 loads the target CMake file. Although we only exported a single
target, this file may import any number of targets. Their locations are
computed relative to the file location so that the install tree may be
easily moved. Line 4 references the imported MathFunctions library. The
resulting build system will link to the library from its installed location.

Executables may also be exported and imported using the same process.

Any number of target installations may be associated with the same
export name. Export names are considered global so any directory may
contribute a target installation. The install(EXPORT) command only
needs to be called once to install a file that references all targets. Below
is an example of how multiple exports may be combined into a single
export file, even if they are in different subdirectories of the project.

# A/CMakeLists.txt
add_executable(myexe src1.c)
install(TARGETS myexe DESTINATION lib/myproj
        EXPORT myproj-targets)

# B/CMakeLists.txt
add_library(foo STATIC foo1.c)
install(TARGETS foo DESTINATION lib EXPORTS myproj-targets)

# Top CMakeLists.txt
add_subdirectory (A)
add_subdirectory (B)
install(EXPORT myproj-targets DESTINATION lib/myproj)

Creating Packages¶

At this point, the MathFunctions project is exporting the target
information required to be used by other projects. We can make this project
even easier for other projects to use by generating a configuration file so
that the CMake find_package() command can find our project.

To start, we will need to make a few additions to the CMakeLists.txt
file. First, include the CMakePackageConfigHelpers module to get
access to some helper functions for creating config files.

include(CMakePackageConfigHelpers)

Then we will create a package configuration file and a package version file.

Creating a Package Configuration File¶

Use the configure_package_config_file() command provided by the
CMakePackageConfigHelpers to generate the package configuration
file. Note that this command should be used instead of the plain
configure_file() command. It helps to ensure that the resulting
package is relocatable by avoiding hardcoded paths in the installed
configuration file. The path given to INSTALL_DESTINATION must  be the
destination where the MathFunctionsConfig.cmake file will be installed.
We will examine the contents of the package configuration file in the next
section.

configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
  "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake"
  INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MathFunctions
)

Install the generated configuration files with the INSTALL(files)
command. Both MathFunctionsConfigVersion.cmake and
MathFunctionsConfig.cmake are installed to the same location, completing
the package.

install(FILES
          "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake"
          "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake"
        DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MathFunctions
)

Now we need to create the package configuration file itself. In this case, the
Config.cmake.in file is very simple but sufficient to allow downstreams
to use the IMPORTED targets.

@PACKAGE_INIT@

include("${CMAKE_CURRENT_LIST_DIR}/MathFunctionsTargets.cmake")

check_required_components(MathFunctions)

The first line of the file contains only the string @PACKAGE_INIT@. This
expands when the file is configured and allows the use of relocatable paths
prefixed with PACKAGE_. It also provides the set_and_check() and
check_required_components() macros.

The check_required_components helper macro ensures that all requested,
non-optional components have been found by checking the
<Package>_<Component>_FOUND variables for all required components. This
macro should be called at the end of the package configuration file even if the
package does not have any components. This way, CMake can make sure that the
downstream project hasn't specified any non-existent components. If
check_required_components fails, the <Package>_FOUND variable is set to
FALSE, and the package is considered to be not found.

The set_and_check() macro should be used in configuration files instead
of the normal set() command for setting directories and file locations.
If a referenced file or directory does not exist, the macro will fail.

If any macros should be provided by the MathFunctions package, they should
be in a separate file which is installed to the same location as the
MathFunctionsConfig.cmake file, and included from there.

All required dependencies of a package must also be found in the package
configuration file. Let's imagine that we require the Stats library in
our project. In the CMakeLists file, we would add:

find_package(Stats 2.6.4 REQUIRED)
target_link_libraries(MathFunctions PUBLIC Stats::Types)

As the Stats::Types target is a PUBLIC dependency of MathFunctions,
downstreams must also find the Stats package and link to the
Stats::Types library.  The Stats package should be found in the
configuration file to ensure this.

include(CMakeFindDependencyMacro)
find_dependency(Stats 2.6.4)

The find_dependency macro from the CMakeFindDependencyMacro
module helps by propagating  whether the package is REQUIRED, or
QUIET, etc. The find_dependency macro also sets
MathFunctions_FOUND to False if the dependency is not found, along
with a diagnostic that the MathFunctions package cannot be used without
the Stats package.

Exercise: Add a required library to the MathFunctions project.

Creating a Package Version File¶

The CMakePackageConfigHelpers module provides the
write_basic_package_version_file() command for creating a simple
package version file.  This file is read by CMake when find_package()
is called to determine the compatibility with the requested version, and to set
some version-specific variables such as <PackageName>_VERSION,
<PackageName>_VERSION_MAJOR, <PackageName>_VERSION_MINOR, etc. See
cmake-packages documentation for more details.

set(version 3.4.1)

set_property(TARGET MathFunctions PROPERTY VERSION ${version})
set_property(TARGET MathFunctions PROPERTY SOVERSION 3)
set_property(TARGET MathFunctions PROPERTY
  INTERFACE_MathFunctions_MAJOR_VERSION 3)
set_property(TARGET MathFunctions APPEND PROPERTY
  COMPATIBLE_INTERFACE_STRING MathFunctions_MAJOR_VERSION
)

# generate the version file for the config file
write_basic_package_version_file(
  "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake"
  VERSION "${version}"
  COMPATIBILITY AnyNewerVersion
)

In our example, MathFunctions_MAJOR_VERSION is defined as a
COMPATIBLE_INTERFACE_STRING which means that it must be
compatible among the dependencies of any depender. By setting this
custom defined user property in this version and in the next version of
MathFunctions, cmake will issue a diagnostic if
there is an attempt to use version 3 together with version 4.  Packages can
choose to employ such a pattern if different major versions of the package
are designed to be incompatible.

Exporting Targets from the Build Tree¶

Typically, projects are built and installed before being used by an outside
project. However, in some cases, it is desirable to export targets directly
from a build tree. The targets may then be used by an outside project that
references the build tree with no installation involved. The export()
command is used to generate a file exporting targets from a project build tree.

If we want our example project to also be used from a build directory we only
have to add the following to CMakeLists.txt:

export(EXPORT MathFunctionsTargets
       FILE "${CMAKE_CURRENT_BINARY_DIR}/cmake/MathFunctionsTargets.cmake"
       NAMESPACE MathFunctions::
)

Here we use the export() command to generate the export targets for
the build tree. In this case, we'll create a file called
MathFunctionsTargets.cmake in the cmake subdirectory of the build
directory. The generated file contains the required code to import the target
and may be loaded by an outside project that is aware of the project build
tree. This file is specific to the build-tree, and is not relocatable.

It is possible to create a suitable package configuration file and package
version file to define a package for the build tree which may be used without
installation.  Consumers of the build tree can simply ensure that the
CMAKE_PREFIX_PATH contains the build directory, or set the
MathFunctions_DIR to <build_dir>/MathFunctions in the cache.

An example application of this feature is for building an executable on a host
platform when cross-compiling. The project containing the executable may be
built on the host platform and then the project that is being cross-compiled
for another platform may load it.

Building and Installing a Package¶

At this point, we have generated a relocatable CMake configuration for our
project that can be used after the project has been installed. Let's try to
build the MathFunctions project:

mkdir MathFunctions_build
cd MathFunctions_build
cmake ../MathFunctions
cmake --build .

In the build directory, notice that the file MathFunctionsTargets.cmake
has been created in the cmake subdirectory.

Now install the project:

$ cmake --install . --prefix "/home/myuser/installdir"

Creating Relocatable Packages¶

Packages created by install(EXPORT) are designed to be relocatable,
using paths relative to the location of the package itself. They must not
reference absolute paths of files on the machine where the package is built
that will not exist on the machines where the package may be installed.

When defining the interface of a target for EXPORT, keep in mind that the
include directories should be specified as relative paths to the
CMAKE_INSTALL_PREFIX but should not explicitly include the
CMAKE_INSTALL_PREFIX:

target_include_directories(tgt INTERFACE
  # Wrong, not relocatable:
  $<INSTALL_INTERFACE:${CMAKE_INSTALL_PREFIX}/include/TgtName>
)

target_include_directories(tgt INTERFACE
  # Ok, relocatable:
  $<INSTALL_INTERFACE:include/TgtName>
)

The $<INSTALL_PREFIX> generator expression may be used as
a placeholder for the install prefix without resulting in a non-relocatable
package.  This is necessary if complex generator expressions are used:

target_include_directories(tgt INTERFACE
  # Ok, relocatable:
  $<INSTALL_INTERFACE:$<INSTALL_PREFIX>/include/TgtName>
)

This also applies to paths referencing external dependencies.
It is not advisable to populate any properties which may contain
paths, such as INTERFACE_INCLUDE_DIRECTORIES or
INTERFACE_LINK_LIBRARIES, with paths relevant to dependencies.
For example, this code may not work well for a relocatable package:

target_link_libraries(MathFunctions INTERFACE
  ${Foo_LIBRARIES} ${Bar_LIBRARIES}
  )
target_include_directories(MathFunctions INTERFACE
  "$<INSTALL_INTERFACE:${Foo_INCLUDE_DIRS};${Bar_INCLUDE_DIRS}>"
  )

The referenced variables may contain the absolute paths to libraries
and include directories as found on the machine the package was made on.
This would create a package with hard-coded paths to dependencies not
suitable for relocation.

Ideally such dependencies should be used through their own
IMPORTED targets that have their own
IMPORTED_LOCATION and usage requirement properties
such as INTERFACE_INCLUDE_DIRECTORIES populated
appropriately.  Those imported targets may then be used with
the target_link_libraries() command for MathFunctions:

target_link_libraries(MathFunctions INTERFACE Foo::Foo Bar::Bar)

With this approach the package references its external dependencies
only through the names of IMPORTED targets.
When a consumer uses the installed package, the consumer will run the
appropriate find_package() commands (via the find_dependency
macro described above) to find the dependencies and populate the
imported targets with appropriate paths on their own machine.

Using the Package Configuration File¶

Now we're ready to create a project to use the installed MathFunctions
library. In this section we will be using source code from
Help\guide\importing-exporting\Downstream. In this directory, there is a
source file called main.cc that uses the MathFunctions library to
calculate the square root of a given number and then prints the results:

// A simple program that outputs the square root of a number
#include <iostream>
#include <string>

#include "MathFunctions.h"

int main(int argc, char* argv[])
{
  if (argc < 2) {
    std::cout << "Usage: " << argv[0] << " number" << std::endl;
    return 1;
  }

  // convert input to double
  const double inputValue = std::stod(argv[1]);

  // calculate square root
  const double sqrt = MathFunctions::sqrt(inputValue);
  std::cout << "The square root of " << inputValue << " is " << sqrt
            << std::endl;

  return 0;
}

As before, we'll start with the cmake_minimum_required() and
project() commands in the CMakeLists.txt file. For this project,
we'll also specify the C++ standard.

cmake_minimum_required(VERSION 3.15)
project(Downstream)

# specify the C++ standard
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

We can use the find_package() command:

find_package(MathFunctions 3.4.1 EXACT)

Create an executable:

add_executable(myexe main.cc)

And link to the MathFunctions library:

target_link_libraries(myexe PRIVATE MathFunctions::MathFunctions)

That's it! Now let's try to build the Downstream project.

mkdir Downstream_build
cd Downstream_build
cmake ../Downstream
cmake --build .

A warning may have appeared during CMake configuration:

CMake Warning at CMakeLists.txt:4 (find_package):
  By not providing "FindMathFunctions.cmake" in CMAKE_MODULE_PATH this
  project has asked CMake to find a package configuration file provided by
  "MathFunctions", but CMake did not find one.

  Could not find a package configuration file provided by "MathFunctions"
  with any of the following names:

    MathFunctionsConfig.cmake
    mathfunctions-config.cmake

  Add the installation prefix of "MathFunctions" to CMAKE_PREFIX_PATH or set
  "MathFunctions_DIR" to a directory containing one of the above files.  If
  "MathFunctions" provides a separate development package or SDK, be sure it
  has been installed.

Set the CMAKE_PREFIX_PATH to where MathFunctions was installed previously
and try again. Ensure that the newly created executable runs as expected.

Adding Components¶

Let's edit the MathFunctions project to use components. The source code for
this section can be found in
Help\guide\importing-exporting\MathFunctionsComponents. The CMakeLists file
for this project adds two subdirectories: Addition and SquareRoot.

cmake_minimum_required(VERSION 3.15)
project(MathFunctionsComponents)

# make cache variables for install destinations
include(GNUInstallDirs)

# specify the C++ standard
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

add_subdirectory(Addition)
add_subdirectory(SquareRoot)

Generate and install the package configuration and package version files:

include(CMakePackageConfigHelpers)

# set version
set(version 3.4.1)

# generate the version file for the config file
write_basic_package_version_file(
  "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake"
  VERSION "${version}"
  COMPATIBILITY AnyNewerVersion
)

# create config file
configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
  "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake"
  INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MathFunctions
  NO_CHECK_REQUIRED_COMPONENTS_MACRO
)

# install config files
install(FILES
          "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake"
          "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake"
        DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MathFunctions
)

If COMPONENTS are specified when the downstream uses
find_package(), they are listed in the
<PackageName>_FIND_COMPONENTS variable. We can use this variable to verify
that all necessary component targets are included in Config.cmake.in. At
the same time, this function will act as a custom check_required_components
macro to ensure that the downstream only attempts to use supported components.

@PACKAGE_INIT@

set(_MathFunctions_supported_components Addition SquareRoot)

foreach(_comp ${MathFunctions_FIND_COMPONENTS})
  if (NOT _comp IN_LIST _MathFunctions_supported_components)
    set(MathFunctions_FOUND False)
    set(MathFunctions_NOT_FOUND_MESSAGE "Unsupported component: ${_comp}")
  endif()
  include("${CMAKE_CURRENT_LIST_DIR}/MathFunctions${_comp}Targets.cmake")
endforeach()

Here, the MathFunctions_NOT_FOUND_MESSAGE is set to a diagnosis that the
package could not be found because an invalid component was specified. This
message variable can be set for any case where the _FOUND variable is set
to False, and will be displayed to the user.

The Addition and SquareRoot directories are similar. Let's look at one
of the CMakeLists files:

# create library
add_library(SquareRoot STATIC SquareRoot.cxx)

add_library(MathFunctions::SquareRoot ALIAS SquareRoot)

# add include directories
target_include_directories(SquareRoot
                           PUBLIC
                           "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>"
                           "$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
)

# install the target and create export-set
install(TARGETS SquareRoot
        EXPORT SquareRootTargets
        LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
        ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
        RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
        INCLUDES DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
)

# install header file
install(FILES SquareRoot.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})

# generate and install export file
install(EXPORT SquareRootTargets
        FILE MathFunctionsSquareRootTargets.cmake
        NAMESPACE MathFunctions::
        DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/MathFunctions
)

Now we can build the project as described in earlier sections. To test using
this package, we can use the project in
Help\guide\importing-exporting\DownstreamComponents. There's two
differences from the previous Downstream project. First, we need to find
the package components. Change the find_package line from:

find_package(MathFunctions 3.4.1 EXACT)

To:

find_package(MathFunctions 3.4 COMPONENTS Addition SquareRoot)

and the target_link_libraries line from:

target_link_libraries(myexe PRIVATE MathFunctions::MathFunctions)

To:

target_link_libraries(myexe PRIVATE MathFunctions::Addition MathFunctions::SquareRoot)

In main.cc, replace #include MathFunctions.h with:

#include "Addition.h"
#include "SquareRoot.h"

Finally, use the Addition library:

  const double sum = MathFunctions::add(inputValue, inputValue);
  std::cout << inputValue << " + " << inputValue << " = " << sum << std::endl;

Build the Downstream project and confirm that it can find and use the
package components.

Table of Contents

Importing and Exporting Guide

Introduction

Importing Targets

Importing Executables

Importing Libraries

Exporting Targets

Creating Packages

Creating a Package Configuration File

Creating a Package Version File

Exporting Targets from the Build Tree

Building and Installing a Package

Creating Relocatable Packages

Using the Package Configuration File

Adding Components

Previous topic

Using Dependencies Guide

Next topic

IDE Integration Guide

This Page

Show Source

Quick search

    <form class="search" action="../../search.html" method="get">
      <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
      <input type="submit" value="Go" />
    </form>

Navigation

          index

          next |

          previous |

    CMake »

    3.29.0-rc3 Documentation »

Importing and Exporting Guide

        © Copyright 2000-2024 Kitware, Inc. and Contributors.
      Created using Sphinx 6.2.1.


code:
<!DOCTYPE html>

    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />

  <title>Step 1: A Basic Starting Point — CMake 3.29.0-rc3 Documentation</title>

    <link rel="stylesheet" type="text/css" href="../../_static/pygments.css" />
    <link rel="stylesheet" type="text/css" href="../../_static/cmake.css" />

    <link rel="icon" href="../../_static/cmake-favicon.ico"/>
    <link rel="index" title="Index" href="../../genindex.html" />
    <link rel="search" title="Search" href="../../search.html" />
    <link rel="next" title="Step 2: Adding a Library" href="Adding%20a%20Library.html" />
    <link rel="prev" title="CMake Tutorial" href="index.html" />

Navigation

          index

          next |

          previous |

    CMake »

    3.29.0-rc3 Documentation »

CMake Tutorial »

Step 1: A Basic Starting Point

Step 1: A Basic Starting Point¶

Where do I start with CMake? This step will provide an introduction to some of
CMake's basic syntax, commands, and variables. As these concepts are
introduced, we will work through three exercises and create a simple CMake
project.

Each exercise in this step will start with some background information. Then, a
goal and list of helpful resources are provided. Each file in the
Files to Edit section is in the Step1 directory and contains one or
more TODO comments. Each TODO represents a line or two of code to
change or add. The TODO s are intended to be completed in numerical order,
first complete  TODO 1 then TODO 2, etc. The Getting Started
section will give some helpful hints and guide you through the exercise. Then
the Build and Run section will walk step-by-step through how to build and
test the exercise. Finally, at the end of each exercise the intended solution
is discussed.

Also note that each step in the tutorial builds on the 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 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 project() command to set the project
name. This call is required with every project and should be called soon after
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 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¶

add_executable()

cmake_minimum_required()

project()

Files to Edit¶

CMakeLists.txt

Getting Started¶

The source code for tutorial.cxx is provided in the
Help/guide/tutorial/Step1 directory and can be used to compute the square
root of a number. This file does not need to be edited in this step.

In the same directory is a CMakeLists.txt file which you will complete.
Start with TODO 1 and work through TODO 3.

Build and Run¶

Once TODO 1 through TODO 3 have been completed, we are ready to build
and run our project! First, run the cmake executable or the
cmake-gui to configure the project and then build it
with your chosen build tool.

For example, from the command line we could navigate to the
Help/guide/tutorial directory of the CMake source code tree and create a
build directory:

mkdir Step1_build

Next, navigate to that build directory and run
cmake to configure the project and generate a native build
system:

cd Step1_build
cmake ../Step1

Then call that build system to actually compile/link the project:

cmake --build .

For multi-config generators (e.g. Visual Studio), first navigate to the
appropriate subdirectory, for example:

cd Debug

Finally, try to use the newly built Tutorial:

Tutorial 4294967296
Tutorial 10
Tutorial

Note: Depending on the shell, the correct syntax may be Tutorial,
./Tutorial or .\Tutorial. For simplicity, the exercises will use
Tutorial throughout.

Solution¶

As mentioned above, a three line CMakeLists.txt is all that we need to get
up and running. The first line is to use cmake_minimum_required() to
set the CMake version as follows:

TODO 1: Click to show/hide answer

TODO 1: CMakeLists.txt¶

cmake_minimum_required(VERSION 3.10)

The next step to make a basic project is to use the project()
command as follows to set the project name:

TODO 2: Click to show/hide answer

TODO 2: CMakeLists.txt¶

project(Tutorial)

The last command to call for a basic project is
add_executable(). We call it as follows:

TODO 3: Click to show/hide answer

TODO 3: CMakeLists.txt¶

add_executable(Tutorial tutorial.cxx)

Exercise 2 - Specifying the C++ Standard¶

CMake has some special variables that are either created behind the scenes or
have meaning to CMake when set by project code. Many of these variables start
with CMAKE_. Avoid this naming convention when creating variables for your
projects. Two of these special user settable variables are
CMAKE_CXX_STANDARD and CMAKE_CXX_STANDARD_REQUIRED.
These may be used together to specify the C++ standard needed to build the
project.

Goal¶

Add a feature that requires C++11.

Helpful Resources¶

CMAKE_CXX_STANDARD

CMAKE_CXX_STANDARD_REQUIRED

set()

Files to Edit¶

CMakeLists.txt

tutorial.cxx

Getting Started¶

Continue editing files in the Step1 directory. Start with TODO 4 and
complete through TODO 6.

First, edit tutorial.cxx by adding a feature that requires C++11. Then
update CMakeLists.txt to require C++11.

Build and Run¶

Let's build our project again. Since we already created a build directory and
ran CMake for Exercise 1, we can skip to the build step:

cd Step1_build
cmake --build .

Now we can try to use the newly built Tutorial with same commands as
before:

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:

TODO 4: Click to show/hide answer

TODO 4: tutorial.cxx¶

  const double inputValue = std::stod(argv[1]);

To complete TODO 5, simply remove #include <cstdlib>.

We will need to explicitly state in the CMake code that it should use the
correct flags. One way to enable support for a specific C++ standard in CMake
is by using the CMAKE_CXX_STANDARD variable. For this tutorial, set
the CMAKE_CXX_STANDARD variable in the CMakeLists.txt file to
11 and CMAKE_CXX_STANDARD_REQUIRED to True. Make sure to
add the CMAKE_CXX_STANDARD declarations above the call to
add_executable().

TODO 6: Click to show/hide answer

TODO 6: CMakeLists.txt¶

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

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 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¶

<PROJECT-NAME>_VERSION_MAJOR

<PROJECT-NAME>_VERSION_MINOR

configure_file()

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 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 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:

cd Step1_build
cmake --build .

Verify that the version number is now reported when running the executable
without any arguments.

Solution¶

In this exercise, we improve our executable by printing a version number.
While we could do this exclusively in the source code, using CMakeLists.txt
lets us maintain a single source of data for the version number.

First, we modify the CMakeLists.txt file to use the
project() command to set both the project name and version number.
When the project() command is called, CMake defines
Tutorial_VERSION_MAJOR and Tutorial_VERSION_MINOR behind the scenes.

TODO 7: Click to show/hide answer

TODO 7: CMakeLists.txt¶

project(Tutorial VERSION 1.0)

Then we used configure_file() to copy the input file with the
specified CMake variables replaced:

TODO 8: Click to show/hide answer

TODO 8: CMakeLists.txt¶

configure_file(TutorialConfig.h.in TutorialConfig.h)

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 target_include_directories() to specify
where the executable target should look for include files.

TODO 9: Click to show/hide answer

TODO 9: CMakeLists.txt¶

target_include_directories(Tutorial PUBLIC
                           "${PROJECT_BINARY_DIR}"
                           )

TutorialConfig.h.in is the input header file to be configured.
When 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.

TODO 10: Click to show/hide answer

TODO 10: TutorialConfig.h.in¶

// the configured options and settings for Tutorial
#define Tutorial_VERSION_MAJOR @Tutorial_VERSION_MAJOR@
#define Tutorial_VERSION_MINOR @Tutorial_VERSION_MINOR@

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

TODO 11: Click to show/hide answer

TODO 11: tutorial.cxx¶

#include "TutorialConfig.h"

Finally, we print out the executable name and version number by updating
tutorial.cxx as follows:

TODO 12: Click to show/hide answer

TODO 12 : tutorial.cxx¶

  if (argc < 2) {
    // report version
    std::cout << argv[0] << " Version " << Tutorial_VERSION_MAJOR << "."
              << Tutorial_VERSION_MINOR << std::endl;
    std::cout << "Usage: " << argv[0] << " number" << std::endl;
    return 1;
  }

Table of Contents

Step 1: A Basic Starting Point

Exercise 1 - Building a Basic Project

Goal

Helpful Resources

Files to Edit

Getting Started

Build and Run

Solution

Exercise 2 - Specifying the C++ Standard

Goal

Helpful Resources

Files to Edit

Getting Started

Build and Run

Solution

Exercise 3 - Adding a Version Number and Configured Header File

Goal

Helpful Resources

Files to Edit

Getting Started

Build and Run

Solution

Previous topic

CMake Tutorial

Next topic

Step 2: Adding a Library

This Page

Show Source

Quick search

    <form class="search" action="../../search.html" method="get">
      <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
      <input type="submit" value="Go" />
    </form>

Navigation

          index

          next |

          previous |

    CMake »

    3.29.0-rc3 Documentation »

CMake Tutorial »

Step 1: A Basic Starting Point

        © Copyright 2000-2024 Kitware, Inc. and Contributors.
      Created using Sphinx 6.2.1.

repo_name: lazytadpole/codenamesilverfish

path: buildtools/windows/cmake/doc/cmake/html/guide/tutorial/A Basic Starting Point.html

license: mit


code:
<!DOCTYPE html>

    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />

  <title>Step 11: Adding Export Configuration — CMake 3.29.0-rc3 Documentation</title>

    <link rel="stylesheet" type="text/css" href="../../_static/pygments.css" />
    <link rel="stylesheet" type="text/css" href="../../_static/cmake.css" />

    <link rel="icon" href="../../_static/cmake-favicon.ico"/>
    <link rel="index" title="Index" href="../../genindex.html" />
    <link rel="search" title="Search" href="../../search.html" />
    <link rel="next" title="Step 12: Packaging Debug and Release" href="Packaging%20Debug%20and%20Release.html" />
    <link rel="prev" title="Step 10: Selecting Static or Shared Libraries" href="Selecting%20Static%20or%20Shared%20Libraries.html" />

Navigation

          index

          next |

          previous |

    CMake »

    3.29.0-rc3 Documentation »

CMake Tutorial »

Step 11: Adding Export Configuration

Step 11: Adding Export Configuration¶

During Installing and Testing of the tutorial we added the
ability for CMake to install the library and headers of the project. During
Packaging an Installer we added the ability to package up
this information so it could be distributed to other people.

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

The first step is to update our install(TARGETS) commands to not
only specify a DESTINATION but also an EXPORT. The EXPORT keyword
generates a CMake file containing code to import all targets listed in the
install command from the installation tree. So let's go ahead and explicitly
EXPORT the MathFunctions library by updating the install command
in MathFunctions/CMakeLists.txt to look like:

MathFunctions/CMakeLists.txt¶

set(installable_libs MathFunctions tutorial_compiler_flags)
if(TARGET SqrtLibrary)
  list(APPEND installable_libs SqrtLibrary)
endif()
install(TARGETS ${installable_libs}
        EXPORT MathFunctionsTargets
        DESTINATION lib)
# install include headers
install(FILES MathFunctions.h DESTINATION include)

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:

CMakeLists.txt¶

install(EXPORT MathFunctionsTargets
  FILE MathFunctionsTargets.cmake
  DESTINATION lib/cmake/MathFunctions
)

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:

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:

MathFunctions/CMakeLists.txt¶

target_include_directories(MathFunctions
                           INTERFACE
                            $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
                            $<INSTALL_INTERFACE:include>
                           )

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

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

Config.cmake.in¶

@PACKAGE_INIT@

include ( "${CMAKE_CURRENT_LIST_DIR}/MathFunctionsTargets.cmake" )

Then, to properly configure and install that file, add the following to the
bottom of the top-level CMakeLists.txt:

CMakeLists.txt¶

install(EXPORT MathFunctionsTargets
  FILE MathFunctionsTargets.cmake
  DESTINATION lib/cmake/MathFunctions
)

include(CMakePackageConfigHelpers)

Next, we execute the configure_package_config_file().  This command
will configure a provided file but with a few specific differences from the
standard configure_file() way.
To properly utilize this function, the input file should have a single line
with the text @PACKAGE_INIT@ in addition to the content that is desired.
That variable will be replaced with a block of code which turns set values into
relative paths.  These values which are new can be referenced by the same name
but prepended with a PACKAGE_ prefix.

CMakeLists.txt¶

install(EXPORT MathFunctionsTargets
  FILE MathFunctionsTargets.cmake
  DESTINATION lib/cmake/MathFunctions
)

include(CMakePackageConfigHelpers)
# generate the config file that includes the exports
configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in
  "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake"
  INSTALL_DESTINATION "lib/cmake/MathFunctions"
  NO_SET_AND_CHECK_MACRO
  NO_CHECK_REQUIRED_COMPONENTS_MACRO
  )

The write_basic_package_version_file() is next.  This command writes
a file which is used by find_package(), documenting the version and
compatibility of the desired package.  Here, we use the Tutorial_VERSION_*
variables and say that it is compatible with AnyNewerVersion, which
denotes that this version or any higher one are compatible with the requested
version.

CMakeLists.txt¶

write_basic_package_version_file(
  "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake"
  VERSION "${Tutorial_VERSION_MAJOR}.${Tutorial_VERSION_MINOR}"
  COMPATIBILITY AnyNewerVersion
)

Finally, set both generated files to be installed:

CMakeLists.txt¶

install(FILES
  ${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfig.cmake
  ${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsConfigVersion.cmake
  DESTINATION lib/cmake/MathFunctions
  )

At this point, we have generated a relocatable CMake Configuration for our
project that can be used after the project has been installed or packaged. If
we want our project to also be used from a build directory we only have to add
the following to the bottom of the top level CMakeLists.txt:

CMakeLists.txt¶

export(EXPORT MathFunctionsTargets
  FILE "${CMAKE_CURRENT_BINARY_DIR}/MathFunctionsTargets.cmake"
)

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

Previous topic

Step 10: Selecting Static or Shared Libraries

Next topic

Step 12: Packaging Debug and Release

This Page

Show Source

Quick search

    <form class="search" action="../../search.html" method="get">
      <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
      <input type="submit" value="Go" />
    </form>

Navigation

          index

          next |

          previous |

    CMake »

    3.29.0-rc3 Documentation »

CMake Tutorial »

Step 11: Adding Export Configuration

        © Copyright 2000-2024 Kitware, Inc. and Contributors.
      Created using Sphinx 6.2.1.


code:
<!DOCTYPE html>

    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />

  <title>Step 4: Adding Generator Expressions — CMake 3.29.0-rc3 Documentation</title>

    <link rel="stylesheet" type="text/css" href="../../_static/pygments.css" />
    <link rel="stylesheet" type="text/css" href="../../_static/cmake.css" />

    <link rel="icon" href="../../_static/cmake-favicon.ico"/>
    <link rel="index" title="Index" href="../../genindex.html" />
    <link rel="search" title="Search" href="../../search.html" />
    <link rel="next" title="Step 5: Installing and Testing" href="Installing%20and%20Testing.html" />
    <link rel="prev" title="Step 3: Adding Usage Requirements for a Library" href="Adding%20Usage%20Requirements%20for%20a%20Library.html" />

Navigation

          index

          next |

          previous |

    CMake »

    3.29.0-rc3 Documentation »

CMake Tutorial »

Step 4: Adding Generator Expressions

Step 4: Adding Generator Expressions¶

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.

Exercise 1 - Adding Compiler Warning Flags with Generator Expressions¶

A common usage of
generator expressions is to
conditionally add compiler flags, such as those for language levels or
warnings. A nice pattern is to associate this information to an INTERFACE
target allowing this information to propagate.

Goal¶

Add compiler warning flags when building but not for installed versions.

Helpful Resources¶

cmake-generator-expressions(7)

cmake_minimum_required()

set()

target_compile_options()

Files to Edit¶

CMakeLists.txt

Getting Started¶

Open the file Step4/CMakeLists.txt and complete TODO 1 through
TODO 4.

First, in the top level CMakeLists.txt file, we need to set the
cmake_minimum_required() to 3.15. In this exercise we are going
to use a generator expression which was introduced in CMake 3.15.

Next we add the desired compiler warning flags that we want for our project.
As warning flags vary based on the compiler, we use the
COMPILE_LANG_AND_ID generator expression to control which flags to apply
given a language and a set of compiler ids.

Build and Run¶

Make a new directory called Step4_build, run the cmake
executable or the cmake-gui to configure the project
and then build it with your chosen build tool or by using cmake --build .
from the build directory.

mkdir Step4_build
cd Step4_build
cmake ../Step4
cmake --build .

Solution¶

Update the cmake_minimum_required() to require at least CMake
version 3.15:

TODO 1: Click to show/hide answer

TODO 1: CMakeLists.txt¶

cmake_minimum_required(VERSION 3.15)

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:

TODO 2: Click to show/hide answer

TODO 2: CMakeLists.txt¶

set(gcc_like_cxx "$<COMPILE_LANG_AND_ID:CXX,ARMClang,AppleClang,Clang,GNU,LCC>")
set(msvc_cxx "$<COMPILE_LANG_AND_ID:CXX,MSVC>")

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 target_compile_options() to apply these flags to our
interface library.

TODO 3: Click to show/hide answer

TODO 3: CMakeLists.txt¶

target_compile_options(tutorial_compiler_flags INTERFACE
  "$<${gcc_like_cxx}:-Wall;-Wextra;-Wshadow;-Wformat=2;-Wunused>"
  "$<${msvc_cxx}:-W3>"
)

Lastly, we only want these warning flags to be used during builds. Consumers
of our installed project should not inherit our warning flags. To specify
this, we wrap our flags from TODO 3 in a generator expression using the
BUILD_INTERFACE condition. The resulting full code looks like the following:

TODO 4: Click to show/hide answer

TODO 4: CMakeLists.txt¶

target_compile_options(tutorial_compiler_flags INTERFACE
  "$<${gcc_like_cxx}:$<BUILD_INTERFACE:-Wall;-Wextra;-Wshadow;-Wformat=2;-Wunused>>"
  "$<${msvc_cxx}:$<BUILD_INTERFACE:-W3>>"
)

Table of Contents

Step 4: Adding Generator Expressions

Exercise 1 - Adding Compiler Warning Flags with Generator Expressions

Goal

Helpful Resources

Files to Edit

Getting Started

Build and Run

Solution

Previous topic

Step 3: Adding Usage Requirements for a Library

Next topic

Step 5: Installing and Testing

This Page

Show Source

Quick search

    <form class="search" action="../../search.html" method="get">
      <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
      <input type="submit" value="Go" />
    </form>

Navigation

          index

          next |

          previous |

    CMake »

    3.29.0-rc3 Documentation »

CMake Tutorial »

Step 4: Adding Generator Expressions

        © Copyright 2000-2024 Kitware, Inc. and Contributors.
      Created using Sphinx 6.2.1.


code:
<!DOCTYPE html>

    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />

  <title>Step 6: Adding Support for a Testing Dashboard — CMake 3.29.0-rc3 Documentation</title>

    <link rel="stylesheet" type="text/css" href="../../_static/pygments.css" />
    <link rel="stylesheet" type="text/css" href="../../_static/cmake.css" />

    <link rel="icon" href="../../_static/cmake-favicon.ico"/>
    <link rel="index" title="Index" href="../../genindex.html" />
    <link rel="search" title="Search" href="../../search.html" />
    <link rel="next" title="Step 7: Adding System Introspection" href="Adding%20System%20Introspection.html" />
    <link rel="prev" title="Step 5: Installing and Testing" href="Installing%20and%20Testing.html" />

Navigation

          index

          next |

          previous |

    CMake »

    3.29.0-rc3 Documentation »

CMake Tutorial »

Step 6: 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
already defined a number of tests for our project in
Testing Support. Now we just have to run
those tests and submit them to CDash.

Exercise 1 - Send Results to a Testing Dashboard¶

Goal¶

Display our CTest results with CDash.

Helpful Resources¶

ctest(1)

include()

CTest

Files to Edit¶

CMakeLists.txt

Getting Started¶

For this exercise, complete TODO 1 in the top-level CMakeLists.txt by
including the CTest module. This will enable testing with CTest as
well as dashboard submissions to CDash, so we can safely remove the call to
enable_testing().

We will also need to acquire a CTestConfig.cmake file to be placed in the
top-level directory. When run, the ctest executable will
read this file to gather information about the testing dashboard. It contains:

The project name

The project "Nightly" start time

The time when a 24 hour "day" starts for this project.

The URL of the CDash instance where the submission's generated documents
will be sent

For this tutorial, a public dashboard server is used and its corresponding
CTestConfig.cmake file is provided for you in this step's root directory.
In practice, this file would be downloaded from a project's Settings page
on the CDash instance intended to host the test results. Once downloaded from
CDash, the file should not be modified locally.

CTestConfig.cmake¶

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)

Build and Run¶

Note that as part of the CDash submission some information about your
development system (e.g. site name or full pathnames) may displayed publicly.

To create a simple test dashboard, run the cmake
executable or the cmake-gui to configure the project
but do not build it yet. Instead, navigate to the build directory and run:

ctest [-VV] -D Experimental

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

ctest [-VV] -C Debug -D Experimental

Or, from an IDE, build the Experimental target.

The ctest executable will build the project, run any
tests, and submit the results to Kitware's public dashboard:
https://my.cdash.org/index.php?project=CMakeTutorial.

Solution¶

The only CMake code changed needed in this step was to enable dashboard
submissions to CDash by including the CTest module in our top-level
CMakeLists.txt:

TODO 1: Click to show/hide answer

TODO 1: CMakeLists.txt¶

include(CTest)

Table of Contents

Step 6: Adding Support for a Testing Dashboard

Exercise 1 - Send Results to a Testing Dashboard

Goal

Helpful Resources

Files to Edit

Getting Started

Build and Run

Solution

Previous topic

Step 5: Installing and Testing

Next topic

Step 7: Adding System Introspection

This Page

Show Source

Quick search

    <form class="search" action="../../search.html" method="get">
      <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
      <input type="submit" value="Go" />
    </form>

Navigation

          index

          next |

          previous |

    CMake »

    3.29.0-rc3 Documentation »

CMake Tutorial »

Step 6: Adding Support for a Testing Dashboard

        © Copyright 2000-2024 Kitware, Inc. and Contributors.
      Created using Sphinx 6.2.1.

path: buildtools/windows/cmake/doc/cmake/html/guide/tutorial/Adding Support for a Testing Dashboard.html


code:
<!DOCTYPE html>

    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />

  <title>Step 7: Adding System Introspection — CMake 3.29.0-rc3 Documentation</title>

    <link rel="stylesheet" type="text/css" href="../../_static/pygments.css" />
    <link rel="stylesheet" type="text/css" href="../../_static/cmake.css" />

    <link rel="icon" href="../../_static/cmake-favicon.ico"/>
    <link rel="index" title="Index" href="../../genindex.html" />
    <link rel="search" title="Search" href="../../search.html" />
    <link rel="next" title="Step 8: Adding a Custom Command and Generated File" href="Adding%20a%20Custom%20Command%20and%20Generated%20File.html" />
    <link rel="prev" title="Step 6: Adding Support for a Testing Dashboard" href="Adding%20Support%20for%20a%20Testing%20Dashboard.html" />

Navigation

          index

          next |

          previous |

    CMake »

    3.29.0-rc3 Documentation »

CMake Tutorial »

Step 7: Adding System Introspection

Step 7: Adding System Introspection¶

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

Exercise 1 - Assessing Dependency Availability¶

Goal¶

Change implementation based on available system dependencies.

Helpful Resources¶

CheckCXXSourceCompiles

target_compile_definitions()

Files to Edit¶

MathFunctions/CMakeLists.txt

MathFunctions/mysqrt.cxx

Getting Started¶

The starting source code is provided in the Step7 directory. In this
exercise, complete TODO 1 through TODO 5.

Start by editing MathFunctions/CMakeLists.txt. Include the
CheckCXXSourceCompiles module. Then, use
check_cxx_source_compiles to determine whether log and exp are
available from cmath. If they are available, use
target_compile_definitions() to specify HAVE_LOG and HAVE_EXP
as compile definitions.

In the MathFunctions/mysqrt.cxx, include cmath. Then, if the system has
log and exp, use them to compute the square root.

Build and Run¶

Make a new directory called Step7_build. Run the
cmake executable or the
cmake-gui to configure the project and then build it
with your chosen build tool and run the Tutorial executable.

This can look like the following:

mkdir Step7_build
cd Step7_build
cmake ../Step7
cmake --build .

Which function gives better results now, sqrt or mysqrt?

Solution¶

In this exercise we will use functions from the
CheckCXXSourceCompiles module so first we must include it in
MathFunctions/CMakeLists.txt.

TODO 1: Click to show/hide answer

TODO 1: MathFunctions/CMakeLists.txt¶

  include(CheckCXXSourceCompiles)

Then test for the availability of
log and exp using check_cxx_compiles_source. This function
lets us try compiling simple code with the required dependency prior to
the true source code compilation. The resulting variables HAVE_LOG
and HAVE_EXP represent whether those dependencies are available.

TODO 2: Click to show/hide answer

TODO 2: MathFunctions/CMakeLists.txt¶

  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)

Next, we need to pass these CMake variables to our source code. This way,
our source code can tell what resources are available. If both log and
exp are available, use target_compile_definitions() to specify
HAVE_LOG and HAVE_EXP as PRIVATE compile definitions.

TODO 3: Click to show/hide answer

TODO 3: MathFunctions/CMakeLists.txt¶

  if(HAVE_LOG AND HAVE_EXP)
    target_compile_definitions(SqrtLibrary
                               PRIVATE "HAVE_LOG" "HAVE_EXP"
                               )
  endif()

  target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
endif()

Since we may be using log and exp, we need to modify
mysqrt.cxx to include cmath.

TODO 4: Click to show/hide answer

TODO 4: MathFunctions/mysqrt.cxx¶

#include <cmath>

If log and exp are available on the system, then use them to
compute the square root in the mysqrt function. The mysqrt function in
MathFunctions/mysqrt.cxx will look as follows:

TODO 5: Click to show/hide answer

TODO 5: MathFunctions/mysqrt.cxx¶

#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
  for (int i = 0; i < 10; ++i) {
    if (result <= 0) {
      result = 0.1;
    }
    double delta = x - (result * result);
    result = result + 0.5 * delta / result;
    std::cout << "Computing sqrt of " << x << " to be " << result << std::endl;
  }
#endif

Table of Contents

Step 7: Adding System Introspection

Exercise 1 - Assessing Dependency Availability

Goal

Helpful Resources

Files to Edit

Getting Started

Build and Run

Solution

Previous topic

Step 6: Adding Support for a Testing Dashboard

Next topic

Step 8: Adding a Custom Command and Generated File

This Page

Show Source

Quick search

    <form class="search" action="../../search.html" method="get">
      <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
      <input type="submit" value="Go" />
    </form>

Navigation

          index

          next |

          previous |

    CMake »

    3.29.0-rc3 Documentation »

CMake Tutorial »

Step 7: Adding System Introspection

        © Copyright 2000-2024 Kitware, Inc. and Contributors.
      Created using Sphinx 6.2.1.


code:
<!DOCTYPE html>

    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />

  <title>Step 3: Adding Usage Requirements for a Library — CMake 3.29.0-rc3 Documentation</title>

    <link rel="stylesheet" type="text/css" href="../../_static/pygments.css" />
    <link rel="stylesheet" type="text/css" href="../../_static/cmake.css" />

    <link rel="icon" href="../../_static/cmake-favicon.ico"/>
    <link rel="index" title="Index" href="../../genindex.html" />
    <link rel="search" title="Search" href="../../search.html" />
    <link rel="next" title="Step 4: Adding Generator Expressions" href="Adding%20Generator%20Expressions.html" />
    <link rel="prev" title="Step 2: Adding a Library" href="Adding%20a%20Library.html" />

Navigation

          index

          next |

          previous |

    CMake »

    3.29.0-rc3 Documentation »

CMake Tutorial »

Step 3: Adding Usage Requirements for a Library

Step 3: Adding Usage Requirements for a Library¶

Exercise 1 - Adding Usage Requirements for a Library¶

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:

target_compile_definitions()

target_compile_options()

target_include_directories()

target_link_directories()

target_link_options()

target_precompile_headers()

target_sources()

Goal¶

Add usage requirements for a library.

Helpful Materials¶

CMAKE_CURRENT_SOURCE_DIR

Files to Edit¶

MathFunctions/CMakeLists.txt

CMakeLists.txt

Getting Started¶

In this exercise, we will refactor our code from
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 target_include_directories() in
MathFunctions/CMakeLists. Remember that
CMAKE_CURRENT_SOURCE_DIR is the path to the source directory
currently being processed.

Then, update (and simplify!) the call to
target_include_directories() in the top-level CMakeLists.txt.

Build and Run¶

Make a new directory called Step3_build, run the cmake executable or the cmake-gui 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:

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
target_include_directories() with the INTERFACE keyword, as
follows:

TODO 1: Click to show/hide answer

TODO 1: MathFunctions/CMakeLists.txt¶

target_include_directories(MathFunctions
                           INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}
                           )

Now that we've specified usage requirements for MathFunctions we can
safely remove our uses of the EXTRA_INCLUDES variable from the top-level
CMakeLists.txt.

Remove this line:

TODO 2: Click to show/hide answer

TODO 2: CMakeLists.txt¶

list(APPEND EXTRA_INCLUDES "${PROJECT_SOURCE_DIR}/MathFunctions")

And remove EXTRA_INCLUDES from target_include_directories:

TODO 3: Click to show/hide answer

TODO 3: CMakeLists.txt¶

target_include_directories(Tutorial PUBLIC
                           "${PROJECT_BINARY_DIR}"
                           )

Notice that with this technique, the only thing our executable target does to
use our library is call target_link_libraries() with the name
of the library target. In larger projects, the classic method of specifying
library dependencies manually becomes very complicated very quickly.

Exercise 2 - Setting the C++ Standard with Interface Libraries¶

Now that we have switched our code to a more modern approach, let's demonstrate
a modern technique to set properties to multiple targets.

Let's refactor our existing code to use an INTERFACE library. We will
use that library in the next step to demonstrate a common use for
generator expressions.

Goal¶

Add an INTERFACE library target to specify the required C++ standard.

Helpful Resources¶

add_library()

target_compile_features()

target_link_libraries()

Files to Edit¶

CMakeLists.txt

MathFunctions/CMakeLists.txt

Getting Started¶

In this exercise, we will refactor our code to use an INTERFACE library to
specify the C++ standard.

Start this exercise from what we left at the end of Step3 exercise 1. You will
have to complete TODO 4 through TODO 7.

Start by editing the top level CMakeLists.txt file. Construct an
INTERFACE library target called tutorial_compiler_flags and
specify cxx_std_11 as a target compiler feature.

Modify CMakeLists.txt and MathFunctions/CMakeLists.txt so that all
targets have a target_link_libraries() call to
tutorial_compiler_flags.

Build and Run¶

Since we have our build directory already configured from Exercise 1, simply
rebuild our code by calling the following:

cd Step3_build
cmake --build .

Next, use the newly built Tutorial and verify that it is working as
expected.

Solution¶

Let's update our code from the previous step to use interface libraries
to set our C++ requirements.

To start, we need to remove the two set() calls on the variables
CMAKE_CXX_STANDARD and CMAKE_CXX_STANDARD_REQUIRED.
The specific lines to remove are as follows:

CMakeLists.txt¶

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED True)

Next, we need to create an interface library, tutorial_compiler_flags. And
then use target_compile_features() to add the compiler feature
cxx_std_11.

TODO 4: Click to show/hide answer

TODO 4: CMakeLists.txt¶

add_library(tutorial_compiler_flags INTERFACE)
target_compile_features(tutorial_compiler_flags INTERFACE cxx_std_11)

Finally, with our interface library set up, we need to link our
executable Tutorial, our SqrtLibrary library and our MathFunctions
library to our new tutorial_compiler_flags library. Respectively, the code
will look like this:

TODO 5: Click to show/hide answer

TODO 5: CMakeLists.txt¶

target_link_libraries(Tutorial PUBLIC MathFunctions tutorial_compiler_flags)

this:

TODO 6: Click to show/hide answer

TODO 6: MathFunctions/CMakeLists.txt¶

  target_link_libraries(SqrtLibrary PUBLIC tutorial_compiler_flags)

and this:

TODO 7: Click to show/hide answer

TODO 7: MathFunctions/CMakeLists.txt¶

target_link_libraries(MathFunctions PUBLIC tutorial_compiler_flags)

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.

Table of Contents

Step 3: Adding Usage Requirements for a Library

Exercise 1 - Adding Usage Requirements for a Library

Goal

Helpful Materials

Files to Edit

Getting Started

Build and Run

Solution

Exercise 2 - Setting the C++ Standard with Interface Libraries

Goal

Helpful Resources

Files to Edit

Getting Started

Build and Run

Solution

Previous topic

Step 2: Adding a Library

Next topic

Step 4: Adding Generator Expressions

This Page

Show Source

Quick search

    <form class="search" action="../../search.html" method="get">
      <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
      <input type="submit" value="Go" />
    </form>

Navigation

          index

          next |

          previous |

    CMake »

    3.29.0-rc3 Documentation »

CMake Tutorial »

Step 3: Adding Usage Requirements for a Library

        © Copyright 2000-2024 Kitware, Inc. and Contributors.
      Created using Sphinx 6.2.1.

path: buildtools/windows/cmake/doc/cmake/html/guide/tutorial/Adding Usage Requirements for a Library.html


code:
<!DOCTYPE html>

    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />

  <title>Step 8: Adding a Custom Command and Generated File — CMake 3.29.0-rc3 Documentation</title>

    <link rel="stylesheet" type="text/css" href="../../_static/pygments.css" />
    <link rel="stylesheet" type="text/css" href="../../_static/cmake.css" />

    <link rel="icon" href="../../_static/cmake-favicon.ico"/>
    <link rel="index" title="Index" href="../../genindex.html" />
    <link rel="search" title="Search" href="../../search.html" />
    <link rel="next" title="Step 9: Packaging an Installer" href="Packaging%20an%20Installer.html" />
    <link rel="prev" title="Step 7: Adding System Introspection" href="Adding%20System%20Introspection.html" />

Navigation

          index

          next |

          previous |

    CMake »

    3.29.0-rc3 Documentation »

CMake Tutorial »

Step 8: 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
the platform log and exp functions and instead would like to
generate a table of precomputed values to use in the mysqrt function.
In this section, we will create the table as part of the build process,
and then compile that table into our application.

First, let's remove the check for the log and exp functions in
MathFunctions/CMakeLists.txt. Then remove the check for HAVE_LOG and
HAVE_EXP from mysqrt.cxx. At the same time, we can remove
#include <cmath>.

In the MathFunctions subdirectory, a new source file named
MakeTable.cxx has been provided to generate the table.

After reviewing the file, we can see that the table is produced as valid C++
code and that the output filename is passed in as an argument.

The next step is to create MathFunctions/MakeTable.cmake. Then, add the
appropriate commands to the file to build the MakeTable executable and
then run it as part of the build process. A few commands are needed to
accomplish this.

First, we add an executable for MakeTable.

MathFunctions/MakeTable.cmake¶

add_executable(MakeTable MakeTable.cxx)

After creating the executable, we add the tutorial_compiler_flags to our
executable using target_link_libraries().

MathFunctions/MakeTable.cmake¶

target_link_libraries(MakeTable PRIVATE tutorial_compiler_flags)

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

MathFunctions/MakeTable.cmake¶

add_custom_command(
  OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/Table.h
  COMMAND MakeTable ${CMAKE_CURRENT_BINARY_DIR}/Table.h
  DEPENDS MakeTable
  )

Next we have to let CMake know that mysqrt.cxx depends on the generated
file Table.h. This is done by adding the generated Table.h to the list
of sources for the library SqrtLibrary.

MathFunctions/CMakeLists.txt¶

  add_library(SqrtLibrary STATIC
              mysqrt.cxx
              ${CMAKE_CURRENT_BINARY_DIR}/Table.h
              )

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.

MathFunctions/CMakeLists.txt¶

  target_include_directories(SqrtLibrary PRIVATE
                             ${CMAKE_CURRENT_BINARY_DIR}
                             )

  # link SqrtLibrary to tutorial_compiler_flags

As the last step, we need to include
MakeTable.cmake at the top of the MathFunctions/CMakeLists.txt.

MathFunctions/CMakeLists.txt¶

  include(MakeTable.cmake)

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:

MathFunctions/mysqrt.cxx¶

double mysqrt(double x)
{
  if (x <= 0) {
    return 0;
  }

  // use the table to help find an initial value
  double result = x;
  if (x >= 1 && x < 10) {
    std::cout << "Use the table to help find an initial value " << std::endl;
    result = sqrtTable[static_cast<int>(x)];
  }

  // do ten iterations
  for (int i = 0; i < 10; ++i) {
    if (result <= 0) {
      result = 0.1;
    }
    double delta = x - (result * result);
    result = result + 0.5 * delta / result;
    std::cout << "Computing sqrt of " << x << " to be " << result << std::endl;
  }

  return result;
}
}
}

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

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

Run the Tutorial executable and verify that it is using the table.

Previous topic

Step 7: Adding System Introspection

Next topic

Step 9: Packaging an Installer

This Page

Show Source

Quick search

    <form class="search" action="../../search.html" method="get">
      <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
      <input type="submit" value="Go" />
    </form>

Navigation

          index

          next |

          previous |

    CMake »

    3.29.0-rc3 Documentation »

CMake Tutorial »

Step 8: Adding a Custom Command and Generated File

        © Copyright 2000-2024 Kitware, Inc. and Contributors.
      Created using Sphinx 6.2.1.

path: buildtools/windows/cmake/doc/cmake/html/guide/tutorial/Adding a Custom Command and Generated File.html


code:
<!DOCTYPE html>

    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />

  <title>Step 2: Adding a Library — CMake 3.29.0-rc3 Documentation</title>

    <link rel="stylesheet" type="text/css" href="../../_static/pygments.css" />
    <link rel="stylesheet" type="text/css" href="../../_static/cmake.css" />

    <link rel="icon" href="../../_static/cmake-favicon.ico"/>
    <link rel="index" title="Index" href="../../genindex.html" />
    <link rel="search" title="Search" href="../../search.html" />
    <link rel="next" title="Step 3: Adding Usage Requirements for a Library" href="Adding%20Usage%20Requirements%20for%20a%20Library.html" />
    <link rel="prev" title="Step 1: A Basic Starting Point" href="A%20Basic%20Starting%20Point.html" />

Navigation

          index

          next |

          previous |

    CMake »

    3.29.0-rc3 Documentation »

CMake Tutorial »

Step 2: Adding a Library

Step 2: Adding a Library¶

At this point, we have seen how to create a basic project using CMake. In this
step, we will learn how to create and use a library in our project. We will
also see how to make the use of our library optional.

Exercise 1 - Creating a Library¶

To add a library in CMake, use the 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 add_subdirectory() command
to add the subdirectory to the build.

Once the library is created, it is connected to our executable target with
target_include_directories() and target_link_libraries().

Goal¶

Add and use a library.

Helpful Resources¶

add_library()

add_subdirectory()

target_include_directories()

target_link_libraries()

PROJECT_SOURCE_DIR

Files to Edit¶

CMakeLists.txt

tutorial.cxx

MathFunctions/CMakeLists.txt

Getting Started¶

In this exercise, we will add a library to our project that contains our own
implementation for computing the square root of a number. The executable can
then use this library instead of the standard square root function provided by
the compiler.

For this tutorial we will put the library into a subdirectory called
MathFunctions. This directory already contains the header files
MathFunctions.h and mysqrt.h. Their respective source files
MathFunctions.cxx and mysqrt.cxx are also provided. We will not need
to modify any of these files. mysqrt.cxx has one function called
mysqrt that provides similar functionality to the compiler's sqrt
function. MathFunctions.cxx contains one function sqrt which serves
to hide the implementation details of sqrt.

From the Help/guide/tutorial/Step2 directory, start with TODO 1 and
complete through TODO 6.

First, fill in the one line CMakeLists.txt in the MathFunctions
subdirectory.

Next, edit the top level CMakeLists.txt.

Finally, use the newly created MathFunctions library in tutorial.cxx

Build and Run¶

Run the cmake executable or the
cmake-gui 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:

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 add_library(). The
source files for the library are passed as an argument to
add_library(). This looks like the following line:

TODO 1: Click to show/hide answer

TODO 1: MathFunctions/CMakeLists.txt¶

add_library(MathFunctions MathFunctions.cxx mysqrt.cxx)

To make use of the new library we will add an add_subdirectory()
call in the top-level CMakeLists.txt file so that the library will get
built.

TODO 2: Click to show/hide answer

TODO 2: CMakeLists.txt¶

add_subdirectory(MathFunctions)

Next, the new library target is linked to the executable target using
target_link_libraries().

TODO 3: Click to show/hide answer

TODO 3: CMakeLists.txt¶

target_link_libraries(Tutorial PUBLIC MathFunctions)

Finally we need to specify the library's header file location.
Modify the existing target_include_directories() call
to add the MathFunctions subdirectory as an include directory
so that the MathFunctions.h header file can be found.

TODO 4: Click to show/hide answer

TODO 4: CMakeLists.txt¶

target_include_directories(Tutorial PUBLIC
                          "${PROJECT_BINARY_DIR}"
                          "${PROJECT_SOURCE_DIR}/MathFunctions"
                          )

Now let's use our library. In tutorial.cxx, include MathFunctions.h:

TODO 5: Click to show/hide answer

TODO 5: tutorial.cxx¶

#include "MathFunctions.h"

Lastly, replace sqrt with the wrapper function mathfunctions::sqrt.

TODO 6: Click to show/hide answer

TODO 6: tutorial.cxx¶

  const double outputValue = mathfunctions::sqrt(inputValue);

Exercise 2 - Adding an Option¶

Now let us add an option in the MathFunctions library to allow developers to
select either the custom square root implementation or the built in standard
implementation. While for the tutorial
there really isn't any need to do so, for larger projects this is a common
occurrence.

CMake can do this using the 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¶

if()

option()

target_compile_definitions()

Files to Edit¶

MathFunctions/CMakeLists.txt

MathFunctions/MathFunctions.cxx

Getting Started¶

Start with the resulting files from Exercise 1. Complete TODO 7 through
TODO 14.

First create a variable USE_MYMATH using the option() command
in MathFunctions/CMakeLists.txt. In that same file, use that option
to pass a compile definition to the MathFunctions library.

Then, update MathFunctions.cxx to redirect compilation based on
USE_MYMATH.

Lastly, prevent mysqrt.cxx from being compiled when USE_MYMATH is on
by making it its own library inside of the USE_MYMATH block of
MathFunctions/CMakeLists.txt.

Build and Run¶

Since we have our build directory already configured from Exercise 1, we can
rebuild by simply calling the following:

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 cmake-gui or  ccmake
if you're in the terminal. Or, alternatively, if you want to change the
option from the command-line, try:

cmake ../Step2 -DUSE_MYMATH=OFF

Now, rebuild the code with the following:

cmake --build .

Then, run the executable again to ensure that it still works with
USE_MYMATH set to OFF. Which function gives better results, sqrt
or mysqrt?

Solution¶

The first step is to add an option to MathFunctions/CMakeLists.txt.
This option will be displayed in the cmake-gui and
ccmake with a default value of ON that can be
changed by the user.

TODO 7: Click to show/hide answer

TODO 7: MathFunctions/CMakeLists.txt¶

option(USE_MYMATH "Use tutorial provided math implementation" ON)

Next, make building and linking our library with mysqrt function
conditional using this new option.

Create an if() statement which checks the value of
USE_MYMATH. Inside the if() block, put the
target_compile_definitions() command with the compile
definition USE_MYMATH.

TODO 8: Click to show/hide answer

TODO 8: MathFunctions/CMakeLists.txt¶

if (USE_MYMATH)
  target_compile_definitions(MathFunctions PRIVATE "USE_MYMATH")
endif()

When USE_MYMATH is ON, the compile definition USE_MYMATH will
be set. We can then use this compile definition to enable or disable
sections of our source code.

The corresponding changes to the source code are fairly straightforward.
In MathFunctions.cxx, we make USE_MYMATH control which square root
function is used:

TODO 9: Click to show/hide answer

TODO 9: MathFunctions/MathFunctions.cxx¶

#ifdef USE_MYMATH
  return detail::mysqrt(x);
#else
  return std::sqrt(x);
#endif

Next, we need to include mysqrt.h if USE_MYMATH is defined.

TODO 10: Click to show/hide answer

TODO 10: MathFunctions/MathFunctions.cxx¶

#ifdef USE_MYMATH
#  include "mysqrt.h"
#endif

Finally, we need to include cmath now that we are using std::sqrt.

TODO 11: Click to show/hide answer

TODO 11 : MathFunctions/MathFunctions.cxx¶

#include <cmath>

At this point, if USE_MYMATH is OFF, mysqrt.cxx would not be used
but it will still be compiled because the MathFunctions target has
mysqrt.cxx listed under sources.

There are a few ways to fix this. The first option is to use
target_sources() to add mysqrt.cxx from within the USE_MYMATH
block. Another option is to create an additional library within the
USE_MYMATH block which is responsible for compiling mysqrt.cxx. For
the sake of this tutorial, we are going to create an additional library.

First, from within USE_MYMATH create a library called SqrtLibrary
that has sources mysqrt.cxx.

TODO 12: Click to show/hide answer

TODO 12 : MathFunctions/CMakeLists.txt¶

  add_library(SqrtLibrary STATIC
              mysqrt.cxx
              )

  # TODO 6: Link SqrtLibrary to tutorial_compiler_flags

  target_link_libraries(MathFunctions PRIVATE SqrtLibrary)
endif()

Next, we link SqrtLibrary onto MathFunctions when USE_MYMATH is
enabled.

TODO 13: Click to show/hide answer

TODO 13 : MathFunctions/CMakeLists.txt¶

  target_link_libraries(MathFunctions PRIVATE SqrtLibrary)

Finally, we can remove mysqrt.cxx from our MathFunctions library
source list because it will be pulled in when SqrtLibrary is included.

TODO 14: Click to show/hide answer

TODO 14 : MathFunctions/CMakeLists.txt¶

add_library(MathFunctions MathFunctions.cxx)

With these changes, the mysqrt function is now completely optional to
whoever is building and using the MathFunctions library. Users can toggle
USE_MYMATH to manipulate what library is used in the build.

Table of Contents

Step 2: Adding a Library

Exercise 1 - Creating a Library

Goal

Helpful Resources

Files to Edit

Getting Started

Build and Run

Solution

Exercise 2 - Adding an Option

Goal

Helpful Resources

Files to Edit

Getting Started

Build and Run

Solution

Previous topic

Step 1: A Basic Starting Point

Next topic

Step 3: Adding Usage Requirements for a Library

This Page

Show Source

Quick search

    <form class="search" action="../../search.html" method="get">
      <input type="text" name="q" aria-labelledby="searchlabel" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false"/>
      <input type="submit" value="Go" />
    </form>

Navigation

          index

          next |

          previous |

    CMake »

    3.29.0-rc3 Documentation »

CMake Tutorial »

Step 2: Adding a Library

        © Copyright 2000-2024 Kitware, Inc. and Contributors.
      Created using Sphinx 6.2.1.