Using CMake#

Note

This documentation is the same documentation that would be generated for your project when using new_cxx_project. The terms ${project_name} and ${PROJECT_NAME} will be replaced with your project’s designated name.

${project_name} has a robust set of configuration options and a library that allows for faster C++ development. This page documents how everything fits together.

Config options#

Default config options#

new_cxx_project.py provides the following config options for all C++ projects.

${PROJECT_NAME}_BUILD_DOCS#
Type:

BOOL

Default:

Yes

Toggles whether the documentation is built. Requires Sphinx and MyST to be installed.

Project-specific config options#

Project-specific config options should be added to config/cmake/install_options.cmake, and documented here.

Packages#

Project-specific package dependencies should be added to config/cmake/import_packages.cmake, and documented here.

Toolchain files#

${project_name} has two toolchain files to config/cmake/toolchain. Both toolchains enable a variety of warnings, security mechanisms, and optimisations (release-only).

LLVM toolchain

Path:

config/cmake/toolchain/x86_64-unknown-linux-gnu-clang-with-llvm-toolchain.cmake

Compiler:

Clang

Linker:

lld

Standard library:

libc++

Compiler runtime:

compiler-rt

Unwind library:

libunwind

GNU toolchain

Path:

config/cmake/toolchain/x86_64-unknown-linux-gnu-gcc.cmake

Compiler:

GCC

Linker:

gold

Standard library:

libstdc++

Compiler runtime:

libgcc

Unwind library:

libgcc_eh

Creating binaries#

To ensure that simple binaries are built with as few CMake errors as possible, this project provides a set of rules that can build executables, libraries, and tests. The primary advantage of using these rules over the default CMake rules is that they handle some desirable defaults for everything, and also bundle all of your rules into a single rule (as opposed to needing to repeat yourself, a la add_executable(target sources...), add_compile_options(target options...), add_compile_definitions(target definitions...), etc., which can be error-prone).

All rules must be provided with a TARGET (the name of the binary to be built), and at least one source file needs to be listed using either the SOURCES named parameter, the HEADER_INTERFACE named parameter (cxx_library() only), or the MODULE_INTERFACE named parameter (cxx_library() only).

# A standalone executable.
cxx_executable(
  TARGET hello
  SOURCES hello.cpp
)

# A greeter using conventional C++ headers.
cxx_library(
  TARGET greeter
  LIBRARY_TYPE OBJECT
  SOURCES greeter.cpp
  HEADER_INTERFACE greeter.hpp
)

cxx_test(
  TARGET test_greeter
  SOURCES test_greeter.cpp
  DEPENDS_ON greeter
)

# A header-only version.
cxx_library(
  TARGET greeter_header_only
  LIBRARY_TYPE HEADER_ONLY
  HEADER_INTERFACE greeter_header_only.hpp
)

cxx_test(
  TARGET test_greeter_header_only
  SOURCES test_greeter.cpp
  DEPENDS_ON greeter_header_only
)

# A greeter using C++20 modules.
cxx_library(
  TARGET module_based_greeter
  MODULE_INTERFACE module_based_greeter.cpp
)

cxx_test(
  TARGET test_module_based_greeter
  SOURCES test_module_based_greeter.cpp
  DEPENDS_ON module_based_greeter
)
cxx_executable(TARGET target_name   SOURCES source_files...  COMPILE_OPTIONS options...  DEFINE macros...  HEADERS headers...  INDCLUDE directories...  LINK_OPTIONS linker_options...  DEPENDS_ON dependencies...   INSTALL_WITH install_target   INSTALL_PERMISSIONS install_permissions...)#

Builds an executable program. Accepts the following parameters:

TARGET:STRING#

The name of the executable.

SOURCES:LIST[STRING]#

Paths to each source file.

cxx_executable(
  TARGET hello
  SOURCES
    hello.cpp
    greeter.cpp
)
COMPILE_OPTIONS:LIST[STRING]#

Provides the compiler with a set of options that are only be applicable to the current target.

cxx_executable(
  TARGET hello
  SOURCES hello.cpp
  COMPILE_OPTIONS
    -Wno-float-conversion
    -Wno-literal-conversion
)
DEFINE:LIST[STRING]#

Tells the compiler to define these macros for every source file.

cxx_executable(
  TARGET hello
  SOURCES hello.cpp
  DEFINE
    ${PROJECT_NAME}_USE_ASAN
    ${PROJECT_NAME}_RETURN_VALUE=1
)
HEADERS:LIST[STRING]#

Tells the compiler the set of headers that the target depends on.

cxx_executable(
  TARGET hello
  SOURCES hello.cpp
  HEADERS
    "${PROJECT_SOURCE_DIR}/include/greeting.hpp"
)

Provides the linker with a set of options that are only be applicable to the current target.

cxx_executable(
  TARGET hello
  SOURCES hello.cpp
  LINK_OPTIONS
    -fuse-ld=mold
)
DEPENDS_ON:LIST[STRING]#

Tells CMake which targets this one depends on.

