Using Corrade with CMake

Guide how to find and use Corrade with CMake build system.

Corrade uses CMake as a primary build system for both building and integration into your projects.

Using Corrade that was externally built and installed

The main logic is in the FindCorrade.cmake module distributed with the engine in the modules/ directory, you are encouraged to copy it into your project and add path to the file to CMAKE_MODULE_PATH:

# Path where FindCorrade.cmake can be found, adapt as needed
set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/modules/" ${CMAKE_MODULE_PATH})

find_package(Corrade REQUIRED ...) # see below

Otherwise, if CMake won't be able to find this file in predefined locations, it will error out even if Corrade might be installed on the system. Note that the module files areupdated as the library evolves, you are encouraged to update your copies from time to time to avoid strange building issues.

If you installed the library to non-standard location (other than /usr, e.g. /home/xyz/projects), set CMAKE_PREFIX_PATH to that directory to help CMake find it.

Using Corrade as a CMake subproject

A self-contained alternative to a shared instance of the libraries, is to add the repositories directly into your project (as Git submodules, bundling downloaded archives etc.), and then to use CMake's add_subdirectory() command to compile them on demand. With this approach, you don't need to care about manually installing Corrade, however the usual tradeoffs when bundling code apply — slower full rebuilds, IDEs having more to parse etc. In this case, build-time options can be set() before calling add_subdirectory(). Note that, unless you require CMake 3.13 at least, it's necessary to use the CACHE ... FORCE arguments in order to have the options set properly. For example:

set(CORRADE_WITH_TESTSUITE OFF CACHE BOOL "" FORCE) # disable what you don't use
add_subdirectory(corrade EXCLUDE_FROM_ALL) # so only things you use are built

find_package(Corrade REQUIRED ...) # see below

Note that the use of add_subdirectory() does not replace the configuration necessary for an installed version of Corrade. The modules/ directory and calls to find_package() are needed in both the installed and the subproject case for a properly configured environment.

To simplify your project setup, the subproject globally configures CMAKE_RUNTIME_OUTPUT_DIRECTORY and friends to <CONFIG>/bin / <CONFIG>/lib directories inside your build directory. This makes the subproject workflow easier when dynamically-loaded plugins are involved; and on Windows it makes it possible to run built executables without having to do a $PATH setup for dependency DLLs. If your project already configures CMAKE_{RUNTIME,LIBRARY,ARCHIVE}_OUTPUT_DIRECTORY, those will get used instead (and you can also set your own output directories after the add_subdirectory() call, which will make Corrade keep the above). If you want to disable this behavior altogether and keep all executables and libraries in their implicit locations, set those variables to an empty string (as opposed to nothing at all, which is the same as if the variable is not set) — Corrade will detect and respect that:

# I'm happy with having binaries scattered around the build dir
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "")
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "")

add_subdirectory(corrade EXCLUDE_FROM_ALL)

Finding the package and its components

Basic usage is:

find_package(Corrade REQUIRED)

This module tries to find the base Corrade library and then defines the following:

  • Corrade_FOUND — Whether the base library was found
  • CORRADE_LIB_SUFFIX_MODULE — Path to CorradeLibSuffix.cmake module, which tries to autodetect value of LIB_SUFFIX variable
  • CORRADE_INCLUDE_INSTALL_PREFIX — Prefix where to put platform-independent include and other files, defaults to .. If a relative path is used, it's relative to CMAKE_INSTALL_PREFIX.

This command will try to find only the base library, not the optional components, which are:

Example usage with specifying additional components is:

find_package(Corrade REQUIRED Utility TestSuite)

For each component is then defined:

  • Corrade_*_FOUND — Whether the component was found
  • Corrade::* — Component imported target

The package is found if either debug or release version of each library is found. If both debug and release libraries are found, proper version is chosen based on actual build configuration of the project (i.e. Debug build is linked to debug libraries, Release build to release libraries).

