A tenet of modern CMake is to avoid setting compiler flags manually, as they
won’t work across all compilers and platforms unless guarded. Unfortunately due
to the extensive range of toolchains which oneAPI Construction Kit supports
utilizing bespoke compiler settings is unavoidable. We try to isolate all these
platform specific configurations in the module cmake/AddCA.cmake
using
generator expressions to create variables for compiler options and
definitions, set as CA_COMPILE_OPTIONS
and
CA_COMPILE_DEFINITIONS
respectively.
See also
For guidance on when and why we use generator expressions see the Generator Expression Usage section.
AddCA.cmake
then consumes these variables in the macros it exposes to wrap
common CMake functions, such as add_ca_library()
,
add_ca_executable()
, and add_ca_subdirectory()
.
These wrappers allow us to add the project wide compiler settings at a central
location rather than scattered over the codebase, and to set target
dependencies on any other targets which could be conditionally required to
support our various
CA build options
for debugging and instrumentation.
The target_compile_options and target_compile_definitions CMake commands are the preferred way of adding flags in CMake, leading to the cleanest code by transitively passing on flags to dependent targets. Alternative add_compile_options is based on directory properties, and CMAKE_CXX_FLAGS is global and doesn’t work with generator expressions.
Our CA_COMPILE_OPTIONS
and
CA_COMPILE_DEFINITIONS
variables are added to
target_compile_options and
target_compile_definitions using a PRIVATE
scope, rather
than PUBLIC
or INTERFACE
, meaning that the options won’t be propagated
to any other targets which depend on the target we are modifing in the wrapper.
This behavior is preferred over propagating the properties to the new target,
where flags like -Werror
could get set on linked application code which
isn’t warning clean.
Argument Parsing
CMake provides the useful command cmake_parse_arguments, which
facilitates complex argument parsing behaviors and is used to implement many of
our add_ca
prefixed helper functions in the AddCA.cmake
module. We make
use of it to parse single and multiple value keyword arguments, utilizing the
first of the two available cmake_parse_arguments function
signatures. This returns the parsed values as variables beginning with the
parameterized prefix
.
# Signature AddCA.cmake helper functions invoke
cmake_parse_arguments(<prefix> <options> <one_value_keywords>
<multi_value_keywords> <args>...)
A case study of this is our helper function add_ca_check()
,
generating check
and check-<name>
build targets used by continuous
integration to verify a baseline of correctness. add_ca_check()
takes a single positional argument name
, for the target to generate a test
for. A new testing target called check-${name}
is created from the name
argument and a dependency on check-${name}
is added to the check
target.
Additional add_ca_check()
options to configure the testing
target are parsed by forwarding on $ARGN
arguments to
cmake_parse_arguments via the <args>
parameter, such as
multi-value keyword COMMAND
for defining the command to run for test
invocation. NOENUMLATE
and NOGLOBAL
are also declared as flags via the
<options>
parameter, parsed as either TRUE
or FALSE
.
# Parse add_ca_check $ARGN arguments
cmake_parse_arguments(args
"NOEMULATE;NOGLOBAL" "" "CLEAN;COMMAND;DEPENDS;ENVIRONMENT" ${ARGN})
After parsing is complete the results will available as variables prefixed with
‘args_
’, e.g $args_COMMAND
, for use in subsequent
add_ca_check()
logic.
Commands and Variables
AddCA.cmake
exposes wrappers to common CMake functions, providing a single
location to add ComputeAorta specific build options. These options may be
platform dependent, or conditional on user provided build flags.
Using these add_ca*
wrappers helps ensure that customer teams’ targets
get built with the same options as ComputeAorta’s own targets.
To access the following commands and variables in this module:
include(AddCA)
- CA_COMPILE_OPTIONS
Compile options to be added in ComputeAorta wrapper commands as
PRIVATE
target_compile_options for targets. Options are both platform and toolchain specific, and determined based on generator expressions.
- CA_COMPILE_DEFINITIONS
Compile definitions to be added in ComputeAorta wrapper commands as
PRIVATE
target_compile_definitions for targets. Definitions are platform specific, and determined based on generator expressions.
- CA_COMPILER_COMPILE_DEFINITIONS
Variable for propagating user options from root ComputeAorta
CMakeLists.txt
asPRIVATE
compile definitions to be set using target_compile_definitions inside wrapper commands.Options propagated as compile definitions:
CA_RUNTIME_COMPILER_ENABLED
CA_ENABLE_DEBUG_SUPPORT
CA_ENABLE_LLVM_OPTIONS_IN_RELEASE
- add_ca_tidy
The
add_ca_tidy()
function creates a tidy target which invokesclang-tidy
on every C or C++ file passed in. The first argument is assumed to be the target name. When an argument does not exist on the filesystem or is not a C or C++ file it is ignored, this allows passing the same list of arguments asadd_ca_library()
andadd_ca_executable()
.- Arguments:
ARGV0
- Target name to tidy withtidy-${ARGV0}
ARGN
- C/C++ files to tidy.
See also
This function consumes the
CA_CLANG_TIDY_FLAGS
user option.
- set_ca_target_output_directory
The
set_ca_target_output_directory()
macro specifies the output directories for static or shared libraries and executables to consistent locations relative to the projects binary directory.- Arguments:
target
- Named target to set output directory properties on.
- add_ca_library
The
add_ca_library()
macro acts exactly like the default CMake add_library command except that it automatically adds project wide compiler options and definitions to the target.
- add_ca_interface_library
The
add_ca_interface_library()
macro acts exactly like ouradd_ca_library()
command except that it is specialised forINTERFACE
libraries, such as header only libraries.
- ca_target_link_options
ca_target_link_options()
acts like a simpler target_link_options from CMake 3.13+, but not in its full generality. Once the minimum required version is 3.13, we can swap out all uses for the builtin command. This command ensure the linker is called withflags
for all build types. To specialize flags for a particular build configuration you must still set LINK_FLAGS_{RELEASE|MINSIZEREL|RELEASEASSERT} manually with set_target_properties, being mindful not to overwrite what is already there.
- add_ca_executable
The
add_ca_executable()
macro acts exactly like the default CMake add_executable command except that it automatically adds project wide compiler options and definitions to the target.
- target_ca_sources
The
target_ca_sources
macro acts exactly like the default CMake target_sources macro, but it also adds the source files to the tidy target astidy-${target_name}
.- Arguments:
target_name
- Named target.
- add_ca_subdirectory
The
add_ca_subdirectory
macro acts exactly like the default CMake add_subdirectory macro except that it automatically adds project wide compiler options and definitions to the target.- Arguments:
directory
- Path of directory to add.
- add_ca_example_subdirectory
The
add_ca_example_subdirectory()
function delays inclusion of a subdirectory containing targets relating to OpenCL or Vulkan examples until after those API source directories have been added to the CMake tree.- Arguments:
directory
- Path to example directory.
Variables:
- CA_EXAMPLE_DIRS
Internally cached variable holding a list of example source directories. Used by root ComputeAorta
CMakeLists.txt
as input to add_subdirectory once the API dependencies have been satisfied.
- get_target_link_libraries
The
get_target_link_libraries()
macro queries, optionally recursively, the given targets link libraries. This is useful for checking the library dependencies of a target.- Arguments:
variable
- The CMake variable name to store the result in.target
- The target to get the link libraries from.
- Keyword Arguments:
RECURSIVE
- Option to enable recursively getting the target link libraries.
- add_ca_check
The
add_ca_check()
macro takes a list of arguments which form a command to run a check. A new target calledcheck-${name}
is created and a dependency forcheck-${name}
is added to the check target. To run an individual check build thecheck-${name}
target and to run all checks build thecheck
target. All checks are executed with a working directory of${PROJECT_SOURCE_DIR}
and a comment of the form “Running ${name} checks” is displayed by the build system during execution.- Arguments:
name
- Target name suffix for the check, this will create a target calledcheck-${name}
.
- Keyword Arguments:
NOEMULATE
- Flag to specify that the first argument of theCOMMAND
should not be emulated using CMAKE_CROSSCOMPILING_EMULATOR, this should be set if the executable driving the check is not cross-compiled.NOGLOBAL
- Flag to specify thatcheck-${name}
should not be added to the global check target.GTEST
- Flag to specify that this check uses GoogleTest and that CA_GTEST_LAUNCHER should be used, if set, to launch the check executable.USES_TERMINAL
- Flag to specify that the check will be given access to the terminal if possible.COMMAND
- Keyword after which one or more arguments should be specified to define the command the check target will execute.CLEAN
- Keyword after which one or more filenames should be listed as addition files to be clean up by theclean
target.DEPENDS
- Keyword after which one or more target dependencies can be specified.ENVIRONMENT
- Keyword after which one or more environment variables can be specified, each must be of the form: “VAR=<value>”
- add_ca_check_group
The
add_ca_check_group()
function creates a named target for a group of targets and/or checks, this is useful to setup check dependencies and for having a single named check for a set of disparate test suites. As withadd_ca_check()
the name is used to generate a target calledcheck-${name}
.- Arguments:
name
- Target name suffix for the check group, this will create a target calledcheck-${name}
.
- Keyword Arguments:
DEPENDS
- A list of targets this check group will depends on, any CMake target can be specified.Note
The full target name including the
check-
prefix should be specified for dependent check targets.
Here’s an example:
add_ca_check_group(foo DEPENDS bar check-foo)
- add_ca_library_import
The
add_ca_library_import()
macro adds a target referring to an external library not produced as part of the ComputeAorta build.- Arguments:
target
- Target name of library.type
- Type of library to be created in add_library, one ofSTATIC
,SHARED
, orMODULE
.location
- Location on disk to set for the IMPORTED_LOCATION property.
- add_ca_executable_import
The
add_ca_executable_import()
macro adds a target referring to an external executable not produced as part of the ComputeAorta build.- Arguments:
target
- Target name of executable.location
- Location on disk to set for IMPORTED_LOCATION property.
- add_ca_configure_file
The
add_ca_configure_file()
function adds a custom command which calls CMake’s builtin configure_file command at build time, this is useful when the only method of getting a path to a build target is by using generator expressions.- Arguments:
input
- Input file configuration description.output
- Output file to be configured.
- Keyword Arguments:
DEFINED
- Specify a list of definitions taking the form “VAR=${value}” these will then be passed to to CMake’s script mode as-DVAR=${value}
.DEPENDS
- Specify a list of dependencies.
Here’s an example:
add_ca_configure_file(path/to/input path/to/output DEFINED TARGET_EXECUTABLE=$<TARGET_FILE:target> DEPENDS target)
- add_ca_copy_file
This function creates a custom command to copy an input file (usually in the
source directory) to the output file (usually in the binary directory). It’s
effectively a simpler version of add_ca_configure_file()
, as it
does not process the file in any way.
See also
- Keyword Arguments:
INPUT
- The input fileOUTPUT
- The output file
- add_ca_cl_runtime_extension
The
add_ca_cl_runtime_extension()
function adds a set of runtime extensions to the OpenCL library build.- Arguments:
tag
- Unique name for this set of extensions, it is used for accessing the extension information later in the build, must be a valid CMake variable name.
- Keyword Arguments:
EXTENSIONS
- List of OpenCL extension names to be added.HEADER
- Public OpenCL extension header to be installed.INCLUDE_DIRS
- List of include directories required to build the extensions.SOURCES
- List of source files required to build the extensions.
- Variables:
- CA_CL_RUNTIME_EXTENSION_TAGS
${tag}
is appended to the list, then is internally cached.
- ${tag}_RUNTIME_EXTENSIONS
Internally cached list of
${tag}
extensions.
- ${tag}_RUNTIME_HEADER
Internally cached extension header for
${tag}
extensions.
- ${tag}_RUNTIME_INCLUDE_DIRS
Internally cached include directory for
${tag}
extensions.
- ${tag}_RUNTIME_SOURCES
Internally cached List of source files for
${tag}
extensions.
- add_ca_cl_compiler_extension
The
add_ca_cl_compiler_extension()
function adds a set of compiler extensions to the OpenCL library build.- Arguments:
tag
- Unique name for this set of extensions, it is used to make accessing the other information later in the build and must be a valid CMake variable name.
- Keyword Arguments:
EXTENSIONS
- List of OpenCL extension names to be added.HEADER
- Public OpenCL extension header to be installed.INCLUDE_DIRS
- List of include directories required to build the extensions.SOURCES
- List of source files required to build the extensions.
- Variables:
- CA_CL_COMPILER_EXTENSION_TAGS
${tag}
is appended to the list, then internally cached.
- ${tag}_COMPILER_EXTENSIONS
Internally cached list of
${tag}
compiler extensions.
- ${tag}_COMPILER_HEADER
Internally cached extension header for
${tag}
extensions.
- ${tag}_COMPILER_INCLUDE_DIRS
Internally cached include directory for
${tag}
extensions.
- ${tag}_COMPILER_SOURCES
Internally cached list of source files for
${tag}
extensions.
- add_ca_install_components
The
add_ca_install_components()
function creates a custom install target that will install all the specified components in the specified install directory.- Arguments:
ARGN
- Target name for custom install target.
- Keyword Arguments:
INSTALL_DIR
- Directory to set for CMAKE_INSTALL_PREFIX.COMPONENTS
- One of more components to set forCMAKE_INSTALL_COMPONENT
.DEPENDS
- One or more target dependencies.
For example to install only the OpenCL library and
clVectorAddition
in a directory calledpkg
:add_ca_install_components(install-cl-clVectorAdd INSTALL_DIR ${CMAKE_BINARY_DIR}/pkg COMPONENTS OCL OCLExamples DEPENDS CL clVectorAddition)
- add_ca_force_header
The
add_ca_force_header()
function adds a per-device force-header into the CA build.- Keyword Arguments:
PREFIX
- A unique prefix for the internally generated files and variablesDEVICE_NAME
- The name of the core device.Important
DEVICE_NAME
must matchdevice_name
fromadd_core_target
inmodules/core/source/CMakeLists.txt
.PATH
- The file path of the force-include header
- add_ca_configure_lit_site_cfg
This function provides an automatic way to ‘configure’-like generate a file based on a set of common and custom variables, specifically targeting the variables needed for the ‘lit.site.cfg’ files. This function bundles the common variables that any Lit instance is likely to need, and custom variables can be passed in.
On success, a custom target called
name
-lit will be created. This function may fail if certain required key LLVM tool components are not found, in which case the custom target will not have been created.Note
Copied and stripped down from LLVM’s
configure_lit_site_cfg
, found in AddLLVM.cmake.- Arguments:
name
- The name of the test suite.site_in
- The input path to the lit.site.cfg.in-like filesite_out
- The output path to the generated lit.site.cfg file
- Keyword Arguments:
MAIN_CONFIG
- Path to the main lit.cfg to load. Can be empty, in which case a lit.cfg sourced from the same directory assite_in
is used.DEFINED
- Extra defines, passed toadd_ca_configure_file
.PATHS
- The keyword PATHS is followed by a list of cmake variable names that are mentioned as path(“@varname@”) in the lit.cfg.py.in file. Variables in that list are treated as paths that are relative to the directory the generated lit.cfg.py file is in, and the path() function converts the relative path back to absolute form. This makes it possible to move a build directory containing lit.cfg.py files from one machine to another.
- add_ca_lit_check
The
add_ca_lit_check(target comment)
raw function provides an automatic way to set up a check target to run a suite of LIT tests. Note that users are advised to useadd_ca_lit_testsuite
instead.- Arguments:
target
- Named target to set output directory properties on. A targetcheck-${target}-lit
will be created which runs LIT tests producing XML results in${target}-lit.xml
.comment
- A comment to display to the terminal when running the check target.
- Keyword Arguments:
NOGLOBAL
- Flag to specify thatcheck-${target}
should not be added to the global check target.PARAMS
- Keyword after which one or more additional parameters to the llvm-lit command can be specified. Each parameter is automatically prepended with –param.DEPENDS
- Keyword after which one or more target dependencies can be specified.ARGS
- Keyword after which one or more arguments to the llvm-lit command can be specified.
- add_ca_lit_testsuite
The
add_ca_lit_testsuite(name)
function creates a new lit test suite. A new target calledcheck-${name}-lit
is created and a dependency forcheck-${name}-lit
is added to the global check target. To run an individual check build thecheck-${name}-lit
target and to run all checks build thecheck
target. All checks are executed with a working directory of${PROJECT_SOURCE_DIR}
and a comment of the form “Running ${name} checks” is displayed by the build system during execution.If
EXCLUDE_FROM_UMBRELLAS
is not set, the test suite will also be added to all open umbrella targets (seeca_umbrella_lit_testsuite_open()
andca_umbrella_lit_testsuite_close()
).- Arguments:
name
- Target name suffix for the check, this will create a target calledcheck-${name}-lit
.
- Keyword Arguments:
NOGLOBAL
- Flag to specify thatcheck-${target}-lit
should not be added to the global check target.EXCLUDE_FROM_UMBRELLAS
- Flag to specify that${name}
should not be added to any currently open test-suite umbrellas.TARGET
- Keyword after which a target name can be specified. If set, the test suite will be appended to a global set of test suites relating to that target. A globalcheck-${target}-lit
target will be created, comprised of all test suites relating totarget
. Has no effect ifEXCLUDE_FROM_UMBRELLAS
is set.PARAMS
- Keyword after which one or more additional parameters to the llvm-lit command can be specified. Each parameter is automatically prepended with –param.DEPENDS
- Keyword after which one or more target dependencies can be specified.ARGS
- Keyword after which one or more arguments to the llvm-lit command can be specified.
- ca_umbrella_lit_testsuite_open
The
ca_umbrella_lit_testsuite_open(target)
function opens a new umbrella lit test suite.All subsequent calls to
add_ca_lit_testsuite
(which don’t passEXCLUDE_FROM_UMBRELLAS
) are implicitly added to this umbrella suite. The umbrella suite is open until a corresponding call toca_umbrella_lit_testsuite_close
is made with the sametarget
.For example, given:
ca_umbrella_lit_testsuite_open(all)
* add_ca_lit_testsuite(foo)
* ca_umbrella_lit_testsuite_open(compiler)
* - add_ca_lit_testsuite(bar)
* - add_ca_lit_testsuite(baz)
* - add_ca_lit_testsuite(special EXCLUDE_FROM_UMBRELLAS)
* ca_umbrella_lit_testsuite_close(compiler)
ca_umbrella_lit_testsuite_close(all)
Produces the following check targets, from most outermost to innermost:
check-all-lit: foo, bar, baz
check-compiler-lit: bar, baz
check-foo-lit: foo
check-bar-lit: bar
check-baz-lit: baz
check-special-lit: special
- ca_umbrella_lit_testsuite_close
The
ca_umbrella_lit_testsuite_close(target)
function closes an open umbrella lit test suite.A new check target with the name
check-${target}-lit
will be created using test suites previously registered withadd_ca_lit_testsuite
while the umbrella was open.See
ca_umbrella_lit_testsuite_open
for more details.