cxx_executable(
  TARGET hello_triangle
  SOURCES hello_triangle.cpp
  DEPENDS_ON
    Vulkan
    GLFW3
)
INSTALL_WITH:STRING#

Installs the executable to ${CMAKE_INSTALL_PREFIX}/bin when install_target is invoked as an install step. install_target must be defined in config/cmake/install_targets.cmake.

This executable will be installed to ${CMAKE_INSTALL_PREFIX}/bin when install-targets is executed as an install step.#
cxx_executable(
  TARGET hello_moon
  SOURCES hello_moon.cpp
  INSTALL_WITH install-targets
)
INSTALL_PERMISSIONS:LIST[STRING]#

Determines the permissions that the executable will have when installed. Valid values include OWNER_READ, OWNER_WRITE, OWNER_EXECUTE, GROUP_READ, GROUP_WRITE, GROUP_EXECUTE, WORLD_READ, WORLD_WRITE, and WORLD_EXECUTE.

Defaults to OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE.

The previous case installed hello_moon with the default permissions. We install with some more restricted permissions this time.#
cxx_executable(
  TARGET hello_moon
  SOURCES hello_moon.cpp
  INSTALL_WITH install-targets
  INSTALL_PERMISSIONS
    OWNER_READ OWNER_WRITE OWNER_EXECUTE
)
cxx_library(TARGET target_name  LIBRARY_TYPE library_type  SOURCES sources...  MODULE_INTERFACE export_module_sources...  HEADERS headers  HEADER_INTERFACE headers_to_export  DEFINE macros...  DEPENDS_ON_INTERFACE public_dependencies...  DEPENDS_ON private_dependencies...   INSTALL_WITH install_target   INSTALL_PREFIX_INCLUDE directory   INSTALL_PREFIX_LIBRARY directory   INSTALL_PERMISSIONS install_permissions...)#

Builds a library. cxx_library() supports the following named arguments.

TARGET:STRING#

The name of the library.

SOURCES:LIST[STRING]#
MODULE_INTERFACE:LIST[STRING]#

Both are used to indicate which source files are built for this target. MODULE_INTERFACE refers to any file containing export module.

cxx_library(
  TARGET greeter
  MODULE_INTERFACE greeter.cpp
  SOURCES strings.cpp
)
LIBRARY_TYPE:STRING#

Determines how the library should be produced. Valid values include:

  • STATIC builds the target as a static library. Static libraries are typically shipped as a deliverable for other projects to consume.

    The executable hello will have all of greeter’s code linked at build time. The project does not need to ship greeter for hello to be usable.#
    cxx_library(
      TARGET greeter
      LIBRARY_TYPE STATIC
      HEADER_INTERFACE
        "${PROJECT_SOURCE_DIR}/include/greeter.hpp"
        "${PROJECT_SOURCE_DIR}/include/strings.hpp"
      SOURCES
        greeter.cpp
        strings.cpp
    )
    
    cxx_binary(
      TARGET hello
      DEPENDS_ON greeter
    )
    
  • SHARED builds the target as a shared library. Shared libraries are typically shipped as a deliverable for other projects to consume.

    The executable hello will not contain any of greeter’s code, and requires the project to ship greeter in order for hello to be usable.#
    cxx_library(
      TARGET greeter
      LIBRARY_TYPE SHARED
      HEADER_INTERFACE
        "${PROJECT_SOURCE_DIR}/include/greeter.hpp"
        "${PROJECT_SOURCE_DIR}/include/strings.hpp"
      SOURCES
        greeter.cpp
        strings.cpp
    )
    
    cxx_binary(
      TARGET hello
      DEPENDS_ON greeter
    )
    
  • PLUGIN builds the target as a shared object that must be loaded at runtime, and cannot be linked using the compiler or linker.

    cxx_library(
      TARGET greeter
      LIBRARY_TYPE PLUGIN
      SOURCES
        greeter.cpp
        strings.cpp
    )
    
    # Error: attempting to link greeter
    cxx_binary(
      TARGET hello
      DEPENDS_ON greeter
    )
    

    Note

    The official CMake term for this is MODULE. We use PLUGIN to avoid confusion with C++20 modules.

  • OBJECT builds the target as an intermediary object file. Object files are project-local targets that are used to modularise a build. Unlike all other library types, object files cannot be exported by the project.

    cxx_library(
      TARGET greeter
      LIBRARY_TYPE OBJECT
      HEADER_INTERFACE
        "${PROJECT_SOURCE_DIR}/include/greeter.hpp"
        "${PROJECT_SOURCE_DIR}/include/strings.hpp"
      SOURCES
        greeter.cpp
        strings.cpp
    )
    
    cxx_binary(
      TARGET hello
      DEPENDS_ON greeter
    )
    
  • HEADER_ONLY builds the target as a header-only library. Since header-only libraries only consist of headers, it isn’t possible to use SOURCES, MODULE_INTERFACE, or HEADERS.

    cxx_library(
        TARGET greeter
        LIBRARY_TYPE HEADER_ONLY
        HEADER_INTERFACE
          strings.hpp
          greeter.hpp
      )
    
      cxx_binary(
        TARGET hello
        DEPENDS_ON greeter
      )
    