Corrade conditionally defines the CORRADE_IS_DEBUG_BUILD preprocessor variable in case build configuration is Debug (not Corrade itself, but build configuration of the project using it). Useful e.g. for selecting proper plugin directory.

Corrade defines the following custom target properties:

  • CORRADE_CXX_STANDARD — C++ standard to require when compiling given target. Does nothing if CMAKE_CXX_FLAGS already contains particular standard setting flag or if given target contains either of the CXX_STANDARD or COMPILE_FEATURES properties. Allowed value is 11, 14, 17 or 20. See also the CORRADE_CXX_STANDARD C++ macro, which allows for checking of used C++ standard in a portable way.
  • INTERFACE_CORRADE_CXX_STANDARD — C++ standard to require when using given target. Does nothing if CMAKE_CXX_FLAGS already contains particular standard setting flag or if given target contains CMAKE_CXX_STANDARD property. Allowed value is 11, 14, 17 or 20.
  • CORRADE_USE_PEDANTIC_FLAGS — Enable additional compiler/linker flags. Boolean. The particular flags are contained in the CORRADE_PEDANTIC_COMPILER_OPTIONS and CORRADE_PEDANTIC_COMPILER_DEFINITIONS variables.

These properties are inherited from directory properties, meaning that if you set them on directories, they get implicitly set on all targets in given directory (with a possibility to do target-specific overrides). All Corrade libraries have the INTERFACE_CORRADE_CXX_STANDARD property set to 11, meaning that you will always have at least C++11 enabled once you link to any Corrade library.

Features of found Corrade library are exposed in these variables, they are also available as preprocessor variables if you include Corrade/Corrade.h:

  • CORRADE_MSVC_COMPATIBILITY — Defined if compiled with compatibility mode for MSVC 2019+ without the /permissive- flag set
  • CORRADE_MSVC2017_COMPATIBILITY — Defined if compiled with compatibility mode for MSVC 2017
  • CORRADE_MSVC2015_COMPATIBILITY — Defined if compiled with compatibility mode for MSVC 2015
  • CORRADE_BUILD_DEPRECATED — Defined if compiled with deprecated features included
  • CORRADE_BUILD_STATIC — Defined if compiled as static libraries. Default are shared libraries.
  • CORRADE_BUILD_STATIC_UNIQUE_GLOBALS — Defined if static libraries keep their globals unique even across different shared libraries. Enabled by default for static builds.
  • CORRADE_BUILD_MULTITHREADED — Defined if compiled in a way that makes it possible to safely use certain Corrade features simultaneously in multiple threads.
  • CORRADE_BUILD_CPU_RUNTIME_DISPATCH — Defined if built with code paths optimized for multiple architectres with the best matching variant selected at runtime based on detected CPU features
  • CORRADE_TARGET_UNIX — Defined if compiled for some Unix flavor (Linux, BSD, macOS, iOS, Android, ...)
  • CORRADE_TARGET_APPLE — Defined if compiled for Apple platforms
  • CORRADE_TARGET_IOS — Defined if compiled for iOS (device or simulator)
  • CORRADE_TARGET_IOS_SIMULATOR — Defined if compiled for iOS Simulator
  • CORRADE_TARGET_WINDOWS — Defined if compiled for Windows
  • CORRADE_TARGET_WINDOWS_RT — Defined if compiled for Windows RT
  • CORRADE_TARGET_EMSCRIPTEN — Defined if compiled for Emscripten
  • CORRADE_TARGET_ANDROID — Defined if compiled for Android
  • CORRADE_TARGET_GCC — Defined if compiling with GCC or GCC-compatible Clang
  • CORRADE_TARGET_CLANG — Defined if compiling with Clang or any of its variants
  • CORRADE_TARGET_APPLE_CLANG — Defined if compiling with Apple's Clang
  • CORRADE_TARGET_CLANG_CL — Defined if compiling with Clang-CL (Clang with a MSVC frontend)
  • CORRADE_TARGET_MSVC — Defined if compiling with MSVC or Clang with a MSVC frontend
  • CORRADE_TARGET_MINGW — Defined if compiling under MinGW
  • CORRADE_CPU_USE_IFUNC - Defined if GNU IFUNC is allowed to be used for runtime dispatch in the Cpu library
  • CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT — Defined if PluginManager doesn't support dynamic plugin loading due to platform limitations
  • CORRADE_TESTSUITE_TARGET_XCTEST — Defined if TestSuite is targeting Xcode XCTest
  • CORRADE_UTILITY_USE_ANSI_COLORS — Defined if ANSI escape sequences are used for colored output with Utility::Debug on Windows

Besides all the defines above, the Corrade/Corrade.h additionally defines CORRADE_CXX_STANDARD, CORRADE_TARGET_X86 and related x86-specific variables, CORRADE_TARGET_ARM and related ARM-specific variables, CORRADE_TARGET_POWERPC, CORRADE_TARGET_WASM and related WebAssembly-specific variables, CORRADE_TARGET_32BIT, CORRADE_TARGET_BIG_ENDIAN, CORRADE_TARGET_LIBCXX, CORRADE_TARGET_LIBSTDCXX and CORRADE_TARGET_DINKUMWARE based on target architecture, standard and STL used. They are not exposed in CMake because the meaning is unclear with projects that mix more different C++ standards / STL implementations or on platforms with multi-architecture binaries.

Note that each namespace contains more detailed guide how to use given library with CMake.

Macros and functions

Add unit test using Corrade's TestSuite

corrade_add_test(<test name>
                 <sources>...
                 [LIBRARIES <libraries>...]
                 [FILES <files>...]
                 [ARGUMENTS <arguments>...])

Test name is also executable name. You can use LIBRARIES to specify libraries to link with instead of using target_link_libraries(). The Corrade::TestSuite target is linked automatically to each test, together with Corrade::Main for improved experience on Windows. Note that the enable_testing() function must be called explicitly. Arguments passed after ARGUMENTS will be appended to the test command line. ARGUMENTS are supported everywhere except when CORRADE_TESTSUITE_TARGET_XCTEST is enabled.

You can list files needed by the test in the FILES section. If given filename is relative, it is treated relatively to CMAKE_CURRENT_SOURCE_DIR. The files are added to the REQUIRED_FILES target property. On Emscripten they are bundled to the executable and available in the virtual filesystem root. On Android they are copied along the executable to the target. In case of Emscripten and Android, if the file is absolute or contains .., only the leaf name is used. Alternatively you can have a filename formatted as <input>@<output>, in which case the <input> is treated as local filesystem location and <output> as remote/virtual filesystem location. The remote location can't be absolute or contain .. / @ characters.

Unless CORRADE_TESTSUITE_TARGET_XCTEST is set, test cases run on an iOS device are created as bundles with bundle identifier set to CMake project name by default. Use the cache variable CORRADE_TESTSUITE_BUNDLE_IDENTIFIER_PREFIX to change it to something else.

On Emscripten this automatically adds -s DISABLE_EXCEPTION_CATCHING=0 to both compiler and linker flags since early-exit from test cases (failure, expected failure, skipped test case...) is done via exceptions.

By default, the tests are compiled as part of the implicit ALL target. If that's undesirable, the CORRADE_TESTSUITE_TEST_TARGET variable can be set to create a dedicated target for building just the tests. For example, passing -DCORRADE_TESTSUITE_TEST_TARGET=build-tests to CMake will mean cmake --build . builds only the project, and cmake --build . --target build-tests builds the tests. The variable can be also set by the project itself, and even to a different value for different tests for more precise grouping.

Compile data resources into application binary

corrade_add_resource(<name> <input> [SINGLE])