HEADERS:LIST[STRING]#
HEADER_INTERFACE:LIST[STRING]#

Tells the build system the set of headers that the target depends on. Headers listed under HEADER_INTERFACE are installed, while headers listed under HEADERS are not.

cxx_library(
  TARGET hello
  LIBRARY_TYPE OBJECT
  HEADER_INTERFACE
    "${PROJECT_SOURCE_DIR}/include/greeter.hpp"
  HEADERS
    "${PROJECT_SOURCE_DIR}/source/strings.hpp"
  SOURCES
    greeter.cpp
    strings.cpp
)
DEFINE:LIST[STRING]#

As above, but for macros.

DEPENDS_ON_INTERFACE:LIST[STRING]#
DEPENDS_ON:LIST[STRING]#

Tells CMake which targets this one depends on. DEPENDS_ON_INTERFACE dependencies are propagated; dependencies listed under DEPENDS_ON are not.

cxx_executable(
  TARGET hello_triangle
  SOURCES hello_triangle.cpp
  DEPENDS_ON
    Vulkan
    GLFW3
)
INSTALL_WITH:STRING#

Installs header interfaces to ${CMAKE_INSTALL_PREFIX}/include, and static archives, shared objects, and plugins to ${CMAKE_INSTALL_PREFIX}/lib when install-targets is executed as an install step.

Note

Module interfaces can’t be installed at the moment due to technical limitations.

The precompiled binary component of this library will be installed to ${CMAKE_INSTALL_PREFIX}/lib, and the headers will be installed to ${CMAKE_INSTALL_PREFIX}/include when install-targets is executed as an install step.#
cxx_library(
  TARGET greeter
  LIBRARY_TYPE STATIC
  HEADERS greeter.hpp
  SOURCES greeter.cpp
  INSTALL_WITH install-targets
)
INSTALL_PREFIX_INCLUDE:STRING#

Tells the build system to install headers to the path in ${CMAKE_INSTALL_PREFIX}/include/${INSTALL_PREFIX_INCLUDE}.

The precompiled binary component of this library will be installed to ${CMAKE_INSTALL_PREFIX}/lib, and the headers will be installed to :code:`${CMAKE_INSTALL_PREFIX}/include/greeter` when install-targets is executed as an install step.#
cxx_library(
  TARGET greeter
  LIBRARY_TYPE STATIC
  HEADERS greeter.hpp
  SOURCES greeter.cpp
  INSTALL_WITH install-targets
  INSTALL_PREFIX_INCLUDE greeter
)
INSTALL_PREFIX_LIBRARY:STRING#

Tells the build system to install static archives, shared objects, and plugins to the path in ${CMAKE_INSTALL_PREFIX}/include/${INSTALL_PREFIX_LIBRARY}.

The precompiled binary component of this library will be installed to :code:`${CMAKE_INSTALL_PREFIX}/lib/greeter`, and the headers will be installed to ${CMAKE_INSTALL_PREFIX}/include/greeter when install-targets is executed as an install step.#
cxx_library(
  TARGET greeter
  LIBRARY_TYPE STATIC
  HEADERS greeter.hpp
  SOURCES greeter.cpp
  INSTALL_WITH install-targets
  INSTALL_PREFIX_INCLUDE greeter
)
INSTALL_PERMISSIONS:LIST[STRING]#

Determines the permissions that the library will have when installed. Valid values include OWNER_READ, OWNER_WRITE, OWNER_EXECUTE, GROUP_READ, GROUP_WRITE, GROUP_EXECUTE, WORLD_READ, WORLD_WRITE, and WORLD_EXECUTE.

Defaults to OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ.

The previous case installed greeter with the default permissions. We install with some more restricted permissions this time.#
cxx_library(
  TARGET greeter
  LIBRARY_TYPE shared
  HEADERS greeter.hpp
  SOURCES greeter.cpp
  INSTALL_WITH install-targets
  INSTALL_PERMISSIONS
    OWNER_READ OWNER_WRITE
    GROUP_READ
)
cxx_test()#

A wrapper around cxx_executable() to register the executable with CTest. The parameters are identical, excluding install options.

The test will be named test.$TARGET_NAME, where $TARGET_NAME is a placeholder for what you passed to TARGET.

Installing binaries#

The named parameter INSTALL_WITH install-targets indicates to a cxx_executable() or cxx_library() that you intend to install this target. In order to do so, you’ll first need to define install-targets as something to install. You do this by adding an install(EXPORT) to config/cmake/install_targets.cmake, like the one that’s below.

install(
  EXPORT ${project_name}-install
  FILE ${project_name}-config.cmake
  NAMESPACE ${project_name}::
  DESTINATION lib/cmake/${project_name}
)

Your project will automatically warn that an installation target hasn’t been created so that you don’t forget to do this.