Depends on corrade-rc, which is part of Corrade utilities. This command generates resource data using a resource configuration file passed in <input>. The <name> argument is a CMake variable name that subsequently contains a filename of the resulting C++ file, which is meant to be passed to add_executable() or add_library(), and is also a C identifier under which the resources can be explicitly loaded if needed as described in CORRADE_RESOURCE_INITIALIZE(). See Utility::Resource and Resource management for more information. Example usage:

corrade_add_resource(app_resources resources.conf)
add_executable(app source1 source2 ... ${app_resources})

Alternatively, the SINGLE signature can be used to directly compile a single file into a C++ source file containing its binary representation, exposing the data under extern const unsigned char resourceData_name[] and extern const unsigned int resourceSize_name symbols, with no dependency on Utility::Resource or any other header.

corrade_add_resource(binary_contents binary.dat SINGLE)
# resourceData_binary_contents and resourceSize_binary_contents should be then
# directly referenced by application sources
add_executable(app ... ${binary_contents})

Add dynamic plugin

corrade_add_plugin(<plugin name>
                   "<debug binary install dir>;<debug library install dir>"
                   "<release binary install dir>;<release library install dir>"
                   <metadata file>
                   <sources>...)

The macro adds a preprocessor directive CORRADE_DYNAMIC_PLUGIN when compiling <sources>. Additional libraries can be linked in via target_link_libraries(plugin_name ...). On DLL platforms, the plugin DLLs and metadata files are put into <debug binary install dir> / <release binary install dir> and the *.lib files into <debug library install dir> / <release library install dir>. On non-DLL platforms everything is put into <debug library install dir> / <release library install dir>.

If <metadata file> is not an absolute path, it's treated as relative to CMAKE_CURRENT_SOURCE_DIR. If the plugin interface disables plugin metadata files via PluginManager::AbstractPlugin::pluginMetadataSuffix(), the <metadata file> can be set to "", in which case no metadata file is copied anywhere. Otherwise the metadata file is copied and renamed to <plugin name>, retaining its original extension.

corrade_add_plugin(<plugin name>
                   <debug install dir>
                   <release install dir>
                   <metadata file>
                   <sources>...)

Unlike the above version this puts everything into <debug install dir> on both DLL and non-DLL platforms. If <debug install dir> is set to CMAKE_CURRENT_BINARY_DIR (e.g. for testing purposes), the files are copied directly, without the need to perform install step. Note that the files are actually put into configuration-based subdirectory, i.e. ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CFG_INTDIR}. See documentation of CMAKE_CFG_INTDIR variable for more information.

Add static plugin

corrade_add_static_plugin(<plugin name>
                          "<binary install dir>;<library install dir>"
                          <metadata file>
                          <sources>...)

The macro adds a preprocessor directive CORRADE_STATIC_PLUGIN when compiling <sources>. Additional libraries can be linked in via target_link_libraries(plugin_name ...). The <binary install dir> is ignored and included just for compatibility with the corrade_add_plugin() command, everything is installed into <library install dir>. Note that plugins built in debug configuration (e.g. with CMAKE_BUILD_TYPE set to Debug) have -d suffix to make it possible to have both debug and release plugins installed alongside each other.

If <metadata file> is not an absolute path, it's treated as relative to CMAKE_CURRENT_SOURCE_DIR. If the plugin interface disables plugin metadata files via PluginManager::AbstractPlugin::pluginMetadataSuffix(), the <metadata file> can be set to "", in which case no metadata file is used. Otherwise the metadata file is bundled and renamed to <plugin name>, retaining its original extension.

corrade_add_static_plugin(<plugin name>
                          <install dir>
                          <metadata file>
                          <sources>...)

Equivalent to the above with <library install dir> set to <install dir>. If <install dir> is set to CMAKE_CURRENT_BINARY_DIR (e.g. for testing purposes), no installation rules are added.

Find corresponding DLLs for library files

corrade_find_dlls_for_libs(<output variable> <libs>...)

Available only on Windows, for all *.lib files tries to find corresponding DLL file. Useful for bundling dependencies for e.g. WinRT packages.