CMAKE-COMMANDS(7)
๐ธ NAME ๐ธ
cmake-commands โ CMake Language Command Reference. Yep bestie, this is the CMAKE-COMMANDS(7) manual page. Buckle up. ๐
โจ SCRIPTING COMMANDS โจ
These commands are always available. No cap.
๐ block ๐
Added in version 3.25.
Okay so block() is literally the โevaluate a group of commands with a dedicated variable and/or policy scopeโ icon. ๐ซถ
block([SCOPE_FOR [DIAGNOSTICS] [POLICIES] [VARIABLES]]
[PROPAGATE <var-name>...])
<commands>
endblock()
All commands between block() and the matching endblock() are recorded without being invoked. Once the endblock() is evaluated, the recorded list of commands is invoked inside the requested scopes, then the scopes created by the block() command are removed. Not me casually recording commands and then running them later. ๐ญ
SCOPE_FORโ specify which scopes must be created:DIAGNOSTICSโ Added in version 4.4. Create a new diagnostic scope. This is equivalent tocmake_diagnostic(PUSH)with an automaticcmake_diagnostic(POP)when leaving the block scope.POLICIESโ create a new policy scope. This is equivalent tocmake_policy(PUSH)with an automaticcmake_policy(POP)when leaving the block scope.VARIABLESโ create a new variable scope.
If SCOPE_FOR is not specified, this is equivalent to:
block(SCOPE_FOR VARIABLES POLICIES DIAGNOSTICS)
PROPAGATEโ when a variable scope is created by theblock()command, this option sets or unsets the specified variables in the parent scope. This is equivalent toset(PARENT_SCOPE)orunset(PARENT_SCOPE)commands. ๐ซก
set(var1 "INIT1")
set(var2 "INIT2")
set(var3 "INIT3")
block(PROPAGATE var1 var2)
set(var1 "VALUE1")
unset(var2)
set(var3 "VALUE3")
endblock()
# Now var1 holds VALUE1, var2 is unset, and var3 holds the initial value INIT3
This option is only allowed when a variable scope is created. An error will be raised in the other cases. โ ๏ธ
When the block() is inside a foreach() or while() command, the break() and continue() commands can be used inside the block. Bestie, thatโs the good stuff. ๐
while(TRUE)
block()
...
# the break() command will terminate the while() command
break()
endblock()
endwhile()
๐ See Also
endblock()return()cmake_policy()
๐ break ๐
Break from an enclosing foreach or while loop. Periodt.
break()
Breaks from an enclosing foreach() or while() loop.
See also the continue() command. ๐ฆ
๐ฉบ cmake_diagnostic ๐ฉบ
Added in version 4.4.
Manage CMake Diagnostic settings. See the cmake-diagnostics(7) manual for a list of available categories. This is giving โIโm in charge of the diagnostic vibes.โ ๐ฅ
๐ Synopsis
Setting Diagnostics
cmake_diagnostic(SET <category> <action> [RECURSE])
cmake_diagnostic(PROMOTE <category> <action> [NO_RECURSE])
cmake_diagnostic(DEMOTE <category> <action> [NO_RECURSE])
Checking Diagnostic Actions
cmake_diagnostic(GET <diagnostic> <out-var>)
CMake Diagnostic Stack
cmake_diagnostic(PUSH)
cmake_diagnostic(POP)
โ๏ธ Setting Diagnostics
cmake_diagnostic(SET CMD_<CATEGORY> <action> [RECURSE])
cmake_diagnostic(PROMOTE CMD_<CATEGORY> <action> [NO_RECURSE])
cmake_diagnostic(DEMOTE CMD_<CATEGORY> <action> [NO_RECURSE])
Set or alter the action taken when a diagnostic belonging to a particular category is triggered.
The SET subcommand sets the action for the specified diagnostic category. The PROMOTE subcommand increases the severity for the specified diagnostic category, or does nothing if the action was already set to an equal or higher severity. The DEMOTE subcommand decreases the severity for the specified diagnostic category, or does nothing if the action was already set to an equal or lower severity.
The possible <action>s (in order of severity) are:
IGNOREโ do nothing.WARNโ report a warning and continue processing.SEND_ERRORโ report an error, continue processing, but skip generation. Thecmake(1)executable will return a non-zero exit code. ๐ญFATAL_ERRORโ report an error, stop processing and generation. Thecmake(1)executable will return a non-zero exit code. ๐
Some diagnostic categories are hierarchical. The RECURSE and NO_RECURSE options determine whether changing the action for a diagnostic category also modifies any child categories. By default, the PROMOTE and DEMOTE subcommands are recursive, while the SET subcommand is not. Note that the alteration for child categories is independent of the prior action set on any parents; that is, PROMOTE and DEMOTE, when operating recursively, will operate on all child categories even if a parent category's action was not altered.
๐ Checking Diagnostic Actions
cmake_diagnostic(GET CMD_<CATEGORY> <variable>)
Check what action is currently specified for a diagnostic category. The output <variable> value will be one of IGNORE, WARN, SEND_ERROR or FATAL_ERROR.
๐ฅ CMake Diagnostic Stack
CMake keeps diagnostic settings on a stack, so changes made by the cmake_diagnostic command affect only the top of the stack. A new entry on the diagnostic stack is managed automatically for each subdirectory to protect its parents and siblings. CMake also manages a new entry for scripts loaded by include() and find_package() commands except when invoked with the NO_DIAGNOSTIC_SCOPE option. The cmake_diagnostic command provides an interface to manage custom entries on the diagnostic stack:
cmake_diagnostic(PUSH)โ create a new entry on the diagnostic stack.cmake_diagnostic(POP)โ remove the last diagnostic stack entry created withcmake_diagnostic(PUSH).
EachPUSHmust have a matchingPOPto erase any changes. This is useful to make temporary changes to diagnostic settings. Calls to thecmake_diagnostic(SET),cmake_diagnostic(PROMOTE), orcmake_diagnostic(DEMOTE)commands influence only the current top of the diagnostic stack. ๐ซถ
The block(SCOPE_FOR DIAGNOSTICS) command offers a more flexible and more secure way to manage the diagnostic stack. The pop action is done automatically when leaving the block scope, so there is no need to precede each return() with a call to cmake_diagnostic(POP). Slay. โจ
# stack management with cmake_diagnostic()
function(my_func)
cmake_diagnostic(PUSH)
cmake_diagnostic(SET ...)
if (<cond1>)
...
cmake_diagnostic(POP)
return()
elseif(<cond2>)
...
cmake_diagnostic(POP)
return()
endif()
...
cmake_diagnostic(POP)
endfunction()
# stack management with block()/endblock()
function(my_func)
block(SCOPE_FOR DIAGNOSTICS)
cmake_diagnostic(SET ...)
if (<cond1>)
...
return()
elseif(<cond2>)
...
return()
endif()
...
endblock()
endfunction()
Commands created by the function() and macro() commands record diagnostic settings when they are created and use the pre-record diagnostics when they are invoked. If the function or macro implementation sets diagnostics, the changes automatically propagate up through callers until they reach the closest nested diagnostic stack entry.
๐ฅ๏ธ cmake_host_system_information ๐ฅ๏ธ
Query various host system information. Itโs giving โtell me everything about this machine.โ ๐
๐ Synopsis
Query host system specific information
cmake_host_system_information(RESULT <variable> QUERY <key> ...)
Query the Windows registry
cmake_host_system_information(RESULT <variable> QUERY WINDOWS_REGISTRY <key> ...)
๐ Query host system specific information
cmake_host_system_information(RESULT <variable> QUERY <key> ...)
Queries system information of the host system on which cmake runs. One or more <key> can be provided to select the information to be queried. The list of queried values is stored in <variable>.
<key> can be one of the following values:
NUMBER_OF_LOGICAL_CORESโ Number of logical coresNUMBER_OF_PHYSICAL_CORESโ Number of physical coresHOSTNAMEโ HostnameFQDNโ Fully qualified domain nameTOTAL_VIRTUAL_MEMORYโ Total virtual memory in MiB [1]AVAILABLE_VIRTUAL_MEMORYโ Available virtual memory in MiB [1]TOTAL_PHYSICAL_MEMORYโ Total physical memory in MiB [1]AVAILABLE_PHYSICAL_MEMORYโ Available physical memory in MiB [1]IS_64BITโ Added in version 3.10. One if processor is 64BitHAS_FPUโ Added in version 3.10. One if processor has floating point unitHAS_MMXโ Added in version 3.10. One if processor supports MMX instructionsHAS_MMX_PLUSโ Added in version 3.10. One if processor supports Ext. MMX instructionsHAS_SSEโ Added in version 3.10. One if processor supports SSE instructionsHAS_SSE2โ Added in version 3.10. One if processor supports SSE2 instructionsHAS_SSE_FPโ Added in version 3.10. One if processor supports SSE FP instructionsHAS_SSE_MMXโ Added in version 3.10. One if processor supports SSE MMX instructionsHAS_AMD_3DNOWโ Added in version 3.10. One if processor supports 3DNow instructionsHAS_AMD_3DNOW_PLUSโ Added in version 3.10. One if processor supports 3DNow+ instructionsHAS_IA64โ Added in version 3.10. One if IA64 processor emulating x86HAS_SERIAL_NUMBERโ Added in version 3.10. One if processor has serial numberHAS_APICโ Added in version 4.3. One if processor supports APICHAS_L1_CACHEโ Added in version 4.3. One if processor has L1 cachePROCESSOR_SERIAL_NUMBERโ Added in version 3.10. Processor serial numberPROCESSOR_NAMEโ Added in version 3.10. Human readable processor namePROCESSOR_DESCRIPTIONโ added in version 3.10. A human-readable, full description of the processor. ๐LOCALE_CHARSETโ added in version 4.3. The locale's character set โ if known, otherwise empty. This is the encoding expected incmake-language(7)files and scripts:- On Windows, this is always
UTF-8. - On UNIX and macOS, this is based on the current locale.
- On Windows, this is always
OS_NAMEโ added in version 3.10. The host operating system name:- On UNIX platforms, this is
uname -s. - On Apple platforms, this is
sw_vers -productName. - On Windows, this is
Windows.
- On UNIX platforms, this is
See also CMAKE_HOST_SYSTEM_NAME. ๐ฆ
OS_RELEASEโ added in version 3.10. The OS sub-type, e.g. on WindowsProfessional. Lowkey important, no cap.OS_VERSIONโ added in version 3.10. The OS build ID.OS_PLATFORMโ added in version 3.10. SeeCMAKE_HOST_SYSTEM_PROCESSOR.MSYSTEM_PREFIXโ added in version 3.28. Available only on Windows hosts. In a MSYS or MinGW development environment that sets theMSYSTEMenvironment variable, this is its installation prefix. Otherwise, this is the empty string. ๐ซถFAMILY_IDโ added in version 4.3. The processor family name.MODEL_IDโ added in version 4.3. The processor model ID.MODEL_NAMEโ added in version 4.3. The processor model name.PROCESSOR_APIC_IDโ added in version 4.3. The processor APIC ID.PROCESSOR_CACHE_SIZEโ added in version 4.3. The processor L1 cache size.PROCESSOR_CLOCK_FREQUENCYโ added in version 4.3. The processor clock frequency.VENDOR_IDโ added in version 4.3. The processor vendor ID.VENDOR_STRINGโ added in version 4.3. The processor vendor string.DISTRIB_INFOโ added in version 3.22. Reads the/etc/os-releasefile and defines the given<variable>into a list of read variables. Bookkeeping queen. ๐DISTRIB_<name>โ added in version 3.22. Gets the<name>variable (seeman 5 os-releaseโhttps://www.freedesktop.org/software/systemd/man/latest/os-release.html) if it exists in the/etc/os-releasefile.
Example:
cmake_host_system_information(RESULT PRETTY_NAME QUERY DISTRIB_PRETTY_NAME)
message(STATUS "${PRETTY_NAME}")
cmake_host_system_information(RESULT DISTRO QUERY DISTRIB_INFO)
foreach(VAR IN LISTS DISTRO)
message(STATUS "${VAR}=`${${VAR}}`")
endforeach()
Output:
-- Ubuntu 20.04.2 LTS
-- DISTRO_BUG_REPORT_URL=`https://bugs.launchpad.net/ubuntu/`
-- DISTRO_HOME_URL=`https://www.ubuntu.com/`
-- DISTRO_ID=`ubuntu`
-- DISTRO_ID_LIKE=`debian`
-- DISTRO_NAME=`Ubuntu`
-- DISTRO_PRETTY_NAME=`Ubuntu 20.04.2 LTS`
-- DISTRO_PRIVACY_POLICY_URL=`https://www.ubuntu.com/legal/terms-and-policies/privacy-policy`
-- DISTRO_SUPPORT_URL=`https://help.ubuntu.com/`
-- DISTRO_UBUNTU_CODENAME=`focal`
-- DISTRO_VERSION=`20.04.2 LTS (Focal Fossa)`
-- DISTRO_VERSION_CODENAME=`focal`
-- DISTRO_VERSION_ID=`20.04`
If the /etc/os-release file is not found, the command tries to gather OS identification via fallback scripts. The fallback script can use various distribution-specific files (http://linuxmafia.com/faq/Admin/release-files.html) to collect OS identification data and map it into man 5 os-release variables.
Fallback Interface Variables
CMAKE_GET_OS_RELEASE_FALLBACK_SCRIPTSโ In addition to the scripts shipped with CMake, a user may append full paths of their script(s) to this list. The script filename has the following format:NNN-<name>.cmake, whereNNNis three digits used to apply collected scripts in a specific order. Order matters bestie, don't skip it. ๐CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_<varname>โ Variables collected by the user-provided fallback script ought to be assigned to CMake variables using this naming convention. Example: theIDvariable from the manual becomesCMAKE_GET_OS_RELEASE_FALLBACK_RESULT_ID.CMAKE_GET_OS_RELEASE_FALLBACK_RESULTโ The fallback script ought to store names of all assignedCMAKE_GET_OS_RELEASE_FALLBACK_RESULT_<varname>variables in this list.
Example:
# 000-FallbackScript.cmake
#
# Try to detect some old distribution
# See also
# - http://linuxmafia.com/faq/Admin/release-files.html
#
if(NOT EXISTS "${CMAKE_SYSROOT}/etc/foobar-release")
return()
endif()
# Get the first string only
file(
STRINGS "${CMAKE_SYSROOT}/etc/foobar-release" CMAKE_GET_OS_RELEASE_FALLBACK_CONTENT
LIMIT_COUNT 1
)
#
# Example:
#
# Foobar distribution release 1.2.3 (server)
#
if(CMAKE_GET_OS_RELEASE_FALLBACK_CONTENT MATCHES "Foobar distribution release ([0-9\.]+) .*")
set(CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_NAME Foobar)
set(CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_PRETTY_NAME "${CMAKE_GET_OS_RELEASE_FALLBACK_CONTENT}")
set(CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_ID foobar)
set(CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_VERSION ${CMAKE_MATCH_1})
set(CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_VERSION_ID ${CMAKE_MATCH_1})
list(
APPEND CMAKE_GET_OS_RELEASE_FALLBACK_RESULT
CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_NAME
CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_PRETTY_NAME
CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_ID
CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_VERSION
CMAKE_GET_OS_RELEASE_FALLBACK_RESULT_VERSION_ID
)
endif()
unset(CMAKE_GET_OS_RELEASE_FALLBACK_CONTENT)
Then this script can be applied as a fallback to determine the missing host system information:
list(
APPEND
CMAKE_GET_OS_RELEASE_FALLBACK_SCRIPTS
${CMAKE_CURRENT_SOURCE_DIR}/000-FallbackScript.cmake
)
cmake_host_system_information(RESULT info QUERY DISTRIB_INFO)
๐ FOOTNOTES
- [1] One MiB (mebibyte) is equal to 1024x1024 bytes. Math girlies rise ๐ง
Query the Windows registry
Added in version 3.24. Windows besties, this one's for you ๐ชโจ
cmake_host_system_information(RESULT <variable> QUERY WINDOWS_REGISTRY <key> [VALUE_NAMES|SUBKEYS|VALUE <name>]
[VIEW (64|32|64_32|32_64|HOST|TARGET|BOTH)] [SEPARATOR <separator>]
[ERROR_VARIABLE <result>])
Performs query operations on a local computer registry subkey. Returns a list of subkeys or value names that are located under the specified subkey in the registry, or the data of the specified value name. The result of the queried entity is stored in <variable>.
โ ๏ธ Note: querying the registry on any platform other than Windows โ includingCYGWINโ will always return an empty string and sets an error message in the variable specified with the sub-optionERROR_VARIABLE. It's giving "wrong OS, bestie." ๐
<key> specifies the full path of a subkey on the local computer. The <key> must include a valid root key. Valid root keys for the local computer are:
HKLMorHKEY_LOCAL_MACHINEHKCUorHKEY_CURRENT_USERHKCRorHKEY_CLASSES_ROOTHKUorHKEY_USERSHKCCorHKEY_CURRENT_CONFIG
And, optionally, the path to a subkey under the specified root key. The path separator can be the slash or the backslash. <key> is not case sensitive. For example:
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "HKLM")
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "HKLM/SOFTWARE/Kitware")
cmake_host_system_information(RESULT result QUERY WINDOWS_REGISTRY "HKCU\\SOFTWARE\\Kitware")
VALUE_NAMESโ Request the list of value names defined under<key>. If a default value is defined, it will be identified with the special name(default). ๐SUBKEYSโ Request the list of subkeys defined under<key>.VALUE <name>โ Request the data stored in the value named<name>. IfVALUEis not specified or the argument is the special name(default), the content of the default value, if any, will be returned. Here's the vibe:
# query default value for HKLM/SOFTWARE/Kitware key
cmake_host_system_information(RESULT result
QUERY WINDOWS_REGISTRY "HKLM/SOFTWARE/Kitware")
# query default value for HKLM/SOFTWARE/Kitware key using special value name
cmake_host_system_information(RESULT result
QUERY WINDOWS_REGISTRY "HKLM/SOFTWARE/Kitware"
VALUE "(default)")
Supported types are:
REG_SZ.REG_EXPAND_SZ. The returned data is expanded.REG_MULTI_SZ. The returned value is expressed as a CMake list. See also theSEPARATORsub-option.REG_DWORD.REG_QWORD.
For all other types, an empty string is returned. ๐
VIEWโ Specify which registry views must be queried. When not specified, theBOTHview is used.64โ Query the 64bit registry. On 32bit Windows, always returns an empty string.32โ Query the 32bit registry.64_32โ For theVALUEsub-option or default value, query the registry using view64, and if the request failed, query the registry using view32. For theVALUE_NAMESandSUBKEYSsub-options, query both views (64and32) and merge the results (sorted and duplicates removed).32_64โ For theVALUEsub-option or default value, query the registry using view32, and if the request failed, query the registry using view64. For theVALUE_NAMESandSUBKEYSsub-options, query both views (32and64) and merge the results (sorted and duplicates removed).HOSTโ Query the registry matching the architecture of the host:64on 64bit Windows and32on 32bit Windows.TARGETโ Query the registry matching the architecture specified by theCMAKE_SIZEOF_VOID_Pvariable. If not defined, fallback to theHOSTview. ๐ซ
BOTHโ query both views, the 32-bit one and the 64-bit one ๐ the order it comes out in depends on these rules: if theCMAKE_SIZEOF_VOID_Pvariable is defined, it picks the view off whatever's inside it:8:64_324:32_64
and if CMAKE_SIZEOF_VOID_P is not defined, it just trusts the host architecture instead:
- 64bit:
64_32 - 32bit:
32
SEPARATORโ sets the separator character for theREG_MULTI_SZtype โจ if you don't specify one, the character\0is used, bestie.ERROR_VARIABLE <result>โ hands you back any error that popped up during the query operation ๐ซถ in case of success, the variable holds an empty string (so like, an empty string = we slayed).
๐ cmake_language
Added in version 3.18.
Call meta-operations on CMake commands. Yes, commands about commands, it's giving inception energy ๐
Synopsis
cmake_language(CALL <command> [<arg>...])
cmake_language(EVAL CODE <code>...)
cmake_language(DEFER <options>... CALL <command> [<arg>...])
cmake_language(SET_DEPENDENCY_PROVIDER <command> SUPPORTED_METHODS <methods>...)
cmake_language(GET_MESSAGE_LOG_LEVEL <out-var>)
cmake_language(EXIT <exit-code>)
cmake_language(TRACE <boolean> ...)
๐ธ Introduction
This command calls meta-operations on the built-in CMake commands, or on the ones you made yourself via the macro() or function() commands ๐ฅ
Big heads-up: cmake_language does not introduce a new variable or policy scope. It's a vibe, not a scope ๐
๐ฃ Calling Commands
cmake_language(CALL <command> [<arg>...]) โ calls the named <command> with the given arguments (if there are any). So like, this code:
set(message_command "message")
cmake_language(CALL ${message_command} STATUS "Hello World!")
is equivalent to
message(STATUS "Hello World!")
Note: to keep the code consistent, these commands are not allowed: -if/elseif/else/endif-block/endblock-while/endwhile-foreach/endforeach-function/endfunction-macro/endmacro
๐ง Evaluating Code
cmake_language(EVAL CODE <code>...) โ evaluates the <code>... as CMake code ๐ซ
For example, this:
set(A TRUE)
set(B TRUE)
set(C TRUE)
set(condition "(A AND B) OR C")
cmake_language(EVAL CODE "
if (${condition})
message(STATUS TRUE)
else()
message(STATUS FALSE)
endif()"
)
is equivalent to
set(A TRUE)
set(B TRUE)
set(C TRUE)
set(condition "(A AND B) OR C")
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/eval.cmake "
if (${condition})
message(STATUS TRUE)
else()
message(STATUS FALSE)
endif()"
)
include(${CMAKE_CURRENT_BINARY_DIR}/eval.cmake)
โณ Deferring Calls
Added in version 3.19.
cmake_language(DEFER <options>... CALL <command> [<arg>...]) โ schedules a call to the named <command> with the given arguments (if any) so it happens later ๐ by default, deferred calls execute as if they were written at the very end of the current directory's CMakeLists.txt file โ except they run even after a return() call. And the variable references in the arguments? Those get evaluated at the time the deferred call actually executes. Delayed gratification, truly ๐
The options are:
DIRECTORY <dir>โ schedule the call for the end of the given directory instead of the current one. The<dir>may reference either a source directory or its corresponding binary directory. Relative paths are treated as relative to the current source directory.
The given directory has to be known to CMake โ either the top-level directory or one added by add_subdirectory(). And fr, the given directory must not be finished processing yet, meaning it can be the current directory or one of its ancestors ๐ซถ
ID <id>โ specify an identification for the deferred call. The<id>may not be empty and may not begin with a capital letterA-Z. The<id>may begin with an underscore (_) only if it was generated automatically by an earlier call that usedID_VARto get the id ๐ID_VAR <var>โ specify a variable in which to store the identification for the deferred call. IfID <id>is not given, a new identification gets generated, and that generated id will start with an underscore (_).
The currently scheduled list of deferred calls may be retrieved:
cmake_language(DEFER [DIRECTORY <dir>] GET_CALL_IDS <var>)
This stores in <var> a semicolon-separated list of deferred call ids ๐
the ids are for the directory scope in which the calls have been deferred to (i.e. where they will execute), which can be different from the scope where they were created. The DIRECTORY option lets you specify the scope to retrieve the call ids for. If you don't give that option, you get the call ids for the current directory scope.
Details of a specific call may be retrieved from its id:
cmake_language(DEFER [DIRECTORY <dir>] GET_CALL <id> <var>)
This stores in <var> a semicolon-separated list where the first element is the name of the command to be called, and the remaining elements are its unevaluated arguments (any contained ; characters are included literally and cannot be distinguished from multiple arguments). If multiple calls are scheduled with the same id, this retrieves the first one ๐ if no call is scheduled with the given id in the specified DIRECTORY scope (or the current directory scope if no DIRECTORY option is given), this stores an empty string in the variable.
Deferred calls may be canceled by their id:
cmake_language(DEFER [DIRECTORY <dir>] CANCEL_CALL <id>...)
This cancels all deferred calls matching any of the given ids in the specified DIRECTORY scope (or the current directory scope if no DIRECTORY option is given). Unknown ids are silently ignored โ no drama, no error ๐
๐ Deferred Call Examples
For example, the code:
cmake_language(DEFER CALL message "${deferred_message}")
cmake_language(DEFER ID_VAR id CALL message "Canceled Message")
cmake_language(DEFER CANCEL_CALL ${id})
message("Immediate Message")
set(deferred_message "Deferred Message")
prints:
Immediate Message
Deferred Message
The Canceled Message is never printed because its command is canceled โ๏ธ and the deferred_message variable reference isn't evaluated until the call site, so it can be set after the deferred call is scheduled. Iconic behaviour, honestly.
In order to evaluate variable references immediately when scheduling a deferred call, wrap it using cmake_language(EVAL). But heads-up: the arguments will be re-evaluated in the deferred call, though you can dodge that by using bracket arguments. For example:
set(deferred_message "Deferred Message 1")
set(re_evaluated [[${deferred_message}]])
cmake_language(EVAL CODE "
cmake_language(DEFER CALL message [[${deferred_message}]])
cmake_language(DEFER CALL message \"${re_evaluated}\")
")
message("Immediate Message")
set(deferred_message "Deferred Message 2")
also prints:
Immediate Message
Deferred Message 1
Deferred Message 2
๐ Dependency Providers
Added in version 3.24.
Note: a high-level introduction to this feature can be found in the Using Dependencies Guide.
cmake_language(SET_DEPENDENCY_PROVIDER <command> SUPPORTED_METHODS <methods>...) โ when a call is made to find_package() or FetchContent_MakeAvailable(), that call may be forwarded to a dependency provider, which then gets the chance to fulfill the request ๐ฅ if the request is for one of the <methods> specified when the provider was set, CMake calls the provider's <command> with a set of method-specific arguments. If the provider doesn't fulfill the request, or if it doesn't support the request's method, or if no provider is set at all, then the built-in find_package() or FetchContent_MakeAvailable() implementation is used to fulfill the request the usual way.
One or more of these values can be specified for the <methods> when setting the provider:
FIND_PACKAGEโ the provider command acceptsfind_package()requests ๐FETCHCONTENT_MAKEAVAILABLE_SERIALโ the provider command acceptsFetchContent_MakeAvailable()requests. It expects each dependency to be fed to the provider command one at a time, not the whole list in one go. One at a time, bestie, let it breathe ๐
Only one provider can be set at any point in time. If a provider is already set when cmake_language(SET_DEPENDENCY_PROVIDER) is called, the new provider replaces the previously set one ๐ the specified <command> must already exist when cmake_language(SET_DEPENDENCY_PROVIDER) is called. As a special case, providing an empty string for the <command> and no <methods> will discard any previously set provider โ poof, gone ๐ซฅ
The dependency provider can only be set while processing one of the files specified by the CMAKE_PROJECT_TOP_LEVEL_INCLUDES variable. So basically, dependency providers can only be set as part of the first call to project(). Calling cmake_language(SET_DEPENDENCY_PROVIDER) outside of that context will result in an error ๐ญ so like, read the room.
Added in version 3.30: the PROPAGATE_TOP_LEVEL_INCLUDES_TO_TRY_COMPILE global property can be set if your dependency provider also wants to be enabled in whole-project calls to try_compile(). ๐ซถ
Note: the choice of dependency provider should always be under the user's control, bestie. As a convenience, a project may choose to provide a file that users can list in their CMAKE_PROJECT_TOP_LEVEL_INCLUDES variable โ but the use of such a file should always be the user's choice. No sneaking. ๐
๐ ๏ธ Provider commands ๐ ๏ธ
Providers define a single <command> to accept requests. The name of the command should be specific to that provider โ not something overly generic that another provider might also use. This enables users to compose different providers in their own custom provider (iconic behaviour, honestly โจ). The recommended form is xxx_provide_dependency(), where xxx is the provider-specific part โ e.g. vcpkg_provide_dependency(), conan_provide_dependency(), ourcompany_provide_dependency(), and so on.
xxx_provide_dependency(<method> [<method-specific-args>...])
Because some methods expect certain variables to be set in the calling scope, the provider command should typically be implemented as a macro rather than a function. This ensures it does not introduce a new variable scope. ๐
The arguments CMake passes to the dependency provider depend on the type of request. The first argument is always the method, and it will only ever be one of the <methods> that was specified when setting the provider.
๐ FIND_PACKAGE ๐
The <method-specific-args> will be everything passed to the find_package() call that requested the dependency. The first of these <method-specific-args> will therefore always be the name of the dependency. Dependency names are case-sensitive for this method because find_package() treats them case-sensitively too. fr fr, no cap.
If the provider command fulfills the request, it must set the same variable that find_package() expects to be set. For a dependency named depName, the provider must set depName_FOUND to true if it fulfilled the request. If the provider returns without setting this variable, CMake will assume the request was not fulfilled and will fall back to the built-in implementation. ๐
If the provider needs to call the built-in find_package() implementation as part of its processing, it can do so by including the BYPASS_PROVIDER keyword as one of the arguments. ๐ฆ
๐ง FETCHCONTENT_MAKEAVAILABLE_SERIAL ๐ง
The <method-specific-args> will be everything passed to the FetchContent_Declare() call that corresponds to the requested dependency, with the following exceptions:
- If
SOURCE_DIRorBINARY_DIRwere not part of the original declared arguments, they will be added with their default values. - If
FETCHCONTENT_TRY_FIND_PACKAGE_MODEis set toNEVER, anyFIND_PACKAGE_ARGSwill be omitted. - The
OVERRIDE_FIND_PACKAGEkeyword is always omitted.
The first of the <method-specific-args> will always be the name of the dependency. Dependency names are case-insensitive for this method because FetchContent also treats them case-insensitively. ๐ซถ
If the provider fulfills the request, it should call FetchContent_SetPopulated(), passing the name of the dependency as the first argument. The SOURCE_DIR and BINARY_DIR arguments to that command should only be given if the provider makes the dependency's source and build directories available in exactly the same way as the built-in FetchContent_MakeAvailable() command. ๐ญ
If the provider returns without calling FetchContent_SetPopulated() for the named dependency, CMake will assume the request was not fulfilled and will fall back to the built-in implementation.
Note: empty arguments may be significant for this method (e.g. an empty string following a GIT_SUBMODULES keyword). So if you're forwarding these arguments on to another command, extra care must be taken to avoid such arguments being silently dropped. โ ๏ธ
If FETCHCONTENT_SOURCE_DIR_<uppercaseDepName> is set, then the dependency provider will never see requests for the <depName> dependency for this method. When the user sets such a variable, they are explicitly overriding where to get that dependency from and are taking on the responsibility that their overriding version meets any requirements for that dependency and is compatible with whatever else in the project uses it. Depending on the value of FETCHCONTENT_TRY_FIND_PACKAGE_MODE and whether the OVERRIDE_FIND_PACKAGE option was given to FetchContent_Declare(), having FETCHCONTENT_SOURCE_DIR_<uppercaseDepName> set may also prevent the dependency provider from seeing requests for a find_package(depName) call too. ๐
๐ Provider Examples ๐
This first example only intercepts find_package() calls. The provider command runs an external tool which copies the relevant artifacts into a provider-specific directory, if that tool knows about the dependency. It then relies on the built-in implementation to then find those artifacts. FetchContent_MakeAvailable() calls would not go through the provider, bestie. ๐
โโ๏ธ
mycomp_provider.cmake
# Always ensure we have the policy settings this provider expects
cmake_minimum_required(VERSION 3.24)
set(MYCOMP_PROVIDER_INSTALL_DIR ${CMAKE_BINARY_DIR}/mycomp_packages
CACHE PATH "The directory this provider installs packages to"
)
# Tell the built-in implementation to look in our area first, unless
# the find_package() call uses NO_..._PATH options to exclude it
list(APPEND CMAKE_MODULE_PATH ${MYCOMP_PROVIDER_INSTALL_DIR}/cmake)
list(APPEND CMAKE_PREFIX_PATH ${MYCOMP_PROVIDER_INSTALL_DIR})
macro(mycomp_provide_dependency method package_name)
execute_process(
COMMAND some_tool ${package_name} --installdir ${MYCOMP_PROVIDER_INSTALL_DIR}
COMMAND_ERROR_IS_FATAL ANY
)
endmacro()
cmake_language(
SET_DEPENDENCY_PROVIDER mycomp_provide_dependency
SUPPORTED_METHODS FIND_PACKAGE
)
The user would then typically use the above file like so:
cmake -DCMAKE_PROJECT_TOP_LEVEL_INCLUDES=/path/to/mycomp_provider.cmake ...
The next example demonstrates a provider that accepts both methods, but only handles one specific dependency. It enforces providing Google Test using FetchContent, but leaves all other dependencies to be fulfilled by CMake's built-in implementation. It accepts a few different names, which demonstrates one way of working around projects that hard-code an unusual or undesirable way of adding this particular dependency to the build. The example also demonstrates how to use the list() command to preserve variables that may be overwritten by a call to FetchContent_MakeAvailable(). ๐ธ
mycomp_provider.cmake
cmake_minimum_required(VERSION 3.24)
# Because we declare this very early, it will take precedence over any
# details the project might declare later for the same thing
include(FetchContent)
FetchContent_Declare(
googletest
GIT_REPOSITORY https://github.com/google/googletest.git
GIT_TAG e2239ee6043f73722e7aa812a459f54a28552929 # release-1.11.0
)
# Both FIND_PACKAGE and FETCHCONTENT_MAKEAVAILABLE_SERIAL methods provide
# the package or dependency name as the first method-specific argument.
macro(mycomp_provide_dependency method dep_name)
if("${dep_name}" MATCHES "^(gtest|googletest)$")
# Save our current command arguments in case we are called recursively
list(APPEND mycomp_provider_args ${method} ${dep_name})
# This will forward to the built-in FetchContent implementation,
# which detects a recursive call for the same thing and avoids calling
# the provider again if dep_name is the same as the current call.
FetchContent_MakeAvailable(googletest)
# Restore our command arguments
list(POP_BACK mycomp_provider_args dep_name method)
# Tell the caller we fulfilled the request
if("${method}" STREQUAL "FIND_PACKAGE")
# We need to set this if we got here from a find_package() call
# since we used a different method to fulfill the request.
# This example assumes projects only use the gtest targets,
# not any of the variables the FindGTest module may define.
set(${dep_name}_FOUND TRUE)
elseif(NOT "${dep_name}" STREQUAL "googletest")
# We used the same method, but were given a different name to the
# one we populated with. Tell the caller about the name it used.
FetchContent_SetPopulated(${dep_name}
SOURCE_DIR "${googletest_SOURCE_DIR}"
BINARY_DIR "${googletest_BINARY_DIR}"
)
endif()
endif()
endmacro()
cmake_language(
SET_DEPENDENCY_PROVIDER mycomp_provide_dependency
SUPPORTED_METHODS
FIND_PACKAGE
FETCHCONTENT_MAKEAVAILABLE_SERIAL
)
The final example demonstrates how to modify arguments to a find_package() call. It forces all such calls to have the QUIET keyword. It uses the BYPASS_PROVIDER keyword to prevent calling the provider command recursively for the same dependency. ๐ฅ
mycomp_provider.cmake
cmake_minimum_required(VERSION 3.24)
macro(mycomp_provide_dependency method)
find_package(${ARGN} BYPASS_PROVIDER QUIET)
endmacro()
cmake_language(
SET_DEPENDENCY_PROVIDER mycomp_provide_dependency
SUPPORTED_METHODS FIND_PACKAGE
)
๐ Getting current message log level ๐
Added in version 3.25. ๐
`cmake_language(GET_MESSAGE_LOG_LEVEL <output_variable>)
Okay so this one is basically a little spy ๐ต๏ธ โ it takes the current message() logging level and drops it right into the <output_variable> you hand it.
Want the full menu of possible levels? That lives over in message() โ go peek there.
And where does that current level even come from, you ask? Two places, bestie:
- the
--log-levelcommand line option of thecmake(1)program, or - the
CMAKE_MESSAGE_LOG_LEVELvariable.
If both are set, the command line option wins โ takes precedence, periodt. If neither is set, you just get the default logging level back. Slay. โจ
Terminating Scripts
๐ Added in version 3.29.
cmake_language(EXIT <exit-code>)
This is the "okay I'm done here" button ๐
โ it terminates the current cmake -P script and exits with <exit-code>.
Heads up: this command works only in script mode. Use it outside that context and it'll cause a fatal error. No cap.
Now about the code itself: <exit-code> should be non-negative. If it's negative, the behavior is unspecified โ like, on Windows the error code -1 becomes 0xffffffff, and on Linux it becomes 255. Chaos. ๐ญ
Also, exit codes above 255 may not be supported by the underlying shell or platform, and some shells may interpret values above 125 specially. So the vibe is: only specify an <exit-code> in the range 0 to 125. Trust. ๐ซถ
Trace Control
๐ Added in version 4.2.
cmake_language(TRACE ON [EXPAND])
cmake_language(TRACE OFF)
The TRACE subcommand controls runtime tracing of executed CMake commands and macros within the current process. When you turn it on, the trace output gets written in the exact same format as if CMake had been started with the cmake --trace or cmake --trace-expand command line options. Same energy, same format. ๐
Tracing scopes are nestable โ multiple TRACE ON calls can be active at the same time, and each TRACE OFF deactivates one nesting level. It's giving stack energy, honestly. ๐
Important caveat: if CMake is run withcmake --traceorcmake --trace-expand, those options override and force tracing globally, regardless of anycmake_language(TRACE OFF)calls. In those cases, the command may still be invoked but has no effect on the trace state. Iconic but powerless. ๐
โญ cmake_minimum_required โญ
Require a minimum version of cmake โ the classic "hey bestie, you gotta be at least this new" command.
cmake_minimum_required(VERSION <min>[...<policy_max>] [FATAL_ERROR])
๐ Added in version 3.12: the optional <policy_max> version behavior โ again, this gets ignored in older CMake.
So what does it actually do? It sets the minimum required version of cmake for a project. And it also updates the policy settings, as explained below. ๐
<min> and the optional <policy_max> are each CMake versions of the form major.minor[.patch[.tweak]], and the ... is literal.
If the running version of CMake is lower than the <min> required version, it will stop processing the project and report an error. Bye. ๐
The optional <policy_max> version, if specified, must be at least the <min> version and sets the Policy Version. If the running version of CMake is older than 3.12, the extra ... dots will be seen as version component separators, resulting in the ...<policy_max> part being ignored and preserving the pre-3.12 behavior of basing policies on <min>. Old-school vibes, honestly.
This command will set the value of the CMAKE_MINIMUM_REQUIRED_VERSION variable to <min>.
The FATAL_ERROR option is accepted but ignored by CMake 2.6 and higher. It should be specified so CMake versions 2.4 and lower fail with an error instead of just a warning. Legacy lore ๐ง
Note: Call thecmake_minimum_required()command at the beginning of the top-levelCMakeLists.txtfile โ even before calling theproject()command. It is important to establish version and policy settings before invoking other commands whose behavior they may affect. See also policyCMP0000. Callingcmake_minimum_required()inside afunction()limits some effects to the function scope when invoked. For example, theCMAKE_MINIMUM_REQUIRED_VERSIONvariable won't be set in the calling scope. Functions do not introduce their own policy scope though, so policy settings of the caller will be affected (see below). Due to this mix of things that do and do not affect the calling scope, callingcmake_minimum_required()inside a function is generally discouraged. ๐
Policy Version
Here's the tea โ โ cmake_minimum_required(VERSION <min>[...<policy_max>]) implicitly invokes:
cmake_policy(VERSION <min>[...<policy_max>])
This specifies that the current CMake code is written for the given range of CMake versions, <min>[...<policy_max>]. It sets the "policy version" to:
- the range's
<policy_max>version, if specified, or to - the
<min>version, or to - the value of the
CMAKE_POLICY_VERSION_MINIMUMvariable if it is higher than the other two versions.
The policy version effectively requests behavior preferred as of a given CMake version and tells newer CMake versions to warn about their new policies. All policies known to the running version of CMake and introduced in the policy version or earlier will be set to use NEW behavior. All policies introduced in later versions will be unset (unless the CMAKE_POLICY_DEFAULT_CMP<NNNN> variable sets a default). ๐
Note: ...<policy_max> does not signify that later CMake versions are forbidden. It merely specifies the highest CMake version for which the project or module has been actively updated and maintained. It's a "we've touched this recently" badge, not a lock. ๐ฅ
Changed in version 4.0: Compatibility with versions of CMake older than 3.5 is removed. Calls to cmake_minimum_required(VERSION) or cmake_policy(VERSION) that do not specify at least 3.5 as their policy version (optionally via ...<policy_max>) will produce an error in CMake 4.0 and above. ๐
Changed in version 3.31: Compatibility with versions of CMake older than 3.10 is deprecated. Calls to cmake_minimum_required(VERSION) or cmake_policy(VERSION) that do not specify at least 3.10 as their policy version (optionally via ...<policy_max>) will produce a deprecation warning in CMake 3.31 and above.
Changed in version 3.27: Compatibility with versions of CMake older than 3.5 is deprecated. Calls to cmake_minimum_required(VERSION) or cmake_policy(VERSION) that do not specify at least 3.5 as their policy version (optionally via ...<policy_max>) will produce a deprecation warning in CMake 3.27 and above.
Changed in version 3.19: Compatibility with versions of CMake older than 2.8.12 is deprecated. Calls to cmake_minimum_required(VERSION) or cmake_policy(VERSION) that do not specify at least 2.8.12 as their policy version (optionally via ...<policy_max>) will produce a deprecation warning in CMake 3.19 and above. ๐ธ
See Also
cmake_policy()
๐ cmake_parse_arguments ๐
Parse function or macro arguments โ the group-chat translator for your arguments, fr fr.
cmake_parse_arguments(<prefix> <options> <one_value_keywords>
<multi_value_keywords> <args>...)
cmake_parse_arguments(PARSE_ARGV <N> <prefix> <options>
<one_value_keywords> <multi_value_keywords>)
cmake_parse_arguments(PARSE_ARGN <prefix> <options>
<one_value_keywords> <multi_value_keywords>)
๐ Added in version 3.5: This command is implemented natively. Previously, it has been defined in the module CMakeParseArguments.
This command is for use in macros or functions. It processes the arguments given to that macro or function, and defines a set of variables which hold the values of the respective options. It's literally the friend who reads the whole group chat and summarizes it for you. ๐ซถ
The first signature reads arguments passed in <args>.... This may be used in either a macro() or a function().
๐ Added in version 3.7: The PARSE_ARGV signature is only for use in a function() body. In this case, the arguments that are parsed come from the ARGV# variables of the calling function. The parsing starts with the <N>-th argument, where <N> is an unsigned integer. This allows for the values to have special characters like ; in them. Semi-colon slay. ๐
๐ Added in version 4.4: The PARSE_ARGN signature is only for use in a function() body. This starts parsing after the last named argument of the calling function and works exactly like PARSE_ARGV with <N> being the number of parameters in the function definition.
So like, what are these keyword buckets?
- The
<options>argument contains all options for the respective function or macro. These are keywords that have no value following them, like theOPTIONALkeyword of theinstall()command. - The
<one_value_keywords>argument contains all keywords for this function or macro which are followed by one value, like theDESTINATIONkeyword of theinstall()command. - The
<multi_value_keywords>argument contains all keywords for this function or macro which can be followed by more than one value, like theTARGETSorFILESkeywords of theinstall()command.
Changed in version 3.5: All keywords must be unique. Each keyword can only be specified once in any of the <options>, <one_value_keywords>, or <multi_value_keywords>. A warning will be emitted if uniqueness is violated. Keep them separated, bestie โ no keyword is doing double duty. ๐ซ
When done, cmake_parse_arguments will consider for each of the keywords listed in <options>, <one_value_keywords>, and <multi_value_keywords>, a variable composed of the given <prefix> followed by "_" and the name of the respective keyword. For <one_value_keywords> and <multi_value_keywords>, these variables will then hold the respective value(s) from the argument list, or be undefined if the associated keyword was not given (policy CMP0174 can also affect the behavior for <one_value_keywords>). For the <options> keywords, these variables will always be defined, and they will be set to TRUE if the keyword is present, or FALSE if it is not. โ
โ
All remaining arguments are collected in a variable <prefix>_UNPARSED_ARGUMENTS that will be undefined if all arguments were recognized. This can be checked afterwards to see whether your macro or function was called with unrecognized parameters. It's giving "leftover receipts" energy. ๐งพ
okay so Added in version 3.15: the <one_value_keywords> and <multi_value_keywords> that were given, like, no values at all get collected into a variable called <prefix>_KEYWORDS_MISSING_VALUES, and that variable is undefined if every keyword actually got a value. You can check it to see if any keywords were missing their values, bestie.
Changed in version 3.31: if a <one_value_keyword> is followed by an empty string as its value, policy CMP0174 <#policy:CMP0174> controls whether a corresponding <prefix>_<keyword> variable gets defined or not.
Choose a <prefix> carefully so you donโt clash with existing variable names. When youโre inside a function, itโs usually suitable to use the prefix arg. There is a very strong convention that all keywords are fully uppercase, so this prefix results in variables of the form arg_SOME_KEYWORD. This makes the code more readable, and it minimizes the chance of clashing with cache variables, which also have a very strong convention of being all uppercase.
function(my_install)
set(options OPTIONAL FAST)
set(oneValueArgs DESTINATION RENAME)
set(multiValueArgs TARGETS CONFIGURATIONS)
cmake_parse_arguments(PARSE_ARGV 0 arg
"${options}" "${oneValueArgs}" "${multiValueArgs}"
)
# The above will set or unset variables with the following names:
# arg_OPTIONAL
# arg_FAST
# arg_DESTINATION
# arg_RENAME
# arg_TARGETS
# arg_CONFIGURATIONS
#
# The following will also be set or unset:
# arg_UNPARSED_ARGUMENTS
# arg_KEYWORDS_MISSING_VALUES
When itโs used inside a macro, arg might not be a suitable prefix because the code will affect the calling scope. If another macro also called in the same scope were to use arg in its own call to cmake_parse_arguments(), and if there are any common keywords between the two macros, the later callโs variables can overwrite or remove those of the earlier macroโs call. So it is advisable to incorporate something unique from the macro name in the <prefix>, such as arg_lowercase_macro_name.
macro(my_install)
set(options OPTIONAL FAST)
set(oneValueArgs DESTINATION RENAME)
set(multiValueArgs TARGETS CONFIGURATIONS)
cmake_parse_arguments(arg_my_install
"${options}" "${oneValueArgs}" "${multiValueArgs}"
${ARGN}
)
# ...
endmacro()
macro(my_special_install)
# NOTE: Has the same keywords as my_install()
set(options OPTIONAL FAST)
set(oneValueArgs DESTINATION RENAME)
set(multiValueArgs TARGETS CONFIGURATIONS)
cmake_parse_arguments(arg_my_special_install
"${options}" "${oneValueArgs}" "${multiValueArgs}"
${ARGN}
)
# ...
endmacro()
Suppose the above macros are called one after the other, like so:
my_install(TARGETS foo bar DESTINATION bin OPTIONAL blub CONFIGURATIONS)
my_special_install(TARGETS barry DESTINATION sbin RENAME FAST)
After these two calls, the following describes the variables that will be set or unset:
arg_my_install_OPTIONAL = TRUE
arg_my_install_FAST = FALSE # was not present in call to my_install
arg_my_install_DESTINATION = "bin"
arg_my_install_RENAME <UNSET> # was not present
arg_my_install_TARGETS = "foo;bar"
arg_my_install_CONFIGURATIONS <UNSET> # was not present
arg_my_install_UNPARSED_ARGUMENTS = "blub" # nothing expected after "OPTIONAL"
arg_my_install_KEYWORDS_MISSING_VALUES = "CONFIGURATIONS" # value was missing
arg_my_special_install_OPTIONAL = FALSE # was not present
arg_my_special_install_FAST = TRUE
arg_my_special_install_DESTINATION = "sbin"
arg_my_special_install_RENAME <UNSET> # value was missing
arg_my_special_install_TARGETS = "barry"
arg_my_special_install_CONFIGURATIONS <UNSET> # was not present
arg_my_special_install_UNPARSED_ARGUMENTS <UNSET>
arg_my_special_install_KEYWORDS_MISSING_VALUES = "RENAME"
Keywords terminate lists of values. If a keyword is given directly after a <one_value_keyword>, that preceding <one_value_keyword> receives no value and the keyword is added to the <prefix>_KEYWORDS_MISSING_VALUES variable. In the above example, the call to my_special_install() contains the RENAME keyword immediately followed by the FAST keyword. In this case, FAST terminates processing of the RENAME keyword. arg_my_special_install_FAST is set to TRUE, arg_my_special_install_RENAME is unset, and arg_my_special_install_KEYWORDS_MISSING_VALUES contains the value RENAME.
๐ See Also ๐
function()<#command:function>macro()<#command:macro>
๐ cmake_path ๐
Added in version 3.20.
This command is for the manipulation of paths. Only syntactic aspects of paths are handled โ there is no interaction of any kind with any underlying file system. The path may represent a non-existing path or even one that is not allowed to exist on the current file system or platform. For operations that do interact with the filesystem, see the file() <#command:file> command.
Note: The cmake_path command handles paths in the format of the build system (i.e. the host platform), not the target system. When cross-compiling, if the path contains elements that are not representable on the host platform (e.g. a drive letter when the host is not Windows), the results will be unpredictable.
โจ Synopsis โจ
Conventions
Path Structure And Terminology
Normalization
Decomposition
cmake_path(GET <path-var> ROOT_NAME <out-var>)
cmake_path(GET <path-var> ROOT_DIRECTORY <out-var>)
cmake_path(GET <path-var> ROOT_PATH <out-var>)
cmake_path(GET <path-var> FILENAME <out-var>)
cmake_path(GET <path-var> EXTENSION [LAST_ONLY] <out-var>)
cmake_path(GET <path-var> STEM [LAST_ONLY] <out-var>)
cmake_path(GET <path-var> RELATIVE_PART <out-var>)
cmake_path(GET <path-var> PARENT_PATH <out-var>)
Query
cmake_path(HAS_ROOT_NAME <path-var> <out-var>)
cmake_path(HAS_ROOT_DIRECTORY <path-var> <out-var>)
cmake_path(HAS_ROOT_PATH <path-var> <out-var>)
cmake_path(HAS_FILENAME <path-var> <out-var>)
cmake_path(HAS_EXTENSION <path-var> <out-var>)
cmake_path(HAS_STEM <path-var> <out-var>)
cmake_path(HAS_RELATIVE_PART <path-var> <out-var>)
cmake_path(HAS_PARENT_PATH <path-var> <out-var>)
cmake_path(IS_ABSOLUTE <path-var> <out-var>)
cmake_path(IS_RELATIVE <path-var> <out-var>)
cmake_path(IS_PREFIX <path-var> <input> [NORMALIZE] <out-var>)
Comparison
cmake_path(COMPARE <input1> <op> <input2> <out-var>)
Modification
cmake_path(SET <path-var> [NORMALIZE] <input>)
cmake_path(APPEND <path-var> [<input>...] [OUTPUT_VARIABLE <out-var>])
cmake_path(APPEND_STRING <path-var> [<input>...] [OUTPUT_VARIABLE <out-var>])
cmake_path(REMOVE_FILENAME <path-var> [OUTPUT_VARIABLE <out-var>])
cmake_path(REPLACE_FILENAME <path-var> <input> [OUTPUT_VARIABLE <out-var>])
cmake_path(REMOVE_EXTENSION <path-var> [LAST_ONLY] [OUTPUT_VARIABLE <out-var>])
cmake_path(REPLACE_EXTENSION <path-var> [LAST_ONLY] <input> [OUTPUT_VARIABLE <out-var>])
Generation
cmake_path(NORMAL_PATH <path-var> [OUTPUT_VARIABLE <out-var>])
cmake_path(RELATIVE_PATH <path-var> [BASE_DIRECTORY <input>] [OUTPUT_VARIABLE <out-var>])
cmake_path(ABSOLUTE_PATH <path-var> [BASE_DIRECTORY <input>] [NORMALIZE] [OUTPUT_VARIABLE <out-var>])
Native Conversion
cmake_path(NATIVE_PATH <path-var> [NORMALIZE] <out-var>)
cmake_path(CONVERT <input> TO_CMAKE_PATH_LIST <out-var> [NORMALIZE])
cmake_path(CONVERT <input> TO_NATIVE_PATH_LIST <out-var> [NORMALIZE])
Hashing
cmake_path(HASH <path-var> <out-var>)
๐ Conventions ๐
The following conventions are used in this commandโs documentation:
<path-var>โ always the name of a variable. For commands that expect a<path-var>as input, the variable must exist and it is expected to hold a single path.<input>โ a string literal which may contain a path, path fragment, or multiple paths with a special separator depending on the command. See the description of each command to see how this is interpreted.<input>...โ zero or more string literal arguments.<out-var>โ the name of a variable into which the result of a command will be written.
๐ฆ Path Structure And Terminology ๐ฆ
A path has the following structure (all components are optional, with some constraints):
root-name root-directory-separator (item-name directory-separator)* filename
root-nameโ identifies the root on a filesystem with multiple roots (such as"C:"or"//myserver"). It is optional.root-directory-separatorโ a directory separator that, if present, indicates that this path is absolute. If it is missing and the first element other than theroot-nameis anitem-name, then the path is relative.item-nameโ a sequence of characters that arenโt directory separators. This name may identify a file, a hard link, a symbolic link, or a directory. Two special cases are recognized:- The item name consisting of a single dot character
.is a directory name that refers to the current directory. - The item name consisting of two dot characters
..is a directory name that refers to the parent directory.
- The item name consisting of a single dot character
The (...)* pattern shown above is to indicate that there can be zero or more item names, with multiple items separated by a directory-separator. The ()* characters are not part of the path.
directory-separatorโ the only recognized directory separator is a forward slash character/. If this character is repeated, it is treated as a single directory separator. In other words,/usr///////libis the same as/usr/lib.filenameโ a path has a filename if it does not end with adirectory-separator. The filename is effectively the lastitem-nameof the path, so it can also be a hard link, symbolic link or a directory.
A filename can have an extension. By default, the extension is defined as the sub-string beginning at the left-most period (including the period) and until the end of the filename. In commands that accept a LAST_ONLY keyword, LAST_ONLY changes the interpretation to the sub-string beginning at the right-most period.
The following exceptions apply to the above interpretation:
- If the first character in the filename is a period, that period is ignored (i.e. a filename like
.profileis treated as having no extension). ๐ - If the filename is either
.or.., it has no extension. - The stem is the part of the filename before the extension. ๐ธ
- Some commands refer to a root-path. This is the concatenation of root-name and root-directory-separator, either or both of which can be empty. A relative-part refers to the full path with any root-path removed.
๐ Creating A Path Variable ๐
While a path can be created with care using an ordinary set() <# command:set> command, it is recommended to use cmake_path(SET) instead, as it automatically converts the path to the required form where required. The cmake_path(APPEND) subcommand may be another suitable alternative where a path needs to be constructed by joining fragments. The following example compares the three methods for constructing the same path:
set(path1 "${CMAKE_CURRENT_SOURCE_DIR}/data")
cmake_path(SET path2 "${CMAKE_CURRENT_SOURCE_DIR}/data")
cmake_path(APPEND path3 "${CMAKE_CURRENT_SOURCE_DIR}" "data")
Modification and Generation sub-commands can either store the result in-place, or in a separate variable named after an OUTPUT_VARIABLE keyword. All other sub-commands store the result in a mandatory <out-var> variable. ๐
Note ๐ซถ: Thecmake_pathcommand can be used directly with variables provided by CMake representing paths (e.g.,CMAKE_SOURCE_DIR <# variable:CMAKE_SOURCE_DIR>). However, since the command can modify these variables, and many of them have undefined behavior when modified, they should never be specified as an<out-var>, and only as the<path-var>when a separate<out-var>is specified. Seecmake-variables(7) <#manual:cmake-variables(7)>for the list of CMake variables and identifiers reserved by CMake.
๐ Normalization ๐
Some sub-commands support normalizing a path. The algorithm used to normalize a path is as follows:
- If the path is empty, stop (the normalized form of an empty path is also an empty path).
- Replace each directory-separator, which may consist of multiple separators, with a single
/(/a///b-->/a/b). - Remove each solitary period (
.) and any immediately following directory-separator (/a/./b/.-->/a/b). - Remove each item-name (other than
..) that is immediately followed by a directory-separator and a.., along with any immediately following directory-separator (/a/b/../c-->a/c). - If there is a root-directory, remove any
..and any directory-separators immediately following them. The parent of the root directory is treated as still the root directory (/../a-->/a). - If the last item-name is
.., remove any trailing directory-separator (../-->..). - If the path is empty by this stage, add a dot (normal form of
./is.).
๐งฉ Decomposition ๐งฉ
The following forms of the GET subcommand each retrieve a different component or group of components from a path. See Path Structure And Terminology for the meaning of each path component.
cmake_path(GET <path-var> ROOT_NAME <out-var>)
cmake_path(GET <path-var> ROOT_DIRECTORY <out-var>)
cmake_path(GET <path-var> ROOT_PATH <out-var>)
cmake_path(GET <path-var> FILENAME <out-var>)
cmake_path(GET <path-var> EXTENSION [LAST_ONLY] <out-var>)
cmake_path(GET <path-var> STEM [LAST_ONLY] <out-var>)
cmake_path(GET <path-var> RELATIVE_PART <out-var>)
cmake_path(GET <path-var> PARENT_PATH <out-var>)
If a requested component is not present in the path, an empty string will be stored in <out-var>. For example, only Windows systems have the concept of a root-name, so when the host machine is non-Windows, the ROOT_NAME subcommand will always return an empty string. ๐
For PARENT_PATH, if the HAS_RELATIVE_PART sub-command returns false, the result is a copy of <path-var>. Note that this implies that a root directory is considered to have a parent, with that parent being itself. Where HAS_RELATIVE_PART returns true, the result will essentially be <path-var> with one less element.
๐ฑ Root examples ๐ฑ
set(path "c:/a")
cmake_path(GET path ROOT_NAME rootName)
cmake_path(GET path ROOT_DIRECTORY rootDir)
cmake_path(GET path ROOT_PATH rootPath)
message("Root name is \"${rootName}\"")
message("Root directory is \"${rootDir}\"")
message("Root path is \"${rootPath}\"")
Root name is "c:"
Root directory is "/"
Root path is "c:/"
๐ Filename examples ๐
set(path "/a/b")
cmake_path(GET path FILENAME filename)
message("First filename is \"${filename}\"")
# Trailing slash means filename is empty
set(path "/a/b/")
cmake_path(GET path FILENAME filename)
message("Second filename is \"${filename}\"")
First filename is "b"
Second filename is ""
๐ฆ Extension and stem examples ๐ฆ
set(path "name.ext1.ext2")
cmake_path(GET path EXTENSION fullExt)
cmake_path(GET path STEM fullStem)
message("Full extension is \"${fullExt}\"")
message("Full stem is \"${fullStem}\"")
# Effect of LAST_ONLY
cmake_path(GET path EXTENSION LAST_ONLY lastExt)
cmake_path(GET path STEM LAST_ONLY lastStem)
message("Last extension is \"${lastExt}\"")
message("Last stem is \"${lastStem}\"")
# Special cases
set(dotPath "/a/.")
set(dotDotPath "/a/..")
set(someMorePath "/a/.some.more")
cmake_path(GET dotPath EXTENSION dotExt)
cmake_path(GET dotPath STEM dotStem)
cmake_path(GET dotDotPath EXTENSION dotDotExt)
cmake_path(GET dotDotPath STEM dotDotStem)
cmake_path(GET someMorePath EXTENSION someMoreExt)
cmake_path(GET someMorePath STEM someMoreStem)
message("Dot extension is \"${dotExt}\"")
message("Dot stem is \"${dotStem}\"")
message("Dot-dot extension is \"${dotDotExt}\"")
message("Dot-dot stem is \"${dotDotStem}\"")
message(".some.more extension is \"${someMoreExt}\"")
message(".some.more stem is \"${someMoreStem}\"")
Full extension is ".ext1.ext2"
Full stem is "name"
Last extension is ".ext2"
Last stem is "name.ext1"
Dot extension is ""
Dot stem is "."
Dot-dot extension is ""
Dot-dot stem is ".."
.some.more extension is ".more"
.some.more stem is ".some"
๐ Relative part examples ๐
set(path "c:/a/b")
cmake_path(GET path RELATIVE_PART result)
message("Relative part is \"${result}\"")
set(path "c/d")
cmake_path(GET path RELATIVE_PART result)
message("Relative part is \"${result}\"")
set(path "/")
cmake_path(GET path RELATIVE_PART result)
message("Relative part is \"${result}\"")
Relative part is "a/b"
Relative part is "c/d"
Relative part is ""
๐ Path traversal examples ๐
set(path "c:/a/b")
cmake_path(GET path PARENT_PATH result)
message("Parent path is \"${result}\"")
set(path "c:/")
cmake_path(GET path PARENT_PATH result)
message("Parent path is \"${result}\"")
Parent path is "c:/a"
Parent path is "c:/"
๐ Query ๐
Each of the GET subcommands has a corresponding HAS_... subcommand which can be used to discover whether a particular path component is present. See Path Structure And Terminology for the meaning of each path component.
cmake_path(HAS_ROOT_NAME <path-var> <out-var>)
cmake_path(HAS_ROOT_DIRECTORY <path-var> <out-var>)
cmake_path(HAS_ROOT_PATH <path-var> <out-var>)
cmake_path(HAS_FILENAME <path-var> <out-var>)
cmake_path(HAS_EXTENSION <path-var> <out-var>)
cmake_path(HAS_STEM <path-var> <out-var>)
cmake_path(HAS_RELATIVE_PART <path-var> <out-var>)
cmake_path(HAS_PARENT_PATH <path-var> <out-var>)
Each of the above follows the predictable pattern of setting <out-var> to true if the path has the associated component, or false otherwise. Note the following special cases:
- For
HAS_ROOT_PATH, a true result will only be returned if at least one of root-name or root-directory is non-empty. - For
HAS_PARENT_PATH, the root directory is also considered to have a parent, which will be itself. The result is true except if the path consists of just a filename.
cmake_path(IS_ABSOLUTE <path-var> <out-var>) โ Sets <out-var> to true if <path-var> is absolute. An absolute path is a path that unambiguously identifies the location of a file without reference to an additional starting location. On Windows, this means the path must have both a root-name and a root-directory-separator to be considered absolute. On other platforms, just a root-directory-separator is sufficient. Note that this means on Windows, IS_ABSOLUTE can be false while HAS_ROOT_DIRECTORY can be true. ๐
cmake_path(IS_RELATIVE <path-var> <out-var>) โ This will store the opposite of IS_ABSOLUTE in <out-var>.
cmake_path(IS_PREFIX <path-var> <input> [NORMALIZE] <out-var>) โ Checks if <path-var> is the prefix of <input>.
When the NORMALIZE option is specified, <path-var> and <input> are normalized before the check.
set(path "/a/b/c")
cmake_path(IS_PREFIX path "/a/b/c/d" result) # result = true
cmake_path(IS_PREFIX path "/a/b" result) # result = false
cmake_path(IS_PREFIX path "/x/y/z" result) # result = false
set(path "/a/b")
cmake_path(IS_PREFIX path "/a/c/../b" NORMALIZE result) # result = true
๐ Comparison ๐
cmake_path(COMPARE <input1> EQUAL <input2> <out-var>)
cmake_path(COMPARE <input1> NOT_EQUAL <input2> <out-var>)
Compares the lexical representations of two paths provided as string literals. No normalization is performed on either path, except multiple consecutive directory separators are effectively collapsed into a single separator. Equality is determined according to the following pseudo-code logic:
if(NOT <input1>.root_name() STREQUAL <input2>.root_name())
return FALSE
if(<input1>.has_root_directory() XOR <input2>.has_root_directory())
return FALSE
Return FALSE if a relative portion of <input1> is not lexicographically
equal to the relative portion of <input2>. This comparison is performed path
component-wise. If all of the components compare equal, then return TRUE.
Note ๐ : Unlike most othercmake_path()subcommands, theCOMPAREsubcommand takes literal strings as input, not the names of variables.
โจ Modification โจ
Okay bestie, this is where we actually change paths. Buckle up ๐
cmake_path(SET <path-var> [NORMALIZE] <input>)โ drops<input>into<path-var>. If<input>is a native path, it gets converted into a CMake-style path with forward slashes (/). On Windows, the long filename marker is taken into account. ๐ช
When the NORMALIZE option is specified, the path is normalized after the conversion.
For example:
set(native_path "c:\\a\\b/..\\c")
cmake_path(SET path "${native_path}")
message("CMake path is \"${path}\"")
cmake_path(SET path NORMALIZE "${native_path}")
message("Normalized CMake path is \"${path}\"")
Output:
CMake path is "c:/a/b/../c"
Normalized CMake path is "c:/a/c"
cmake_path(APPEND <path-var> [<input>...] [OUTPUT_VARIABLE <out-var>])โ appends all the<input>arguments to<path-var>using/as the directory-separator. Depending on the<input>, the previous contents of<path-var>may be discarded (yes, literally thrown away, no cap ๐). For each<input>argument, the following algorithm (pseudo-code) applies:
# <path> is the contents of <path-var>
if(<input>.is_absolute() OR
(<input>.has_root_name() AND
NOT <input>.root_name() STREQUAL <path>.root_name()))
replace <path> with <input>
return()
endif()
if(<input>.has_root_directory())
remove any root-directory and the entire relative path from <path>
elseif(<path>.has_filename() OR
(NOT <path-var>.has_root_directory() OR <path>.is_absolute()))
append directory-separator to <path>
endif()
append <input> omitting any root-name to <path>
See Creating A Path Variable for details on the output variable.
cmake_path(APPEND_STRING <path-var> [<input>...] [OUTPUT_VARIABLE <out-var>])โ appends all the<input>arguments to<path-var>without adding any directory-separator. Just raw gluing, no slash drama ๐ซถ
See Creating A Path Variable for details on the output variable.
cmake_path(REMOVE_FILENAME <path-var> [OUTPUT_VARIABLE <out-var>])โ removes the filename component (as returned byGET ... FILENAME) from<path-var>. After removal, any trailing directory-separator is left alone, if present. She's not touching it, she's just letting it be ๐ธ
HAS_FILENAME will return false for the result, whether stored in <out-var> or <path-var>.
For example:
set(path "/a/b")
cmake_path(REMOVE_FILENAME path)
message("First path is \"${path}\"")
# filename is now already empty, the following removes nothing
cmake_path(REMOVE_FILENAME path)
message("Second path is \"${path}\"")
Output:
First path is "/a/"
Second path is "/a/"
See Creating A Path Variable for details on the output variable.
cmake_path(REPLACE_FILENAME <path-var> <input> [OUTPUT_VARIABLE <out-var>])โ replaces the filename component from<path-var>with<input>. If<path-var>has no filename component (i.e.HAS_FILENAMEreturns false), the path is unchanged. The operation is equivalent to the following:
cmake_path(HAS_FILENAME path has_filename)
if(has_filename)
cmake_path(REMOVE_FILENAME path)
cmake_path(APPEND path "${input}")
endif()
See Creating A Path Variable for details on the output variable.
cmake_path(REMOVE_EXTENSION <path-var> [LAST_ONLY] [OUTPUT_VARIABLE <out-var>])โ removes the extension, if any, from<path-var>. Bye-bye.txtera ๐ฆ
See Creating A Path Variable for details on the output variable.
cmake_path(REPLACE_EXTENSION <path-var> [LAST_ONLY] <input> [OUTPUT_VARIABLE <out-var>])โ replaces the extension with<input>. Its effect is equivalent to the following:
cmake_path(REMOVE_EXTENSION path)
if(NOT input MATCHES "^\\.")
cmake_path(APPEND_STRING path ".")
endif()
cmake_path(APPEND_STRING path "${input}")
See Creating A Path Variable for details on the output variable.
๐ Generation ๐
Now we're generating new paths out of the ones we already have. Main character energy fr ๐ฅ
cmake_path(NORMAL_PATH <path-var> [OUTPUT_VARIABLE <out-var>])โ normalizes<path-var>according the steps described in Normalization.
See Creating A Path Variable for details on the output variable.
cmake_path(RELATIVE_PATH <path-var> [BASE_DIRECTORY <input>] [OUTPUT_VARIABLE <out-var>])โ modifies<path-var>to make it relative to theBASE_DIRECTORYargument. IfBASE_DIRECTORYis not specified, the default base directory will beCMAKE_CURRENT_SOURCE_DIR๐
For reference, the algorithm used to compute the relative path is the same as that used by C++ std::filesystem::path::lexically_relative (https://en.cppreference.com/cpp/filesystem/path/lexically_normal).
See Creating A Path Variable for details on the output variable.
cmake_path(ABSOLUTE_PATH <path-var> [BASE_DIRECTORY <input>] [NORMALIZE] [OUTPUT_VARIABLE <out-var>])โ if<path-var>is a relative path (IS_RELATIVEis true), it is evaluated relative to the given base directory specified by theBASE_DIRECTORYoption. IfBASE_DIRECTORYis not specified, the default base directory will beCMAKE_CURRENT_SOURCE_DIR๐
When the NORMALIZE option is specified, the path is normalized after the path computation.
โ ๏ธ Bestie, listen: becausecmake_path()does not access the filesystem, symbolic links are not resolved and any leading tilde is not expanded. To compute a real path with symbolic links resolved and leading tildes expanded, use thefile(REAL_PATH)command instead. ๐
See Creating A Path Variable for details on the output variable.
๐ฆ Native Conversion ๐ฆ
For commands in this section, native refers to the host platform, not the target platform when cross-compiling. Big distinction, don't get it twisted ๐
cmake_path(NATIVE_PATH <path-var> [NORMALIZE] <out-var>)โ converts a CMake-style<path-var>into a native path with platform-specific slashes (\on Windows hosts and/elsewhere). ๐ช๐ธ
When the NORMALIZE option is specified, the path is normalized before the conversion.
See Creating A Path Variable for details on the output variable.
cmake_path(CONVERT <input> TO_CMAKE_PATH_LIST <out-var> [NORMALIZE])โ converts a native<input>path into a CMake-style path with forward slashes (/).
On Windows hosts, the long filename marker is taken into account. The input can be a single path or a system search path like $ENV{PATH}. A search path will be converted to a semicolon-separated list (on non-Windows platforms, this essentially means : separators are replaced with ;). ๐ง
When the NORMALIZE option is specified, the path is normalized before the conversion.
See Creating A Path Variable for details on the output variable.
๐ Note: unlike most othercmake_path()subcommands, theCONVERTsubcommand takes a literal string as input, not the name of a variable. Yes, it's different, it's quirky, it's iconic ๐
cmake_path(CONVERT <input> TO_NATIVE_PATH_LIST <out-var> [NORMALIZE])โ converts a CMake-style<input>path into a native path with platform-specific slashes (\on Windows hosts and/elsewhere).
The input can be a single path or a semicolon-separated list. A list will be converted into a native search path (;-separated on Windows, :-separated on other platforms). โญ
When the NORMALIZE option is specified, the path is normalized before the conversion.
See Creating A Path Variable for details on the output variable.
๐ Note: unlike most othercmake_path()subcommands, theCONVERTsubcommand takes a literal string as input, not the name of a variable.
For example:
set(paths "/a/b/c" "/x/y/z")
cmake_path(CONVERT "${paths}" TO_NATIVE_PATH_LIST native_paths)
message("Native path list is \"${native_paths}\"")
Output on Windows:
Native path list is "\a\b\c;\x\y\z"
Output on all other platforms:
Native path list is "/a/b/c:/x/y/z"
๐ฅ Hashing ๐ฅ
cmake_path(HASH <path-var> <out-var>)โ computes a hash value of<path-var>such that for two pathsp1andp2that compare equal (COMPARE ... EQUAL), the hash value ofp1is equal to the hash value ofp2. The path is always normalized before the hash is computed. Consistent queen behavior, we love to see it ๐
See Creating A Path Variable for details on the output variable.
๐ cmake_pkg_config ๐
Added in version 3.31. โจ
Process pkg-config format package files. Yup, natively, no pkg-config binary required. She ate. ๐
๐ Synopsis ๐
cmake_pkg_config(EXTRACT <package> [<version>] [...])
cmake_pkg_config(POPULATE <package> [<version>] [...])
cmake_pkg_config(IMPORT <package> [<version>] [...])
๐ซ Introduction ๐ซ
This command generates CMake variables and targets from pkg-config format package files natively, without needing to invoke or even require the presence of a pkg-config implementation. ๐ง A <package> is either an absolute path to a package file, or a package name to be searched for using the typical pkg-config search patterns. The optional <version> string has the same format and semantics as a pkg-config style version specifier, with the exception that if no comparison operator is specified = is assumed. Lowkey convenient, ngl ๐
๐ฏ PkgConfig Targets ๐ฏ
cmake_pkg_config may recursively generate target-like names in the global scope in order to resolve a package IMPORT or POPULATE command. These names take the form of @foreign_pkgcfg::[<prefix>_]<package> and are exposed via the INTERFACE_LINK_LIBRARIES target property of an IMPORT-generated target. ๐
โ ๏ธ It is not possible to modify or address these pkg-config native targets via normal target-based commands. Limited control over their generation is possible via the POPULATE command, but modification should generally be performed inside the corresponding package file, not downstream in CMake. Don't try to fight it, bestie ๐ญ
Pkg-config targets are reused across commands. Once a given package name has been resolved via POPULATE or IMPORT (but not EXTRACT), all future requests for the corresponding package name by those commands will resolve to the previously generated pkg-config target. Cache behavior, we stan ๐ซถ
EXTRACT always does the whole package name lookup, no shortcuts โ that's the whole point, bestie: it's what lets you hunt down multiple installations of the same package when you've got a custom dependency management scheme going on. ๐
๐ Common Options ๐
There are multiple signatures for this command (we'll get to those, don't rush me), and a bunch of options are shared between them. Here's the tea:
EXACT/QUIET/REQUIREDโ the big three, let's break them down:- The
EXACToption requests that the version string be matched exactly (and yes, that includes the empty string, if you didn't provide a version at all) โ this overrides the typical pkg-config version comparison algorithm. It will ignore any comparison operator attached to the version string. Like, fully ignores it. ๐ - The
QUIEToption disables informational messages โ including the ones that tell you the package can't be found, if it isn'tREQUIRED. So no sad little "not found" note. ๐ญ - The
REQUIREDoption stops processing with an error message if the package cannot be found. No package, no vibes, we're done here. ๐
- The
STRICTNESS <mode>โ specifies how strictly the contents of the package files get verified during parsing and resolution. An invalid file, under the strictness mode you provided, will cause the command to fail. The possible modes are:STRICTโ closely mirrors the behavior of the original FDO pkg-config. Variables and keywords must be unique. Variables must be defined before they are used. TheName,Description, andVersionkeywords must be present. The overall structure of the file must be valid and parsable. Very "follow the rules" energy. ๐PERMISSIVEโ closely mirrors the behavior of the pkgconf implementation. Duplicate variables are overridden. Duplicate keywords are appended. Undefined variables resolve to empty strings. TheName,Description, andVersionkeywords must be present. The overall structure of the file must be valid and parsable. Chill but not too chill. ๐ธBEST_EFFORTโ same behavior asPERMISSIVEwith regards to duplicate or uninitialized variables and keywords, but will not fail under any conditions. Package files which requireBEST_EFFORTwill fail validation under all other major implementations and should be fixed. So like... it works, but it's giving "we need to talk about your file." ๐ฌ
The default strictness is PERMISSIVE.
ENV_MODEโ specifies which environment variables will be queried when running a given command. The possible modes are:FDOโ queries only the original set ofPKG_CONFIG_*environment variables used by the freedesktop.org pkg-config implementation. Strictly old-school. ๐PKGCONFโ queries the more extensive set of environment variables used by the pkgconf implementation. More to love. โจIGNOREโ ignores the presence, absence, and value of environment variables entirely. In all cases where an environment variable would be queried, it's treated as defined, but with a value of empty string for the purpose of the operation. This does not modify the current environment. For boolean environment variables, such asPKG_CONFIG_ALLOW_*, this means they are evaluated as truthy. โPKG_CONFIG_SYSROOT_PATHis a minor exception. WhenENV_MODE IGNOREis used, no root path prepending will occur by default andpc_sysrootdirremains defaulted to/.
Target-generating subcommands always ignore flag-filtering environment variables. The default environment mode is PKGCONF. ๐ซถ
PC_LIBDIR <path>...โ overrides the default search location for package files; also used to derive thepc_pathpackage variable. When this option is not provided, the default library directory is the first available of the following values:CMAKE_PKG_CONFIG_PC_LIB_DIRS- The
PKG_CONFIG_LIBDIRenvironment variable - The output of
pkg-config --variable pc_path pkg-config - A platform-dependent default value
PC_PATH <path>...โ overrides the supplemental package file directories, which will be prepended to the search path; also used to derive thepc_pathpackage variable. When this option is not provided, the default paths are the first available of the following values:CMAKE_PKG_CONFIG_PC_PATH- The
PKG_CONFIG_PATHenvironment variable - Empty list
DISABLE_UNINSTALLED <bool>โ overrides the search behavior for "uninstalled" package files. These are package files with an-uninstalledsuffix which describe packages integrated directly from a build tree. Normally such package files have higher priority than "installed" packages. WhenDISABLE_UNINSTALLEDis true, searching for "uninstalled" packages is disabled. When this option is not provided, the default search behavior is determined by the first available of the following values:CMAKE_PKG_CONFIG_DISABLE_UNINSTALLED- If the
PKG_CONFIG_DISABLE_UNINSTALLEDenvironment variable is defined the search is disabled, otherwise it is enabled.
PC_SYSROOT_DIR <path>โ overrides the root path which will be prepended to paths specified by-Icompile flags and-Llibrary search locations; also used to derive thepc_sysrootdirpackage variable. When this option is not provided, the default root path is provided by the first available of the following values:CMAKE_PKG_CONFIG_SYSROOT_DIR- The
PKG_CONFIG_SYSROOT_DIRenvironment variable - If no root path is available, nothing will be prepended to include or library directory paths and
pc_sysrootdirwill be set to/
TOP_BUILD_DIR <path>โ overrides the top build directory path used to derive thepc_top_builddirpackage variable. When this option is not provided, the default top build directory path is the first available of the following values:CMAKE_PKG_CONFIG_TOP_BUILD_DIR- The
PKG_CONFIG_TOP_BUILD_DIRenvironment variable - If no top build directory path is available, the
pc_top_builddirpackage variable is not set
PREFIX <name>โ specifying a prefix creates an independent collection of pkg-config targets, separate from previously populated targets. This enables multiple versions of a given package to co-exist โ for example, packages from different sysroots. The default prefix is an empty string. โจBIND_PC_REQUIRES <<name>=<target>>...โ a list of<name>=<target>pairs. The name is a package name as it appears in theRequireslist of a pkg-config file, and the target is a CMake-native target name (not a pkg-config target). When a given package name appears in theRequireslist of a package, it will be fulfilled with the associated CMake target. This behavior applies to all dependencies in the pkg-config graph that have not been previously populated. Honestly? Chef's kiss. ๐ฅ
๐ Signatures ๐
cmake_pkg_config(EXTRACT <package> [<version>] [...])
Added in version 3.31. ๐
Extract the contents of the package into variables. That's it, that's the vibe:
cmake_pkg_config(EXTRACT <package> [<version>]
[REQUIRED] [EXACT] [QUIET]
[SYSTEM_INCLUDE_DIRS <path>...]
[SYSTEM_LIBRARY_DIRS <path>...]
[ALLOW_SYSTEM_INCLUDES <bool>]
[ALLOW_SYSTEM_LIBS <bool>]
[STRICTNESS <mode>]
[ENV_MODE <mode>]
[PC_LIBDIR <path>...]
[PC_PATH <path>...]
[DISABLE_UNINSTALLED <bool>]
[PC_SYSROOT_DIR <path>]
[TOP_BUILD_DIR <path>])
[more coming, hold on, I'm not done]
Okay so real talk bestie, here's the tea on those variables ๐ the following variables will be populated from the contents of package file, and yes we're listing every single one because we don't skip ๐ :
CMAKE_PKG_CONFIG_NAMEโ Type: String. It's giving the value of theNamekeyword โจCMAKE_PKG_CONFIG_DESCRIPTIONโ Type: String. It's giving the value of theDescriptionkeyword ๐CMAKE_PKG_CONFIG_VERSIONโ Type: String. It's giving the value of theVersionkeyword ๐CMAKE_PKG_CONFIG_PROVIDESโ Type: List. It's giving the value of theProvideskeyword ๐ธCMAKE_PKG_CONFIG_REQUIRESโ Type: List. It's giving the value of theRequireskeyword ๐ฆCMAKE_PKG_CONFIG_CONFLICTSโ Type: List. It's giving the value of theConflictskeyword ๐CMAKE_PKG_CONFIG_CFLAGSโ Type: String. It's giving the value of theCFlags/Cflagskeyword ๐ฅCMAKE_PKG_CONFIG_INCLUDESโ Type: List. All-Iprefixed flags fromCMAKE_PKG_CONFIG_CFLAGS๐ซถCMAKE_PKG_CONFIG_COMPILE_OPTIONSโ Type: List. All flags not prefixed with-IfromCMAKE_PKG_CONFIG_CFLAGS๐ญCMAKE_PKG_CONFIG_LIBSโ Type: String. It's giving the value of theLibskeyword ๐CMAKE_PKG_CONFIG_LIBDIRSโ Type: List. All-Lprefixed flags fromCMAKE_PKG_CONFIG_LIBSโญCMAKE_PKG_CONFIG_LIBNAMESโ Type: List. All-lprefixed flags fromCMAKE_PKG_CONFIG_LIBS๐CMAKE_PKG_CONFIG_LINK_OPTIONSโ Type: List. All flags not prefixed with-Lor-lfromCMAKE_PKG_CONFIG_LIBS๐CMAKE_PKG_CONFIG_*_PRIVATEโ Type:*. It'sCFLAGS/LIBS/REQUIRESand derived, but in their.privatesuffix forms ๐
๐ง SYSTEM_INCLUDE_DIRS
This one overrides the "system" directories, and it's all for the purpose of flag mangling include directories in CMAKE_PKG_CONFIG_CFLAGS and derived variables. No cap ๐
When this option is not provided, the default directories are provided by the first available of the following values, in this exact order:
CMAKE_PKG_CONFIG_SYS_INCLUDE_DIRS- The
PKG_CONFIG_SYSTEM_INCLUDE_PATHenvironment variable - The output of
pkgconf --variable pc_system_includedirs pkg-config - A platform-dependent default value
Additionally โ plot twist โ when the ENV_MODE is PKGCONF the CMAKE_PKG_CONFIG_PKGCONF_INCLUDES variable will be concatenated to the list if available. If it is not available, the following environment variables will be queried and concatenated:
CPATHC_INCLUDE_PATHCPLUS_INCLUDE_PATHOBJC_INCLUDE_PATHINCLUDE(Windows Only)
๐ SYSTEM_LIBRARY_DIRS
Same energy, but for libs: this overrides the "system" directories for the purpose of flag mangling library directories in CMAKE_PKG_CONFIG_LIBS and derived variables. Bestie it's literally the same bit but for libraries ๐ธ
When this option is not provided, the default directories are provided by the first available of the following values:
CMAKE_PKG_CONFIG_SYS_LIB_DIRS- The
PKG_CONFIG_SYSTEM_LIBRARY_PATHenvironment variable - The output of
pkgconf --variable pc_system_libdirs pkg-config - A platform-dependent default value
Additionally, when the ENV_MODE is PKGCONF the CMAKE_PKG_CONFIG_PKGCONF_LIB_DIRS variable will be concatenated to the list if available. If it is not available, the LIBRARY_PATH environment variable will be queried and concatenated. Periodt ๐ซถ
โจ ALLOW_SYSTEM_INCLUDES
This one preserves "system" directories during flag mangling of include directories in CMAKE_PKG_CONFIG_CFLAGS and derived variables. Like, it's the "please don't throw these away" button ๐
When this option is not provided, the default value is determined by the first available of the following values:
CMAKE_PKG_CONFIG_ALLOW_SYS_INCLUDES- If the
PKG_CONFIG_ALLOW_SYSTEM_CFLAGSenvironment variable is defined the flags are preserved, otherwise they are filtered during flag mangling.
๐ฆ ALLOW_SYSTEM_LIBS
The library-flavoured twin: this preserves "system" directories during flag mangling of library directories in CMAKE_PKG_CONFIG_LIBS and derived variables ๐
When this option is not provided, the default value is determined by the first available of the following values:
CMAKE_PKG_CONFIG_ALLOW_SYS_LIBS- If the
PKG_CONFIG_ALLOW_SYSTEM_LIBSenvironment variable is defined the flags are preserved, otherwise they are filtered during flag mangling.
๐ cmake_pkg_config(POPULATE <package> [<version>] [...])
Added in version 4.1. ๐
Populate a package in the pkg-config target namespace:
cmake_pkg_config(POPULATE <package> [<version>]
[REQUIRED] [EXACT] [QUIET]
[PREFIX <prefix>]
[BIND_PC_REQUIRES <<name>=<target>>...]
[STRICTNESS <mode>]
[ENV_MODE <mode>]
[PC_LIBDIR <path>...]
[PC_PATH <path>...]
[DISABLE_UNINSTALLED <bool>]
[PC_SYSROOT_DIR <path>]
[TOP_BUILD_DIR <path>])
POPULATE enables manual control of resolution of a given package's Requires list without importing onto a native CMake target. Once populated, a package and its dependencies will be used for resolution of all future POPULATE and IMPORT commands. Iconic behaviour honestly ๐
A PKGCONFIG_<package>_FOUND variable will be set to indicate whether the package was found. Very much the vibe check of variables ๐
๐ฅ cmake_pkg_config(IMPORT <package> [<version>] [...])
Added in version 4.1. โญ
Import a pkg-config target as a CMake IMPORTED <#prop_tgt:IMPORTED> target:
cmake_pkg_config(IMPORT <package> [<version>]
[REQUIRED] [EXACT] [QUIET]
[NAME <name>]
[PREFIX <prefix>]
[BIND_PC_REQUIRES <<name>=<target>>...]
[STRICTNESS <mode>]
[ENV_MODE <mode>]
[PC_LIBDIR <path>...]
[PC_PATH <path>...]
[DISABLE_UNINSTALLED <bool>]
[PC_SYSROOT_DIR <path>]
[TOP_BUILD_DIR <path>])
...and the glow-up continues. This bit makes a native CMake IMPORTED target that you can link to via target_link_libraries(). By default this new target is literally named PkgConfig::<package> ๐
A PKGCONFIG_<package>_FOUND variable gets set to tell you whether the package was found at all (vibe check: passed or not).
NAMEโ Overrides the name of the created CMake target toPkgConfig::<name>. Important: this does not affect thePKGCONFIG_<package>_FOUNDvariable. That one stays exactly as it was, no cap.
๐ cmake_policy ๐
Manage CMake Policy settings. See the cmake-policies(7) manual for defined policies (that's where all the lore lives ๐).
As CMake evolves it is sometimes necessary to change existing behavior in order to fix bugs or improve implementations of existing features. The CMake Policy mechanism is designed to help keep existing projects building as new versions of CMake introduce changes in behavior. Each new policy (behavioral change) is given an identifier of the form CMP<NNNN> where <NNNN> is an integer index. Documentation associated with each policy describes the OLD and NEW behavior and the reason the policy was introduced. Projects may set each policy to select the desired behavior. When CMake needs to know which behavior to use it checks for a setting specified by the project. If no setting is available the OLD behavior is assumed and a warning is produced requesting that the policy be set. So bestie, silence is not golden here โ it's a warning ๐ญ
โจ Setting Policies by CMake Version โจ
The cmake_policy command is used to set policies to OLD or NEW behavior. While setting policies individually is supported, we encourage projects to set policies based on CMake versions:
cmake_policy(VERSION <min>[...<policy_max>])
Added in version 3.12: The optional <policy_max> version.
<min> and the optional <policy_max> are each CMake versions of the form major.minor[.patch[.tweak]], and the ... is literal. The <min> version must be at least 2.4 and at most the running version of CMake. The <policy_max> version, if specified, must be at least the <min> version but may exceed the running version of CMake. If the running version of CMake is older than 3.12, the extra ... dots will be seen as version component separators, resulting in the ...<policy_max> part being ignored and preserving the pre-3.12 behavior of basing policies on <min>. (old CMake really said "I don't see it ๐คทโโ๏ธ")
This specifies that the current CMake code is written for the given range of CMake versions, <min>[...<policy_max>]. It sets the "policy version" to:
- the range's
<policy_max>version, if specified, or to - the
<min>version, or to - the value of the
CMAKE_POLICY_VERSION_MINIMUMvariable if it is higher than the other two versions.
The policy version effectively requests behavior preferred as of a given CMake version and tells newer CMake versions to warn about their new policies. All policies known to the running version of CMake and introduced in the policy version or earlier will be set to use NEW behavior. All policies introduced in later versions will be unset (unless the CMAKE_POLICY_DEFAULT_CMP<NNNN> variable sets a default). That variable is the "no actually, I meant it" override ๐
Note: ...<policy_max> does not signify that later CMake versions are forbidden. It merely specifies the highest CMake version for which the project or module has been actively updated and maintained. It's a "we've tested up to here" sticker, not a locked door ๐ช
Note that the cmake_minimum_required(VERSION) command implicitly calls cmake_policy(VERSION) too. Surprise! It was doing policy work the whole time ๐ซถ
Changed in version 4.0: Compatibility with versions of CMake older than 3.5 is removed. Calls to cmake_minimum_required(VERSION) or cmake_policy(VERSION) that do not specify at least 3.5 as their policy version (optionally via ...<policy_max>) will produce an error in CMake 4.0 and above. Error, not warning. Full stop, periodt ๐
Changed in version 3.31: Compatibility with versions of CMake older than 3.10 is deprecated. Calls to cmake_minimum_required(VERSION) or cmake_policy(VERSION) that do not specify at least 3.10 as their policy version (optionally via ...<policy_max>) will produce a deprecation warning in CMake 3.31 and above.
Changed in version 3.27: Compatibility with versions of CMake older than 3.5 is deprecated. Calls to cmake_minimum_required(VERSION) or cmake_policy(VERSION) that do not specify at least 3.5 as their policy version (optionally via ...<policy_max>) will produce a deprecation warning in CMake 3.27 and above.
Changed in version 3.19: Compatibility with versions of CMake older than 2.8.12 is deprecated. Calls to cmake_minimum_required(VERSION) or cmake_policy(VERSION) that do not specify at least 2.8.12 as their policy version (optionally via ...<policy_max>) will produce a deprecation warning in CMake 3.19 and above.
๐ Setting Policies Explicitly ๐
cmake_policy(SET CMP<NNNN> NEW|OLD)
Tell CMake to use the OLD or NEW behavior for a given policy. Projects depending on the old behavior of a given policy may silence a policy warning by setting the policy state to OLD. Alternatively one may fix the project to work with the new behavior and set the policy state to NEW. Option A: quiet the warning. Option B: actually fix your code. Choose your fighter โ๏ธ
Note: The OLD behavior of a policy is deprecated by definition and may be removed in a future version of CMake. So like... don't get comfy on it, bestie ๐ฌ
๐ธ Checking Policy Settings ๐ธ
cmake_policy(GET CMP<NNNN> <variable>)
Check whether a given policy is set to OLD or NEW behavior. The output <variable> value will be OLD or NEW if the policy is set, and empty otherwise. Empty means "nobody said anything", which is its own kind of answer ๐ซฅ
๐ฆ CMake Policy Stack ๐ฆ
CMake keeps policy settings on a stack, so changes made by the cmake_policy command affect only the top of the stack. A new entry on the policy stack is managed automatically for each subdirectory to protect its parents and siblings. CMake also manages a new entry for scripts loaded by include() and find_package() commands except when invoked with the NO_POLICY_SCOPE option (see also policy CMP0011). Nested scopes stay in their own lane, on god ๐
The cmake_policy command provides an interface to manage custom entries on the policy stack:
cmake_policy(PUSH)โ Create a new entry on the policy stack.cmake_policy(POP)โ Remove the last policy stack entry created withcmake_policy(PUSH).
Each PUSH must have a matching POP to erase any changes. This is useful to make temporary changes to policy settings. Calls to the cmake_minimum_required(VERSION), cmake_policy(VERSION), or cmake_policy(SET) commands influence only the current top of the policy stack. Like, they only touch the very top plate of the stack. Don't @ the rest of it ๐
Added in version 3.25: The block(SCOPE_FOR POLICIES) command offers a more flexible and more secure way to manage the policy stack. The pop action is done automatically when leaving the block scope, so there is no need to precede each return() with a call to cmake_policy(POP). Automatic cleanup?? Obsessed. Main character energy fr fr โจ
# stack management with cmake_policy()
function(my_func)
cmake_policy(PUSH)
cmake_policy(SET ...)
if (<cond1>)
...
cmake_policy(POP)
return()
elseif(<cond2>)
...
cmake_policy(POP)
return()
endif()
...
cmake_policy(POP)
endfunction()
# stack management with block()/endblock()
function(my_func)
block(SCOPE_FOR POLICIES)
cmake_policy(SET ...)
if (<cond1>)
...
return()
elseif(<cond2>)
...
return()
endif()
...
endblock()
endfunction()
Commands created by the function() and macro() commands record policy settings when they are created and use the pre-record policies when they are invoked. If the function or macro implementation sets policies, the changes automatically propagate up through callers until they reach the closest nested policy stack entry. They remember their policy era. Nostalgic little things ๐ฐ๏ธ
๐ See Also ๐
cmake_minimum_required()
๐ configure_file ๐
Copy a file to another location and modify its contents. Copy-paste but make it โจtransformativeโจ
configure_file(<input> <output>
[NO_SOURCE_PERMISSIONS | USE_SOURCE_PERMISSIONS |
FILE_PERMISSIONS <permissions>...]
[COPYONLY] [ESCAPE_QUOTES] [@ONLY]
[NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF]])
Copies an <input> file to an <output> file while performing transformations of the input file content.
If the input file is modified the build system will re-run CMake to re-configure the file and generate the build system again. The generated file is modified and its timestamp updated on subsequent cmake runs only if its content is changed. Content changed or it didn't. No timestamp glow-up for no reason ๐
โจ Options โจ
The options are:
<input>โ Path to the input file. A relative path is treated with respect to the value ofCMAKE_CURRENT_SOURCE_DIR. The input path must be a file, not a directory. File, bestie. Not a directory. It will not accept a directory, don't try it ๐<output>โ Path to the output file or directory. A relative path is treated with respect to the value ofCMAKE_CURRENT_BINARY_DIR. If the path names an existing directory the output file is placed in that directory with the same file name as the input file. If the path contains non-existent directories, they are created. It'll literally build the folders for you. Self-sufficient king ๐NO_SOURCE_PERMISSIONSโ Added in version 3.19. Do not transfer the permissions of the input file to the output file. The copied file permissions default to the standard644value (-rw-r--r--).USE_SOURCE_PERMISSIONSโ Added in version 3.20. Transfer the permissions of the input file to the output file. This is already the default behavior if none of the three permissions-related keywords are given (NO_SOURCE_PERMISSIONS,USE_SOURCE_PERMISSIONSorFILE_PERMISSIONS). TheUSE_SOURCE_PERMISSIONSkeyword mostly serves as a way of making the intended behavior clearer at the call site. It's the "yes I know it's default, I'm saying it out loud" option ๐ซถFILE_PERMISSIONS <permissions>...โ Added in version 3.20. Ignore the input file's permissions and use the specified<permissions>for the output file instead. Input file's perms said "not today", we're doing our own thing ๐COPYONLYโ Copy the file without replacing any variable references or other content. This option may not be used withNEWLINE_STYLE. They do NOT get along. Pick one, seriously ๐ซESCAPE_QUOTESโ Escape any substituted quotes with backslashes (C-style). Backslash goes brrr \ ๐ช@ONLYโ Restrict variable replacement to references of the form@VAR@. This is useful for configuring scripts that use${VAR}syntax. Keeps your${VAR}stuff untouched so it doesn't get eaten alive ๐ญNEWLINE_STYLE <style>โ bestie, this is where you pick the line ending vibe for the output file ๐ SayUNIXorLFfor\nnewlines, or sayDOS,WIN32, orCRLFfor\r\nnewlines. Hard rule though: this option may not be used withCOPYONLY. Not negotiable, she's exclusive.
Transformations โจ
Okay so this is the part where your .in file gets its glow-up. Variables referenced in the input file content as @VAR@, ${VAR}, $CACHE{VAR}, and environment variables referenced as $ENV{VAR} will each be replaced with the current value of the variable โ or the empty string if the variable is not defined. That's it, that's the whole deal. ๐ซถ
Furthermore (love that word), input lines of the form
#cmakedefine VAR ...
will be replaced with either
#define VAR ...
or
/* #undef VAR */
depending on whether VAR is set in CMake to any value not considered a false constant by the if() command. The "..." content on the line after the variable name, if any, is processed as above. So it's not decorative, it's doing work. ๐ช
Unlike lines of the form #cmakedefine VAR ..., in lines of the form #cmakedefine01 VAR, VAR itself will expand to VAR 0 or VAR 1 rather than being assigned the value .... So therefore (yes, therefore, we're being fancy), input lines of the form
#cmakedefine01 VAR
will be replaced with either
#define VAR 0
or
#define VAR 1
โ ๏ธ Heads up bestie, this one's a little cursed: input lines of the form#cmakedefine01 VAR ...will expand as#cmakedefine01 VAR ... 0or#cmakedefine01 VAR ... 1, which may lead to undefined behavior. Not the cute kind of surprise. ๐ญ
Added in version 3.10: the result lines (with the exception of the #undef comments) can be indented using spaces and/or tabs between the # character and the cmakedefine or cmakedefine01 words. This whitespace indentation will be preserved in the output lines โ so your formatting survives the transformation, iconic behavior honestly:
# cmakedefine VAR
# cmakedefine01 VAR
will be replaced, if VAR is defined, with
# define VAR
# define VAR 1
Example ๐ธ
Consider a source tree containing a foo.h.in file:
#cmakedefine FOO_ENABLE
#cmakedefine FOO_STRING "@FOO_STRING@"
An adjacent CMakeLists.txt may use configure_file to configure the header:
option(FOO_ENABLE "Enable Foo" ON)
if(FOO_ENABLE)
set(FOO_STRING "foo")
endif()
configure_file(foo.h.in foo.h @ONLY)
This creates a foo.h in the build directory corresponding to this source directory. If the FOO_ENABLE option is on, the configured file will contain:
#define FOO_ENABLE
#define FOO_STRING "foo"
Otherwise it will contain:
/* #undef FOO_ENABLE */
/* #undef FOO_STRING */
One may then use the target_include_directories() command to specify the output directory as an include directory:
target_include_directories(<target> [SYSTEM] {INTERFACE|PUBLIC|PRIVATE} "${CMAKE_CURRENT_BINARY_DIR}")
so that sources may include the header as #include <foo.h>. Look at you, wiring up include paths like a whole main character ๐
See Also ๐
file(GENERATE)
continue ๐
Added in version 3.2.
Continue to the top of enclosing foreach or while loop.
continue()
The continue() command allows a cmake script to abort the rest of the current iteration of a foreach() or while() loop, and start at the top of the next iteration. Basically: "nope, skipping the rest of this round, see you at the top." ๐จ
See also the break() command โ that one's the full bail, continue() is just the skip.
else ๐
Starts the else portion of an if block.
else([<condition>])
See the if() command.
The optional <condition> argument is supported for backward compatibility only and is not evaluated. So like... she's there, she's vintage, she does nothing. ๐
elseif ๐ฆ
Starts an elseif portion of an if block.
elseif(<condition>)
See the if() command, especially for the syntax and logic of the <condition>. Go read that one, it's the whole brain of the operation.
endblock ๐ฌ
Added in version 3.25.
Ends a list of commands in a block() and removes the scopes created by the block() command.
endblock()
Closing the block and cleaning up the scopes it made โ she tidies as she leaves, we love a respectful queen ๐
endforeach ๐
Ends a list of commands in a foreach block.
endforeach([<loop_var>])
See the foreach() command.
The optional <loop_var> argument is supported for backward compatibility only. If used it must be a verbatim repeat of the <loop_var> argument of the opening foreach clause. Verbatim, bestie โ character for character, no creative liberties. โ๏ธ
endfunction โญ
Ends a list of commands in a function block.
endfunction([<name>])
See the function() command.
The optional <name> argument is supported for backward compatibility only. If used it must be a verbatim repeat of the <name> argument of the opening function command.
endif ๐
Ends a list of commands in an if block.
endif([<condition>])
See the if() command.
The optional <condition> argument is supported for backward compatibility only. If used it must be a verbatim repeat of the argument of the opening if clause. Same energy as endforeach and endfunction โ legacy, keep it matching or keep it out. ๐ซก
endmacro ๐
Ends a list of commands in a macro block.
endmacro([<name>])
See the macro() command.
The optional <name> argument is supported for backward compatibility only. If used it must be a verbatim repeat of the <name> argument of the opening macro command.
endwhile ๐
Ends a list of commands in a while block.
endwhile([<condition>])
See the while() command.
The optional <condition> argument is supported for backward compatibility only. If used it must be a verbatim repeat of the argument of the opening while clause.
execute_process ๐ฅ
Execute one or more child processes. This is the big one, gather round.
execute_process(COMMAND <cmd1> [<arguments>]
[COMMAND <cmd2> [<arguments>]]...
[WORKING_DIRECTORY <directory>]
[TIMEOUT <seconds>]
[RESULT_VARIABLE <variable>]
[RESULTS_VARIABLE <variable>]
[OUTPUT_VARIABLE <variable>]
[ERROR_VARIABLE <variable>]
[INPUT_FILE <file>]
[OUTPUT_FILE <file>]
[ERROR_FILE <file>]
[OUTPUT_QUIET]
[ERROR_QUIET]
[COMMAND_ECHO <where>]
[OUTPUT_STRIP_TRAILING_WHITESPACE]
[ERROR_STRIP_TRAILING_WHITESPACE]
[ENCODING <name>]
[ENVIRONMENT <variable=value>...]
[ENVIRONMENT_MODIFICATION <env-mod-op>...]
[ECHO_OUTPUT_VARIABLE]
[ECHO_ERROR_VARIABLE]
[COMMAND_ERROR_IS_FATAL <ANY|LAST|NONE>])
Runs the given sequence of one or more commands.
Commands are executed concurrently as a pipeline, with the standard output of each process piped to the standard input of the next. A single standard error pipe is used for all processes. It's giving assembly line, it's giving relay race ๐โโ๏ธ
execute_process runs commands while CMake is configuring the project, prior to build system generation. Use the add_custom_target() and add_custom_command() commands to create custom commands that run at build time. Different times, different commands, don't mix them up bestie. โฐ
Options:
COMMANDโ A child process command line.
CMake executes the child process using operating system APIs directly:
- On POSIX platforms, the command line is passed to the child process in an
argv[]style array. No intermediate shell is executed, so shell operators such as>are treated as normal arguments. Yes,>is just text here. No redirect for you. ๐ โโ๏ธ - On Windows platforms, the command line is encoded as a string such that child processes using
CommandLineToArgvWwill decode the original arguments.
If the command runs a .exe, .com, or other executable, no intermediate command interpreter is executed, so shell operators such as > are treated as normal arguments.
If the command runs a .bat or .cmd script, it is executed through the cmd command interpreter. The command interpreter does not use CommandLineToArgvW, so some arguments may be received by the script with extra quoting. ๐ฌ
Changed in version 4.0: .bat and .cmd scripts are now explicitly executed through the command interpreter by prepending cmd /c call to the command line. Previously, they were implicitly executed through cmd /c, without call, by undocumented behavior of CreateProcessW. Undocumented behavior, we do not miss you. ๐
Use the INPUT_*, OUTPUT_*, and ERROR_* options to redirect stdin, stdout, and stderr.
For sequential execution of multiple commands use multiple execute_process calls each with a single COMMAND argument.
WORKING_DIRECTORYโ The named directory will be set as the current working directory of the child processes. If not given, the child processes' working directory is unspecified. So like... could be anywhere. Chaos. Specify it. ๐TIMEOUTโ After the specified number of seconds (fractions allowed), all unfinished child processes will be terminated, and theRESULT_VARIABLEwill be set to a string mentioning the"timeout".RESULT_VARIABLEโ The variable will be set to contain the result of last child process. This will be an integer return code from the last child or a string describing an error condition.RESULTS_VARIABLE <variable>โ Added in version 3.10.
The variable will be set to contain the result of all processes as a semicolon-separated list, in order of the given COMMAND arguments. Each entry will be an integer return code from the corresponding child or a string describing an error condition.
INPUT_FILE <file>โ<file>is attached to the standard input pipe of the firstCOMMANDprocess.OUTPUT_FILE <file>โ<file>is attached to the standard output pipe of the lastCOMMANDprocess.ERROR_FILE <file>โ<file>is attached to the standard error pipe of allCOMMANDprocesses.
Added in version 3.3: If the same <file> is named for both OUTPUT_FILE and ERROR_FILE then it will be used for both standard output and standard error pipes. Two pipes, one file, iconic efficiency โจ
OUTPUT_QUIET,ERROR_QUIETโ The standard output onOUTPUT_VARIABLEor standard error onERROR_VARIABLEare not connected (no variable content). The*_FILEandECHO_*_VARIABLEoptions are not affected. So quiet means quiet for the variable only, the files still get everything. ๐OUTPUT_VARIABLE,ERROR_VARIABLEโ bestie, these set the named variable to the contents of the standard output and standard error pipes, respectively. If you name the same variable for both pipes, their output gets merged in the order produced. ๐OUTPUT_STRIP_TRAILING_WHITESPACE,ERROR_STRIP_TRAILING_WHITESPACEโ removes whitespace characters from the end of the values stored in the correspondingOUTPUT_VARIABLEandERROR_VARIABLEvariables. โจECHO_OUTPUT_VARIABLE,ECHO_ERROR_VARIABLEโ Added in version 3.18. The standard output or standard error will not be exclusively redirected to the specified variables. The output will be duplicated into the specified variables and also onto standard output or standard error, analogous to theteeUnix command. ๐ซถ
Note: If more than oneOUTPUT_*orERROR_*option is given for the same pipe, the precedence is not specified. If noOUTPUT_*orERROR_*options are given, the output will be shared with the corresponding pipes of the CMake process itself. ๐ญ
COMMAND_ECHO <where>โ Added in version 3.15. The command being run will be echo'ed to<where>, with<where>being set to one ofSTDERR,STDOUTorNONE. See theCMAKE_EXECUTE_PROCESS_COMMAND_ECHOvariable for a way to control the default behavior when this option is not present. ๐ENCODING <name>โ Added in version 3.8. On Windows, the encoding that is used to decode output from the process. Ignored on other platforms. Valid encoding names are:NONEโ perform no decoding. This assumes that the process output is encoded in the same way as CMake's internal encoding (UTF-8). This was the default in CMake 3.14 and older.AUTOโ use the current active console's codepage or, if that isn't available, then useANSI. This was the default in CMake 3.15 through 3.30.ANSIโ use the ANSI codepage.OEMโ use the original equipment manufacturer (OEM) code page.UTF-8โ Added in version 3.11. Use the UTF-8 codepage. This is the default since CMake 3.31. See policyCMP0176.UTF8โ use the UTF-8 codepage. Use of this name is discouraged in favor ofUTF-8to match the UTF-8 RFC (https://datatracker.ietf.org/doc/html/rfc3629) naming convention.
ENVIRONMENT <variable=value>...โ Added in version 4.4. Add environment variable definitions to the environment of the child processes. Each entry must be of the formNAME=valueand is interpreted as settingNAMEtovaluefor the duration of theexecute_process()call. These entries are processed in order. If the same variable name is given multiple times, the last value wins. ๐ENVIRONMENT_MODIFICATION <env-mod-op>...โ Added in version 4.4. Apply one or moreENVIRONMENT_MODIFICATIONoperations to the environment of the child processes. Each operation is applied in the given order, and failures to parse an operation are treated as errors. Environment modifications are applied afterENVIRONMENTentries, if both options are specified. ๐COMMAND_ERROR_IS_FATAL <ANY|LAST|NONE>โ Added in version 3.19. The option followingCOMMAND_ERROR_IS_FATALdetermines the behavior when an error is encountered:ANYโ if any of the commands in the list of commands fail, theexecute_process()command halts with an error.LASTโ if the last command in the list of commands fails, theexecute_process()command halts with an error. Commands earlier in the list will not cause a fatal error.NONEโ Added in version 4.0. Regardless of any of the commands failing, theexecute_process()command will not halt with an error.
Added in version 4.0: If not provided, the CMAKE_EXECUTE_PROCESS_COMMAND_ERROR_IS_FATAL variable is checked. If the variable is not set, the default is NONE. If RESULT_VARIABLE or RESULTS_VARIABLE is supplied, CMAKE_EXECUTE_PROCESS_COMMAND_ERROR_IS_FATAL is ignored. ๐ฅ
๐ file
File manipulation command. This one is dedicated to file and path manipulation that actually requires access to the filesystem. ๐๏ธ
For other path manipulation, handling only syntactic aspects, see the cmake_path() command.
Note: The sub-commandsfile(RELATIVE_PATH),file(TO_CMAKE_PATH), andfile(TO_NATIVE_PATH)have been superseded, respectively, by the sub-commandscmake_path(RELATIVE_PATH),cmake_path(CONVERT ... TO_CMAKE_PATH_LIST), andcmake_path(CONVERT ... TO_NATIVE_PATH_LIST). ๐ซถ
โจ Synopsis
Reading
file(READ <filename> <out-var> [...])
file(STRINGS <filename> <out-var> [...])
file(<HASH> <filename> <out-var>)
file(TIMESTAMP <filename> <out-var> [...])
Writing
file({WRITE | APPEND} <filename> <content>...)
file({TOUCH | TOUCH_NOCREATE} <file>...)
file(GENERATE OUTPUT <output-file> [...])
file(CONFIGURE OUTPUT <output-file> CONTENT <content> [...])
Filesystem
file({GLOB | GLOB_RECURSE} <out-var> [...] <globbing-expr>...)
file(MAKE_DIRECTORY <directories>... [...])
file({REMOVE | REMOVE_RECURSE } <files>...)
file(RENAME <oldname> <newname> [...])
file(COPY_FILE <oldname> <newname> [...])
file({COPY | INSTALL} <file>... DESTINATION <dir> [...])
file(SIZE <filename> <out-var>)
file(READ_SYMLINK <linkname> <out-var> [...])
file(CREATE_LINK <original> <linkname> [...])
file(CHMOD <files>... <directories>... PERMISSIONS <permissions>... [...])
file(CHMOD_RECURSE <files>... <directories>... PERMISSIONS <permissions>... [...])
Path Conversion
file(REAL_PATH <path> <out-var> [BASE_DIRECTORY <dir>] [EXPAND_TILDE])
file(RELATIVE_PATH <out-var> <directory> <file>)
file({TO_CMAKE_PATH | TO_NATIVE_PATH} <path> <out-var>)
Transfer
file(DOWNLOAD <url> [<file>] [...])
file(UPLOAD <file> <url> [...])
Locking
file(LOCK <path> [...])
Archiving
file(ARCHIVE_CREATE OUTPUT <archive> PATHS <paths>... [...])
file(ARCHIVE_EXTRACT INPUT <archive> [...])
Handling Runtime Binaries
file(GET_RUNTIME_DEPENDENCIES [...])
๐ Reading
file(READ <filename> <variable> [OFFSET <offset>] [LIMIT <max-in>] [HEX]) โ read content from a file called <filename> and store it in a <variable>. Optionally start from the given <offset> and read at most <max-in> bytes. The HEX option causes data to be converted to a hexadecimal representation (useful for binary data). If the HEX option is specified, letters in the output (a through f) are in lowercase. ๐
file(STRINGS <filename> <variable> <options>...) โ parse a list of ASCII strings from <filename> and store it in <variable>. Binary data in the file are ignored. Carriage return (\r, CR) characters are ignored. The options are: ๐ธ
LENGTH_MAXIMUM <max-len>โ consider only strings of at most a given length.LENGTH_MINIMUM <min-len>โ consider only strings of at least a given length.LIMIT_COUNT <max-num>โ limit the number of distinct strings to be extracted.LIMIT_INPUT <max-in>โ limit the number of input bytes to read from the file.LIMIT_OUTPUT <max-out>โ limit the number of total bytes to store in the<variable>.NEWLINE_CONSUMEโ treat newline characters (\n, LF) as part of string content instead of terminating at them.NO_HEX_CONVERSIONโ Intel Hex and Motorola S-record files are automatically converted to binary while reading unless this option is given.REGEX <regex>โ consider only strings that match the given regular expression, as described understring(REGEX). Changed in version 3.29: Capture groups from the last match in the file are stored inCMAKE_MATCH_<n>, similar tostring(REGEX MATCHALL). See policyCMP0159.ENCODING <encoding-type>โ Added in version 3.1. Consider strings of a given encoding. Currently supported encodings are:UTF-8,UTF-16LE,UTF-16BE,UTF-32LE,UTF-32BE. If theENCODINGoption is not provided and the file has a Byte Order Mark, theENCODINGoption will be defaulted to respect the Byte Order Mark.
Added in version 3.2: Added the UTF-16LE, UTF-16BE, UTF-32LE, UTF-32BE encodings. ๐
For example, the code
file(STRINGS myfile.txt myfile)
stores a list in the variable myfile in which each item is a line from the input file. โจ
file(<HASH> <filename> <variable>) โ compute a cryptographic hash of the content of <filename> and store it in a <variable>. The supported <HASH> algorithm names are those listed by the string(<HASH>) command. ๐ฅ
file(TIMESTAMP <filename> <variable> [<format>] [UTC]) โ compute a string representation of the modification time of <filename> and store it in <variable>. Should the command be unable to obtain a timestamp, variable will be set to the empty string (""). See the string(TIMESTAMP) command for documentation of the <format> and UTC options. ๐
โ๏ธ Writing
file(WRITE <filename> <content>...)
file(APPEND <filename> <content>...)
Writes <content> into a file called <filename>. If the file doesn't exist yet, it gets created โ no cap. If it does already exist, then: WRITE mode overwrites it, and APPEND mode appends to the end. And any directories in the path you gave in <filename> that don't exist yet? Yeah, they get created too. Convenient bestie behavior ๐
If the file is a build input, use the configure_file() command to update the file only when its content actually changes. That's the move. โจ
file(TOUCH <files>...)
file(TOUCH_NOCREATE <files>...)
Added in version 3.12.
Creates a file with no content if it doesn't already exist. If the file does exist, its access and/or modification time gets bumped to whenever the function call runs. Classic touch, iconic behavior. ๐
Use TOUCH_NOCREATE to touch a file only if it exists but never create it. If a file doesn't exist, it's just silently ignored โ no drama, no error, she simply moves on ๐
With both TOUCH and TOUCH_NOCREATE, the contents of an existing file will not be modified. We're touching, not rewriting, okay?
Changed in version 3.30: <files> can be an empty list. CMake 3.29 and earlier required at least one file to be given. Glow-up fr fr ๐ธ
file(GENERATE [...])
Generates an output file for each build configuration supported by the current CMake Generator. It evaluates generator expressions from the input content to produce the output content. It's giving very demure, very configuration-aware ๐
file(GENERATE OUTPUT <output-file>
<INPUT <input-file>|CONTENT <content>>
[CONDITION <expression>] [TARGET <target>]
[NO_SOURCE_PERMISSIONS | USE_SOURCE_PERMISSIONS |
FILE_PERMISSIONS <permissions>...]
[NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF]])
Okay so the options are:
CONDITION <condition>โ generates the output file for a particular configuration only if the condition is true. And heads up: the condition must be either0or1after evaluating generator expressions. Binary queen. No in-betweens ๐CONTENT <content>โ use the content given explicitly as input.INPUT <input-file>โ use the content from a given file as input.
Changed in version 3.10: a relative path is treated with respect to the value of CMAKE_CURRENT_SOURCE_DIR. See policy CMP0070.
OUTPUT <output-file>โ specify the output file name to generate. Use generator expressions such as$<CONFIG>to specify a configuration-specific output file name. Multiple configurations may generate the same output file only if the generated content is identical. Otherwise, the<output-file>must evaluate to a unique name for each configuration. Don't be out here colliding, bestie ๐ญ
Changed in version 3.10: a relative path (after evaluating generator expressions) is treated with respect to the value of CMAKE_CURRENT_BINARY_DIR. See policy CMP0070.
TARGET <target>โ added in version 3.19. Specifies which target to use when evaluating generator expressions that require a target for evaluation (e.g.$<COMPILE_FEATURES:...>,$<TARGET_PROPERTY:prop>).NO_SOURCE_PERMISSIONSโ added in version 3.20. The generated file permissions default to the standard644value (-rw-r--r--).USE_SOURCE_PERMISSIONSโ added in version 3.20. Transfers the file permissions of theINPUTfile to the generated file. This is already the default behavior if none of the three permissions-related keywords are given (NO_SOURCE_PERMISSIONS,USE_SOURCE_PERMISSIONSorFILE_PERMISSIONS). TheUSE_SOURCE_PERMISSIONSkeyword mostly serves as a way of making the intended behavior clearer at the call site โ it's basically wearing a little name tag so everyone knows what's going on ๐ซถ It is an error to specify this option withoutINPUT.FILE_PERMISSIONS <permissions>...โ added in version 3.20. Use the specified permissions for the generated file.NEWLINE_STYLE <style>โ added in version 3.20. Specify the newline style for the generated file. SpecifyUNIXorLFfor\nnewlines, or specifyDOS,WIN32, orCRLFfor\r\nnewlines. Pick your fighter โญ
Exactly one CONTENT or INPUT option must be given. A specific OUTPUT file may be named by at most one invocation of file(GENERATE). Generated files are modified and their timestamp updated on subsequent cmake runs only if their content is changed. Lowkey respectful of your build times, honestly.
Note also thatfile(GENERATE)does not create the output file until the generation phase. The output file will not yet have been written when thefile(GENERATE)command returns โ it is written only after processing all of a project'sCMakeLists.txtfiles. So don't go looking for it immediately and then panic, bestie ๐
file(CONFIGURE OUTPUT <output-file> CONTENT <content> [ESCAPE_QUOTES] [@ONLY] [NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF]])
Added in version 3.18.
Generates an output file using the input given by CONTENT and substitutes variable values referenced as @VAR@ or ${VAR} contained therein. The substitution rules behave the same as the configure_file() command. And to match configure_file()'s behavior, generator expressions are not supported for both OUTPUT and CONTENT, and the output file is only modified (with its timestamp updated) if the content is changed or the file previously didn't exist. Consistency is the vibe โจ
The arguments are:
OUTPUT <output-file>โ specify the output file name to generate. A relative path is treated with respect to the value ofCMAKE_CURRENT_BINARY_DIR.<output-file>does not support generator expressions.CONTENT <content>โ use the content given explicitly as input.<content>does not support generator expressions.ESCAPE_QUOTESโ escape any substituted quotes with backslashes (C-style).@ONLYโ restrict variable replacement to references of the form@VAR@. This is useful for configuring scripts that use${VAR}syntax. Very thoughtful, very demure ๐NEWLINE_STYLE <style>โ specify the newline style for the output file. SpecifyUNIXorLFfor\nnewlines, or specifyDOS,WIN32, orCRLFfor\r\nnewlines.
๐ Filesystem
file(GLOB ...)
file(GLOB_RECURSE ...)
file(GLOB <variable> [LIST_DIRECTORIES true|false] [RELATIVE <path>]
[CONFIGURE_DEPENDS] <globbing-expressions>...)
file(GLOB_RECURSE <variable> [FOLLOW_SYMLINKS]
[LIST_DIRECTORIES true|false] [RELATIVE <path>] [CONFIGURE_DEPENDS]
<globbing-expressions>...)
Generates a list of files that match the <globbing-expressions> and stores it into the <variable>. Globbing expressions are similar to regular expressions but much simpler โ regex's chiller little sister ๐ If the RELATIVE flag is specified, the results will be returned as relative paths to the given path.
Changed in version 3.6: the results will be ordered lexicographically. Organized queen.
On Windows and macOS, globbing is case-insensitive even if the underlying filesystem is case-sensitive (both filenames and globbing expressions are converted to lowercase before matching). On other platforms, globbing is case-sensitive. Platform-dependent behavior, love that for us ๐
Added in version 3.3: by default GLOB lists directories. Directories are omitted in the result if LIST_DIRECTORIES is set to false.
Added in version 3.12: if the CONFIGURE_DEPENDS flag is specified, CMake will add logic to the main build system check target to rerun the flagged GLOB commands at build time. If any of the outputs change, CMake will regenerate the build system. She's checking in on you ๐ซถ
Note: we do not recommend usingGLOBto collect a list of source files from your source tree. If noCMakeLists.txtfile changes when a source is added or removed, then the generated build system cannot know when to ask CMake to regenerate. TheCONFIGURE_DEPENDSflag may not work reliably on all generators, or if a new generator is added in the future that cannot support it, projects using it will be stuck. Even ifCONFIGURE_DEPENDSworks reliably, there is still a cost to performing the check on every rebuild. It's giving "cheap now, expensive later" and we don't stan ๐ญ
Examples of globbing expressions include:
*.cxxโ match all files with extensioncxx*.vt?โ match all files with extensionvta, ...,vtzf[3-5].txtโ match filesf3.txt,f4.txt,f5.txt
The GLOB_RECURSE mode will traverse all the subdirectories of the matched directory and match the files. Subdirectories that are symlinks are only traversed if FOLLOW_SYMLINKS is given or policy CMP0009 is not set to NEW. Respect the boundaries, bestie ๐ฆ
LIST_DIRECTORIESโ ok so added in version 3.3: by defaultGLOB_RECURSEbe leaving directories out of the result list entirely (rude but true ๐ ). SetLIST_DIRECTORIESto true and directories get added in. But bestie, listen: ifFOLLOW_SYMLINKSis given, or policyCMP0009<#policy:CMP0009> is not set toNEW, thenLIST_DIRECTORIEStreats symlinks as directories. That's the whole vibe check there ๐ฆ
Examples of recursive globbing include:
/dir/*.pyโ match all python files in/dirand subdirectories โจ
file(MAKE_DIRECTORY <directories>... [RESULT <result>])
Create the given directories and their parents as needed โ like, it'll build the whole family tree for you, no cap ๐ Relative input paths are evaluated with respect to the current source directory.
The options are:
RESULT <result>โ added in version 3.31. Sets the<result>variable to0on success or an error message otherwise. IfRESULTis not specified and the operation fails, an error is emitted. So like, either you catch the drama or the drama catches you ๐
Changed in version 3.30: <directories> can be an empty list. CMake 3.29 and earlier required at least one directory to be given โ those were stricter times, we don't talk about it ๐
file(REMOVE <files>...)
file(REMOVE_RECURSE <files>...)
Remove the given files. The REMOVE_RECURSE mode will remove the given files and directories, including non-empty directories โ yes bestie, it goes all the way in ๐ฅ No error is emitted if a given file does not exist (it's very "no thoughts, head empty, whatever" about missing files). Relative input paths are evaluated with respect to the current source directory.
Changed in version 3.15: empty input paths are ignored with a warning. Previous versions of CMake interpreted empty strings as a relative path with respect to the current directory and removed its contents. So likeโฆ the old behaviour was lowkey a jumpscare. Do not recreate it. โ
file(RENAME <oldname> <newname> [RESULT <result>] [NO_REPLACE])
Move a file or directory within a filesystem from <oldname> to <newname>, replacing the destination atomically โ slay, no half-finished situations ๐
The options are:
RESULT <result>โ added in version 3.21. Sets the<result>variable to0on success or an error message otherwise. IfRESULTis not specified and the operation fails, an error is emitted.NO_REPLACEโ added in version 3.21. If the<newname>path already exists, do not replace it. IfRESULT <result>is used, the result variable will be set toNO_REPLACE. Otherwise, an error is emitted. She said "not today" ๐ซถ
file(COPY_FILE <oldname> <newname> [RESULT <result>] [ONLY_IF_DIFFERENT] [INPUT_MAY_BE_RECENT])
Added in version 3.21.
Copy a file from <oldname> to <newname>. Directories are not supported (sorry bestie, file only, this is a file-only zone). Symlinks are ignored and <oldfile>'s content is read and written to <newname> as a new file โ so the link's whole identity gets left behind ๐ญ
The options are:
RESULT <result>โ sets the<result>variable to0on success or an error message otherwise. IfRESULTis not specified and the operation fails, an error is emitted.ONLY_IF_DIFFERENTโ if the<newname>path already exists, do not replace it if the file's contents are already the same as<oldname>(this avoids updating<newname>'s timestamp). Basically "if it's already iconic, why touch it" โจINPUT_MAY_BE_RECENTโ added in version 3.26. Tell CMake that the input file may have been recently created. This is meaningful only on Windows, where files may be inaccessible for a short time after they are created. With this option, if permission is denied, CMake will retry reading the input a few times. Patience is a virtue, iykyk ๐ง
This sub-command has some similarities to configure_file() <#command:configure_file> with the COPYONLY option. An important difference is that configure_file() <#command:configure_file> creates a dependency on the source file, so CMake will be re-run if it changes. The file(COPY_FILE) sub-command does not create such a dependency. Different vibes entirely, don't confuse them ๐
See also the file(COPY) sub-command just below which provides further file-copying capabilities.
file(COPY [...])
file(INSTALL [...])
The COPY signature copies files, directories, and symlinks to a destination folder. Relative input paths are evaluated with respect to the current source directory, and a relative destination is evaluated with respect to the current build directory. Copying preserves input file timestamps, and optimizes out a file if it exists at the destination with the same timestamp (efficient queen behavior ๐). Copying preserves input permissions unless explicit permissions or NO_SOURCE_PERMISSIONS are given โ and the default is USE_SOURCE_PERMISSIONS.
file(<COPY|INSTALL> <files>... DESTINATION <dir>
[NO_SOURCE_PERMISSIONS | USE_SOURCE_PERMISSIONS]
[FILE_PERMISSIONS <permissions>...]
[DIRECTORY_PERMISSIONS <permissions>...]
[FOLLOW_SYMLINK_CHAIN]
[FILES_MATCHING]
[[PATTERN <pattern> | REGEX <regex>]
[EXCLUDE] [PERMISSIONS <permissions>...]] [...])
Note: for a simple file copying operation, the file(COPY_FILE) sub-command just above may be easier to use. Shortcut era ๐
Added in version 3.15: if FOLLOW_SYMLINK_CHAIN is specified, COPY will recursively resolve the symlinks at the paths given until a real file is found, and install a corresponding symlink in the destination for each symlink encountered. For each symlink that is installed, the resolution is stripped of the directory, leaving only the filename, meaning that the new symlink points to a file in the same directory as the symlink. This feature is useful on some Unix systems, where libraries are installed as a chain of symlinks with version numbers, with less specific versions pointing to more specific versions. FOLLOW_SYMLINK_CHAIN will install all of these symlinks and the library itself into the destination directory. For example, if you have the following directory structure:
/opt/foo/lib/libfoo.so.1.2.3/opt/foo/lib/libfoo.so.1.2 -> libfoo.so.1.2.3/opt/foo/lib/libfoo.so.1 -> libfoo.so.1.2/opt/foo/lib/libfoo.so -> libfoo.so.1
and you do:
file(COPY /opt/foo/lib/libfoo.so DESTINATION lib FOLLOW_SYMLINK_CHAIN)
This will install all of the symlinks and libfoo.so.1.2.3 itself into lib. The whole friend group comes along ๐ซถ
See the install(DIRECTORY) <#directory> command for documentation of permissions, FILES_MATCHING, PATTERN, REGEX, and EXCLUDE options. Copying directories preserves the structure of their content even if options are used to select a subset of files.
The INSTALL signature differs slightly from COPY: it prints status messages, and NO_SOURCE_PERMISSIONS is default. Installation scripts generated by the install() <#command:install> command use this signature (with some undocumented options for internal use โ mysterious, we love a secret ๐คซ).
Changed in version 3.22: the environment variable CMAKE_INSTALL_MODE <#envvar:CMAKE_INSTALL_MODE> can override the default copying behavior of file(INSTALL). She has range ๐
file(SIZE <filename> <variable>)
Added in version 3.14.
Determine the file size of the <filename> and put the result in <variable> variable. Requires that <filename> is a valid path pointing to a file and is readable โ so like, it has to actually exist and let you look at it, bestie. No fake files ๐ค
file(READ_SYMLINK <linkname> <variable> [RESULT <result>])
Added in version 3.14.
Query the symlink <linkname> and stores the path it points to in the result <variable>.
The options are:
RESULT <result>โ added in version 4.4. Capture the status of the operation in a<result>variable. The variable is set to0on success or an error message otherwise. If not specified, and the operation fails, a fatal error is emitted. Dramatic but fair ๐
Note that this command returns the raw symlink path and does not resolve a relative path. The following is an example of how to ensure that an absolute path is obtained:
set(linkname "/path/to/foo.sym")
file(READ_SYMLINK "${linkname}" result)
if(NOT IS_ABSOLUTE "${result}")
get_filename_component(dir "${linkname}" DIRECTORY)
set(result "${dir}/${result}")
endif()
Do the little manual labor yourself, she said ๐
file(CREATE_LINK <original> <linkname> [RESULT <result>] [COPY_ON_ERROR] [SYMBOLIC])
Added in version 3.14.
Create a link <linkname> that points to <original>. It will be a hard link by default, but providing the SYMBOLIC option results in a symbolic link instead. Hard links require that <original> exists and is a file, not a directory. If <linkname> already exists, it will be overwritten. No hesitation, she just goes for it ๐ฅ
The <result> variable, if specified, receives the status of the operation. It is set to 0 upon success or an error message otherwise. If RESULT is not specified and the operation fails, a fatal error is emitted.
Specifying COPY_ON_ERROR enables copying the file as a fallback if creating the link fails. It can be useful for handling situations such as <original> and <linkname> being on different drives or mount points, which would make them unable to support a hard link. Backup plan energy, we stan ๐ธ
Changed in version 4.3: if the source is a directory, CMake versions prior to 4.3 will create the destination directory if it does not exist, but not copy any files. With CMake 4.3 and above, the contents of the source directory will be copied recursively to the destination. See policy CMP0205 <#policy:CMP0205>. Glow-up of the century tbh โจ
file(CHMOD <files>... <directories>... [PERMISSIONS <permissions>...] [FILE_PERMISSIONS <permissions>...] [DIRECTORY_PERMISSIONS <permissions>...])
Added in version 3.19.
OWNER_READ,OWNER_WRITE,OWNER_EXECUTE,GROUP_READ,GROUP_WRITE,GROUP_EXECUTE,WORLD_READ,WORLD_WRITE,WORLD_EXECUTE,SETUID,SETGIDโ those are the valid permissions, bestie, and if you type anything else the vibe check fails, ok.
The valid keyword combos are like, the whole point, so pay attention:
PERMISSIONSโ literally every item gets changed. All of them. Periodt.FILE_PERMISSIONSโ only the files change, directories get to chill.DIRECTORY_PERMISSIONSโ only the directories change, files stay unbothered.PERMISSIONS+FILE_PERMISSIONSโFILE_PERMISSIONSoverridesPERMISSIONSfor files. Like,PERMISSIONSis the general rule andFILE_PERMISSIONSis the exception that ate.PERMISSIONS+DIRECTORY_PERMISSIONSโDIRECTORY_PERMISSIONSoverridesPERMISSIONSfor directories. Same energy, different target ๐ฏFILE_PERMISSIONS+DIRECTORY_PERMISSIONSโ useFILE_PERMISSIONSfor files andDIRECTORY_PERMISSIONSfor directories. Slay, they each got their own lane.
โจ CHMOD_RECURSE, the girlypop who goes deeper โจ
file(CHMOD_RECURSE <files>... <directories>...
[PERMISSIONS <permissions>...] [FILE_PERMISSIONS <permissions>...]
[DIRECTORY_PERMISSIONS <permissions>...])
๐ธ Added in version 3.19.
It's giving "same as CHMOD" but make it recurse โ it changes the permissions of the files and directories present in the <directories>... recursively. Yes she goes through everything. Obsessed ๐
Path Conversion ๐ฆ
file(REAL_PATH <path> <out-var> [BASE_DIRECTORY <dir>] [EXPAND_TILDE])
โญ Added in version 3.19.
Computes the absolute path to an existing file or directory, with symlinks resolved. The options are:
BASE_DIRECTORY <dir>โ if the<path>you handed over is a relative path, it gets evaluated relative to this base directory<dir>. If you didn't provide a base directory, the default base directory isCMAKE_CURRENT_SOURCE_DIR. That's just the house rules, no cap.EXPAND_TILDE
๐ Added in version 3.21.
If <path> is ~ or starts with ~/, the ~ gets replaced by the user's home directory. And where does the home directory come from? Environment variables, obviously. On Windows the USERPROFILE environment variable is used, falling back to the HOME environment variable if USERPROFILE is not defined. On all other platforms, only HOME is used. Windows stays extra, we been knew ๐
๐ฅ Changed in version 3.28: All symlinks are resolved before collapsing../components. See policyCMP0152. That ordering is the main character here, don't sleep on it.
file(RELATIVE_PATH <variable> <directory> <file>)
Computes the relative path from a <directory> to a <file> and stores it in the <variable>. Cute, straightforward, no drama ๐ธ
file(TO_CMAKE_PATH "<path>" <variable>)
file(TO_NATIVE_PATH "<path>" <variable>)
Okay so these two share a brain cell, here's the tea:
The TO_CMAKE_PATH mode converts a native <path> into a CMake-style path with forward-slashes (/). The input can be a single path or a system search path like $ENV{PATH}. A search path gets converted to a semicolon-separated list. Yep, that's the CMake list life ๐ซถ
The TO_NATIVE_PATH mode converts a CMake-style <path> into a native path with platform-specific slashes (\ on Windows hosts and / elsewhere).
๐ Always use double quotes around the <path> to be sure it is treated as a single argument to this command. Like, always. I'm begging.
Transfer ๐
file(DOWNLOAD <url> [<file>] <options>...)
file(UPLOAD <file> <url> <options>...)
The DOWNLOAD subcommand downloads the given <url> to a local <file>. The UPLOAD mode uploads a local <file> to a given <url>. Two directions, one command, iconic behavior honestly ๐
โจ Added in version 3.19: If<file>is not specified forfile(DOWNLOAD), the file is not saved. This can be useful if you want to know if a file can be downloaded (for example, to check that it exists) without actually saving it anywhere. Ghost mode ๐ป โ you get the info, keep none of the baggage.
Options to both DOWNLOAD and UPLOAD are:
INACTIVITY_TIMEOUT <seconds>โ terminates the operation after a period of inactivity. Girl gets bored, she leaves ๐ชLOG <variable>โ stores a human-readable log of the operation in a variable.SHOW_PROGRESSโ prints progress information as status messages until the operation is complete. Little updates, we love to see them ๐STATUS <variable>โ stores the resulting status of the operation in a variable. The status is a;separated list of length 2. The first element is the numeric return value for the operation, and the second element is a string value for the error. A0numeric error means no error in the operation. Zero equals everything's fine, we stan a clear signal ๐ฏTIMEOUT <seconds>โ terminates the operation after a given total time has elapsed.USERPWD <username>:<password>
๐ Added in version 3.7.
Sets username and password for the operation.
HTTPHEADER <HTTP-header>
๐ Added in version 3.7.
HTTP header for DOWNLOAD and UPLOAD operations. HTTPHEADER can be repeated for multiple options:
file(DOWNLOAD <url>
HTTPHEADER "Authorization: Bearer <auth-token>"
HTTPHEADER "UserAgent: Mozilla/5.0")
Stack them headers, she's collecting them like stickers โจ
NETRC <level>
๐ธ Added in version 3.11.
Specifies whether the .netrc file is to be used for the operation. If this option is not specified, the value of the CMAKE_NETRC variable will be used instead.
Valid levels are:
IGNOREDโ the.netrcfile is ignored. This is the default. Not invited to the party ๐OPTIONALโ the.netrcfile is optional, and information in the URL is preferred. The file will be scanned to find whichever information is not specified in the URL. Filler energy, but helpful.REQUIREDโ the.netrcfile is required, and information in the URL is ignored. It's the main character, the URL gets โจnothingโจ
NETRC_FILE <file>
๐ฆ Added in version 3.11.
Specifies an alternative .netrc file to the one in your home directory, if the NETRC level is OPTIONAL or REQUIRED. If this option is not specified, the value of the CMAKE_NETRC_FILE variable will be used instead.
TLS_VERSION <min>
๐ Added in version 3.30.
Specifies minimum TLS version for https:// URLs. If this option is not specified, the value of the CMAKE_TLS_VERSION variable or CMAKE_TLS_VERSION environment variable will be used instead. See CMAKE_TLS_VERSION for allowed values.
โญ Changed in version 3.31: The default is TLS 1.2. Previously, no minimum version was enforced by default. Glow up for security, fr fr.
TLS_VERIFY <ON|OFF>โ specifies whether to verify the server certificate forhttps://URLs. If this option is not specified, the value of theCMAKE_TLS_VERIFYvariable orCMAKE_TLS_VERIFYenvironment variable will be used instead. If neither is set, the default is on.
๐ฅ Changed in version 3.31: The default is on. Previously, the default was off. Users may set theCMAKE_TLS_VERIFYenvironment variable to0to restore the old default.
๐ Added in version 3.18: Added support to file(UPLOAD).
TLS_CAINFO <file>โ specifies a custom Certificate Authority file forhttps://URLs. If this option is not specified, the value of theCMAKE_TLS_CAINFOvariable will be used instead.
๐ Added in version 3.18: Added support to file(UPLOAD).
โ ๏ธ For https:// URLs CMake must be built with SSL/TLS support. No support, no vibes, the operation is just not happening.
Additional options to DOWNLOAD are:
EXPECTED_HASH <algorithm>=<value>โ verifies that the downloaded content hash matches the expected value, where<algorithm>is one of the algorithms supported by<HASH>. If the file already exists and matches the hash, the download is skipped. If the file already exists and does not match the hash, the file is downloaded again. If after download the file does not match the hash, the operation fails with an error. It is an error to specify this option ifDOWNLOADis not given a<file>. She checks the receipts, always ๐EXPECTED_MD5 <value>โ historical short-hand forEXPECTED_HASH MD5=<value>. It is an error to specify this ifDOWNLOADis not given a<file>. Vintage, but still valid.RANGE_START <value>
๐ Added in version 3.24.
Offset of the start of the range in the file in bytes. Could be omitted to download up to the specified RANGE_END.
RANGE_END <value>
๐ Added in version 3.24.
Offset of the end of the range in the file in bytes. Could be omitted to download everything from the specified RANGE_START to the end of the file. Snippets only, we don't need the whole thing bestie โ๏ธ
Locking ๐
file(LOCK <path> [DIRECTORY] [RELEASE] [GUARD <FUNCTION|FILE|PROCESS>]
[RESULT_VARIABLE <variable>] [TIMEOUT <seconds>])
๐ Added in version 3.2.
Lock a file specified by <path> if there's no DIRECTORY option, and the file <path>/cmake.lock otherwise. It stays locked for the scope set by the GUARD option (and the default value is PROCESS, bestie). The RELEASE option is your unlock button โ use it to explicitly free the file. If you don't throw in a TIMEOUT option, CMake will just sit there waiting until the lock succeeds or something fatally explodes. If TIMEOUT is set to 0, the lock is tried exactly once and the result gets reported immediately. If TIMEOUT isn't 0, CMake keeps trying to grab the lock for the period given by the TIMEOUT <seconds> value. Any errors get treated as fatal if there's no RESULT_VARIABLE option โ but if you do pass one, the result lands in <variable> and it'll be 0 on success or an error message on failure. ๐
Ok so important vibe check: this lock is advisory โ there is literally no guarantee other processes will respect it. It synchronizes two or more CMake instances that are sharing some modifiable resources, that's it. Same energy applies to the DIRECTORY option; locking a parent directory doesn't stop other LOCK commands from locking any child directory or file.
Trying to lock the same file twice? Not allowed, periodt. Any intermediate directories and the file itself get created if they don't already exist. And the GUARD and TIMEOUT options are just ignored on the RELEASE operation, like they're not even invited to the party. ๐
๐๏ธ Archiving
file(ARCHIVE_CREATE OUTPUT <archive> PATHS <paths>... [FORMAT <format>]
[COMPRESSION <compression> [COMPRESSION_LEVEL <compression-level>]]
[ENCODING <encoding>] [MTIME <mtime>] [THREADS <number>]
[WORKING_DIRECTORY <dir>] [VERBOSE])
Added in version 3.18. โจ
This creates the <archive> file you named, stuffed with the files and directories listed in <paths>. Heads up though: <paths> has to list actual files or directories โ wildcards are not supported, sorry bestie. ๐ญ
The options are:
FORMAT <format>โ specifies the archive format. Supported values for<format>are7zip,gnutar,pax,paxr,rawandzip. IfFORMATisn't given, the default format ispaxr.
The default compression method depends on the format:
7zipusesLZMAcompressionzipusesDeflatecompression- others use no compression by default
COMPRESSION <compression>โ some archive formats let you pick the type of compression. The7zipandzipformats already imply a specific type of compression. The other formats use no compression by default, but you can direct them to do it with theCOMPRESSIONoption. Valid values for<compression>are:NoneBZip2Deflateโ added in version 4.3. This is an alias forGZip.GZipLZMAโ added in version 4.3.LZMA2โ added in version 4.3. This is an alias forXZ.PPMdโ added in version 4.3. This compression method is only supported by the7ziparchive format.XZZstd
Note: withFORMATset toraw, only one file will be compressed with the compression type specified byCOMPRESSION. ๐ซถ
Added in version 4.3: the 7zip and zip formats support changing the default compression.
COMPRESSION_LEVEL <compression-level>โ added in version 3.19. The compression level gets set with theCOMPRESSION_LEVELoption. The<compression-level>should be between0-9, with the default being0. TheCOMPRESSIONoption must be present whenCOMPRESSION_LEVELis given โ no solo missions allowed.
The value 0 is used to specify the default compression level. It's selected automatically by the archive library backend and not directly set by CMake itself, so the default compression level may vary between archive formats, platforms, etc.
Added in version 3.26: the <compression-level> of the Zstd algorithm can be set between 0-19.
Added in version 4.3: the <compression-level> can be specified for the 7zip and zip formats too. The Zstd algorithm compression level can be set between 0-19, except for zip format.
ENCODING <encoding>โ added in version 4.4. Specifies the pathname character encoding used in the archive.
The <encoding> may be one of:
UTF-8โ archive pathnames are encoded as UTF-8. In CMake 4.4 and below, this is the default. See policyCMP0213for CMake 4.3 and below compatibility details.OEMโ on Windows platforms, pathnames are encoded as using the original equipment manufacturer (OEM) code page. On non-Windows platforms, pathnames are encoded according to the current locale. In CMake 4.3 and below, the OEM encoding (current locale) was always used.UTF-16LE,UTF-16BEโ archive pathnames are encoded as UTF-16 little-endian or big-endian....โ any encoding name supported byiconvon the current platform. On Windows, code page names may be specified.
Note:7ziparchives always encode paths asUTF-16LE, so this option is silently ignored for that format. ๐
MTIME <mtime>โ specifies the modification time recorded in tarball entries.THREADS <number>โ added in version 4.3. Use the<number>threads to operate on the archive. The number of available cores on the machine will be used if set to0. Note that not all compression modes support threading in all environments.WORKING_DIRECTORY <dir>โ added in version 3.31. Specifies the directory in which the archive creation operation will be executed. Paths in the<paths>argument can be relative to this directory. If this option isn't provided, the current working directory is used by default.VERBOSEโ enables verbose output from the archive operation. ๐ฅ
file(ARCHIVE_EXTRACT INPUT <archive> [DESTINATION <dir>]
[ENCODING <encoding>] [PATTERNS <pattern>...] [LIST_ONLY] [VERBOSE]
[TOUCH])
Added in version 3.18. Extracts or lists the content of the specified <archive>. ๐ธ
The options are:
DESTINATION <dir>โ specifies the directory under which the content of the archive will be extracted. If the directory doesn't exist, it will be created. IfDESTINATIONisn't given, the current binary directory will be used.ENCODING <encoding>โ added in version 4.4. Specifies the pathname character encoding used in the archive.
The <encoding> may be one of:
UTF-8โ archive pathnames are encoded as UTF-8. In CMake 4.3 and below, this is the default if theCMP0213policy isNEW.OEMโ on Windows platforms, pathnames are encoded as using the original equipment manufacturer (OEM) code page. On non-Windows platforms, pathnames are encoded according to the current locale. In CMake 4.3 and below, the OEM encoding (current locale) was always used. In CMake 4.4 and above, the OEM encoding (current locale) is only used if theCMP0213policy is notNEW.UTF-16LE,UTF-16BEโ archive pathnames are encoded as UTF-16 little-endian or big-endian....โ any encoding name supported byiconvon the current platform. On Windows, code page names may be specified.
Note:7ziparchives always encode paths asUTF-16LE, so this option is silently ignored for that format. ๐
PATTERNS <pattern>...โ extract/list only files and directories that match one of the given patterns. Wildcards are supported. If thePATTERNSoption isn't given, the entire archive gets listed or extracted.LIST_ONLYโ lists the files in the archive rather than extracting them.TOUCHโ added in version 3.24. Gives extracted files a current local timestamp instead of extracting file timestamps from the archive.VERBOSEโ enables verbose output from the extraction operation.
Changed in version 4.3: archive entries containing path traversal sequences (..), or absolute paths, are rejected for security. ๐ Not up for debate, bestie.
Note: the working directory for this subcommand is theDESTINATIONdirectory (provided or computed) except whenLIST_ONLYis specified. Therefore, outside of script mode, it may be best to provide absolute paths toINPUTarchives, as they're unlikely to be extracted where a relative path works. ๐ซถ
๐ง Handling Runtime Binaries
file(GET_RUNTIME_DEPENDENCIES [...])
Added in version 3.16. Recursively get the list of libraries depended on by the given files:
file(GET_RUNTIME_DEPENDENCIES
[RESOLVED_DEPENDENCIES_VAR <deps_var>]
[UNRESOLVED_DEPENDENCIES_VAR <unresolved_deps_var>]
[CONFLICTING_DEPENDENCIES_PREFIX <conflicting_deps_prefix>]
[EXECUTABLES <executable_files>...]
[LIBRARIES <library_files>...]
[MODULES <module_files>...]
[DIRECTORIES <directories>...]
[BUNDLE_EXECUTABLE <bundle_executable_file>]
[PRE_INCLUDE_REGEXES <regexes>...]
[PRE_EXCLUDE_REGEXES <regexes>...]
[POST_INCLUDE_REGEXES <regexes>...]
[POST_EXCLUDE_REGEXES <regexes>...]
[POST_INCLUDE_FILES <files>...]
[POST_EXCLUDE_FILES <files>...]
)
Okay so bestie, real talk before you go sprinting with this: this sub-command is not meant for project mode. Like, don't just drop it into your normal CMakeLists.txt and act surprised when it gets weird. It's built for install time โ either from code that the install(RUNTIME_DEPENDENCY_SET) command generates, or from code your project hands over via install(CODE) or install(SCRIPT). โจ
Like, for example:
install(CODE [[
file(GET_RUNTIME_DEPENDENCIES
# ...
)
]])
๐ The arguments, one by one
RESOLVED_DEPENDENCIES_VAR <deps_var>โ the name of the variable where the list of resolved dependencies gets stashed. That's your good-stuff variable. ๐UNRESOLVED_DEPENDENCIES_VAR <unresolved_deps_var>โ the name of the variable holding the list of unresolved dependencies. Lowkey important: if you don't specify this one and there happen to be any unresolved dependencies, an error gets issued. So likeโฆ she's optional but also she's not. ๐CONFLICTING_DEPENDENCIES_PREFIX <conflicting_deps_prefix>โ the variable prefix for conflicting-dependency info. A dependency counts as conflicting when two files with the same name turn up in two different directories. The list of conflicting filenames lands in<conflicting_deps_prefix>_FILENAMES, and for each of those filenames, the paths that were found for it get stored in<conflicting_deps_prefix>_<filename>. Bookkeeping slay. ๐๏ธEXECUTABLES <executable_files>...โ list of executable files to read for dependencies. These are the executables you'd typically make withadd_executable(), but ngl they don't have to come from CMake. On Apple platforms, the paths to these files decide the value of@executable_pathwhen libraries get recursively resolved. โ ๏ธ And heads up: passing any kind of library here (STATIC,MODULE, orSHARED) gives you undefined behavior. Don't do that. ๐LIBRARIES <library_files>...โ list of library files to read for dependencies. Typically the ones fromadd_library(SHARED), but again, not required to be CMake-born. PassingSTATIClibraries,MODULElibraries, or executables here? Undefined behavior. Periodt. ๐MODULES <module_files>...โ list of loadable module files to read for dependencies. These are the modules you'd usually make withadd_library(MODULE), but they don't have to be from CMake. They're the kind you load withdlopen()at runtime instead of linking at link time withld -l. And yep โ passingSTATIClibraries,SHAREDlibraries, or executables here is undefined behavior. ๐ธDIRECTORIES <directories>...โ extra directories to search for dependencies. The vibes differ per platform: on Linux, these get searched only if the dependency isn't found in any of the other usual paths โ and if it is found in one of these, a warning gets issued, because that means the file is incomplete (it doesn't list all the directories that contain its dependencies). On Windows, they're searched if the dependency isn't found in the other search paths, but no warning gets issued, because searching other paths is just a normal part of Windows dependency resolution. On Apple platforms, this argument has no effect at all. ๐BUNDLE_EXECUTABLE <bundle_executable_file>โ the executable to treat as the "bundle executable" when resolving libraries. On Apple platforms, this argument decides the value of@executable_pathwhen recursively resolving libraries forLIBRARIESandMODULESfiles. It has no effect onEXECUTABLESfiles. On other platforms, it has no effect, period. Typically (but not always!) it's one of the executables in theEXECUTABLESargument that designates the package's "main" executable. ๐
๐ฆ The filter arguments
The following arguments are filters for including or excluding libraries to be resolved. Full description of how they work is right below โ and remember, directory separators in file paths may be matched using forward slashes unless policy CMP0207 is not set to NEW. โจ
PRE_INCLUDE_REGEXES <regexes>...โ list of pre-include regexes that filter the names of not-yet-resolved dependencies.PRE_EXCLUDE_REGEXES <regexes>...โ list of pre-exclude regexes that filter the names of not-yet-resolved dependencies.POST_INCLUDE_REGEXES <regexes>...โ list of post-include regexes that filter the names of resolved dependencies.POST_EXCLUDE_REGEXES <regexes>...โ list of post-exclude regexes that filter the names of resolved dependencies.POST_INCLUDE_FILES <files>...โ Added in version 3.21. List of post-include filenames that filter the names of resolved dependencies. Symlinks get resolved when attempting to match these filenames. ๐POST_EXCLUDE_FILES <files>...โ Added in version 3.21. List of post-exclude filenames that filter the names of resolved dependencies. Symlinks get resolved when attempting to match these filenames too. ๐
These arguments are how you exclude unwanted system libraries when resolving dependencies, or include libraries from a specific directory. The filtering works like this:
- If the not-yet-resolved dependency matches any of the
PRE_INCLUDE_REGEXES, steps 2 and 3 get skipped, and dependency resolution proceeds straight to step 4. โญ๏ธ - If the not-yet-resolved dependency matches any of the
PRE_EXCLUDE_REGEXES, dependency resolution stops for that dependency. ๐ - Otherwise, dependency resolution proceeds.
file(GET_RUNTIME_DEPENDENCIES)searches for the dependency according to the linking rules of the platform (see below). ๐- If the dependency is found, and its full path matches one of the
POST_INCLUDE_REGEXESorPOST_INCLUDE_FILES, the full path is added to the resolved dependencies, andfile(GET_RUNTIME_DEPENDENCIES)recursively resolves that library's own dependencies. Otherwise, resolution proceeds to step 6. ๐ซถ - If the dependency is found, but its full path matches one of the
POST_EXCLUDE_REGEXESorPOST_EXCLUDE_FILES, it is not added to the resolved dependencies, and dependency resolution stops for that dependency. - If the dependency is found, and its full path matches none of
POST_INCLUDE_REGEXES,POST_INCLUDE_FILES,POST_EXCLUDE_REGEXES, orPOST_EXCLUDE_FILES, the full path is added to the resolved dependencies, andfile(GET_RUNTIME_DEPENDENCIES)recursively resolves that library's own dependencies. ๐
๐ Platform specifics
Different platforms have different rules for how dependencies get resolved. The specifics are described right here, iykyk.
๐ง On Linux platforms
Library resolution works as follows:
- If the depending file doesn't have any
RUNPATHentries, and the library exists in one of the depending file'sRPATHentries, or its parents', in that order, the dependency is resolved to that file. - Otherwise, if the depending file has any
RUNPATHentries, and the library exists in one of those entries, the dependency is resolved to that file. - Otherwise, if the library exists in one of the directories listed by
ldconfig, the dependency is resolved to that file. - Otherwise, if the library exists in one of the
DIRECTORIESentries, the dependency is resolved to that file. In this case, a warning is issued, because finding a file in one of theDIRECTORIESmeans that the depending file isn't complete (it doesn't list all the directories from which it pulls dependencies). - Otherwise, the dependency is unresolved. ๐ญ
Changed in version 3.31: resolution of each encountered library file name occurs at most once while processing a given root ELF file (executable or shared object). If a library file name is encountered again in the dependency tree, the original resolution is assumed. This behavior more closely matches the dynamic loader's behavior on Linux. โญ
๐ช On Windows platforms
Library resolution works as follows:
- DLL dependency names get lowercased for filter matching โจ Windows DLL names are case-insensitive, and some linkers just straight-up mangle the case of DLL dependency names (rude, honestly). But heads up โ this makes it harder for
PRE_INCLUDE_REGEXES,PRE_EXCLUDE_REGEXES,POST_INCLUDE_REGEXES, andPOST_EXCLUDE_REGEXESto properly filter DLL names, because every regex would have to check both uppercase and lowercase letters ๐ญ Like, for example:
file(GET_RUNTIME_DEPENDENCIES
# ...
PRE_INCLUDE_REGEXES "^[Mm][Yy][Ll][Ii][Bb][Rr][Aa][Rr][Yy]\\.[Dd][Ll][Ll]$"
)
Converting the DLL name to lowercase lets the regexes only match lowercase names, which simplifies the regex so much. For example:
file(GET_RUNTIME_DEPENDENCIES
# ...
PRE_INCLUDE_REGEXES "^mylibrary\\.dll$"
)
This regex will match mylibrary.dll regardless of how it's cased, either on disk or in the depending file. (Like, it'll match mylibrary.dll, MyLibrary.dll, and MYLIBRARY.DLL โ all of them, slay ๐
)
Changed in version 3.27: The conversion to lowercase only applies while matching filters. Results reported after filtering case-preserve each DLL name as it is found on disk, if resolved, and otherwise as it is referenced by the dependent binary.
Prior to CMake 3.27, the results were reported with lowercase DLL file names, but the directory portion retained its casing ๐
- (Not yet implemented) If the depending file is a Windows Store app, and the dependency is listed as a dependency in the application's package manifest, the dependency is resolved to that file.
- Otherwise, if the library exists in the same directory as the depending file, the dependency is resolved to that file.
- Otherwise, if the library exists in either the operating system's
system32directory or the Windows directory, in that order, the dependency is resolved to that file. - Otherwise, if the library exists in one of the directories specified by
DIRECTORIES, in the order they are listed, the dependency is resolved to that file. In this case, a warning is not issued, because searching other directories is a normal part of Windows library resolution ๐ซถ - Otherwise, the dependency is unresolved.
On Apple platforms, library resolution works like this:
- If the dependency starts with
@executable_path/, and anEXECUTABLESargument is in the process of being resolved, and replacing@executable_path/with the directory of the executable yields an existing file, the dependency is resolved to that file. - Otherwise, if the dependency starts with
@executable_path/, and there is aBUNDLE_EXECUTABLEargument, and replacing@executable_path/with the directory of the bundle executable yields an existing file, the dependency is resolved to that file. - Otherwise, if the dependency starts with
@loader_path/, and replacing@loader_path/with the directory of the depending file yields an existing file, the dependency is resolved to that file. - Otherwise, if the dependency starts with
@rpath/, and replacing@rpath/with one of theRPATHentries of the depending file yields an existing file, the dependency is resolved to that file. Note thatRPATHentries that start with@executable_path/or@loader_path/also have these items replaced with the appropriate path ๐ - Otherwise, if the dependency is an absolute file that exists, the dependency is resolved to that file.
- Otherwise, the dependency is unresolved.
This function accepts several variables that determine which tool is used for dependency resolution:
๐ ๏ธ CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM
Determines which operating system and executable format the files are built for. This could be one of several values:
linux+elfwindows+pemacos+macho
If this variable is not specified, it is determined automatically by system introspection ๐
๐ ๏ธ CMAKE_GET_RUNTIME_DEPENDENCIES_TOOL
Determines the tool to use for dependency resolution. It could be one of several values, depending on the value of CMAKE_GET_RUNTIME_DEPENDENCIES_PLATFORM:
linux+elfโobjdumpwindows+peโobjdumpordumpbinmacos+machoโotool
If this variable is not specified, it is determined automatically by system introspection.
๐ ๏ธ CMAKE_GET_RUNTIME_DEPENDENCIES_COMMAND
Determines the path to the tool to use for dependency resolution. This is the actual path to objdump, dumpbin, or otool.
If this variable is not specified, it is determined by the value of CMAKE_OBJDUMP <#variable:CMAKE_OBJDUMP> variable if set, else by system introspection.
Added in version 3.18: Uses CMAKE_OBJDUMP <#variable:CMAKE_OBJDUMP> if set.
๐ธ find_file ๐ธ
A short-hand signature is:
find_file (<VAR> <name> [<path>...])
The general signature is:
find_file (
<VAR>
{<name> | NAMES <name>...}
[HINTS {<path> | ENV <var>}...]
[PATHS {<path> | ENV <var>}...]
[REGISTRY_VIEW {64|32|64_32|32_64|HOST|TARGET|BOTH}]
[PATH_SUFFIXES <suffix>...]
[VALIDATOR <function>]
[DOC "cache documentation string"]
[NO_CACHE]
[REQUIRED|OPTIONAL]
[NO_DEFAULT_PATH]
[NO_PACKAGE_ROOT_PATH]
[NO_CMAKE_PATH]
[NO_CMAKE_ENVIRONMENT_PATH]
[NO_SYSTEM_ENVIRONMENT_PATH]
[NO_CMAKE_SYSTEM_PATH]
[NO_CMAKE_INSTALL_PREFIX]
[CMAKE_FIND_ROOT_PATH_BOTH |
ONLY_CMAKE_FIND_ROOT_PATH |
NO_CMAKE_FIND_ROOT_PATH]
)
This command is used to find a full path to a named file ๐
Prior to searching, find_file checks if variable <VAR> is defined. If the variable is not defined, the search will be performed. If the variable is defined and its value is NOTFOUND, or ends in -NOTFOUND, the search will be performed. If the variable contains any other value the search is not performed ๐
Note:VARis considered defined if it is available in the current scope. See thecmake-language(7)variables <#cmake-language-variables> documentation for details on scopes, and the interaction of normal variables and cache entries.
The results of the search will be stored in a cache entry named <VAR>. Future calls to find_file will inspect this cache entry when specifying the same <VAR>. This optimization ensures successful searches will not be repeated unless the cache entry is unset() <#command:unset> ๐
If the full path to a file is found the recorded value in cache entry <VAR> will be the result of the search. If nothing is found, the recorded value will be <VAR>-NOTFOUND.
Options include:
NAMESโ Specify one or more possible names for the full path to a file.
When using this to specify names with and without a version suffix, we recommend specifying the unversioned name first so that locally-built packages can be found before those provided by distributions ๐ซถ
HINTS,PATHSโ Specify directories to search in addition to the default locations. TheENVvar sub-option reads paths from a system environment variable.
Changed in version 3.24: On Windows platform, it is possible to include registry queries as part of the directories, using a dedicated syntax <#find-using-windows-registry>. Such specifications will be ignored on all other platforms.
REGISTRY_VIEWโ Added in version 3.24.
Specify which registry views must be queried. This option is only meaningful on Windows platforms and will be ignored on other ones. When not specified, the TARGET view is used when the CMP0134 <#policy:CMP0134> policy is NEW. Refer to CMP0134 <#policy:CMP0134> for the default view when the policy is OLD.
64โ Query the 64-bit registry. On 32-bit Windows, it always returns the string/REGISTRY-NOTFOUND๐32โ Query the 32-bit registry.64_32โ Query both views (64and32) and generate a path for each.32_64โ Query both views (32and64) and generate a path for each.HOSTโ Query the registry matching the architecture of the host:64on 64-bit Windows and32on 32-bit Windows.
TARGETโ queries the registry matching whatever architectureCMAKE_SIZEOF_VOID_Psays we're on. If that variable isn't defined, no stress โ it just falls back to theHOSTview. ๐BOTHโ queries both views (32 and 64). The order it picks depends on these rules, bestie, so pay attention:
If CMAKE_SIZEOF_VOID_P is defined, the view follows whatever's inside it:
8: โ64_324: โ32_64
If CMAKE_SIZEOF_VOID_P is not defined, it just goes off the host's architecture:
- 64-bit host: โ
64_32 - 32-bit host: โ
32
PATH_SUFFIXESโ extra subdirectories to check below each directory location that's otherwise considered. Little bonus folders, yk? โจVALIDATORโ added in version 3.25. Hand it afunction()to be called for every candidate item found (amacro()is not allowed โ pass one and you get an error, sorry babe). Two arguments get passed to your validator: the name of a result variable, and the absolute path to the candidate item. The item is accepted and the search ends โ unless the function sets that result variable's value to false in the calling scope. When the validator function is entered, the result variable is holding a true value. ๐ซถ
function(my_check validator_result_var item)
if(NOT item MATCHES ...)
set(${validator_result_var} FALSE PARENT_SCOPE)
endif()
endfunction()
find_file (result NAMES ... VALIDATOR my_check)
Note: if a cached result gets used, the search is skipped and any VALIDATOR is ignored entirely. And no, the cached result isn't required to pass the validation function. ๐
DOCโ the documentation string for the<VAR>cache entry. Give your cache variable a little glow-up description. ๐NO_CACHEโ added in version 3.21. The search result gets stored in a normal variable instead of a cache entry.
Note:find_filewill still check for<VAR>as usual โ first looking for a variable, then a cache entry. If either one indicates a previous successful search, the search just doesn't happen.
Warning: use this one with caution, fr fr โ it can greatly increase the cost of repeated configure steps. ๐ญ
REQUIREDโ added in version 3.18. Stops processing with an error message if nothing's found; otherwise the search gets attempted again the next timefind_fileis invoked with the same variable.
Added in version 4.1: every find_file command is treated as REQUIRED when the CMAKE_FIND_REQUIRED variable is enabled.
OPTIONALโ added in version 4.1. Ignores the value ofCMAKE_FIND_REQUIREDand keeps going without an error message if nothing is found. Incompatible withREQUIREDโ pick a lane. ๐
If NO_DEFAULT_PATH is specified, then no additional paths get added to the search. If NO_DEFAULT_PATH is not specified, the search process goes like this, in order:
- If called from within a find module or any other script loaded by a call to
find_package(<PackageName>), it searches prefixes unique to the current package being found. See policyCMP0074. ๐ฆ
Added in version 3.12.
Specifically, it searches paths specified by the following variables, in order:
<PackageName>_ROOTCMake variable, where<PackageName>is the case-preserved package name.<PACKAGENAME>_ROOTCMake variable, where<PACKAGENAME>is the upper-cased package name. See policyCMP0144.
Added in version 3.27.
<PackageName>_ROOTenvironment variable, where<PackageName>is the case-preserved package name.<PACKAGENAME>_ROOTenvironment variable, where<PACKAGENAME>is the upper-cased package name. See policyCMP0144.
Added in version 3.27.
The package root variables are maintained as a stack, so if you're called from nested find modules or config packages, the root paths from the parent's find module or config package get searched after the paths from the current module or package. In other words, the search order is <CurrentPackage>_ROOT, ENV{<CurrentPackage>_ROOT}, <ParentPackage>_ROOT, ENV{<ParentPackage>_ROOT}, etc. You can skip this whole thing if NO_PACKAGE_ROOT_PATH is passed, or by setting CMAKE_FIND_USE_PACKAGE_ROOT_PATH to FALSE.
<prefix>/include/<arch>ifCMAKE_LIBRARY_ARCHITECTUREis set, and<prefix>/includefor each<prefix>in the<PackageName>_ROOTCMake variable and the<PackageName>_ROOTenvironment variable, if called from within a find module loaded byfind_package(<PackageName>). ๐ธ
- Search paths specified in cmake-specific cache variables. These are meant to be used on the command line with a
-DVAR=value. The values get interpreted as semicolon-separated lists. Skippable ifNO_CMAKE_PATHis passed, or by settingCMAKE_FIND_USE_CMAKE_PATHtoFALSE.<prefix>/include/<arch>ifCMAKE_LIBRARY_ARCHITECTUREis set, and<prefix>/includefor each<prefix>inCMAKE_PREFIX_PATHCMAKE_INCLUDE_PATHCMAKE_FRAMEWORK_PATH
- Search paths specified in cmake-specific environment variables. These are meant to be set in the user's shell config, so they use the host's native path separator (
;on Windows and:on UNIX). Skippable ifNO_CMAKE_ENVIRONMENT_PATHis passed, or by settingCMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATHtoFALSE.<prefix>/include/<arch>ifCMAKE_LIBRARY_ARCHITECTUREis set, and<prefix>/includefor each<prefix>inCMAKE_PREFIX_PATHCMAKE_INCLUDE_PATHCMAKE_FRAMEWORK_PATH
- Search the paths specified by the
HINTSoption. These should be paths computed by system introspection โ like a hint from the location of another item you already found. Hard-coded guesses belong in thePATHSoption, okay? ๐ - Search the standard system environment variables. Skippable if
NO_SYSTEM_ENVIRONMENT_PATHis passed, or by settingCMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATHtoFALSE.- The directories in
INCLUDEandPATH.
- The directories in
On Windows hosts, CMake 3.3 through 3.27 searched additional paths: <prefix>/include/<arch> if CMAKE_LIBRARY_ARCHITECTURE is set, and <prefix>/include for each <prefix>/[s]bin in PATH, plus <entry>/include for other entries in PATH. This behavior was removed by CMake 3.28. rip to that era. ๐
- Search cmake variables defined in the Platform files for the current system. The searching of
CMAKE_INSTALL_PREFIXandCMAKE_STAGING_PREFIXcan be skipped ifNO_CMAKE_INSTALL_PREFIXis passed, or by settingCMAKE_FIND_USE_INSTALL_PREFIXtoFALSE. All these locations can be skipped ifNO_CMAKE_SYSTEM_PATHis passed, or by settingCMAKE_FIND_USE_CMAKE_SYSTEM_PATHtoFALSE.<prefix>/include/<arch>ifCMAKE_LIBRARY_ARCHITECTUREis set, and<prefix>/includefor each<prefix>inCMAKE_SYSTEM_PREFIX_PATHCMAKE_SYSTEM_INCLUDE_PATHCMAKE_SYSTEM_FRAMEWORK_PATH
The platform paths these variables contain are locations that typically include installed software โ /usr/local on UNIX-based platforms is the classic example. ๐
- Search the paths specified by the
PATHSoption or in the short-hand version of the command. These are typically hard-coded guesses. ๐คทโโ๏ธ
The CMAKE_IGNORE_PATH, CMAKE_IGNORE_PREFIX_PATH, CMAKE_SYSTEM_IGNORE_PATH and CMAKE_SYSTEM_IGNORE_PREFIX_PATH variables can also cause some of the locations above to be ignored. Not me ignoring stuff โ that's literally what these do. ๐
Added in version 3.16: added CMAKE_FIND_USE_<CATEGORY>_PATH variables to globally disable various search locations.
On macOS, the CMAKE_FIND_FRAMEWORK and CMAKE_FIND_APPBUNDLE variables decide the order of preference between Apple-style and unix-style package components. ๐
The CMake variable CMAKE_FIND_ROOT_PATH specifies one or more directories to be prepended to all other search directories. It effectively "re-roots" the entire search under those locations. Paths that are descendants of CMAKE_STAGING_PREFIX are excluded from this re-rooting, because that variable is always a path on the host system. By default, CMAKE_FIND_ROOT_PATH is empty. ๐ซถ
The CMAKE_SYSROOT variable can also be used to specify exactly one directory to use as a prefix. Heads up: setting CMAKE_SYSROOT also has other effects โ check the docs for that variable for more. โจ
So these are especially the vibe when you're cross-compiling and you need to point at the root dir of the target environment โ CMake will go look there too, bestie. ๐
By default, the order is: first the directories listed in CMAKE_FIND_ROOT_PATH get searched, then the CMAKE_SYSROOT directory, and then the non-rooted directories. You can adjust that default by setting CMAKE_FIND_ROOT_PATH_MODE_INCLUDE. And if you're a control freak like me, you can override the whole thing manually on a per-call basis with these options:
CMAKE_FIND_ROOT_PATH_BOTHโ search in the order described above.NO_CMAKE_FIND_ROOT_PATHโ do not use theCMAKE_FIND_ROOT_PATHvariable.ONLY_CMAKE_FIND_ROOT_PATHโ search only the re-rooted directories and directories belowCMAKE_STAGING_PREFIX.
The default search order is designed to go most-specific โ least-specific for common use cases. And if a project wants a different order? Literally just call the command multiple times and use the NO_* options. Obsessed with the simplicity:
find_file (<VAR> NAMES name PATHS <paths>... NO_DEFAULT_PATH)
find_file (<VAR> NAMES name)
Once one of those calls succeeds, the result variable is set and stored in the cache, so no call will search again. Slay. ๐
๐ธ find_library ๐ธ
Short-hand signature, for when you're being chill:
find_library (<VAR> <name> [<path>...])
The general signature, for when you're being thorough:
find_library (
<VAR>
{<name> | NAMES <name>... [NAMES_PER_DIR]}
[HINTS {<path> | ENV <var>}...]
[PATHS {<path> | ENV <var>}...]
[REGISTRY_VIEW {64|32|64_32|32_64|HOST|TARGET|BOTH}]
[PATH_SUFFIXES <suffix>...]
[VALIDATOR <function>]
[DOC "cache documentation string"]
[NO_CACHE]
[REQUIRED|OPTIONAL]
[NO_DEFAULT_PATH]
[NO_PACKAGE_ROOT_PATH]
[NO_CMAKE_PATH]
[NO_CMAKE_ENVIRONMENT_PATH]
[NO_SYSTEM_ENVIRONMENT_PATH]
[NO_CMAKE_SYSTEM_PATH]
[NO_CMAKE_INSTALL_PREFIX]
[CMAKE_FIND_ROOT_PATH_BOTH |
ONLY_CMAKE_FIND_ROOT_PATH |
NO_CMAKE_FIND_ROOT_PATH]
)
Bestie. This command finds a library. That's the whole assignment. ๐
Before it searches, find_library checks whether the variable <VAR> is defined:
- Not defined โ the search happens.
- Defined and its value is
NOTFOUND, or ends in-NOTFOUNDโ the search happens. - Any other value โ the search does not happen.
Note:<VAR>counts as defined if it's available in the current scope. Peep thecmake-language(7)variables docs for the tea on scopes and how normal variables and cache entries interact. ๐ซถ
The results of the search get stored in a cache entry named <VAR>. Future calls to find_library will inspect that cache entry when the same <VAR> comes up. This optimization means successful searches don't get repeated โ unless you unset() that cache entry. ๐
If the library is found, the recorded value in cache entry <VAR> is the result of the search. If nothing is found, the recorded value is <VAR>-NOTFOUND. Simple as.
Options include:
NAMESโ specify one or more possible names for the library. When you use this to specify names with and without a version suffix, we recommend putting the unversioned name first, so locally-built packages get found before the ones distributions provide. Order matters, periodt.HINTS,PATHSโ specify directories to search in addition to the default locations. TheENVvar sub-option reads paths from a system environment variable. ๐ฆ
Changed in version 3.24: on Windows platform you can include registry queries as part of the directories, using a dedicated syntax. Such specifications are ignored on all other platforms.
REGISTRY_VIEWโ added in version 3.24. Specify which registry views must be queried. This option is only meaningful on Windows platforms and gets ignored on other ones. When not specified, theTARGETview is used when theCMP0134policy isNEW. Refer toCMP0134for the default view when the policy isOLD. ๐64โ query the 64-bit registry. On 32-bit Windows, it always returns the string/REGISTRY-NOTFOUND. ๐32โ query the 32-bit registry.64_32โ query both views (64and32) and generate a path for each.32_64โ query both views (32and64) and generate a path for each.HOSTโ query the registry matching the architecture of the host:64on 64-bit Windows and32on 32-bit Windows.TARGETโ query the registry matching the architecture specified by theCMAKE_SIZEOF_VOID_Pvariable. If it's not defined, fall back to theHOSTview.BOTHโ query both views (32and64). The order depends on these rules: if theCMAKE_SIZEOF_VOID_Pvariable is defined, use the following view depending on its content:8:64_324:32_64
If the CMAKE_SIZEOF_VOID_P variable is not defined, rely on the architecture of the host:
- 64-bit:
64_32 - 32-bit:
32
PATH_SUFFIXESโ specify extra subdirectories to check below each directory location otherwise considered. Little bonus levels. โจVALIDATORโ added in version 3.25. Specify afunction()to be called for each candidate item found (amacro()can't be provided โ that results in an error). Two arguments get passed to the validator function: the name of a result variable, and the absolute path to the candidate item. The item is accepted and the search ends โ unless the function sets the value in the result variable to false in the calling scope. The result variable holds a true value when the validator function is entered. ๐
function(my_check validator_result_var item)
if(NOT item MATCHES ...)
set(${validator_result_var} FALSE PARENT_SCOPE)
endif()
endfunction()
find_library (result NAMES ... VALIDATOR my_check)
Note that if a cached result is used, the search is skipped and any VALIDATOR is ignored. And the cached result is not required to pass the validation function. ๐
DOCโ specify the documentation string for the<VAR>cache entry.NO_CACHEโ added in version 3.21. The result of the search gets stored in a normal variable rather than a cache entry. ๐
Note:find_librarywill still check for<VAR>as usual โ checking first for a variable, then a cache entry. If either one indicates a previous successful search, the search won't be performed.
Warning: use this option with caution, because it can greatly increase the cost of repeated configure steps. Not me warning you twice ๐
REQUIREDโ added in version 3.18. Stop processing with an error message if nothing is found; otherwise the search will be attempted again the next timefind_libraryis invoked with the same variable. Added in version 4.1: everyfind_librarycommand will be treated asREQUIREDwhen theCMAKE_FIND_REQUIREDvariable is enabled.OPTIONALโ added in version 4.1. Ignore the value ofCMAKE_FIND_REQUIREDand continue without an error message if nothing is found. Incompatible withREQUIRED. (they cannot both be present, pick a lane ๐)
If NO_DEFAULT_PATH is specified, then no additional paths get added to the search. If NO_DEFAULT_PATH is not specified, the search process goes like this:
- If called from within a find module or any other script loaded by a call to
find_package(<PackageName>), search prefixes unique to the current package being found. See policyCMP0074. Added in version 3.12. ๐
Specifically, search paths specified by the following variables, in order:
a. <PackageName>_ROOT CMake variable, where <PackageName> is the case-preserved package name.
b. <PACKAGENAME>_ROOT CMake variable, where <PACKAGENAME> is the upper-cased package name. See policy CMP0144. Added in version 3.27.
c. <PackageName>_ROOT environment variable, where <PackageName> is the case-preserved package name.
d. <PACKAGENAME>_ROOT environment variable, where <PACKAGENAME> is the upper-cased package name. See policy CMP0144. Added in version 3.27.
The package root variables are maintained as a stack, so if you're called from nested find modules or config packages, root paths from the parent's find module or config package get searched after paths from the current module or package. In other words, the search order would be <CurrentPackage>_ROOT, ENV{<CurrentPackage>_ROOT}, <ParentPackage>_ROOT, ENV{<ParentPackage>_ROOT}, etc. You can skip this by passing NO_PACKAGE_ROOT_PATH or by setting CMAKE_FIND_USE_PACKAGE_ROOT_PATH to FALSE.
<prefix>/lib/<arch>ifCMAKE_LIBRARY_ARCHITECTUREis set, and<prefix>/libfor each<prefix>in the<PackageName>_ROOTCMake variable and the<PackageName>_ROOTenvironment variable if called from within a find module loaded byfind_package(<PackageName>)
- Search paths that come from cmake-specific cache variables. These are the ones you're meant to set on the command line with a
-DVAR=value, bestie. The values get read as semicolon-separated lists. You can skip this whole step ifNO_CMAKE_PATHis passed, or by setting theCMAKE_FIND_USE_CMAKE_PATHvariable toFALSE.<prefix>/lib/<arch>ifCMAKE_LIBRARY_ARCHITECTUREis set, and<prefix>/libfor each<prefix>inCMAKE_PREFIX_PATHCMAKE_LIBRARY_PATHCMAKE_FRAMEWORK_PATH
- Search paths that come from cmake-specific environment variables ๐ฑ. These are the ones you'd set in your shell config, so they use your host's native path separator (
;on Windows,:on UNIX โ yes the eternal feud continues). Skip this step ifNO_CMAKE_ENVIRONMENT_PATHis passed, or by settingCMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATHtoFALSE.<prefix>/lib/<arch>ifCMAKE_LIBRARY_ARCHITECTUREis set, and<prefix>/libfor each<prefix>inCMAKE_PREFIX_PATHCMAKE_LIBRARY_PATHCMAKE_FRAMEWORK_PATH
- Search the paths you handed over with the
HINTSoption. These are supposed to be paths your build figured out by looking at the system โ like a hint from where some other thing was already found. Hard-coded guesses? Those go inPATHS, not here. Keep the vibes correct ๐ . - Search the standard system environment variables. Skip it if
NO_SYSTEM_ENVIRONMENT_PATHis passed, or by settingCMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATHtoFALSE.- The directories in
LIBandPATH.
- The directories in
On Windows hosts, CMake 3.3 through 3.27 went ahead and searched extra paths too: <prefix>/lib/<arch> if CMAKE_LIBRARY_ARCHITECTURE is set, and <prefix>/lib for each <prefix>/[s]bin in PATH, plus <entry>/lib for other entries in PATH. That behavior was removed by CMake 3.28 โ it's gone, it's not coming back, we don't talk about it ๐ซก.
- Search cmake variables defined in the Platform files for whatever system you're on. The searching of
CMAKE_INSTALL_PREFIXandCMAKE_STAGING_PREFIXcan be skipped ifNO_CMAKE_INSTALL_PREFIXis passed, or by settingCMAKE_FIND_USE_INSTALL_PREFIXtoFALSE. And all of these locations can be skipped ifNO_CMAKE_SYSTEM_PATHis passed, or by settingCMAKE_FIND_USE_CMAKE_SYSTEM_PATHtoFALSE.<prefix>/lib/<arch>ifCMAKE_LIBRARY_ARCHITECTUREis set, and<prefix>/libfor each<prefix>inCMAKE_SYSTEM_PREFIX_PATHCMAKE_SYSTEM_LIBRARY_PATHCMAKE_SYSTEM_FRAMEWORK_PATH
The platform paths those variables hold are the spots that typically have installed software living in them. Think /usr/local on UNIX-based platforms โ iconic behavior honestly.
- Search the paths you gave with the
PATHSoption, or in the short-hand version of the command. These are typically hard-coded guesses. Yeah. We've all been there ๐ญ.
The CMAKE_IGNORE_PATH, CMAKE_IGNORE_PREFIX_PATH, CMAKE_SYSTEM_IGNORE_PATH and CMAKE_SYSTEM_IGNORE_PREFIX_PATH variables can also cause some of the locations above to just... not be searched. Blocked. Ignored. Uninvited from the party ๐.
Added in version 3.16: Added the CMAKE_FIND_USE_<CATEGORY>_PATH variables so you can globally disable various search locations. One switch, so much power โจ.
On macOS, the CMAKE_FIND_FRAMEWORK and CMAKE_FIND_APPBUNDLE variables decide the order of preference between Apple-style and unix-style package components. Pick your fighter ๐.
The CMake variable CMAKE_FIND_ROOT_PATH specifies one or more directories to be prepended to all other search directories. Basically it "re-roots" the entire search underneath the locations you give it. Paths that are descendants of CMAKE_STAGING_PREFIX are excluded from this re-rooting, because that variable is always a path on the host system. By default CMAKE_FIND_ROOT_PATH is empty (she's low maintenance).
The CMAKE_SYSROOT variable can also be used to specify exactly one directory to use as a prefix. Setting CMAKE_SYSROOT also has other effects though โ see that variable's documentation for the full tea โ.
These variables are especially useful when you're cross-compiling and want to point at the root directory of the target environment, so CMake searches there too. By default the order goes: first the directories listed in CMAKE_FIND_ROOT_PATH get searched, then the CMAKE_SYSROOT directory, and then the non-rooted directories. You can adjust that default by setting CMAKE_FIND_ROOT_PATH_MODE_LIBRARY, or override it manually per-call with these options:
CMAKE_FIND_ROOT_PATH_BOTHโ Search in the order described above.NO_CMAKE_FIND_ROOT_PATHโ Do not use theCMAKE_FIND_ROOT_PATHvariable.ONLY_CMAKE_FIND_ROOT_PATHโ Search only the re-rooted directories and directories belowCMAKE_STAGING_PREFIX.
The default search order is designed to go most-specific to least-specific for the common cases โ a whole gradient, gorgeous ๐. But projects can override the order whenever they want by just calling the command multiple times and using the NO_* options:
find_library (<VAR> NAMES name PATHS <paths>... NO_DEFAULT_PATH)
find_library (<VAR> NAMES name)
Once one of those calls succeeds, the result variable gets set and stuffed into the cache so that no later call will search again. Found it once, found it forever ๐.
When you give more than one value to the NAMES option, this command by default considers one name at a time and searches every directory for it. The NAMES_PER_DIR option flips that: it considers one directory at a time and searches for all the names inside it. Different strategy, same goal ๐.
Each library name you hand to NAMES is first considered as-is if it contains a library suffix, and then considered with platform-specific prefixes (like lib) and suffixes (like .so), as defined by the CMAKE_FIND_LIBRARY_PREFIXES and CMAKE_FIND_LIBRARY_SUFFIXES variables. So yes, you can absolutely just specify library filenames like libfoo.a directly โ super useful for locating static libraries on UNIX-like systems ๐ธ.
If the library found is a framework, then <VAR> gets set to the full path to the framework, <fullPath>/A.framework. And when a full path to a framework is used as a library, CMake will use a -framework A and a -F<fullPath> to link the framework to the target. Neat, right?
Added in version 3.28: The library found can now be a .xcframework folder. Upgrade szn ๐ฆ.
If the CMAKE_FIND_LIBRARY_CUSTOM_LIB_SUFFIX variable is set, all search paths get tested as normal โ with the suffix appended, and with all matches of lib/ replaced with lib${CMAKE_FIND_LIBRARY_CUSTOM_LIB_SUFFIX}/. This variable overrides the FIND_LIBRARY_USE_LIB32_PATHS, FIND_LIBRARY_USE_LIBX32_PATHS, and FIND_LIBRARY_USE_LIB64_PATHS global properties. She's the boss ๐.
If the FIND_LIBRARY_USE_LIB32_PATHS global property is set, all search paths get tested as normal with 32/ appended, and with all matches of lib/ replaced with lib32/. This property is automatically set for platforms that are known to need it, if at least one of the languages supported by the project() command is enabled.
If the FIND_LIBRARY_USE_LIBX32_PATHS global property is set, all search paths get tested as normal with x32/ appended, and with all matches of lib/ replaced with libx32/. Same deal โ automatically set for platforms known to need it, if at least one language supported by the project() command is enabled.
If the FIND_LIBRARY_USE_LIB64_PATHS global property is set, all search paths get tested as normal with 64/ appended, and with all matches of lib/ replaced with lib64/. Also automatically set for the platforms that need it when at least one language supported by the project() command is enabled. Three siblings, three suffixes, one very thorough search ๐ฅ.
find_package
Note: The Using Dependencies Guide gives you a high-level introduction to this whole general topic. It serves up a broader overview of where thefind_package()command fits into the bigger picture โ including its relationship to theFetchContentmodule. The guide is recommended pre-reading before you dive into the details below. Do your homework bestie, it's worth it ๐.
Find a package (usually something provided by something external to the project), and load its package-specific details. Calls to this command can also be intercepted by dependency providers ๐.
Typical Usage
Most calls to find_package() look like this:
find_package(<PackageName> [<version>] [REQUIRED] [COMPONENTS <components>...])
The <PackageName> is the only mandatory argument โ everything else is optional and that's the vibe. The <version> is often omitted, and REQUIRED should be given if the project literally cannot configure successfully without the package. Some more complicated packages support components, which you can select with the COMPONENTS keyword, but most packages don't have that level of complexity. Keep it simple, slay ๐
.
The above is a reduced form of the basic signature. Wherever possible, projects should find packages using this form โ it reduces complexity and maximizes the ways the package can be found or provided. Win-win ๐ซถ.
Understanding the basic signature should be enough for general usage of find_package(). But project maintainers who intend to provide a package configuration file should understand the bigger picture, as explained in Full Signature and all the subsequent sections on this page. Big main character energy required for that one โจ.
Search Modes
The command has a few modes by which it searches for packages:
๐ Module mode
okay so in this mode, CMake goes looking for a file called Find<PackageName>.cmake. It checks the locations listed in CMAKE_MODULE_PATH first, then it rummages through the Find Modules that ship with your CMake installation. If it finds the file, CMake reads it and processes it.
That file is the one doing all the work โ it's responsible for finding the package, checking the version, and producing any messages that need producing. Heads up: some Find modules give you limited version support or literally no version support at all, so go read that Find module's documentation, bestie. ๐
Here's the tea though ๐: the Find<PackageName>.cmake file is not typically provided by the package itself. Nope โ it's normally supplied by something external to the package, like the operating system, CMake itself, or even the project from which the find_package() command was called. And because it's externally provided, Find Modules tend to be heuristic in nature (read: vibes-based detective work) and they're super susceptible to becoming out-of-date. ๐ญ They typically search for certain libraries, files, and other package artifacts.
Also, key detail: Module mode is only supported by the basic command signature. periodt.
๐ Config mode
In this mode, CMake searches for a file matching any of these:
<PackageName>.cps<lowercasePackageName>.cps<lowercasePackageName>-config.cmake<PackageName>Config.cmake
If one of the latter two gets found, CMake will also look โ respectively โ for <lowercasePackageName>-config-version.cmake or <PackageName>ConfigVersion.cmake, but only if version details were specified (peep Config Mode Version Selection for the whole explanation of how these separate version files get used). ๐
So the last two are CMake-script package descriptions. The first two are Common Package Specification <https://cps-org.github.io/cps/> (CPS) package descriptions, which are more portable and include version information in the 'base' file. And aside from any explicitly noted exceptions, any references to "config files", "config mode", "package configuration files", and so on refer equally to both CPS and CMake-script files.
Note: Search is implemented in a manner that will tend to prefer Common Package Specification files over CMake-script config files in most cases. Specifying CONFIGS suppresses consideration of CPS files. ๐ซถ
In config mode, the command can be given a list of names to search for as package names. The locations where CMake searches for the config and version files is considerably more complicated than for Module mode (see Config Mode Search Procedure โ it's giving whole questline).
The config and version files are typically installed as part of the package, so they tend to be way more reliable than Find modules. They usually contain direct knowledge of the package contents, so no searching or heuristics are needed inside the config or version files themselves. icon behavior honestly. ๐
Config mode is supported by both the basic and full command signatures.
๐ง FetchContent redirection mode
Added in version 3.24: A call to find_package() can be redirected internally to a package provided by the FetchContent module. To the caller, the behavior will appear similar to Config mode โ except the search logic is by-passed and the component information is not used. See FetchContent_Declare() and FetchContent_MakeAvailable() for further details. โจ
When not redirected to a package provided by FetchContent, the command arguments determine whether Module or Config mode is used. When the basic signature is used, the command searches in Module mode first. If the package is not found, the search falls back to Config mode. ๐ฆ
A user may set the CMAKE_FIND_PACKAGE_PREFER_CONFIG variable to true to reverse that priority and direct CMake to search using Config mode first before falling back to Module mode. The basic signature can also be forced to use only Module mode with a MODULE keyword. And if the full signature is used? The command only searches in Config mode. no fallbacks, no take-backs. ๐
๐ Basic Signature
find_package(<PackageName> [<version>] [EXACT] [QUIET] [MODULE]
[REQUIRED|OPTIONAL] [[COMPONENTS] <component>...]
[OPTIONAL_COMPONENTS <component>...]
[REGISTRY_VIEW {64|32|64_32|32_64|HOST|TARGET|BOTH}]
[GLOBAL]
[NO_POLICY_SCOPE]
[BYPASS_PROVIDER]
[UNWIND_INCLUDE])
The basic signature is supported by both Module and Config modes. The MODULE keyword implies that only Module mode can be used to find the package, with no fallback to Config mode. ๐ซ
Regardless of the mode used, a <PackageName>_FOUND variable will be set to indicate whether the package was found. When the package is found, package-specific information may be provided through other variables and Imported Targets documented by the package itself. ๐
The QUIET option disables informational messages โ including those indicating that the package cannot be found if it is not REQUIRED. The REQUIRED option stops processing with an error message if the package cannot be found. ๐ค
A package-specific list of required components may be listed after the COMPONENTS keyword. If any of these components are not able to be satisfied, the package overall is considered to be not found. If the REQUIRED option is also present, this is treated as a fatal error; otherwise execution still continues. As a form of shorthand, if the REQUIRED option is present, the COMPONENTS keyword can be omitted and the required components can be listed directly after REQUIRED. ๐
The CMAKE_FIND_REQUIRED variable can be enabled to make this call REQUIRED by default. This behavior can be overridden by providing the OPTIONAL keyword. As with the REQUIRED option, a list of components can be listed directly after OPTIONAL, which is equivalent to listing them after the COMPONENTS keyword. When the OPTIONAL keyword is given, the warning output when a package is not found is suppressed. ๐คซ
Additional optional components may be listed after OPTIONAL_COMPONENTS. If these cannot be satisfied, the package overall can still be considered found โ as long as all required components are satisfied. slay. โจ
The set of available components and their meaning are defined by the target package:
- For CMake-script package configuration files, it is formally up to the target package how to interpret the component information given to it, but it should follow the expectations stated above. For calls where no components are specified, there is no single expected behavior and target packages should clearly define what occurs in such cases. Common arrangements include assuming it should find all components, no components, or some well-defined subset of the available components. ๐ค
- Common Package Specification packages consist of a root configuration file and zero or more appendices, each of which provide components and may have dependencies. CMake always attempts to load the root configuration file. Appendices are only loaded if their dependencies can be satisfied, and if they either provide requested components or if no components were requested. If the dependencies of an appendix providing a required component cannot be satisfied, the package is considered not found. Otherwise, that appendix is ignored. ๐
Added in version 3.24: The REGISTRY_VIEW keyword specifies which registry views should be queried. This keyword is only meaningful on Windows platforms and will be ignored on all others. Formally, it is up to the target package how to interpret the registry view information given to it.
Added in version 3.24: Specifying the GLOBAL keyword will promote all imported targets to a global scope in the importing project. Alternatively, this functionality can be enabled by setting the CMAKE_FIND_PACKAGE_TARGETS_GLOBAL variable. ๐
The <version> argument requests a version with which the package found should be compatible. There are two possible forms in which it may be specified:
- A single version with the format
major[.minor[.patch[.tweak]]], where each component is a numeric value. - A version range with the format
versionMin...[<]versionMaxwhereversionMinandversionMaxhave the same format and constraints on components being integers as the single version. By default, both end points are included. By specifying<, the upper end point will be excluded. Version ranges are only supported with CMake 3.19 or later. ๐ฅ
Note: With the exception of CPS packages, version support is currently provided only on a package-by-package basis. When a version range is specified but the package is only designed to expect a single version, the package will ignore the upper end point of the range and only take the single version at the lower end of the range into account. Non-CPS packages that do support version ranges do so in a manner that is determined by the individual package. See the Version Selection section below for details and important caveats. ๐ญ
The EXACT option requests that the version be matched exactly. This option is incompatible with the specification of a version range. ๐ฏ
If no <version> and/or component list is given to a recursive invocation inside a find-module, the corresponding arguments are forwarded automatically from the outer call (including the EXACT flag for <version>). ๐
See the cmake_policy() command documentation for discussion of the NO_POLICY_SCOPE option.
Added in version 3.24: The BYPASS_PROVIDER keyword is only allowed when find_package() is being called by a dependency provider. It can be used by providers to call the built-in find_package() implementation directly and prevent that call from being re-routed back to itself. Future versions of CMake may detect attempts to use this keyword from places other than a dependency provider and halt with a fatal error. ๐ So like, don't be weird about it.
Added in version 4.2: okay so the UNWIND_INCLUDE keyword is only allowed when find_package() is being called from inside a parent find_package() call โ that's the whole vibe check it has to pass ๐
And when a find_package(UNWIND_INCLUDE) call fails to find the package it was looking for, it enters what we're calling an "unwind" state. Bestie, in that state it is so over for further searching: any more calls to find_package() and include() are forbidden ๐ญ, and all the parent include() commands will immediately invoke return() the moment their scope is reached. That unwinding keeps going until we get all the way back up to the parent find_package().
Fr fr, UNWIND_INCLUDE is only intended to be used by calls to find_package() generated by install(EXPORT_PACKAGE_DEPENDENCIES) โ but ngl, if you're the type of icon who wants to manually manage your dependencies in a similar manner, it may be useful to you too ๐ซถ
๐ Full Signature
find_package(<PackageName> [version] [EXACT] [QUIET]
[REQUIRED|OPTIONAL] [[COMPONENTS] <component>...]
[OPTIONAL_COMPONENTS <component>...]
[CONFIG|NO_MODULE]
[GLOBAL]
[NO_POLICY_SCOPE]
[BYPASS_PROVIDER]
[NAMES <name>...]
[CONFIGS <config>...]
[HINTS <path>...]
[PATHS <path>...]
[REGISTRY_VIEW {64|32|64_32|32_64|HOST|TARGET|BOTH}]
[PATH_SUFFIXES <suffix>...]
[NO_DEFAULT_PATH]
[NO_PACKAGE_ROOT_PATH]
[NO_CMAKE_PATH]
[NO_CMAKE_ENVIRONMENT_PATH]
[NO_SYSTEM_ENVIRONMENT_PATH]
[NO_CMAKE_PACKAGE_REGISTRY]
[NO_CMAKE_BUILDS_PATH] # Deprecated; does nothing.
[NO_CMAKE_SYSTEM_PATH]
[NO_CMAKE_INSTALL_PREFIX]
[NO_CMAKE_SYSTEM_PACKAGE_REGISTRY]
[CMAKE_FIND_ROOT_PATH_BOTH |
ONLY_CMAKE_FIND_ROOT_PATH |
NO_CMAKE_FIND_ROOT_PATH]
So here's the tea โ โ the CONFIG option, its synonymous little twin NO_MODULE, or honestly just using any of the options that aren't in the basic signature, all force pure Config mode. And in pure Config mode the command skips Module mode search entirely and goes straight to Config mode search. No detours, no side quests, periodt โจ
Config mode search is out here trying to locate a configuration file that the package itself provides. A cache entry called <PackageName>_DIR gets created to hold the directory where that file lives ๐ By default the command searches for a package named <PackageName>. But if you pass the NAMES option, the names after it get used instead of <PackageName>. Those names also matter when deciding whether to redirect the call to a package provided by FetchContent.
For each package name you specify, the command is hunting for a file whose name matches any of these ๐
<PackageName>Config.cmake<lowercasePackageName>-config.cmake<PackageName>.cps<lowercasePackageName>.cps
You can swap in your own set of possible config file names with the CONFIGS option. The Config Mode Search Procedure is spelled out below. Once a file is found, any version constraint gets checked, and if it's satisfied the config file is read and processed by CMake. And since the package itself provided that file, it already knows where its contents live โ iconic, honestly ๐
Note: because CPS files aren't allowed to have names that don't match the package name, specifying CONFIGS will suppress searching for CPS files. ๐ซ
Every configuration file CMake has considered while searching for the package with a suitable version gets stashed in the <PackageName>_CONSIDERED_CONFIGS variable, with their associated versions living in <PackageName>_CONSIDERED_VERSIONS ๐๏ธ
If the package configuration file just cannot be found, CMake generates an error describing the problem โ unless you specified the QUIET argument ๐คซ. And if REQUIRED is specified and the package isn't found? Fatal error, configure step stops executing, we're done here, lights out ๐. Also: if <PackageName>_DIR has been set to a directory that doesn't contain a configuration file, or the requested version isn't compatible with the package found in that directory (peep Config Mode Version Selection), CMake will ignore it and search from scratch. Fresh start, new me ๐ธ
Package maintainers out there providing package configuration files โ you're encouraged to name and install them so that the Config Mode Search Procedure below finds them without needing any extra options. Do it for the plot ๐ซถ
๐ฆ Config Mode Search Procedure
Note: when Config mode is used, this search procedure applies regardless of whether you used the full signature or the basic one. Same energy either way ๐
Added in version 3.24: literally all calls to find_package() โ even in Module mode โ first look for a config package file in the CMAKE_FIND_PACKAGE_REDIRECTS_DIR directory ๐. The FetchContent module, or even your project itself, can write files to that location to redirect find_package() calls to content the project already provides. If no config package file turns up in there, the search carries on with the logic described below โญ
Okay so CMake builds up a whole little โจsetโจ of possible installation prefixes for the package, and under each one it goes rummaging through several directories looking for a config file. The lists below are literally the directories it searches. Every entry is marked for install trees that follow Windows (W), UNIX (U), or Apple (A) conventions:
<prefix>/<name>/cps/[2] โW๐<prefix>/<name>/*/cps/[2] โW๐<prefix>/cps/<name>/[2] โW๐<prefix>/cps/<name>/*/[2] โW๐<prefix>/cps/[2] โW๐<prefix>/โW๐<prefix>/(cmake|CMake)/โW๐<prefix>/<name>*/โW๐<prefix>/<name>*/(cmake|CMake)/โW๐<prefix>/<name>*/(cmake|CMake)/<name>*/[1] โW๐<prefix>/(lib/<arch>|lib*|share)/cps/<name>/[2] โU๐ง<prefix>/(lib/<arch>|lib*|share)/cps/<name>/*/[2] โU๐ง<prefix>/(lib/<arch>|lib*|share)/cps/[2] โU๐ง<prefix>/(lib/<arch>|lib*|share)/cmake/<name>*/โU๐ง<prefix>/(lib/<arch>|lib*|share)/<name>*/โU๐ง<prefix>/(lib/<arch>|lib*|share)/<name>*/(cmake|CMake)/โU๐ง<prefix>/<name>*/(lib/<arch>|lib*|share)/cmake/<name>*/โW/U๐ซถ<prefix>/<name>*/(lib/<arch>|lib*|share)/<name>*/โW/U๐ซถ<prefix>/<name>*/(lib/<arch>|lib*|share)/<name>*/(cmake|CMake)/โW/U๐ซถ
๐ [1] โ added in version 3.25. she's new-ish, be nice to her ๐
๐ [2] โ added in version 4.3. even newer, iconic behaviour โจ
๐ okay but what about Apple stuff
On systems that support the FRAMEWORK and BUNDLE target properties, CMake also goes looking in these directories for Frameworks or Application Bundles that contain a configuration file:
<prefix>/<name>.framework/Versions/*/Resources/CPS/[3] โA๐<prefix>/<name>.framework/Resources/CPS/[3] โA๐<prefix>/<name>.framework/Resources/โA๐<prefix>/<name>.framework/Resources/CMake/โA๐<prefix>/<name>.framework/Versions/*/Resources/โA๐<prefix>/<name>.framework/Versions/*/Resources/CMake/โA๐<prefix>/<name>.app/Contents/Resources/CPS/[3] โA๐<prefix>/<name>.app/Contents/Resources/โA๐<prefix>/<name>.app/Contents/Resources/CMake/โA๐
๐ [3] โ added in version 4.3. yes another 4.3 baby, they came in a batch ๐
๐ซง the .cps vs .cmake rule (iykyk)
So when find_package is walking through all those paths up there, it's lowkey picky about file extensions ngl:
- it will only look for
.cpsfiles in search paths that contain/cps/ - and it will only look for
.cmakefiles everywhere else
And bestie, that rule applies strictly to the paths as specified โ it does not go peeking at what's actually inside <prefix> or <name> to make up its mind. no cap ๐
And in literally all of the cases above, <name> is treated as case-insensitive and it matches any of the names you specified โ so that's <PackageName>, or whatever names you handed over via NAMES. slay ๐
โจ
So like, if at least one compiled language has been enabled, CMake may go snooping through the architecture-specific lib/<arch> and lib* directories, all based on the compiler's target architecture โ and it does it in this exact order, bestie:
lib/<arch>โ probed if theCMAKE_LIBRARY_ARCHITECTUREvariable is set. ๐lib64โ probed on 64-bit platforms (CMAKE_SIZEOF_VOID_Pis8) and when theFIND_LIBRARY_USE_LIB64_PATHSproperty is set toTRUE.lib32โ probed on 32-bit platforms (CMAKE_SIZEOF_VOID_Pis4) and when theFIND_LIBRARY_USE_LIB32_PATHSproperty is set toTRUE.libx32โ probed on platforms using the x32 ABI if theFIND_LIBRARY_USE_LIBX32_PATHSproperty is set toTRUE.libโ always searched, no questions asked. ๐
Changed in version 3.24: on Windows, you can totally sneak registry queries into the directories you specify through the HINTS and PATHS keywords, using a dedicated syntax. On every other platform those specifications just get ignored, respectfully. ๐
Added in version 3.24: REGISTRY_VIEW can be specified to manage the Windows registry queries you passed as part of PATHS and HINTS.
๐ป REGISTRY_VIEW โ pick your registry view
Okay so this one specifies which registry views must be queried. It's only meaningful on Windows and gets ignored everywhere else, iykyk. When you don't specify it, the TARGET view is used when the CMP0134 policy is NEW. And for the default view when that policy is OLD, go read CMP0134, bestie โ it's all laid out there.
64โ query the 64-bit registry. On 32-bit Windows it always returns the string/REGISTRY-NOTFOUND. ๐32โ query the 32-bit registry.64_32โ query both views (64and32) and generate a path for each.32_64โ query both views (32and64) and generate a path for each.HOSTโ query the registry matching the architecture of the host:64on 64-bit Windows,32on 32-bit Windows.TARGETโ query the registry matching the architecture specified by theCMAKE_SIZEOF_VOID_Pvariable. If that's not defined, it falls back to theHOSTview.BOTHโ query both views (32and64). The order depends on these rules, so pay attention:- If the
CMAKE_SIZEOF_VOID_Pvariable is defined, use the following view depending on what's inside it:8:64_324:32_64
- If the
CMAKE_SIZEOF_VOID_Pvariable is not defined, rely on the architecture of the host:- 64-bit:
64_32 - 32-bit:
32
- 64-bit:
- If the
If PATH_SUFFIXES is specified, the suffixes get appended to each (W) or (U) directory entry, one-by-one. ๐
This whole set of directories is designed to work in cooperation with projects that provide configuration files in their installation trees. Directories marked with (W) are intended for installations on Windows, where the prefix may point at the top of an application's installation directory. Those marked with (U) are intended for installations on UNIX platforms, where the prefix is shared by multiple packages. Ngl it's merely a convention โ so all the (W) and (U) directories still get searched on all platforms. โจ Directories marked with (A) are intended for installations on Apple platforms. The CMAKE_FIND_FRAMEWORK and CMAKE_FIND_APPBUNDLE variables decide the order of preference.
Warning, bestie: settingCMAKE_FIND_FRAMEWORKorCMAKE_FIND_APPBUNDLEto anything other thanFIRST(the default) will cause CMake to search for Common Package Specification files in an order that's different from the order set forth in the specification. So like... be careful. ๐ญ
The set of installation prefixes is constructed using the following steps. And heads up: if NO_DEFAULT_PATH is specified, all the NO_* options are enabled.
- Search prefixes unique to the current
<PackageName>being found. See policyCMP0074. Added in version 3.12. Specifically, search prefixes specified by these variables, in order:- a.
<PackageName>_ROOTCMake variable, where<PackageName>is the case-preserved package name. - b.
<PACKAGENAME>_ROOTCMake variable, where<PACKAGENAME>is the upper-cased package name. See policyCMP0144. Added in version 3.27. - c.
<PackageName>_ROOTenvironment variable, where<PackageName>is the case-preserved package name. - d.
<PACKAGENAME>_ROOTenvironment variable, where<PACKAGENAME>is the upper-cased package name. See policyCMP0144. Added in version 3.27.
- a.
The package root variables are maintained as a stack, so if it's called from within a find module, root paths from the parent's find module will also be searched โ after the paths for the current package. You can skip this whole thing if NO_PACKAGE_ROOT_PATH is passed, or by setting CMAKE_FIND_USE_PACKAGE_ROOT_PATH to FALSE. ๐ซถ
- Search paths specified in CMake-specific cache variables. These are meant to be used on the command line with
-DVAR=VALUE. The values are interpreted as semicolon-separated lists. You can skip this ifNO_CMAKE_PATHis passed or by settingCMAKE_FIND_USE_CMAKE_PATHtoFALSE:CMAKE_PREFIX_PATHCMAKE_FRAMEWORK_PATHCMAKE_APPBUNDLE_PATH
- Search paths specified in CMake-specific environment variables. These are meant to be set in the user's shell configuration, so they use the host's native path separator (
;on Windows and:on UNIX). Skip it ifNO_CMAKE_ENVIRONMENT_PATHis passed or by settingCMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATHtoFALSE:<PackageName>_DIRCMAKE_PREFIX_PATHCMAKE_FRAMEWORK_PATHCMAKE_APPBUNDLE_PATH
- Search paths specified by the
HINTSoption. These should be paths computed by system introspection, like a hint provided by the location of another item you already found. Hard-coded guesses go with thePATHSoption instead, bestie. - Search the standard system environment variables. Skip it if
NO_SYSTEM_ENVIRONMENT_PATHis passed or by settingCMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATHtoFALSE. Path entries ending in/binor/sbinare automatically converted to their parent directories:PATH
- Search paths stored in the CMake User Package Registry. Skip it if
NO_CMAKE_PACKAGE_REGISTRYis passed, or by setting the variableCMAKE_FIND_USE_PACKAGE_REGISTRYtoFALSE, or the deprecated variableCMAKE_FIND_PACKAGE_NO_PACKAGE_REGISTRYtoTRUE. For the details on the user package registry, see thecmake-packages(7)manual. ๐ฆ - Search CMake variables defined in the Platform files for the current system. The searching of
CMAKE_INSTALL_PREFIXandCMAKE_STAGING_PREFIXcan be skipped ifNO_CMAKE_INSTALL_PREFIXis passed or by settingCMAKE_FIND_USE_INSTALL_PREFIXtoFALSE. All these locations can be skipped ifNO_CMAKE_SYSTEM_PATHis passed or by settingCMAKE_FIND_USE_CMAKE_SYSTEM_PATHtoFALSE:CMAKE_SYSTEM_PREFIX_PATHCMAKE_SYSTEM_FRAMEWORK_PATHCMAKE_SYSTEM_APPBUNDLE_PATH
The platform paths these variables contain are locations that typically include installed software โ an example being /usr/local for UNIX based platforms. ๐
- Search paths stored in the CMake System Package Registry. Skip it if
NO_CMAKE_SYSTEM_PACKAGE_REGISTRYis passed, or by setting theCMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRYvariable toFALSE, or the deprecated variableCMAKE_FIND_PACKAGE_NO_SYSTEM_PACKAGE_REGISTRYtoTRUE. See thecmake-packages(7)manual for details on the system package registry. - Search paths specified by the
PATHSoption. These are typically hard-coded guesses. ๐
The CMAKE_IGNORE_PATH, CMAKE_IGNORE_PREFIX_PATH, CMAKE_SYSTEM_IGNORE_PATH and CMAKE_SYSTEM_IGNORE_PREFIX_PATH variables can also cause some of the above locations to be ignored. So like, those are your blocklist, basically. โจ
Paths are searched in the order described above. The first viable package configuration file found is used, even if a newer version of the package resides later in the list of search paths. No cap. ๐ฅ
For search paths which contain glob expressions (*), directories matching the glob are searched in natural, descending order by default. You can override that behavior by setting the variables CMAKE_FIND_PACKAGE_SORT_ORDER and CMAKE_FIND_PACKAGE_SORT_DIRECTION accordingly. Those variables determine the order in which CMake considers glob matches. For example, if the file system contains these package configuration files:
<prefix>/example-1.2/example-config.cmake
<prefix>/example-1.10/example-config.cmake
<prefix>/share/example-2.0/example-config.cmake
like okay so find_package(example) will โ when those variables up there are unset โ pick example-1.10 (assuming both example-1.2 and example-1.10 are viable). But bestie, note that find_package will not find example-2.0, because one of the other two gets found first. that's just how the queue works ๐
So if you want to actually control the order in which find_package searches directories matching a glob expression, you use CMAKE_FIND_PACKAGE_SORT_ORDER and CMAKE_FIND_PACKAGE_SORT_DIRECTION. For instance, to make the example above select example-1.2, you just set:
set(CMAKE_FIND_PACKAGE_SORT_ORDER NATURAL)
set(CMAKE_FIND_PACKAGE_SORT_DIRECTION ASC)
...before calling find_package. that's it, that's the whole trick โจ
Added in version 3.16: they added the CMAKE_FIND_USE_<CATEGORY> variables so you can globally disable various search locations. very slay of them.
Changed in version 4.0: the variables CMAKE_FIND_PACKAGE_SORT_ORDER and CMAKE_FIND_PACKAGE_SORT_DIRECTION now also control the order in which find_package searches directories matching the glob expression in the search paths <prefix>/<name>.framework/Versions/*/Resources/ and <prefix>/<name>.framework/Versions/*/Resources/CMake. In previous versions of CMake, this order was just... unspecified ๐ซ
Changed in version 4.2: when it hits multiple viable matches, find_package now picks the one with the most recent version by default. In previous versions of CMake, the result was unspecified ๐ญ accordingly, the default of CMAKE_FIND_PACKAGE_SORT_ORDER has changed from NONE to NATURAL, and CMAKE_FIND_PACKAGE_SORT_DIRECTION now defaults to DEC (descending) instead of ASC (ascending). glow-up fr fr.
The CMake variable CMAKE_FIND_ROOT_PATH specifies one or more directories to be prepended to all other search directories. This effectively "re-roots" the entire search under given locations. Paths which are descendants of the CMAKE_STAGING_PREFIX are excluded from this re-rooting, because that variable is always a path on the host system. By default the CMAKE_FIND_ROOT_PATH is empty โ iconic, minimal, nothing to see here.
The CMAKE_SYSROOT variable can also be used to specify exactly one directory to use as a prefix. Setting CMAKE_SYSROOT also has other effects, so go read the documentation for that variable for more ๐
These variables are especially useful when cross-compiling to point to the root directory of the target environment โ and CMake will search there too. By default: first the directories listed in CMAKE_FIND_ROOT_PATH are searched, then the CMAKE_SYSROOT directory is searched, and then the non-rooted directories will be searched. You can adjust that default behavior by setting CMAKE_FIND_ROOT_PATH_MODE_PACKAGE. And you can manually override it per-call using these options:
CMAKE_FIND_ROOT_PATH_BOTHโ search in the order described above.NO_CMAKE_FIND_ROOT_PATHโ do not use theCMAKE_FIND_ROOT_PATHvariable.ONLY_CMAKE_FIND_ROOT_PATHโ search only the re-rooted directories and directories belowCMAKE_STAGING_PREFIX.
The default search order is designed to be most-specific to least-specific for common use cases. Projects may override the order by simply calling the command multiple times and using the NO_* options:
find_package (<PackageName> PATHS <paths>... NO_DEFAULT_PATH)
find_package (<PackageName>)
Once one of the calls succeeds, the result variable will be set and stored in the cache so that no call will search again. one and done, bestie ๐
By default the value stored in the result variable will be the path at which the file is found. The CMAKE_FIND_PACKAGE_RESOLVE_SYMLINKS variable may be set to TRUE before calling find_package in order to resolve symbolic links and store the real path to the file.
Every non-REQUIRED find_package call can be disabled or made REQUIRED:
- Setting the
CMAKE_DISABLE_FIND_PACKAGE_<PackageName>variable toTRUEdisables the package. This also disables redirection to a package provided byFetchContent. - Setting the
CMAKE_REQUIRE_FIND_PACKAGE_<PackageName>variable toTRUEmakes the packageREQUIRED.
Setting both variables to TRUE simultaneously is an error ๐ค pick a lane.
The CMAKE_REQUIRE_FIND_PACKAGE_<PackageName> variable takes priority over the OPTIONAL keyword in determining whether a package is required. so like, it wins. periodt.
โจ Config Mode Version Selection โจ
Note: when Config mode is used, this version selection process is applied regardless of whether the full or basic signature was given. no loopholes, bestie.
When the <version> argument is given, Config mode will only find a version of the package that claims compatibility with the requested version (see format specification). If the EXACT option is given, only a version of the package claiming an exact match of the requested version may be found. CMake does not establish any convention for the meaning of version numbers. it's giving "your vibes, your rules" ๐ซ
๐ CMake-script
For CMake-script package configuration files, package version numbers are checked by "version" files provided by the packages themselves or by FetchContent. For a candidate package configuration file <config-file>.cmake, the corresponding version file is located next to it and named either <config-file>-version.cmake or <config-file>Version.cmake. If no such version file is available then the configuration file is assumed to not be compatible with any requested version ๐ซถ A basic version file containing generic version matching code can be created using the CMakePackageConfigHelpers module. When a version file is found it is loaded to check the requested version number. The version file is loaded in a nested scope in which the following variables have been defined:
PACKAGE_FIND_NAMEโ the<PackageName>PACKAGE_FIND_VERSIONโ full requested version stringPACKAGE_FIND_VERSION_MAJORโ major version if requested, else0PACKAGE_FIND_VERSION_MINORโ minor version if requested, else0PACKAGE_FIND_VERSION_PATCHโ patch version if requested, else0PACKAGE_FIND_VERSION_TWEAKโ tweak version if requested, else0PACKAGE_FIND_VERSION_COUNTโ number of version components,0to4
When a version range is specified, the above version variables will hold values based on the lower end of the version range. This is to preserve compatibility with packages that have not been implemented to expect version ranges. In addition, the version range will be described by the following variables:
PACKAGE_FIND_VERSION_RANGEโ full requested version range stringPACKAGE_FIND_VERSION_RANGE_MINโ this specifies whether the lower end point of the version range should be included or excluded. Currently, the only supported value for this variable isINCLUDE.PACKAGE_FIND_VERSION_RANGE_MAXโ this specifies whether the upper end point of the version range should be included or excluded. The supported values for this variable areINCLUDEandEXCLUDE.PACKAGE_FIND_VERSION_MINโ full requested version string of the lower end point of the rangePACKAGE_FIND_VERSION_MIN_MAJORโ major version of the lower end point if requested, else0PACKAGE_FIND_VERSION_MIN_MINORโ minor version of the lower end point if requested, else0PACKAGE_FIND_VERSION_MIN_PATCHโ patch version of the lower end point if requested, else0PACKAGE_FIND_VERSION_MIN_TWEAKโ tweak version of the lower end point if requested, else0PACKAGE_FIND_VERSION_MIN_COUNTโ number of version components of the lower end point,0to4PACKAGE_FIND_VERSION_MAXโ full requested version string of the upper end point of the rangePACKAGE_FIND_VERSION_MAX_MAJORโ major version of the upper end point if requested, else0PACKAGE_FIND_VERSION_MAX_MINORโ minor version of the upper end point if requested, else0PACKAGE_FIND_VERSION_MAX_PATCHโ patch version of the upper end point if requested, else0PACKAGE_FIND_VERSION_MAX_TWEAKโ tweak version of the upper end point if requested, else0PACKAGE_FIND_VERSION_MAX_COUNTโ number of version components of the upper end point,0to4
Regardless of whether a single version or a version range is specified, the variable PACKAGE_FIND_VERSION_COMPLETE will be defined and will hold the full requested version string as specified. the receipts, basically ๐งพ
The version file checks whether it satisfies the requested version and sets these variables:
PACKAGE_VERSIONโ full provided version stringPACKAGE_VERSION_EXACTโ true if version is exact matchPACKAGE_VERSION_COMPATIBLEโ true if version is compatiblePACKAGE_VERSION_UNSUITABLEโ true if unsuitable as any version
These variables are checked by the find_package command to determine whether the configuration file provides an acceptable version. They are not available after the find_package call returns. If the version is acceptable, the following variables are set:
<PackageName>_VERSIONโ full provided version string<PackageName>_VERSION_MAJORโ major version if provided, else0<PackageName>_VERSION_MINORโ minor version if provided, else0<PackageName>_VERSION_PATCHโ patch version if provided, else0<PackageName>_VERSION_TWEAKโ tweak version if provided, else0<PackageName>_VERSION_COUNTโ number of version components,0to4
...and the corresponding package configuration file is loaded. we love a happy ending ๐ธ
Note: while the exact behavior of version matching is determined by the individual package, many packages use write_basic_package_version_file() to supply this logic. The version check scripts this produces have some notable caveats with respect to version ranges:
โฆso picking up right where the range talk left off, bestie ๐ซถ โ two more little rules and then we're free:
- The upper end of a version range acts as a hard limit on what versions will be accepted. So like, a request for version
1.4.0might be satisfied by a package whose version is1.6.0and which advertises 'same major version' compatibility โ but that exact same package gets rejected if the requested version range is1.4.0...1.5.0. The ceiling is the ceiling, periodt ๐ - Both ends of the version range have to match the package's advertised compatibility level. Example: if a package advertises 'same major and minor version' compatibility, then requesting the version range
1.4.0...<1.5.5or1.4.0...1.5.0will result in that package being rejected, even if the package version is1.4.1. ๐ญ
As a result โ and this is the takeaway, write it on your hand โ it is not possible to use a version range to extend the range of compatible package versions that will be accepted. Nope. Not a thing. ๐ซ
๐ธ Common Package Specification ๐ธ
For Common Package Specification package configuration files, CMake checks package version numbers according to the set of recognized version schemas. Right now, these are the schemas it knows about:
simpleโ version numbers are a tuple of integers followed by an optional trailing segment which gets ignored when it comes to version comparisons.customโ the mechanism for interpreting version numbers is unspecified. The version strings must match exactly for the package to be accepted. No vibes-based matching here, it's literally exact or nothing ๐
Refer to version_schema <https://cps-org.github.io/cps/schema.html#version-schema> for a more detailed explanation of each schema and how comparisons for each are performed. Note that the specification may include schemas that are not supported by CMake โ so don't come crying to CMake about those, k?
On top of the package's version, CPS lets packages optionally specify a compat_version <https://cps-org.github.io/cps/schema.html#compat-version>, which is the oldest version for which the package provides compatibility. Basically the package is warranting that a consumer expecting the compat_version should be able to use the package, even if the package's actual version is newer. Iconic of it, honestly ๐ If compat_version isn't specified, it's implicitly equal to the package version โ meaning no backwards compatibility is provided at all.
When a package uses a recognized schema, CMake decides whether it's acceptable according to these rules:
- If
EXACTwas specified, or if the package does not supply acompat_version, the package's version must equal the requested version. - Otherwise:
- The package's version must be greater than or equal to the requested (minimum) version, and
- the package's
compat_versionmust be less than or equal to the requested (minimum) version, and - if a requested maximum version was given, it must be greater than (or equal to, depending on whether the maximum version is specified as inclusive or exclusive) the package's version.
Note: this implementation of range matching was chosen in order to most closely match the behavior of write_basic_package_version_file() <#command:write_basic_package_version_file>, albeit without the case where an overly broad range matches nothing. Cute of them to keep the receipts ๐งพ
For packages using the simple version schema, if the version is acceptable, these variables get set:
<PackageName>_VERSIONโ full provided version string<PackageName>_VERSION_MAJORโ major version if provided, else0<PackageName>_VERSION_MINORโ minor version if provided, else0<PackageName>_VERSION_PATCHโ patch version if provided, else0<PackageName>_VERSION_TWEAKโ tweak version if provided, else0<PackageName>_VERSION_COUNTโ number of version components, non-negative
๐ Package File Interface Variables ๐
When it's loading a find module or a CMake-script package configuration file, find_package defines a whole lil family of variables so the file knows about the call arguments (and it restores their original state before returning, so tidy โจ):
CMAKE_FIND_PACKAGE_NAMEโ the<PackageName>which is searched for<PackageName>_FIND_REQUIREDโ true if theREQUIREDoption was given<PackageName>_FIND_QUIETLYโ true if theQUIEToption was given<PackageName>_FIND_REGISTRY_VIEWโ the requested view if theREGISTRY_VIEWoption was given<PackageName>_FIND_VERSIONโ full requested version string<PackageName>_FIND_VERSION_MAJORโ major version if requested, else0<PackageName>_FIND_VERSION_MINORโ minor version if requested, else0<PackageName>_FIND_VERSION_PATCHโ patch version if requested, else0<PackageName>_FIND_VERSION_TWEAKโ tweak version if requested, else0<PackageName>_FIND_VERSION_COUNTโ number of version components,0to4<PackageName>_FIND_VERSION_EXACTโ true if theEXACToption was given<PackageName>_FIND_COMPONENTSโ list of specified components (required and optional)<PackageName>_FIND_REQUIRED_<c>โ true if component<c>is required, false if component<c>is optional
When a version range is specified, all those version variables above hold values based on the lower end of the range. Why? To preserve compatibility with packages that were never implemented to expect version ranges โ they get to keep living their peaceful little lives ๐๏ธ On top of that, the version range itself gets described by these:
<PackageName>_FIND_VERSION_RANGEโ full requested version range string<PackageName>_FIND_VERSION_RANGE_MINโ specifies whether the lower end point of the version range is included or excluded. Currently,INCLUDEis the only supported value.<PackageName>_FIND_VERSION_RANGE_MAXโ specifies whether the upper end point of the version range is included or excluded. Possible values areINCLUDEorEXCLUDE.<PackageName>_FIND_VERSION_MINโ full requested version string of the lower end point of the range<PackageName>_FIND_VERSION_MIN_MAJORโ major version of the lower end point if requested, else0<PackageName>_FIND_VERSION_MIN_MINORโ minor version of the lower end point if requested, else0<PackageName>_FIND_VERSION_MIN_PATCHโ patch version of the lower end point if requested, else0<PackageName>_FIND_VERSION_MIN_TWEAKโ tweak version of the lower end point if requested, else0<PackageName>_FIND_VERSION_MIN_COUNTโ number of version components of the lower end point,0to4<PackageName>_FIND_VERSION_MAXโ full requested version string of the upper end point of the range<PackageName>_FIND_VERSION_MAX_MAJORโ major version of the upper end point if requested, else0<PackageName>_FIND_VERSION_MAX_MINORโ minor version of the upper end point if requested, else0<PackageName>_FIND_VERSION_MAX_PATCHโ patch version of the upper end point if requested, else0<PackageName>_FIND_VERSION_MAX_TWEAKโ tweak version of the upper end point if requested, else0<PackageName>_FIND_VERSION_MAX_COUNTโ number of version components of the upper end point,0to4
And regardless of whether a single version or a version range was specified, the variable <PackageName>_FIND_VERSION_COMPLETE will be defined, and it holds the full requested version string as specified. Every time. No exceptions, bestie ๐
In Module mode, the loaded find module is the one responsible for honoring the request detailed by these variables โ go read the find module for details, it's the main character of that story. In Config mode, find_package handles the REQUIRED, QUIET, and <version> options automatically, but it leaves it to the package configuration file to handle components in a way that makes sense for that package. The package configuration file may set <PackageName>_FOUND to false to tell find_package that component requirements are not satisfied. Snitching on itself, honestly, we love the honesty ๐
๐ฆ CPS Transitive Requirements ๐ฆ
A Common Package Specification package description consists of one or more components which may in turn depend on other components, either internal or external to the package. When external components are required, the providing package gets noted as a package-level requirement of the package. And typically, the set of required components is noted inside that external package requirement too. Chain of custody, but make it fancy โจ
Where a CMake-script package description would use the find_dependency() <#command:find_dependency> command to handle transitive dependencies, CMake handles transitive dependencies for CPS itself using an internally nested find_package call. That call can resolve CPS package dependencies either via another CPS package, or via a CMake-script package. The manner in which the CPS component dependencies are handled is subject to some caveats โ buckle up ๐ข
When the candidate for resolving a transitive dependency is another CPS package, things are simple; COMPONENTS and CPS "components" are directly comparable (and are effectively synonymous with CMake "imported targets"). CMake-script packages, however, are encouraged to (and often do) check that required components were found, whether or not the package describes separate components. Plus, even the ones that do describe components typically don't have the same correlation to imported targets that's normal for CPS. As a result, passing the set of required components declared by a CPS package to COMPONENTS would result in spurious failures to resolve dependencies. Not the vibe. ๐
To address that: if a candidate for resolving a CPS transitive dependency is a CMake-script package, CMake passes the required components as declared by the consuming CPS package as OPTIONAL_COMPONENTS, and performs a separate, internal check that the candidate package supplied the required imported targets. Those targets must be named <PackageName>::<ComponentName>, in conformance with CPS convention โ otherwise the check will consider the package not found. Name your targets right or it's a wrap, iykyk ๐
๐ find_path ๐
Okay so here's the short-hand signature, the little snack version:
find_path (<VAR> <name> [<path>...])
And here's the general signature, the full meal, the whole entire menu:
find_path (
<VAR>
{<name> | NAMES <name>...}
[HINTS {<path> | ENV <var>}...]
[PATHS {<path> | ENV <var>}...]
[REGISTRY_VIEW {64|32|64_32|32_64|HOST|TARGET|BOTH}]
[PATH_SUFFIXES <suffix>...]
[VALIDATOR <function>]
[DOC "cache documentation string"]
[NO_CACHE]
[REQUIRED|OPTIONAL]
[NO_DEFAULT_PATH]
[NO_PACKAGE_ROOT_PATH]
[NO_CMAKE_PATH]
[NO_CMAKE_ENVIRONMENT_PATH]
[NO_SYSTEM_ENVIRONMENT_PATH]
[NO_CMAKE_SYSTEM_PATH]
[NO_CMAKE_INSTALL_PREFIX]
[CMAKE_FIND_ROOT_PATH_BOTH |
ONLY_CMAKE_FIND_ROOT_PATH |
NO_CMAKE_FIND_ROOT_PATH]
)
So like, this command's whole job is finding a directory that has the file you named. That's it. That's the mission. ๐ฏ
Before it even starts searching, find_path does a vibe check on whether the variable <VAR> is defined. Not defined? Search happens, periodt. Defined but its value is NOTFOUND, or ends in -NOTFOUND? Search still happens, we move. But if the variable holds any other value โ nope, search is not performed. It's giving "we already know her, we don't need to look again." ๐
Note:<VAR>counts as defined if it's available in the current scope. Peep thecmake-language(7)variables documentation for the whole tea on scopes, plus how normal variables and cache entries interact with each other. ๐ซถ
Where do the results go? Into a cache entry named <VAR>, obviously. Next time find_path gets called with that same <VAR>, it'll peek at this cache entry first. This is the little optimization that means successful searches don't get repeated โ unless, of course, the cache entry gets unset(). ๐ง
If the file gets found in some directory, the recorded value in cache entry <VAR> is the result of the search. If nothing turns up, the recorded value is <VAR>-NOTFOUND. Sad but honest. ๐ญ
Options include:
NAMESโ specify one or more possible names for the file in a directory. โจ When you're using this to list names with and without a version suffix, the recommendation is to put the unversioned name first, so locally-built packages get found before the ones your distro handed you. Priorities, bestie.HINTS,PATHSโ specify directories to search in addition to the default locations. TheENVvar sub-option reads paths straight out of a system environment variable. ๐ธ Changed in version 3.24: on Windows platforms you can include registry queries as part of the directories, using a dedicated syntax. Those specs get straight-up ignored on every other platform. ๐REGISTRY_VIEWโ Added in version 3.24. Specify which registry views must be queried. This option is only meaningful on Windows platforms and gets ignored everywhere else. When you don't specify it, theTARGETview is used when theCMP0134policy isNEW. Go readCMP0134for what the default view is when the policy isOLD. ๐64โ query the 64-bit registry. On 32-bit Windows, it always returns the string/REGISTRY-NOTFOUND. ๐32โ query the 32-bit registry.64_32โ query both views (64and32) and generate a path for each.32_64โ query both views (32and64) and generate a path for each.HOSTโ query the registry matching the architecture of the host:64on 64-bit Windows and32on 32-bit Windows.TARGETโ query the registry matching the architecture specified by theCMAKE_SIZEOF_VOID_Pvariable. If that's not defined, fall back to theHOSTview.BOTHโ query both views (32and64). The order depends on these rules: ifCMAKE_SIZEOF_VOID_Pis defined, use the following view depending on the content of that variable:8:64_324:32_64
If CMAKE_SIZEOF_VOID_P is not defined, rely on the architecture of the host:
- 64-bit:
64_32 - 32-bit:
32
PATH_SUFFIXESโ specify additional subdirectories to check below each directory location that would otherwise be considered. Little bonus layers. ๐VALIDATORโ Added in version 3.25. Specify afunction()to be called for each candidate item found (you cannot hand it amacro()โ that results in an error, no cap). Two arguments get passed to the validator function: the name of a result variable, and the absolute path to the candidate item. The item is accepted and the search ends unless the function sets the value in the result variable to false in the calling scope. The result variable holds a true value when the validator function is entered. ๐ฆ
function(my_check validator_result_var item)
if(NOT item MATCHES ...)
set(${validator_result_var} FALSE PARENT_SCOPE)
endif()
endfunction()
find_path (result NAMES ... VALIDATOR my_check)
Keep in mind: if a cached result is used, the search is skipped and any VALIDATOR is ignored. The cached result is not required to pass the validation function. Iconic loophole, honestly. ๐
DOCโ specify the documentation string for the<VAR>cache entry. ๐NO_CACHEโ Added in version 3.21. The result of the search gets stored in a normal variable rather than a cache entry.
Note:find_pathwill still check for<VAR>as usual โ checking first for a variable, then a cache entry. If either indicates a previous successful search, the search will not be performed. Warning: use this option with caution, because it can greatly increase the cost of repeated configure steps. Like, greatly. โ ๏ธ
REQUIREDโ Added in version 3.18. Stop processing with an error message if nothing is found; otherwise the search gets attempted again the next timefind_pathis invoked with the same variable. Added in version 4.1: everyfind_pathcommand is treated asREQUIREDwhen theCMAKE_FIND_REQUIREDvariable is enabled. ๐ฅOPTIONALโ Added in version 4.1. Ignore the value ofCMAKE_FIND_REQUIREDand continue without an error message if nothing is found. Incompatible withREQUIRED. Pick a lane, babe. โญ
If NO_DEFAULT_PATH is specified, then no additional paths get added to the search. Full stop. If NO_DEFAULT_PATH is not specified, the search process goes like this:
- If it's called from within a find module or any other script loaded by a call to
find_package(<PackageName>), search the prefixes unique to the current package being found. See policyCMP0074. Added in version 3.12. Specifically, search paths specified by the following variables, in order:<PackageName>_ROOTCMake variable, where<PackageName>is the case-preserved package name.<PACKAGENAME>_ROOTCMake variable, where<PACKAGENAME>is the upper-cased package name. See policyCMP0144. Added in version 3.27.<PackageName>_ROOTenvironment variable, where<PackageName>is the case-preserved package name.<PACKAGENAME>_ROOTenvironment variable, where<PACKAGENAME>is the upper-cased package name. See policyCMP0144. Added in version 3.27.
The package root variables are maintained as a stack, so if you're called from nested find modules or config packages, root paths from the parent's find module or config package get searched after the paths from the current module or package. In other words, the search order would be <CurrentPackage>_ROOT, ENV{<CurrentPackage>_ROOT}, <ParentPackage>_ROOT, ENV{<ParentPackage>_ROOT}, etc. You can skip all this if NO_PACKAGE_ROOT_PATH is passed, or by setting CMAKE_FIND_USE_PACKAGE_ROOT_PATH to FALSE. ๐ซถ
<prefix>/include/<arch>ifCMAKE_LIBRARY_ARCHITECTUREis set, and<prefix>/includefor each<prefix>in the<PackageName>_ROOTCMake variable and the<PackageName>_ROOTenvironment variable if called from within a find module loaded byfind_package(<PackageName>)
- Search paths specified in cmake-specific cache variables. These are intended to be used on the command line with a
-DVAR=value. The values are interpreted as semicolon-separated lists. You can skip this ifNO_CMAKE_PATHis passed, or by settingCMAKE_FIND_USE_CMAKE_PATHtoFALSE. ๐<prefix>/include/<arch>ifCMAKE_LIBRARY_ARCHITECTUREis set, and<prefix>/includefor each<prefix>inCMAKE_PREFIX_PATHCMAKE_INCLUDE_PATHCMAKE_FRAMEWORK_PATH
- Search paths specified in cmake-specific environment variables. These are meant to be set in the user's shell configuration, and therefore use the host's native path separator (
;on Windows and:on UNIX). You can skip this ifNO_CMAKE_ENVIRONMENT_PATHis passed, or by settingCMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATHtoFALSE. ๐ธ<prefix>/include/<arch>ifCMAKE_LIBRARY_ARCHITECTUREis set, and<prefix>/includefor each<prefix>inCMAKE_PREFIX_PATHCMAKE_INCLUDE_PATHCMAKE_FRAMEWORK_PATH
- Search the paths specified by the
HINTSoption. These should be paths computed by system introspection โ like a hint provided by the location of another item you already found. Hard-coded guesses belong in thePATHSoption, bestie. ๐ - Search the standard system environment variables. You can skip this if
NO_SYSTEM_ENVIRONMENT_PATHis passed, or by settingCMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATHtoFALSE. ๐- The directories in
INCLUDEandPATH.
- The directories in
On Windows hosts, CMake 3.3 through 3.27 searched additional paths: <prefix>/include/<arch> if CMAKE_LIBRARY_ARCHITECTURE is set, and <prefix>/include for each <prefix>/[s]bin in PATH, and <entry>/include for other entries in PATH. This behavior was removed by CMake 3.28. Rip to a real one. ๐
- Now it goes digging in the cmake variables defined in the Platform files for your current system. โจ The search of
CMAKE_INSTALL_PREFIXandCMAKE_STAGING_PREFIXcan be skipped if you passNO_CMAKE_INSTALL_PREFIX, or by setting theCMAKE_FIND_USE_INSTALL_PREFIXvariable toFALSE. And like, all of these locations can be skipped if you passNO_CMAKE_SYSTEM_PATH, or by settingCMAKE_FIND_USE_CMAKE_SYSTEM_PATHtoFALSE. ๐<prefix>/include/<arch>ifCMAKE_LIBRARY_ARCHITECTUREis set, and<prefix>/includefor each<prefix>inCMAKE_SYSTEM_PREFIX_PATHCMAKE_SYSTEM_INCLUDE_PATHCMAKE_SYSTEM_FRAMEWORK_PATH
The platform paths that these variables contain are locations that typically include installed software. An example being /usr/local for UNIX based platforms. ๐
- Search the paths specified by the
PATHSoption or in the short-hand version of the command. These are typically hard-coded guesses. ๐
The CMAKE_IGNORE_PATH, CMAKE_IGNORE_PREFIX_PATH, CMAKE_SYSTEM_IGNORE_PATH and CMAKE_SYSTEM_IGNORE_PREFIX_PATH variables can also cause some of the above locations to be ignored. (Yes bestie, you can yeet a whole search location. blocking, muted, unfollowed. ๐)
Added in version 3.16: Added CMAKE_FIND_USE_<CATEGORY>_PATH variables to globally disable various search locations. ๐
On macOS the CMAKE_FIND_FRAMEWORK and CMAKE_FIND_APPBUNDLE variables determine the order of preference between Apple-style and unix-style package components. ๐
The CMake variable CMAKE_FIND_ROOT_PATH specifies one or more directories to be prepended to all other search directories. This effectively "re-roots" the entire search under given locations. Paths which are descendants of the CMAKE_STAGING_PREFIX are excluded from this re-rooting, because that variable is always a path on the host system. By default the CMAKE_FIND_ROOT_PATH is empty. ๐ฆ
The CMAKE_SYSROOT variable can also be used to specify exactly one directory to use as a prefix. Setting CMAKE_SYSROOT also has other effects. See the documentation for that variable for more. ๐
These variables are especially useful when cross-compiling to point to the root directory of the target environment and CMake will search there too. By default at first the directories listed in CMAKE_FIND_ROOT_PATH are searched, then the CMAKE_SYSROOT directory is searched, and then the non-rooted directories will be searched. The default behavior can be adjusted by setting CMAKE_FIND_ROOT_PATH_MODE_INCLUDE. This behavior can be manually overridden on a per-call basis using options:
CMAKE_FIND_ROOT_PATH_BOTHโ Search in the order described above.NO_CMAKE_FIND_ROOT_PATHโ Do not use theCMAKE_FIND_ROOT_PATHvariable.ONLY_CMAKE_FIND_ROOT_PATHโ Search only the re-rooted directories and directories belowCMAKE_STAGING_PREFIX.
The default search order is designed to be most-specific to least-specific for common use cases. Projects may override the order by simply calling the command multiple times and using the NO_* options:
find_path (<VAR> NAMES name PATHS <paths>... NO_DEFAULT_PATH)
find_path (<VAR> NAMES name)
Once one of the calls succeeds the result variable will be set and stored in the cache so that no call will search again. ๐ (one and done, she's not doing overtime)
When searching for frameworks, if the file is specified as A/b.h, then the framework search will look for A.framework/Headers/b.h. If that is found the path will be set to the path to the framework. CMake will convert this to the correct -F option to include the file. ๐ง
find_program ๐
A short-hand signature is:
find_program (<VAR> <name> [<path>...])
The general signature is:
find_program (
<VAR>
{<name> | NAMES <name>... [NAMES_PER_DIR]}
[HINTS {<path> | ENV <var>}...]
[PATHS {<path> | ENV <var>}...]
[REGISTRY_VIEW {64|32|64_32|32_64|HOST|TARGET|BOTH}]
[PATH_SUFFIXES <suffix>...]
[VALIDATOR <function>]
[DOC "cache documentation string"]
[NO_CACHE]
[REQUIRED|OPTIONAL]
[NO_DEFAULT_PATH]
[NO_PACKAGE_ROOT_PATH]
[NO_CMAKE_PATH]
[NO_CMAKE_ENVIRONMENT_PATH]
[NO_SYSTEM_ENVIRONMENT_PATH]
[NO_CMAKE_SYSTEM_PATH]
[NO_CMAKE_INSTALL_PREFIX]
[CMAKE_FIND_ROOT_PATH_BOTH |
ONLY_CMAKE_FIND_ROOT_PATH |
NO_CMAKE_FIND_ROOT_PATH]
)
This command is used to find a program. ๐ซถ Like, literally its whole job.
Prior to searching, find_program checks if variable <VAR> is defined. If the variable is not defined, the search will be performed. If the variable is defined and its value is NOTFOUND, or ends in -NOTFOUND, the search will be performed. If the variable contains any other value the search is not performed. โจ
Note:<VAR>is considered defined if it is available in the current scope. See thecmake-language(7)variables documentation for details on scopes, and the interaction of normal variables and cache entries. ๐
The results of the search will be stored in a cache entry named <VAR>. Future calls to find_program will inspect this cache entry when specifying the same <VAR>. This optimization ensures successful searches will not be repeated unless the cache entry is unset(). (slay, no redundant work ๐
)
If the program is found the recorded value in cache entry <VAR> will be the result of the search. If nothing is found, the recorded value will be <VAR>-NOTFOUND. ๐ญ
Options include:
NAMESโ Specify one or more possible names for the program.
When using this to specify names with and without a version suffix, we recommend specifying the unversioned name first so that locally-built packages can be found before those provided by distributions. ๐
HINTS,PATHSโ Specify directories to search in addition to the default locations. TheENVvar sub-option reads paths from a system environment variable. ๐
Changed in version 3.24: On Windows platform, it is possible to include registry queries as part of the directories, using a dedicated syntax. Such specifications will be ignored on all other platforms. ๐
REGISTRY_VIEWโ Added in version 3.24. Specify which registry views must be queried. This option is only meaningful on Windows platforms and will be ignored on other ones. When not specified, theBOTHview is used when theCMP0134policy isNEW. Refer toCMP0134for the default view when the policy isOLD. ๐ช64โ Query the 64-bit registry. On 32-bit Windows, it always returns the string/REGISTRY-NOTFOUND.32โ Query the 32-bit registry.64_32โ Query both views (64 and 32) and generate a path for each.32_64โ Query both views (32 and 64) and generate a path for each.HOSTโ Query the registry matching the architecture of the host:64on 64-bit Windows and32on 32-bit Windows.TARGETโ Query the registry matching the architecture specified by theCMAKE_SIZEOF_VOID_Pvariable. If not defined, fall back toHOSTview.BOTHโ Query both views (32 and 64). The order depends on the following rules: If theCMAKE_SIZEOF_VOID_Pvariable is defined, use the following view depending on the content of this variable:8:64_324:32_64
If the CMAKE_SIZEOF_VOID_P variable is not defined, rely on the architecture of the host:
- 64-bit:
64_32 - 32-bit:
32
PATH_SUFFIXESโ Specify additional subdirectories to check below each directory location otherwise considered. ๐VALIDATORโ Added in version 3.25. Specify afunction()to be called for each candidate item found (amacro()cannot be provided, that will result in an error). Two arguments will be passed to the validator function: the name of a result variable, and the absolute path to the candidate item. The item will be accepted and the search will end unless the function sets the value in the result variable to false in the calling scope. The result variable will hold a true value when the validator function is entered. ๐ต๏ธโโ๏ธ
function(my_check validator_result_var item)
if(NOT item MATCHES ...)
set(${validator_result_var} FALSE PARENT_SCOPE)
endif()
endfunction()
find_program (result NAMES ... VALIDATOR my_check)
Note that if a cached result is used, the search is skipped and any VALIDATOR is ignored. The cached result is not required to pass the validation function. ๐
DOCโ Specify the documentation string for the<VAR>cache entry. ๐NO_CACHEโ Added in version 3.21. The result of the search will be stored in a normal variable rather than a cache entry.
Note:find_programwill still check for<VAR>as usual, checking first for a variable, and then a cache entry. If either indicate a previous successful search, the search will not be performed. ๐
Warning: This option should be used with caution because it can greatly increase the cost of repeated configure steps. ๐ญ (she's expensive, bestie)
REQUIREDโ Added in version 3.18. Stop processing with an error message if nothing is found, otherwise the search will be attempted again the next timefind_programis invoked with the same variable. ๐ฅ- Added in version 4.1: every
find_programcall lowkey gets treated asREQUIREDwhen theCMAKE_FIND_REQUIREDvariable is enabled. โจ OPTIONALโ added in version 4.1. This one's the chill one: it ignores whateverCMAKE_FIND_REQUIREDis set to and just keeps going with no error message if nothing turns up. ๐ซถ Heads up tho, it's incompatible withREQUIREDโ they cannot both be in the group chat.
If NO_DEFAULT_PATH is specified, then no extra paths get added to the search. Periodt. If NO_DEFAULT_PATH is not specified, the search goes like this, in order:
- If it's called from inside a find module or any other script loaded by a call to
find_package(<PackageName>), it searches the prefixes that are unique to the current package being found. See policyCMP0074. ๐ง
Added in version 3.12.
Specifically, it searches paths specified by these variables, in order:
- The
<PackageName>_ROOTCMake variable, where<PackageName>is the case-preserved package name. - The
<PACKAGENAME>_ROOTCMake variable, where<PACKAGENAME>is the upper-cased package name. See policyCMP0144.
Added in version 3.27.
- The
<PackageName>_ROOTenvironment variable, where<PackageName>is the case-preserved package name. - The
<PACKAGENAME>_ROOTenvironment variable, where<PACKAGENAME>is the upper-cased package name. See policyCMP0144.
Added in version 3.27.
The package root variables are maintained as a stack, so if you're called from nested find modules or config packages, root paths from the parent's find module or config package get searched after the paths from the current module or package. In other words, the search order is <CurrentPackage>_ROOT, ENV{<CurrentPackage>_ROOT}, <ParentPackage>_ROOT, ENV{<ParentPackage>_ROOT}, etc. You can skip this whole vibe by passing NO_PACKAGE_ROOT_PATH or by setting CMAKE_FIND_USE_PACKAGE_ROOT_PATH to FALSE.
<prefix>/[s]binfor each<prefix>in the<PackageName>_ROOTCMake variable and the<PackageName>_ROOTenvironment variable, if it's called from within a find module loaded byfind_package(<PackageName>)๐ฆ
- Search the paths specified in CMake-specific cache variables. These are meant to be used on the command line with
-DVAR=value. The values are interpreted as semicolon-separated lists. You can skip this ifNO_CMAKE_PATHis passed or by settingCMAKE_FIND_USE_CMAKE_PATHtoFALSE.<prefix>/[s]binfor each<prefix>inCMAKE_PREFIX_PATHCMAKE_PROGRAM_PATHCMAKE_APPBUNDLE_PATH
- Search the paths specified in CMake-specific environment variables. These are meant to be set in the user's shell configuration, and therefore they use the host's native path separator (
;on Windows and:on UNIX). You can skip this ifNO_CMAKE_ENVIRONMENT_PATHis passed or by settingCMAKE_FIND_USE_CMAKE_ENVIRONMENT_PATHtoFALSE.<prefix>/[s]binfor each<prefix>inCMAKE_PREFIX_PATHCMAKE_PROGRAM_PATHCMAKE_APPBUNDLE_PATH
- Search the paths specified by the
HINTSoption. These should be paths computed by system introspection โ like, a hint provided by the location of another item you already found. Hard-coded guesses belong in thePATHSoption, bestie. ๐ - Search the standard system environment variables. You can skip this if
NO_SYSTEM_ENVIRONMENT_PATHis passed or by settingCMAKE_FIND_USE_SYSTEM_ENVIRONMENT_PATHtoFALSE.- The directories in
PATHitself.
- The directories in
- Search CMake variables defined in the Platform files for the current system. The search of
CMAKE_INSTALL_PREFIXandCMAKE_STAGING_PREFIXcan be skipped ifNO_CMAKE_INSTALL_PREFIXis passed or by settingCMAKE_FIND_USE_INSTALL_PREFIXtoFALSE. And, like, all of these locations can be skipped ifNO_CMAKE_SYSTEM_PATHis passed or by settingCMAKE_FIND_USE_CMAKE_SYSTEM_PATHtoFALSE. ๐<prefix>/[s]binfor each<prefix>inCMAKE_SYSTEM_PREFIX_PATHCMAKE_SYSTEM_PROGRAM_PATHCMAKE_SYSTEM_APPBUNDLE_PATH
The platform paths these variables contain are locations that typically include installed software. An example being /usr/local for UNIX based platforms. ๐
- Search the paths specified by the
PATHSoption or in the short-hand version of the command. These are typically hard-coded guesses.
The CMAKE_IGNORE_PATH, CMAKE_IGNORE_PREFIX_PATH, CMAKE_SYSTEM_IGNORE_PATH and CMAKE_SYSTEM_IGNORE_PREFIX_PATH variables can also cause some of the above locations to be ignored. ๐
Added in version 3.16: the CMAKE_FIND_USE_<CATEGORY>_PATH variables got added so you can globally disable various search locations.
On macOS, the CMAKE_FIND_FRAMEWORK and CMAKE_FIND_APPBUNDLE variables decide the order of preference between Apple-style and unix-style package components. ๐
The CMake variable CMAKE_FIND_ROOT_PATH specifies one or more directories to be prepended to all other search directories. This effectively "re-roots" the entire search under the given locations. Paths which are descendants of CMAKE_STAGING_PREFIX are excluded from this re-rooting, because that variable is always a path on the host system. By default CMAKE_FIND_ROOT_PATH is empty.
The CMAKE_SYSROOT variable can also be used to specify exactly one directory to use as a prefix. Setting CMAKE_SYSROOT also has other effects โ see the documentation for that variable for more. ๐ง
These variables are super useful when cross-compiling, to point at the root directory of the target environment, and CMake will search there too. By default, at first the directories listed in CMAKE_FIND_ROOT_PATH are searched, then the CMAKE_SYSROOT directory is searched, and then the non-rooted directories get searched. The default behavior can be adjusted by setting CMAKE_FIND_ROOT_PATH_MODE_PROGRAM. And you can manually override this behavior per-call using these options:
CMAKE_FIND_ROOT_PATH_BOTHโ search in the order described above.NO_CMAKE_FIND_ROOT_PATHโ do not use theCMAKE_FIND_ROOT_PATHvariable.ONLY_CMAKE_FIND_ROOT_PATHโ search only the re-rooted directories and directories belowCMAKE_STAGING_PREFIX.
The default search order is designed to be most-specific to least-specific for common use cases. Projects can override the order by simply calling the command multiple times and using the NO_* options:
find_program (<VAR> NAMES name PATHS <paths>... NO_DEFAULT_PATH)
find_program (<VAR> NAMES name)
Once one of the calls succeeds, the result variable gets set and stored in the cache so that no call will search again. One and done, slay. ๐
When more than one value is given to the NAMES option, this command by default considers one name at a time and searches every directory for it. The NAMES_PER_DIR option tells this command to flip it: consider one directory at a time and search for all the names in it. ๐ฅ
The set of files considered to be programs is platform-specific:
- On Windows, filename suffixes are considered in order
.com,.exe, and no suffix. - On non-Windows systems, no filename suffix is considered, but files must have execute permission (see policy
CMP0109). โญ
To search for scripts, specify an extension explicitly:
if(WIN32)
set(_script_suffix .bat)
else()
set(_script_suffix .sh)
endif()
find_program(MY_SCRIPT NAMES my_script${_script_suffix})
๐ foreach ๐
Evaluate a group of commands for each value in a list. Basically a glow-up for "do the thing again but with the next item." โจ
foreach(<loop_var> <items>)
<commands>
endforeach()
where <items> is a list of items separated by semicolon or whitespace. All commands between foreach and the matching endforeach are recorded without being invoked. Once the endforeach is evaluated, that recorded list of commands is invoked once for each item in <items>. At the beginning of each iteration, the variable <loop_var> gets set to the value of the current item. ๐
The scope of <loop_var> is restricted to the loop scope. See policy CMP0124 for the details.
The commands break() and continue() are your escape hatches from the normal control flow. ๐ฆ
Per legacy, the endforeach() command admits an optional <loop_var> argument. If you use it, it must be a verbatim repeat of the argument of the opening foreach command. No creative liberty. ๐ญ
foreach(<loop_var> RANGE <stop>)
In this variant, foreach iterates over the numbers 0, 1, ... up to (and including) the nonnegative integer <stop>.
foreach(<loop_var> RANGE <start> <stop> [<step>])
In this variant, foreach iterates over the numbers from <start> up to at most <stop> in steps of <step>. If <step> is not specified, then the step size is 1. The three arguments <start> <stop> <step> must all be nonnegative integers, and <stop> must not be smaller than <start>; otherwise you enter the danger zone ๐ of undocumented behavior that may change in future releases.
foreach(<loop_var> IN [LISTS [<lists>]] [ITEMS [<items>]])
okay so in this variant, <lists> is a whitespace- or semicolon-separated list of list-valued variables, and foreach just iterates over every single item in every single one of those lists, one by one ๐
The <items> that come after the ITEMS keyword get processed exactly like in the first variant of foreach. And fr fr, LISTS A and ITEMS ${A} are literally the same thing. But here's the tea: if you don't give any <lists> or <items>, the body of the loop never runs โ it's processed as empty, bestie ๐ซถ
Here's how the LISTS option gets processed, watch the magic:
set(A 0;1)
set(B 2 3)
set(C "4 5")
set(D 6;7 8)
set(E "")
foreach(X IN LISTS A B C D E)
message(STATUS "X=${X}")
endforeach()
and it yields:
-- X=0
-- X=1
-- X=2
-- X=3
-- X=4 5
-- X=6
-- X=7
-- X=8
not the "4 5" staying glued together as one item ๐ญ that's the whole point, she's quoting it
foreach(<loop_var>... IN ZIP_LISTS <lists>)
โจ Added in version 3.17.
In this variant, <lists> is again a whitespace- or semicolon-separated list of list-valued variables. The foreach command iterates over each list simultaneously, setting the iteration variables like this:
- if you pass a single
loop_var, it sets a whole series ofloop_var_Nvariables to the current item from the corresponding list ๐ - if you pass multiple variable names, it sets each variable to the current item from the corresponding list. The number of iteration variables has to match the number of list variables โ no cap, that's the rule ๐
If no <lists> are given, the body of the loop will never be executed (i.e., it's processed as empty). Same energy as before.
Here's ZIP_LISTS in action:
list(APPEND English one two three four)
list(APPEND Bahasa satu dua tiga)
foreach(num IN ZIP_LISTS English Bahasa)
message(STATUS "num_0=${num_0}, num_1=${num_1}")
endforeach()
foreach(en ba IN ZIP_LISTS English Bahasa)
message(STATUS "en=${en}, ba=${ba}")
endforeach()
yields:
-- num_0=one, num_1=satu
-- num_0=two, num_1=dua
-- num_0=three, num_1=tiga
-- num_0=four, num_1=
-- en=one, ba=satu
-- en=two, ba=dua
-- en=three, ba=tiga
-- en=four, ba=
see how English has four things and Bahasa only has three? The fourth round just leaves the Bahasa side empty. She zips as far as she can, periodt ๐ธ
See Also
break()<#command:break>continue()<#command:continue>endforeach()<#command:endforeach>while()<#command:while>
function
Start recording a function for later invocation as a command. It's giving "write it down now, run it later" ๐
function(<name> [<arg1> ...])
<commands>
endfunction()
Defines a function named <name> that takes arguments named <arg1>, ... The <commands> in the function definition are recorded โ nobody runs them until the function actually gets invoked. Iconic lazy-loading behaviour honestly โจ
Per legacy, the endfunction() <#command:endfunction> command admits an optional <name> argument. If you use it, it has to be a verbatim repeat of the argument of the opening function command. No paraphrasing, bestie ๐
A function opens a new scope: see set(var PARENT_SCOPE) <#command:set> for the deets.
Pop over to the cmake_policy() <#command:cmake_policy> command docs for how policies behave inside functions.
And check the macro() <#command:macro> command docs for the differences between CMake functions and macros โ they are not the same vibe, iykyk ๐
Invocation
The function invocation is case-insensitive. A function defined as
function(foo)
<commands>
endfunction()
can be invoked through any of
foo()
Foo()
FOO()
cmake_language(CALL foo)
and so on. But like, it is strongly recommended to stay with the case chosen in the function definition. Typically functions use all-lowercase names. Consistency ate, fr fr ๐
Added in version 3.18: The cmake_language(CALL ...) <#command:cmake_language> command can also be used to invoke the function.
Arguments
When the function is invoked, the recorded <commands> are first modified by replacing formal parameters (${arg1}, ...) with the arguments passed, and then invoked as normal commands ๐ฅ
On top of referencing the formal parameters, you can reference the ARGC variable, which gets set to the number of arguments passed into the function, plus ARGV0, ARGV1, ARGV2, ... which hold the actual values of the arguments passed in. This is literally how you make functions with optional arguments. Chef's kiss ๐
Furthermore, ARGV holds the list of all arguments given to the function, and ARGN holds the list of arguments past the last expected argument. Big main character energy for varargs girlies ๐ฆ
โ ๏ธ ReferencingARGV#arguments beyondARGChas undefined behavior. Deadass. Checking thatARGCis greater than#is the only way to ensure thatARGV#was passed to the function as an extra argument. Don't skip the check ๐
See Also
cmake_parse_arguments()<#command:cmake_parse_arguments>endfunction()<#command:endfunction>return()<#command:return>
get_cmake_property
Get a global property of the CMake instance. Global. Everywhere. All at once ๐
get_cmake_property(<variable> <property>)
Gets a global property from the CMake instance. The value of the <property> gets stored in the specified <variable>. If the property isn't found, <variable> will be set to NOTFOUND โ sad but honest ๐ญ
See the cmake-properties(7) <#manual:cmake-properties(7)> manual for the available properties.
On top of global properties, this command (for historical reasons, i.e. she's a legacy icon) also supports the VARIABLES <#prop_dir:VARIABLES> and MACROS <#prop_dir:MACROS> directory properties. She also supports a special COMPONENTS global property that lists the components given to the install() <#command:install> command. Versatile queen ๐
See Also
- the
get_property()<#command:get_property> command'sGLOBALoption
get_directory_property
Get a property of DIRECTORY scope. Very "this folder specifically" of her ๐
get_directory_property(<variable> [DIRECTORY <dir>] <prop-name>)
Stores a property of directory scope in the named <variable>.
The DIRECTORY argument specifies another directory to pull the property value from instead of the current directory. Relative paths are treated as relative to the current source directory. CMake must already know about that directory โ either because it was added through a call to add_subdirectory() <#command:add_subdirectory>, or because it's the top level directory. No sneaking in strangers ๐ซ
Added in version 3.19: <dir> may reference a binary directory.
If the property isn't defined for the nominated directory scope, you get an empty string back. And for INHERITED properties, if the property isn't found for the nominated directory scope, the search chains up to a parent scope, exactly as described for the define_property() <#command:define_property> command. She goes looking upstairs ๐ง
get_directory_property(<variable> [DIRECTORY <dir>]
DEFINITION <var-name>)
Get a variable definition from a directory. This form hits different when you need a variable definition from another directory ๐ฆ
See Also
define_property()<#command:define_property>- the more general
get_property()<#command:get_property> command
get_filename_component
Get a specific component of a full filename. Path surgery, but make it cute โ๏ธ
Changed in version 3.20: This command has been superseded by the cmake_path() <#command:cmake_path> command โ except for REALPATH, which is now offered by file(REAL_PATH) <#real-path>, and PROGRAM, now available in separate_arguments(PROGRAM) <#command:separate_arguments>. She's not cancelled, she's just... resting ๐
Changed in version 3.24: The undocumented feature offering the capability to query the Windows registry is superseded by the cmake_host_system_information(QUERY WINDOWS_REGISTRY) <#query-windows-registry> command.
get_filename_component(<var> <FileName> <mode> [CACHE])
Sets <var> to a component of <FileName>, where <mode> is one of:
DIRECTORYโ directory without file name.NAMEโ file name without directory.EXTโ file name longest extension (.b.cfromd/a.b.c).NAME_WEโ file name with neither the directory nor the longest extension.LAST_EXTโ file name last extension (.cfromd/a.b.c).NAME_WLEโ file name with neither the directory nor the last extension.PATHโ legacy alias forDIRECTORY(use for CMake <= 2.8.11).
Added in version 3.14: Added the LAST_EXT and NAME_WLE modes. New modes just dropped โจ
Paths are returned with forward slashes and have no trailing slashes. If the optional CACHE argument is specified, the result variable gets added to the cache. Organized ๐
get_filename_component(<var> <FileName> <mode> [BASE_DIR <dir>] [CACHE])
Added in version 3.4.
Sets <var> to the absolute path of <FileName>, where <mode> is one of:
ABSOLUTEโ full path to file.REALPATHโ full path to existing file with symlinks resolved.
If the <FileName> you hand her is a relative path, it gets evaluated relative to the given base directory <dir>. If no base directory is provided, the default base directory is CMAKE_CURRENT_SOURCE_DIR <#variable:CMAKE_CURRENT_SOURCE_DIR>. Default behaviour, but make it documented ๐ซถ
Paths are returned with forward slashes and have no trailing slashes. If the optional CACHE argument is specified, the result variable gets added to the cache.
get_filename_component(<var> <FileName> PROGRAM [PROGRAM_ARGS <arg_var>] [CACHE])
The program in <FileName> will be found in the system search path, or left as a full path. If PROGRAM_ARGS is present alongside PROGRAM, then any command-line arguments present in the <FileName> string get split away from the program name and stored in <arg_var>. This is how you separate a program name from its arguments inside a command line string. She does the splitting so you don't have to ๐
See Also
cmake_path()<#command:cmake_path>
get_property
Get a property. That's it. That's the whole description, and honestly? Slay for the brevity ๐
get_property(<variable>
<GLOBAL |
DIRECTORY [<dir>] |
TARGET <target> |
FILE_SET <file_set> TARGET <target> |
SOURCE <source>
[DIRECTORY <dir> | TARGET_DIRECTORY <target>] |
INSTALL <file> |
TEST <test>
[DIRECTORY <dir>] |
CACHE <entry> |
VARIABLE>
PROPERTY <name>
[SET | DEFINED | BRIEF_DOCS | FULL_DOCS])
Gets one property from one object in a scope. One. Singular. Don't be greedy ๐
The first argument specifies the variable where the result gets stored. The second argument determines the scope you're pulling the property from. It has to be one of the following:
GLOBAL : Scope is unique and does not accept a name. No name needed, she's everything already ๐
DIRECTORY : Scope defaults to the current directory, but another directory (one already processed by CMake) may be named by the full or relative path <dir>. Relative paths are treated as relative to the current source directory. See also the get_directory_property() <#command:get_directory_property> command.
- Added in version 3.19:
<dir>can reference a binary directory too ๐ซถ TARGETโ scope has to name one target that actually exists. Also peep theget_target_property()command ๐FILE_SETโ Added in version 4.3. Scope must name one existing file set.
This next option is required, no skipping bestie:
TARGET <target>โ the target that the file set is attached to.
SOURCEโ scope must name one source file. Default behavior: the source file's property gets read from the current source directory's scope.
Added in version 3.18: the directory scope can be overridden with one of these sub-options ๐
DIRECTORY <dir>โ the source file property gets read from the<dir>directory's scope. CMake has to already know about that directory, either because it was added through a call toadd_subdirectory()or because<dir>is the top level directory. Relative paths are treated as relative to the current source directory.
Added in version 3.19: <dir> may reference a binary directory.
TARGET_DIRECTORY <target>โ the source file property gets read from the directory scope in which<target>was created (so<target>must already exist, periodt).
Also check out the get_source_file_property() command.
INSTALLโ Added in version 3.1. Scope must name one installed file path.TESTโ scope must name one existing test. Also see theget_test_property()command.
Added in version 3.28: the directory scope can be overridden with this sub-option:
DIRECTORY <dir>โ the test property gets read from the<dir>directory's scope. CMake must already know about the directory, either by having added it through a call toadd_subdirectory()or because<dir>is the top level directory. Relative paths are treated as relative to the current source directory.<dir>may reference a binary directory.
CACHEโ scope must name one cache entry.VARIABLEโ this scope is unique and does not accept a name.
The required PROPERTY option is immediately followed by the name of the property you're getting. If the property isn't set, the named <variable> will be unset in the calling scope when it returns โ although some properties support inheriting from a parent scope if they're defined to behave that way (see define_property()) ๐ซถ
If the SET option is given, the variable gets set to a boolean value indicating whether the property has been set. If the DEFINED option is given, the variable gets set to a boolean value indicating whether the property has been defined, like with the define_property() command.
If BRIEF_DOCS or FULL_DOCS is given, the variable gets set to a string containing documentation for the requested property. If you ask for documentation on a property that hasn't been defined, NOTFOUND comes back ๐ซ
Note: the GENERATED source file property may be globally visible. See its documentation for the deets.
๐ See Also ๐
define_property()set_property()
๐ฅ if ๐ฅ
Conditionally execute a group of commands. It's giving "choose your own adventure" but make it build system ๐
๐ Synopsis ๐
if(<condition>)
<commands>
elseif(<condition>) # optional block, can be repeated
<commands>
else() # optional block
<commands>
endif()
It evaluates the condition argument of the if clause according to the Condition syntax described below. If the result is true, then the commands in the if block get executed. Otherwise the optional elseif blocks get processed the same way. And finally, if no condition is true, the commands in the optional else block get executed โจ
Per legacy, the else() and endif() commands admit an optional <condition> argument. If you use it, it must be a verbatim repeat of the argument of the opening if command. No paraphrasing bestie ๐ญ
๐ธ Condition Syntax ๐ธ
The following syntax applies to the condition argument of the if, elseif and while() clauses.
Compound conditions are evaluated in this order of precedence:
- Parentheses.
- Unary tests such as:
- The Existence Checks
COMMAND,DEFINED,DIAGNOSTIC,EXISTS,POLICY,TARGET, andTEST. - The File Operations
IS_READABLE,IS_WRITABLE,IS_EXECUTABLE,IS_DIRECTORY,IS_SYMLINK, andIS_ABSOLUTE.
- The Existence Checks
- Binary tests such as those described in Comparisons, Version Comparisons, and Path Comparisons, as well as
IN_LISTandIS_NEWER_THAN. - Unary logical operator
NOT. - Binary logical operators
ANDandOR, from left to right, without any short-circuit.
๐ฆ Basic Expressions ๐ฆ
if(<constant>)โ true if the constant is1,ON,YES,TRUE,Y, or a non-zero number (floating point numbers included). False if the constant is0,OFF,NO,FALSE,N,IGNORE,NOTFOUND, the empty string, or ends in the suffix-NOTFOUND. Named boolean constants are case-insensitive. If the argument is not one of these specific constants, it's treated as a variable or string (see Variable Expansion further below), and one of the following two forms applies.if(<variable>)โ true if you give it a variable that's defined to a value that is not a false constant. False otherwise, undefined variable included. Note that macro arguments are not variables. Environment Variables also cannot be tested this way โ likeif(ENV{some_var})will always evaluate to false ๐ญif(<string>)โ a quoted string always evaluates to false unless:- the string's value is one of the true constants, or
- in CMake versions prior to
4.0, policyCMP0054is not set toNEWand the string's value happens to be a variable name that is affected byCMP0054's behavior.
if()โ false if no argument is provided.
๐ Logic Operators ๐
if(NOT <condition>)โ true if the condition is not true.if(<cond1> AND <cond2>)โ true if both conditions would be considered true individually.if(<cond1> OR <cond2>)โ true if either condition would be considered true individually.if((condition) AND (condition OR (condition)))โ the conditions inside the parentheses get evaluated first, then the remaining condition gets evaluated as in the other examples. Where there are nested parentheses, the innermost ones get evaluated as part of evaluating the condition that contains them ๐ง
๐ Existence Checks ๐
if(COMMAND <command-name>)โ true if the given name is a command, macro or function that can be invoked.if(DIAGNOSTIC <category>)โ Added in version 4.4. True if the given name is an existing diagnostic category.if(POLICY <policy-id>)โ true if the given name is an existing policy (of the formCMP<NNNN>).if(TARGET <target-name>)โ true if the given name is an existing logical target name created by a call to theadd_executable(),add_library(), oradd_custom_target()command that has already been invoked (in any directory).if(TEST <test-name>)โ Added in version 3.3. True if the given name is an existing test name created by theadd_test()command.if(DEFINED <name>|CACHE{<name>}|ENV{<name>})โ true if a variable, cache variable or environment variable with the given<name>is defined. The value of the variable does not matter. Note these caveats:- Macro arguments are not variables.
- It is not possible to test directly whether a
<name>is a non-cache variable. The expressionif(DEFINED someName)will evaluate to true if either a cache or non-cache variablesomeNameexists. In comparison, the expressionif(DEFINED CACHE{someName})will only evaluate to true if a cache variablesomeNameexists. Both expressions need to be tested if you need to know whether a non-cache variable exists:if(DEFINED someName AND NOT DEFINED CACHE{someName}).
Added in version 3.14: added support for CACHE{<name>} variables.
if(<variable|string> IN_LIST <variable>)โ Added in version 3.3. True if the given element is contained in the named list variable.
๐ File Operations ๐
if(EXISTS <path-to-file-or-directory>)โ true if the named file or directory exists and is readable. Behavior is well-defined only for explicit full paths (a leading~/is not expanded as a home directory and is considered a relative path). Resolves symbolic links, i.e. if the named file or directory is a symbolic link, it returns true if the target of the symbolic link exists.
False if the given path is an empty string.
Note: preferif(IS_READABLE)to check file readability.if(EXISTS)may be changed in the future to only check file existence ๐
if(IS_READABLE <path-to-file-or-directory>)โ Added in version 3.29. True if the named file or directory is readable. Behavior is well-defined only for explicit full paths (a leading~/is not expanded as a home directory and is considered a relative path). Resolves symbolic links, i.e. if the named file or directory is a symbolic link, it returns true if the target of the symbolic link is readable.
False if the given path is an empty string.
if(IS_WRITABLE <path-to-file-or-directory>)โ Added in version 3.29. True if the named file or directory is writable. Behavior is well-defined only for explicit full paths (a leading~/is not expanded as a home directory and is considered a relative path). Resolves symbolic links, i.e. if the named file or directory is a symbolic link, it returns true if the target of the symbolic link is writable.
False if the given path is an empty string.
if(IS_EXECUTABLE <path-to-file-or-directory>)โ Added in version 3.29. True if the file or directory you named is executable. Lowkey important caveat: the behavior is only well-defined for explicit full paths (so a leading~/is not expanded as a home directory โ it counts as a relative path, sorry bestie ๐ญ). It resolves symbolic links, meaning if the thing you named is a symlink, you get true when the target of that symlink is executable. False if the given path is an empty string.if(<file1> IS_NEWER_THAN <file2>)โ True iffile1is newer thanfile2, or if one of the two files doesn't even exist. Behavior is well-defined only for full paths. And here's the chaotic bit: if the file time stamps are exactly the same,IS_NEWER_THANreturns true, so that any dependent build operations will occur in the event of a tie ๐. That includes the case of passing the same file name for bothfile1andfile2.if(IS_DIRECTORY <path>)โ True if path is a directory. Behavior is well-defined only for full paths. False if the given path is an empty string.if(IS_SYMLINK <path>)โ True if the given path is a symbolic link ๐. Behavior is well-defined only for full paths.if(IS_ABSOLUTE <path>)โ True if the given path is an absolute path. But bestie, note these special cases, they're giving "edge case icon":- An empty path evaluates to false.
- On Windows hosts, any path that begins with a drive letter and colon (e.g.
C:), a forward slash or a backslash will evaluate to true. Which means a path likeC:no\base\dirwill evaluate to true, even though the non-drive part of the path is relative ๐ญ. - On non-Windows hosts, any path that begins with a tilde (
~) evaluates to true.
๐ Comparisons
if(<variable|string> MATCHES <regex>)โ True if the given string or the variable's value matches the given regular expression. Head to the Regex Specification for the regex format. The()groups get captured intoCMAKE_MATCH_<n>variables, no cap โจ.if(<variable|string> LESS <variable|string>)โ True if the given string or variable's value parses as a real number (like a Cdouble) and is less than the one on the right.if(<variable|string> GREATER <variable|string>)โ True if the given string or variable's value parses as a real number (like a Cdouble) and is greater than the one on the right.if(<variable|string> EQUAL <variable|string>)โ True if the given string or variable's value parses as a real number (like a Cdouble) and is equal to the one on the right.if(<variable|string> LESS_EQUAL <variable|string>)โ Added in version 3.7. True if the given string or variable's value parses as a real number (like a Cdouble) and is less than or equal to the one on the right.if(<variable|string> GREATER_EQUAL <variable|string>)โ Added in version 3.7. True if the given string or variable's value parses as a real number (like a Cdouble) and is greater than or equal to the one on the right.if(<variable|string> STRLESS <variable|string>)โ True if the given string or variable's value is lexicographically less than the string or variable on the right.if(<variable|string> STRGREATER <variable|string>)โ True if the given string or variable's value is lexicographically greater than the string or variable on the right.if(<variable|string> STREQUAL <variable|string>)โ True if the given string or variable's value is lexicographically equal to the string or variable on the right.if(<variable|string> STRLESS_EQUAL <variable|string>)โ Added in version 3.7. True if the given string or variable's value is lexicographically less than or equal to the string or variable on the right.if(<variable|string> STRGREATER_EQUAL <variable|string>)โ Added in version 3.7. True if the given string or variable's value is lexicographically greater than or equal to the string or variable on the right.
๐ Version Comparisons
Ok so all five of these work the same way, and the way is: component-wise integer version number comparison โ the version format is major[.minor[.patch[.tweak]]], and omitted components are treated as zero. Any non-integer version component, or a non-integer trailing part of a version component, effectively truncates the string at that point. Slay ๐ซถ
if(<variable|string> VERSION_LESS <variable|string>)โ the component-wise integer version comparison described above, checking "less than".if(<variable|string> VERSION_GREATER <variable|string>)โ component-wise integer version number comparison (version format ismajor[.minor[.patch[.tweak]]], omitted components treated as zero, non-integer bits truncate the string right there), checking "greater than".if(<variable|string> VERSION_EQUAL <variable|string>)โ same component-wise integer version number comparison rules, checking "equal to".if(<variable|string> VERSION_LESS_EQUAL <variable|string>)โ Added in version 3.7. Same component-wise integer version number comparison (formatmajor[.minor[.patch[.tweak]]], omitted components are zero, any non-integer version component or non-integer trailing part of one truncates the string at that point), checking "less than or equal to".if(<variable|string> VERSION_GREATER_EQUAL <variable|string>)โ Added in version 3.7. Same component-wise integer version number comparison (formatmajor[.minor[.patch[.tweak]]], omitted components are zero, non-integer version components or non-integer trailing parts truncate the string there), checking "greater than or equal to".
๐ฆ Path Comparisons
if(<variable|string> PATH_EQUAL <variable|string>)โ Added in version 3.24. Lexicographically compares two CMake paths component-by-component, without accessing the filesystem (no peeking, we respect privacy ๐ ). Only if every component of both paths match will the two paths compare equal. Multiple path separators are effectively collapsed into a single separator, but heads up: backslashes are not converted to forward slashes. No other path normalization is performed. Trailing slashes are preserved, so/a/band/a/b/are not equal.
Component-wise comparison is superior to string-based comparison because of how it handles multiple path separators. In the example below, the expression evaluates to true using PATH_EQUAL, but false with STREQUAL:
# comparison is TRUE
if ("/a//b/c" PATH_EQUAL "/a/b/c")
...
endif()
# comparison is FALSE
if ("/a//b/c" STREQUAL "/a/b/c")
...
endif()
See cmake_path(COMPARE) for more details ๐
โจ Variable Expansion
Ok this is the lore bestie. The if command was written very early in CMake's history โ literally predating the ${} variable evaluation syntax โ and for convenience it evaluates variables named by its arguments as shown in the signatures above. Note that normal variable evaluation with ${} applies before the if command even receives the arguments. So code like
set(var1 OFF)
set(var2 "var1")
if(${var2})
appears to the if command as
if(var1)
and is evaluated according to the if(<variable>) case documented above. The result is OFF, which is false. But if we remove the ${} from the example, then the command sees
if(var2)
which is true, because var2 is defined to var1, which is not a false constant. Iconic behavior honestly ๐ญ
Automatic evaluation applies in the other cases whenever the above-documented condition syntax accepts <variable|string>:
- The left hand argument to
MATCHESis first checked to see if it is a defined variable. If so, the variable's value is used, otherwise the original value is used. - If the left hand argument to
MATCHESis missing it returns false without error ๐ - Both left and right hand arguments to
LESS,GREATER,EQUAL,LESS_EQUAL, andGREATER_EQUALare independently tested to see if they are defined variables. If so, their defined values are used; otherwise the original value is used. - Both left and right hand arguments to
STRLESS,STRGREATER,STREQUAL,STRLESS_EQUAL, andSTRGREATER_EQUALare independently tested to see if they are defined variables. If so, their defined values are used; otherwise the original value is used. - Both left and right hand arguments to
VERSION_LESS,VERSION_GREATER,VERSION_EQUAL,VERSION_LESS_EQUAL, andVERSION_GREATER_EQUALare independently tested to see if they are defined variables. If so, their defined values are used; otherwise the original value is used. - The left hand argument to
IN_LISTis tested to see if it is a defined variable. If so, the variable's value is used; otherwise the original value is used. - The right hand argument to
NOTis tested to see if it is a boolean constant. If so, the value is used; otherwise it is assumed to be a variable and it is dereferenced. - The left and right hand arguments to
ANDandORare independently tested to see if they are boolean constants. If so, they are used as such, otherwise they are assumed to be variables and are dereferenced.
Changed in version 3.1: To prevent ambiguity, potential variable or keyword names can be specified in a Quoted Argument or a Bracket Argument. A quoted or bracketed variable or keyword will be interpreted as a string and not dereferenced or interpreted. See policy CMP0054.
There is no automatic evaluation for environment or cache Variable References. Their values must be referenced as $ENV{<name>} or $CACHE{<name>} wherever the above-documented condition syntax accepts <variable|string>.
๐ See also
else()elseif()endif()
๐ include
Load and run CMake code from a file or module. It's giving "bring your own script" energy โจ
include(<file|module> [OPTIONAL] [RESULT_VARIABLE <var>]
[NO_POLICY_SCOPE] [NO_DIAGNOSTIC_SCOPE])
So like, include() pulls in a file and runs whatever CMake code is in it, and the variable reads/writes inside totally access the scope of whoever called it โ that's dynamic scoping bestie, it's giving "what's mine is yours" ๐. If OPTIONAL is chilling there, then no error gets raised when the file doesn't exist (iconic, no drama). And if you hand it RESULT_VARIABLE, the variable <var> gets set to the full filename that got included, or to NOTFOUND if it flopped ๐ญ.
Now โจ the module tea โจ โ if you specify a module instead of a file, then the file named <modulename>.cmake gets searched first in CMAKE_MODULE_PATH, and then in the CMake module directory. But there's literally one exception to this whole situation: if the file calling include() is itself sitting in the CMake builtin module directory, then the CMake builtin module directory gets searched first and CMAKE_MODULE_PATH comes afterwards. Sneaky! Also go peek at policy CMP0017 for the deets.
For the whole discussion of the NO_POLICY_SCOPE option, check the cmake_policy() command docs. And for the NO_DIAGNOSTIC_SCOPE option, check the cmake_diagnostic() command docs. Both of those, bestie, not me making it up ๐ซถ.
๐ก๏ธ include_guard
Added in version 3.10. โจ
It literally provides an include guard for the file that CMake is currently processing. Main character energy for your headers.
include_guard([DIRECTORY|GLOBAL])
So it sets up an include guard for the current CMake file (peep the CMAKE_CURRENT_LIST_FILE variable docs for the context, iykyk).
Here's the vibe: CMake will end its processing of the current file right at the location of the include_guard command if that file has already been processed for the applicable scope (scopes explained below, keep reading ๐
). Which is basically the same energy as those include guards people put in source headers, or the #pragma once directive. And if the current file has been processed before for the applicable scope, the effect is exactly as though return() had been called. Chef's kiss.
๐จ Bestie do not call this command from inside a function that's being defined within the current file. Just don't. It's not the move.
You can optionally pass an argument saying what the scope of the guard is. The possible values are:
DIRECTORYโ the include guard applies within the current directory and below ๐ธ. The file only gets included once within this directory scope, but it may get included again by other files outside of this directory โ like a parent directory, or another directory that wasn't pulled in byadd_subdirectory()orinclude()from the current file or its children. Boundaries, we love them.GLOBALโ the include guard applies globally to the whole build ๐. The current file only gets included once, regardless of the scope. Periodt.
If you give it no arguments at all, include_guard has the same scope as a variable โ meaning the include guard effect gets isolated by the most recent function scope, or by the current directory if there are no inner function scopes existing. In that case the command behavior is the same as:
if(__CURRENT_FILE_VAR__)
return()
endif()
set(__CURRENT_FILE_VAR__ TRUE)
No cap, that's it. Simple. Slay.
๐ list
Operations on semicolon-separated lists ๐. Yes, semicolons. We don't make the rules.
Synopsis
Reading
list(LENGTH <list> <out-var>)
list(GET <list> <element index> [<index> ...] <out-var>)
list(JOIN <list> <glue> <out-var>)
list(SUBLIST <list> <begin> <length> <out-var>)
Search
list(FIND <list> <value> <out-var>)
Modification
list(APPEND <list> [<element>...])
list(FILTER <list> <INCLUDE|EXCLUDE> <MODE>)
list(INSERT <list> <index> [<element>...])
list(POP_BACK <list> [<out-var>...])
list(POP_FRONT <list> [<out-var>...])
list(PREPEND <list> [<element>...])
list(REMOVE_ITEM <list> <value>...)
list(REMOVE_AT <list> <index>...)
list(REMOVE_DUPLICATES <list>)
list(TRANSFORM <list> <ACTION> [...])
Ordering
list(REVERSE <list>)
list(SORT <list> [...])
Introduction
Okay so the list subcommands APPEND, INSERT, FILTER, PREPEND, POP_BACK, POP_FRONT, REMOVE_AT, REMOVE_ITEM, REMOVE_DUPLICATES, REVERSE and SORT may create new values for the list within the current CMake variable scope. Just like the set() command, the list command creates new variable values in the current scope โ even if the list itself is actually defined in a parent scope. Rude? Maybe. But that's the deal ๐.
So if you wanna propagate the results of these operations upwards, use set() with PARENT_SCOPE, or set() with CACHE INTERNAL, or literally some other means of value propagation. Your call, bestie.
๐ Note: A list in cmake is a;separated group of strings. To create a list, theset()command can be used. For example,set(var a b c d e)creates a list witha;b;c;d;e, andset(var "a b c d e")creates a string or a list with one item in it. (Also note that macro arguments are not variables, and therefore cannot be used in LIST commands โ tragic, I know ๐ญ.) Individual elements may not contain an unequal number of[and]characters, and may not end in a backslash (\). See semicolon-separated lists for the full details.
๐ Note: When specifying index values, if<element index>is0or greater, it's indexed from the beginning of the list, with0representing the first list element. If<element index>is-1or lesser, it's indexed from the end of the list, with-1representing the last list element. Be careful when counting with negative indices, bestie โ they do not start from 0. And-0is equivalent to0, the first list element. Math is math.
Reading
list(LENGTH <list> <output variable>)โ returns the list's length. That's it. Iconic.list(GET <list> <element index> [<element index> ...] <output variable>)โ returns the list of elements specified by the indices from the list.list(JOIN <list> <glue> <output variable>)โ added in version 3.12. โจ Returns a string joining all of the list's elements using the glue string. And if you need to join multiple strings that aren't part of a list, usestring(JOIN)instead, bestie.list(SUBLIST <list> <begin> <length> <output variable>)โ added in version 3.12. ๐ธ Returns a sublist of the given list. If<length>is0, an empty list will be returned. If<length>is-1, or the list is smaller than<begin>+<length>, then the remaining elements of the list starting at<begin>will be returned. Giving "the rest of it, whatever's left" energy.
Search
list(FIND <list> <value> <output variable>)โ returns the index of the element specified in the list, or-1if it wasn't found ๐. She looked everywhere. Not there.
Modification
list(APPEND <list> [<element> ...])โ appends elements to the list. If no variable named<list>exists in the current scope, its value is treated as empty and the elements get appended to that empty list. Manifesting from nothing โจ.list(FILTER <list> <INCLUDE|EXCLUDE> <MODE>)โ added in version 3.6. Includes or removes items from the list that match the mode's pattern ๐.
<MODE> must be one of the following:
REGEXโ items will be matched against the given regular expression.
list(FILTER <list> <INCLUDE|EXCLUDE> REGEX <regular_expression>)
For more info on regular expressions, look under string(REGEX). Regex girlies rise ๐ฆ.
PREDICATEโ specify a user-definedfunction()as a predicate.
list(FILTER <list> <INCLUDE|EXCLUDE> PREDICATE <function>)
Added in version 4.4. ๐
<function> is a user-defined function() that acts as a unary predicate. The function must accept exactly two parameters: the input value and the name of an output variable. The function must set the output variable to a boolean value in the calling scope. That output variable gets interpreted using standard CMake boolean evaluation. And if the function does not set the output variable โ that's an error, bestie. No silent fails allowed ๐.
Example, so you can see the vision:
function(file_exists path result)
if(EXISTS "${path}")
set(${result} TRUE PARENT_SCOPE)
else()
set(${result} FALSE PARENT_SCOPE)
endif()
endfunction()
set(candidate_files main.c missing.c utils.c)
list(FILTER candidate_files INCLUDE PREDICATE file_exists)
list(INSERT <list> <element_index> <element> [<element> ...])โ inserts elements into the list at the specified index. It is an error to specify an out-of-range index ๐จ. Valid indexes are0toN, whereNis the length of the list, inclusive. An empty list has length0. If no variable named<list>exists in the current scope, its value is treated as empty and the elements are inserted into that empty list.list(POP_BACK <list> [<out-var>...])โ added in version 3.15. If no variable name is given, it removes exactly one element. Otherwise, withNvariable names provided, it assigns the lastNelements' values to the given variables and then removes the lastNvalues from<list>. Bye from the back ๐.list(POP_FRONT <list> [<out-var>...])โ added in version 3.15. If no variable name is given, it removes exactly one element. Otherwise, withNvariable names provided, it assigns the firstNelements' values to the given variables and then removes the firstNvalues from<list>. Front row, evicted ๐ .list(PREPEND <list> [<element> ...])โ added in version 3.15. Inserts elements into the0th position in the list. If no variable named<list>exists in the current scope, its value is treated as empty and the elements are prepended to that empty list. Cutting the line, respectfully ๐.list(REMOVE_ITEM <list> <value> [<value> ...])โ removes all instances of the given items from the list. All of them. Every single one. Gone ๐ซถ.list(REMOVE_AT <list> <index> [<index> ...])โ removes items at the given indices from the list.list(REMOVE_DUPLICATES <list>)โ removes duplicated items in the list. The relative order of items is preserved, but if duplicates are encountered, only the first instance is preserved. Original only, no remakes โจ.list(TRANSFORM <list> <ACTION> [<SELECTOR>] [OUTPUT_VARIABLE <output variable>])โ added in version 3.12. Transforms the list by applying an<ACTION>to all of the elements โ or, by specifying a<SELECTOR>, to the selected elements of the list โ storing the result in-place or in the specified output variable. Glow-up service, basically ๐.
Note: theTRANSFORMsub-command does not change how many elements are in your list. Bestie, the count stays exactly the same. If you hand it a<SELECTOR>, only some elements get changed and the rest just chill there looking exactly like they did before the transformation. No glow-ups for them. ๐
<ACTION> is the actual ~thing~ you're doing to the elements, and it has to be one of these:
APPEND,PREPENDโ stick the value you give onto each element's end (APPEND) or beginning (PREPEND).
list(TRANSFORM <list> (APPEND|PREPEND) <value> ...)
TOLOWER,TOUPPERโ convert each element to lower / upper characters. Case glow-up โจ
list(TRANSFORM <list> (TOLOWER|TOUPPER) ...)
STRIPโ remove leading and trailing spaces from each element. Say bye to the extra whitespace ๐
list(TRANSFORM <list> STRIP ...)
GENEX_STRIPโ strip any generator expressions out of each element (you know, thecmake-generator-expressions(7)kind).
list(TRANSFORM <list> GENEX_STRIP ...)
REPLACEโ matches the regular expression as many times as possible and substitutes the replacement expression for the match, for each element of the list (same semantic asstring(REGEX REPLACE)).
list(TRANSFORM <list> REPLACE <regular_expression> <replace_expression> ...)
Changed in version 4.1: the ^ anchor now matches only at the beginning of the input element instead of the beginning of each repeated search. See policy CMP0186 for the whole story ๐ซถ
APPLYโ invokes a user-definedfunction()once for each element of the list. The function has to accept exactly two parameters: the input value, and the name of an output variable. And it must set that output variable in the calling scope. no cap.
list(TRANSFORM <list> APPLY <function> ...)
Added in version 4.4.
<function> is a function() with exactly two formal parameters. You set the output variable via set(<variable> <value> PARENT_SCOPE):
function(<function> <input> <output>)
# Transform <input>, store result in ${<output>}
set(${<output>} "<result>" PARENT_SCOPE)
endfunction()
Before each invocation, the output variable is unset in the calling scope, so you never get stuck with a stale value from the last call. icon behaviour honestly ๐
Example:
function(make_absolute in out)
cmake_path(ABSOLUTE_PATH in BASE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}")
set(${out} "${in}" PARENT_SCOPE)
endfunction()
set(mylist main.c utils.c io.c)
list(TRANSFORM mylist APPLY make_absolute)
# mylist is now absolute paths relative to CMAKE_CURRENT_SOURCE_DIR
<SELECTOR> is the โจvibe checkโจ that decides which elements get transformed. Only one type of selector at a time, pls โ don't be greedy. When you give one, it must be one of these:
ATโ specify a list of indexes.
list(TRANSFORM <list> <ACTION> AT <index> [<index> ...] ...)
FORโ specify a range, optionally with an increment used to iterate over that range.
list(TRANSFORM <list> <ACTION> FOR <start> <stop> [<step>] ...)
REGEXโ specify a regular expression. Only the elements that match it get transformed. everybody else stays unbothered ๐
list(TRANSFORM <list> <ACTION> REGEX <regular_expression> ...)
PREDICATEโ specify a user-definedfunction()to act as a predicate. Only elements for which the function returns a true value get transformed.
list(TRANSFORM <list> <ACTION> PREDICATE <function> ...)
Added in version 4.4.
<function> is a user-defined function() with exactly two formal parameters: the input value, and the name of an output variable. The function must set that output variable to a boolean value, and standard CMake boolean evaluation is used. If the function doesn't set the output variable โ that's an error, fr fr. The function is evaluated for each element in turn, immediately before that element would be transformed.
Example:
function(is_relative path result)
if(NOT IS_ABSOLUTE "${path}")
set(${result} TRUE PARENT_SCOPE)
else()
set(${result} FALSE PARENT_SCOPE)
endif()
endfunction()
set(search_paths /usr/include src lib /opt/lib)
list(TRANSFORM search_paths PREPEND "${CMAKE_CURRENT_SOURCE_DIR}/"
PREDICATE is_relative)
๐ Ordering
list(REVERSE <list>)โ reverses the contents of the list in-place. Like flipping your camera roll ๐list(SORT <list> [COMPARE <compare>] [CASE <case>] [ORDER <order>])list(SORT <list> COMPARATOR <function> [CASE <case>] [ORDER <order>])
Sorts the list in-place alphabetically.
Added in version 3.13: added the COMPARE, CASE, and ORDER options.
Added in version 3.18: added the COMPARE NATURAL option.
Use the COMPARE keyword to pick your sorting method, bestie. The <compare> option should be one of:
STRINGโ sorts a list of strings alphabetically. This is the default behaviour if you don't give theCOMPAREoption at all.FILE_BASENAMEโ sorts a list of pathnames of files by their basenames.NATURALโ sorts a list of strings using natural order (see thestrverscmp(3)manual), i.e. such that contiguous digits get compared as whole numbers. For example: the following list10.0 1.1 2.1 8.0 2.0 3.1will be sorted as1.1 2.0 2.1 3.1 8.0 10.0if theNATURALcomparison is selected, whereas it will be sorted as1.1 10.0 2.0 2.1 3.1 8.0with theSTRINGcomparison. numbers behaving like actual numbers, we love to see it ๐ฅ
Use the CASE keyword to select a case sensitive or case insensitive sort mode. The <case> option should be one of:
SENSITIVEโ list items are sorted in a case-sensitive manner. This is the default behaviour if theCASEoption is not given.INSENSITIVEโ list items are sorted case insensitively. The order of items which differ only by upper/lowercase is not specified, so don't come for it ๐
To control the sort order, the ORDER keyword can be given. The <order> option should be one of:
ASCENDINGโ sorts the list in ascending order. This is the default behaviour when theORDERoption is not given.DESCENDINGโ sorts the list in descending order.
Instead of the built-in COMPARE methods, a user-defined comparison function() may be used with the COMPARATOR keyword.
Added in version 4.4.
COMPARATOR is mutually exclusive with COMPARE. The CASE and ORDER options may still be used alongside COMPARATOR: the CASE filter is applied to both values before they're passed to the function, and ORDER DESCENDING reverses the comparison by swapping the two arguments. sneaky but correct ๐ง
The function must accept exactly three parameters: two input values and the name of an output variable. It must set the output variable to a boolean value (TRUE if the first value should come before the second, FALSE otherwise) in the calling scope. If the function does not set the output variable, it's an error.
The comparator must define a strict weak ordering (https://en.wikipedia.org/wiki/Weak_ordering#Strict_weak_orderings). In particular:
- It must return
FALSEwhen comparing an element to itself (irreflexivity). - If it returns
TRUEfor (a, b), it must returnFALSEfor (b, a) (asymmetry).
An error is raised if the comparator violates these requirements. it WILL catch you ๐
Example:
function(version_less a b result)
if("${a}" VERSION_LESS "${b}")
set(${result} TRUE PARENT_SCOPE)
else()
set(${result} FALSE PARENT_SCOPE)
endif()
endfunction()
set(versions 3.1 1.2 2.0 1.10)
list(SORT versions COMPARATOR version_less)
# versions is now: 1.2;1.10;2.0;3.1
๐ load_cache
Loads in the values from another project's CMakeCache.txt cache file. Super useful for projects that depend on another project that was built in a separate directory tree. cross-project bestie behaviour ๐ซถ
This command has two signatures. The recommended one is:
load_cache(<build-dir> READ_WITH_PREFIX <prefix> <entry>...)
Loads the cache file from the specified <build-dir> build directory and retrieves the listed cache entries. The retrieved values are stored in local variables, with their names prefixed by the <prefix> you provide. This only reads the cache values โ it does not create or modify entries in the local project's cache. look, don't touch ๐ธ
READ_WITH_PREFIX <prefix>โ for each cache<entry>, a local variable is created using the specified<prefix>followed by the entry name.
This signature can also be used in cmake -P script mode. cute and versatile โญ
The following signature of this command is strongly discouraged, but it's provided for backward compatibility:
EXCLUDE <entry>...โ bestie this one lets you skip a whole list of non-internal cache entries when the values get imported. like a guest list but for variables ๐ซINCLUDE_INTERNALS <entry>...โ and this one hands you a way to name internal cache entries you want pulled in on top of the non-internal ones ๐
This signature can be used only in CMake projects. Script mode is not supported, periodt. ๐ โโ๏ธ
Note: okay so instead of loading the outside project's cache file and then manually poking at variables yourself, the way more robust and convenient glow-up is to use the export() command in the outside project, when it's available. it lets that project hand over its targets, configuration, or features in a structured and maintainable way, so integration is simpler and less error-prone. iykyk ๐ซถ
Examples
Reading specific cache variables from another project and storing them as local variables:
load_cache(
path/to/other-project/build-dir
READ_WITH_PREFIX prefix_
OTHER_PROJECT_CACHE_VAR_1
OTHER_PROJECT_CACHE_VAR_2
)
message(STATUS "${prefix_OTHER_PROJECT_CACHE_VAR_1")
message(STATUS "${prefix_OTHER_PROJECT_CACHE_VAR_2")
# Outputs:
# -- some-value...
# -- another-value...
Reading all non-internal cache entries from another project and storing them as internal cache variables using the obsolete signature:
load_cache(path/to/other-project/build-dir)
message(STATUS "${OTHER_PROJECT_CACHE_VAR_1")
message(STATUS "${OTHER_PROJECT_CACHE_VAR_2")
# Outputs:
# -- some-value...
# -- another-value...
Excluding specific non-internal cache entries and including internal ones using the obsolete signature:
load_cache(
path/to/other-project/build-dir
EXCLUDE OTHER_PROJECT_CACHE_VAR_2
INCLUDE_INTERNALS OTHER_PROJECT_INTERNAL_CACHE_VAR
)
message(STATUS "${OTHER_PROJECT_CACHE_VAR_1")
message(STATUS "${OTHER_PROJECT_CACHE_VAR_2")
message(STATUS "${OTHER_PROJECT_INTERNAL_CACHE_VAR}")
# Outputs:
# -- some-value...
# --
# -- some-internal-value...
๐ macro
Start recording a macro for later invocation as a command ๐ฌ
macro(<name> [<arg1> ...])
<commands>
endmacro()
Defines a macro named <name> that takes arguments named <arg1>, ... The commands listed after macro, but before the matching endmacro(), are not executed until the macro actually gets invoked. think of it as a saved draft you haven't hit send on yet โจ
Per legacy, the endmacro() command admits an optional <name> argument. If you use it, it has to be a verbatim repeat of the argument of the opening macro command. no paraphrasing, bestie ๐
See the cmake_policy() command documentation for the behavior of policies inside macros.
See the Macro vs Function section below for the differences between CMake macros and functions. ๐
Invocation
The macro invocation is case-insensitive. A macro defined as
macro(foo)
<commands>
endmacro()
can be invoked through any of
foo()
Foo()
FOO()
cmake_language(CALL foo)
and so on. However, it is strongly recommended to stay with the case chosen in the macro definition. Typically macros use all-lowercase names. consistency is the vibe check here ๐ธ
Added in version 3.18: The cmake_language(CALL ...) command can also be used to invoke the macro. slay ๐
Arguments
When a macro is invoked, first all the commands recorded in the macro are modified by replacing formal parameters (${arg1}, ...) with the arguments passed. Then all the modified commands are invoked as normal commands. it's literally find-and-replace then go ๐โโ๏ธ
In addition to referencing the formal parameters you can reference the values ${ARGC}, which will be set to the number of arguments passed into the macro, as well as ${ARGV0}, ${ARGV1}, ${ARGV2}, ... which will have the actual values of the arguments passed in. This facilitates creating macros with optional arguments. so handy ๐
Furthermore, ${ARGV} holds the list of all arguments given to the macro, and ${ARGN} holds the list of arguments past the last expected argument. Referencing ${ARGV#} arguments beyond ${ARGC} has undefined behavior ๐ญโ ๏ธ Checking that ${ARGC} is greater than # is the only way to ensure that ${ARGV#} was passed to the function as an extra argument. no cap.
Macro vs Function
The macro command is very similar to the function() command. Nonetheless, there are a few important differences. ๐
In a function, ARGN, ARGC, ARGV, and ARGV0, ARGV1, ... are true variables in the usual CMake sense. In a macro, they are not โ they're string replacements, much like the C preprocessor would do with a macro. This has a number of consequences, as explained in the Argument Caveats section below. ๐
Another difference between macros and functions is the control flow. A function is executed by transferring control from the calling statement to the function body. A macro is executed as if the macro body were pasted in place of the calling statement. This has the consequence that a return() in a macro body does not just terminate execution of the macro; rather, control is returned from the scope of the macro call. To avoid confusion, it is recommended to avoid return() in macros altogether. ๐
Unlike a function, the CMAKE_CURRENT_FUNCTION, CMAKE_CURRENT_FUNCTION_LIST_DIR, CMAKE_CURRENT_FUNCTION_LIST_FILE, CMAKE_CURRENT_FUNCTION_LIST_LINE variables are not set for a macro. ๐ซฅ
Argument Caveats
Since ARGN, ARGC, ARGV, ARGV0 etc. are not variables, you will NOT be able to use commands like
if(ARGV1) # ARGV1 is not a variable
if(DEFINED ARGV2) # ARGV2 is not a variable
if(ARGC GREATER 2) # ARGC is not a variable
foreach(loop_var IN LISTS ARGN) # ARGN is not a variable
In the first case, you can use if(${ARGV1}). In the second and third case, the proper way to check if an optional variable was passed to the macro is to use if(${ARGC} GREATER 2). In the last case, you can use foreach(loop_var ${ARGN}), but this will skip empty arguments. If you need to include them, you can use
set(list_var "${ARGN}")
foreach(loop_var IN LISTS list_var)
Note that if you have a variable with the same name in the scope from which the macro is called, using unreferenced names will use the existing variable instead of the arguments. For example:
macro(bar)
foreach(arg IN LISTS ARGN)
<commands>
endforeach()
endmacro()
function(foo)
bar(x y z)
endfunction()
foo(a b c)
Will loop over a;b;c and not over x;y;z as one might have expected. ๐ญ If you want true CMake variables and/or better CMake scope control you should look at the function command. fr fr, that one's the upgrade.
See Also
cmake_parse_arguments()endmacro()
โญ mark_as_advanced
Mark cmake cached variables as advanced. ๐ง
mark_as_advanced([CLEAR|FORCE] <var1> ...)
Sets the advanced/non-advanced state of the named cached variables.
An advanced variable will not be displayed in any of the cmake GUIs unless the show advanced option is on. In script mode, the advanced/non-advanced state has no effect. it's giving "hidden level unlocked" ๐
If the keyword CLEAR is given then advanced variables are changed back to unadvanced. If the keyword FORCE is given then the variables are made advanced. If neither FORCE nor CLEAR is specified, new values will be marked as advanced, but if a variable already has an advanced/non-advanced state, it will not be changed. classic "if it ain't decided, we decide; if it is, we leave it alone" ๐
Changed in version 3.17: Variables passed to this command which are not already in the cache are ignored. See policy CMP0102. ๐
๐งฎ math
Evaluate a mathematical expression.
math(EXPR <variable> "<expression>" [OUTPUT_FORMAT <format>])
Evaluates a mathematical <expression> and sets <variable> to the resulting value. The result of the expression must be representable as a 64-bit signed integer. Floating point inputs are invalid, e.g. 1.1 * 10. Non-integer results, e.g. 3 / 2, are truncated. so no decimals bestie, we're doing integer math only ๐ค
The mathematical expression must be given as a string (i.e. enclosed in double quotation marks). An example is "5 * (10 + 13)". Supported operators are +, -, *, /, %, |, &, ^, ~, <<, >>, and (...); they have the same meaning as in C code. ๐ฅ
Added in version 3.13: Hexadecimal numbers are recognized when prefixed with 0x, as in C code.
Added in version 3.13: The result is formatted according to the option OUTPUT_FORMAT, where <format> is one of
HEXADECIMALโ Hexadecimal notation as in C code, i. e. starting with"0x". ๐ฆDECIMALโ Decimal notation. Which is also used if noOUTPUT_FORMAToption is specified. the default, the main character ๐
For example
math(EXPR value "100 * 0xA" OUTPUT_FORMAT DECIMAL) # value is set to "1000"
math(EXPR value "100 * 0xA" OUTPUT_FORMAT HEXADECIMAL) # value is set to "0x3e8"
๐ฌ message
Log a message.
Synopsis
General messages
message([<mode>] "message text" ...)
Reporting checks
message(<checkState> "message text" ...)
Configure Log
message(CONFIGURE_LOG <text>...)
General messages
message([<mode>] "message text" ...)
Record the specified message text in the log. If more than one message string is given, they are concatenated into a single message with no separator between the strings. ๐ซถ
The optional <mode> keyword determines the type of message, which influences the way the message is handled:
FATAL_ERRORโ CMake Error, stop processing and generation. Thecmake(1)executable will return a non-zero exit code. ๐ like, everything stops.SEND_ERRORโ CMake Error, continue processing, but skip generation. ๐ฌWARNINGโ CMake Warning, continue processing. โ ๏ธAUTHOR_WARNINGโ CMakeCMD_AUTHORdiagnostic.DEPRECATIONโ CMakeCMD_DEPRECATEDdiagnostic.(none)orNOTICEโ Important message printed tostderrto attract user's attention. ๐ like tapping you on the shoulder.STATUSโ bestie these are the messages your project's users actually care about ๐ keep 'em short, ideally a single line, but still make them say something useful.VERBOSEโ the detailed info drops for project users โจ extra deets that most people won't need, but that the folks building the project will lowkey love when they want a deeper look at what's going on.DEBUGโ this one's for the devs working on the project, not the users who just wanna build it ๐ซถ usually not interesting to anyone else building it, and it's often super tied to internal implementation details.TRACEโ fine-grained, very low-level implementation tea ๐ these are normally temporary and are expected to be gone before the project ships, gets packaged up, etc.
Added in version 3.15: added the NOTICE, VERBOSE, DEBUG, and TRACE levels.
So here's the vibe check on where stuff shows up ๐ the CMake command-line tool prints STATUS through TRACE messages on stdout, with each message prefixed by two hyphens and a space. Every other message type goes to stderr and gets no hyphens. The CMake GUI shows all messages in its log area. The curses interface (ccmake) shows STATUS through TRACE one at a time on a status line, and everything else in an interactive pop-up box. The --log-level command-line option on each of these tools controls which messages get shown ๐
Added in version 3.17: want a log level that persists between CMake runs? Set the CMAKE_MESSAGE_LOG_LEVEL variable instead โจ but note the command-line option takes precedence over the cache variable.
Added in version 3.16: messages at log level NOTICE and below get every line prefixed with the contents of the CMAKE_MESSAGE_INDENT variable (converted to a single string by concatenating its list items). For STATUS through TRACE messages, that indent content goes after the hyphens ๐
Added in version 3.17: messages at NOTICE and below can also get each line prefixed with context that looks like [some.context.example]. The stuff inside the square brackets comes from converting the CMAKE_MESSAGE_CONTEXT list variable into a dot-separated string. Message context always shows up before any indenting content, but after any automatically added leading hyphens ๐ธ by default context is not shown โ you have to explicitly turn it on with the cmake --log-context command-line option, or by setting the CMAKE_MESSAGE_CONTEXT_SHOW variable to true. Peep the CMAKE_MESSAGE_CONTEXT docs for usage examples.
CMake Warning and Error message text renders with a simple markup language ๐ง non-indented text gets formatted into line-wrapped paragraphs delimited by newlines. Indented text is treated as pre-formatted.
๐ฆ Reporting checks
Added in version 3.17.
Okay so the classic pattern in CMake output is: a message saying a check is starting, then another message reporting the result. Like this:
message(STATUS "Looking for someheader.h")
#... do the checks, set checkSuccess with the result
if(checkSuccess)
message(STATUS "Looking for someheader.h - found")
else()
message(STATUS "Looking for someheader.h - not found")
endif()
The way that this is so much more robust and convenient is with the CHECK_... keyword form of the message() command ๐
message(<checkState> "message" ...)
where <checkState> has to be one of these:
CHECK_STARTโ records a concise message about the check that's about to happen ๐CHECK_PASSโ records a successful result for a check โCHECK_FAILโ records an unsuccessful result for a check ๐ญ
When it records a check result, the command repeats the message from the most recently started check that hasn't had a result reported yet, then some separator characters, then the message text you handed it after CHECK_PASS or CHECK_FAIL. Check messages are always reported at STATUS log level, no cap.
Checks can nest, and every CHECK_START should have exactly one matching CHECK_PASS or CHECK_FAIL ๐ฏ you can also use CMAKE_MESSAGE_INDENT to add indent to nested checks if that's your vibe. For example:
message(CHECK_START "Finding my things")
list(APPEND CMAKE_MESSAGE_INDENT " ")
unset(missingComponents)
message(CHECK_START "Finding partA")
# ... do check, assume we find A
message(CHECK_PASS "found")
message(CHECK_START "Finding partB")
# ... do check, assume we don't find B
list(APPEND missingComponents B)
message(CHECK_FAIL "not found")
list(POP_BACK CMAKE_MESSAGE_INDENT)
if(missingComponents)
message(CHECK_FAIL "missing components: ${missingComponents}")
else()
message(CHECK_PASS "all components found")
endif()
The output from that would look something like this ๐
-- Finding my things
-- Finding partA
-- Finding partA - found
-- Finding partB
-- Finding partB - not found
-- Finding my things - missing components: B
๐ Configure Log
Added in version 3.26.
message(CONFIGURE_LOG <text>...)
Records a configure-log message event with the <text> you specify โจ by convention, if the text has more than one line, the first line should be a summary of the event.
This mode is for recording the details of a system inspection check or some other one-time operation that's guarded by a cache entry โ but that isn't done with try_compile() or try_run(), because those automatically log their own details ๐
projects should avoid calling it every single time CMake runs. For example:
if (NOT DEFINED MY_CHECK_RESULT)
# Print check summary in configure output.
message(CHECK_START "My Check")
# ... perform system inspection, e.g., with execute_process ...
# Cache the result so we do not run the check again.
set(MY_CHECK_RESULT "${MY_CHECK_RESULT}" CACHE INTERNAL "My Check")
# Record the check details in the cmake-configure-log.
message(CONFIGURE_LOG
"My Check Result: ${MY_CHECK_RESULT}\n"
"${details}"
)
# Print check result in configure output.
if(MY_CHECK_RESULT)
message(CHECK_PASS "passed")
else()
message(CHECK_FAIL "failed")
endif()
endif()
If no project is currently being configured โ like in cmake -P script mode โ this command does absolutely nothing ๐
๐ See Also
cmake_language(GET_MESSAGE_LOG_LEVEL)
๐ option
Gives the user a boolean option they can optionally select ๐
option(<variable> "<help_text>" [value])
If no initial <value> is given, boolean OFF is the default. If <variable> is already set as a normal or cache variable, then the command does nothing (see policy CMP0077) ๐คทโโ๏ธ
In CMake project mode, a boolean cache variable gets created with the option value. In CMake script mode, a boolean variable gets set with the option value โญ
๐ธ See Also
- The
CMakeDependentOptionmodule, for specifying boolean options that depend on the values of other options or on a set of conditions.
๐ฆ return
Bounce out of a file, directory, or function ๐ซถ
return([PROPAGATE <var-name>...])
When this command shows up inside an included file (via include() or find_package()), it stops processing of the current file and hands control back to the including file โจ if it shows up in a file that isn't included by another file โ like a CMakeLists.txt โ then deferred calls scheduled by cmake_language(DEFER) get invoked, and control returns to the parent directory if there is one.
If return() is called inside a function, control goes back to that function's caller ๐
heads up though: a macro(), unlike a function(), is expanded in place and therefore cannot handle return() ๐ญ
Policy CMP0140 controls the behavior around the command's arguments. All arguments are ignored unless that policy is set to NEW.
๐ฅ PROPAGATE
Added in version 3.25.
This option sets or unsets the specified variables in the parent directory or the function caller's scope ๐ it's equivalent to the set(PARENT_SCOPE) or unset(PARENT_SCOPE) commands โ except for how it interacts with the block() command, which we're about to get into.
PROPAGATE is so useful alongside block() ๐ a return will propagate the specified variables through any enclosing block scopes created by block() commands. Inside a function, that means the variables make it out to the function's caller no matter how many blocks are in the function. If you're not inside a function, it means the variables propagate to the parent file or directory scope. For example:
CMakeLists.txt
cmake_minimum_required(VERSION 3.25)
project(example)
set(var1 "top-value")
block(SCOPE_FOR VARIABLES)
add_subdirectory(subDir)
# var1 has the value "block-nested"
endblock()
# var1 has the value "top-value"
subDir/CMakeLists.txt
function(multi_scopes result_var1 result_var2)
block(SCOPE_FOR VARIABLES)
# This would only propagate out of the immediate block, not to
# the caller of the function.
#set(${result_var1} "new-value" PARENT_SCOPE)
#unset(${result_var2} PARENT_SCOPE)
# This propagates the variables through the enclosing block and
# out to the caller of the function.
set(${result_var1} "new-value")
unset(${result_var2})
return(PROPAGATE ${result_var1} ${result_var2})
endblock()
endfunction()
set(var1 "some-value")
set(var2 "another-value")
multi_scopes(var1 var2)
# Now var1 will hold "new-value" and var2 will be unset
block(SCOPE_FOR VARIABLES)
# This return() will set var1 in the directory scope that included us
# via add_subdirectory(). The surrounding block() here does not limit
# propagation to the current file, but the block() in the parent
# directory scope does prevent propagation going any further.
set(var1 "block-nested")
return(PROPAGATE var1)
endblock()
๐ธ See Also ๐ธ
block()โ the scope-making icon itselffunction()โ because functions make scopes too, bestie
โจ separate_arguments โจ
Okay so this one takes a command line and splits it up into a semicolon-separated list, like the little organizational queen it is. ๐
separate_arguments(<variable> <mode> [PROGRAM [SEPARATE_ARGS]] <args>)
So what it does: it parses a space-separated string <args> into a list of items, and then stores that list in <variable> in semicolon-separated standard form. ๐
This function is for parsing command-line arguments โ that's literally its whole job. And the entire command line has to be passed as one single string in the <args> argument. One string. That's the vibe. ๐ซถ
Now โ the exact parsing rules depend on the operating system. They're specified by the <mode> argument, and it has to be one of these keywords:
UNIX_COMMANDโ Arguments are separated by unquoted whitespace. Both single-quote and double-quote pairs are respected. A backslash escapes the next literal character (\"is"); and heads up, there are no special escapes โ\nis justn. Literally just the letter n. ๐ญWINDOWS_COMMANDโ A Windows command-line is parsed using the same syntax the runtime library uses to constructargvat startup. It separates arguments by whitespace that is not double-quoted. Backslashes are literal unless they precede double-quotes. See the MSDN article Parsing C Command-Line Arguments (<https://learn.microsoft.com/en-us/cpp/c-language/parsing-c-command-line-arguments>) for details. iykyk ๐ฆNATIVE_COMMANDโ Added in version 3.9. Proceeds as inWINDOWS_COMMANDmode if the host system is Windows. Otherwise proceeds as inUNIX_COMMANDmode. Basically it reads the room. ๐PROGRAMโ Added in version 3.19. Here's the slay: the first item in<args>is assumed to be an executable, and it will be searched in the system search path โ or left as a full path. If it's not found,<variable>will be empty. Otherwise,<variable>is a list of 2 elements:- Absolute path of the program
- Any command-line arguments present in
<args>as a string
For example:
separate_arguments (out UNIX_COMMAND PROGRAM "cc -c main.c")
- First element of the list:
/path/to/cc - Second element of the list:
" -c main.c"
SEPARATE_ARGSโ When this sub-option of thePROGRAMoption is specified, command-line arguments will be split as well and stored in<variable>. Extra splitting! We love options. ๐
For example:
separate_arguments (out UNIX_COMMAND PROGRAM SEPARATE_ARGS "cc -c main.c")
The contents of out will be: /path/to/cc;-c;main.c
the two-argument form ๐
separate_arguments(<var>)
Convert the value of <var> to a semi-colon separated list. All spaces are replaced with ;. This helps with generating command lines. Simple, clean, iconic. โจ
๐ set ๐
Set a normal, cache, or environment variable to a given value. Main character energy โ this command does it all. ๐
See the cmake-language(7) variables documentation for the scopes and interaction of normal variables and cache entries.
Signatures of this command that specify a <value>... placeholder expect zero or more arguments. Multiple arguments will be joined as a semicolon-separated list to form the actual variable value to be set. So like, they all get smooshed together with semicolons. Fr fr. ๐
๐ Set Normal Variable ๐
set(<variable> <value>... [PARENT_SCOPE])
Set or unset <variable> in the current function or directory scope:
- If at least one
<value>...is given, set the variable to that value. - If no value is given, unset the variable. This is equivalent to
unset(<variable>).
If the PARENT_SCOPE option is given, the variable will be set in the scope above the current scope. Okay so every new directory or function() command creates a new scope. And a scope can also be created with the block() command. set(PARENT_SCOPE) will set the value of a variable into the parent directory, calling function, or encompassing scope โ whichever is applicable to the case at hand. ๐ง
Important detail bestie: the previous state of the variable's value stays the same in the current scope. Like, if it was undefined before, it's still undefined; if it had a value, it's still that value. No take-backs in the current scope. ๐
The block(PROPAGATE) and return(PROPAGATE) commands can be used as an alternate method to the set(PARENT_SCOPE) and unset(PARENT_SCOPE) commands to update the parent scope. Options, options, options. ๐
Note: When evaluating variable references of the form${VAR}, CMake first searches for a normal variable with that name. If no such normal variable exists, CMake will then search for a cache entry with that name. Because of this, unsetting a normal variable can expose a cache variable that was previously hidden. ๐ To force a variable reference of the form${VAR}to return an empty string, useset(<variable> ""), which clears the normal variable but leaves it defined.
๐ฆ Set Cache Entry ๐ฆ
set(CACHE{<variable>} [TYPE <type>] [HELP <helpstring>...] [FORCE] VALUE [<value>...])
Added in version 4.2. Sets the given cache <variable> (cache entry). The options are:
TYPE <type>โ Specify the type of the cache entry. The<type>must be one of:BOOLโ BooleanON/OFFvalue.cmake-gui(1)offers a checkbox. โFILEPATHโ Path to a file on disk.cmake-gui(1)offers a file dialog.PATHโ Path to a directory on disk.cmake-gui(1)offers a file dialog.STRINGโ A line of text.cmake-gui(1)offers a text field or a drop-down selection if theSTRINGScache entry property is set.INTERNALโ A line of text.cmake-gui(1)does not show internal entries. They may be used to store variables persistently across runs. Use of this type impliesFORCE.
If TYPE is not specified: if the cache variable already exists and its type is not UNINITIALIZED, the type previously specified will be kept โ otherwise, STRING will be used. Default behavior, we love her. ๐
HELP <helpstring>...โ The<helpstring>must be specified as a line of text providing a quick summary of the option for presentation tocmake-gui(1)users. If more than one string is given, they are concatenated into a single string with no separator between them. (No separator. Not even a space. Just glued together. ๐ญ) IfHELPis not specified, an empty string will be used.FORCEโ Since cache entries are meant to provide user-settable values, this does not overwrite existing cache entries by default. Use theFORCEoption to overwrite existing entries. Use it responsibly, bestie. ๐VALUE <value>...โ List of values to be set to the cache<variable>. This argument must always be the last one. Periodt. ๐ฅ
If the cache entry does not exist prior to the call, or the FORCE option is given, then the cache entry will be set to the given value.
Note: The content of the cache variable will not be directly accessible if a normal variable of the same name already exists (see rules of variable evaluation). If policyCMP0126is set toOLD, any normal variable binding in the current scope will be removed.
It is possible for the cache entry to exist prior to the call but have no type set โ that happens if it was created on the cmake(1) command line by a user through the -D<var>=<value> option without specifying a type. In this case the set command will add the type. ๐ Furthermore, if the <type> is PATH or FILEPATH and the <value> provided on the command line is a relative path, then the set command will treat the path as relative to the current working directory and convert it to an absolute path. Slay.
set(<variable> <value>... CACHE <type> <docstring> [FORCE])
This signature is supported for compatibility purpose. Use preferably the other one. ๐ (that's the polite way of saying "the new one ate, use that")
๐ Set Environment Variable ๐
set(ENV{<variable>} [<value>])
Sets an Environment Variable to the given value. Subsequent calls of $ENV{<variable>} will return this new value. ๐
Okay but here's the catch, and it's lowkey important: this command affects only the current CMake process. Not the process from which CMake was called, not the system environment at large, and not the environment of subsequent build or test processes. Just this one process. That's it. ๐ซถ
If no argument is given after ENV{<variable>}, or if <value> is an empty string, then this command will clear any existing value of the environment variable.
Arguments after <value> are ignored. If extra arguments are found, then an author warning is issued. (Not me forgetting that and getting yelled at by CMake ๐)
๐ธ See Also ๐ธ
unset()โ the opposite bestie, go check her out
๐ set_directory_properties ๐
Set properties of the current directory and subdirectories. Passing those properties down like hand-me-downs, but make it CMake. ๐
set_directory_properties(PROPERTIES <prop1> <value1> [<prop2> <value2>] ...)
Sets properties of the current directory and its subdirectories in key-value pairs. Very neat, very organized. โจ
See also the set_property(DIRECTORY) command.
See Properties on Directories for the list of properties known to CMake and their individual documentation for the behavior of each property. (Go read those, they're important, no cap.)
๐ See Also ๐
define_property()get_directory_property()- the more general
set_property()command โ she's the versatile one ๐
โญ set_property โญ
Set a named property in a given scope.
...and here's the full shape of it, bestie:
set_property({GLOBAL |
DIRECTORY [<dir>] |
TARGET <target>... |
FILE_SET <file_set>... TARGET <target> |
SOURCE <source>...
[DIRECTORY <dirs> ...]
[TARGET_DIRECTORY <targets>...] |
INSTALL <file>... |
TEST <test>...
[DIRECTORY <dir>] |
CACHE <entry>...}
[APPEND] [APPEND_STRING]
PROPERTY <name> [<value>...])
Sets one property on zero or more objects of a scope. Zero is allowed, yes โ it's giving "no thoughts, head empty, still valid." ๐
The first argument determines the scope in which the property is set. It must be one of the following, no substitutions:
GLOBALโ Scope is unique and does not accept a name. One global, no last name needed. ๐DIRECTORYโ Scope defaults to the current directory, but other directories (already processed by CMake) may be named by full or relative path. Relative paths are treated as relative to the current source directory. See also theset_directory_properties()command.- Added in version 3.19:
<dir>may reference a binary directory.
- Added in version 3.19:
TARGETโ Scope may name zero or more existing targets. See also theset_target_properties()command.- Alias Targets do not support setting target properties. like, they said no. respect it. ๐
FILE_SETโ Added in version 4.3.- Scope may name zero or more existing file sets.
- The following option is required:
TARGET <target>โ The target to which the file set is attached.
SOURCEโ Scope may name zero or more source files. By default, source file properties are only visible to targets added in the same directory (CMakeLists.txt).- Added in version 3.18: Visibility can be set in other directory scopes using one or both of the following sub-options:
DIRECTORY <dirs>...โ The source file property will be set in each of the<dirs>directories' scopes. CMake must already know about each of these directories, either by having added them through a call toadd_subdirectory()or it being the top level source directory. Relative paths are treated as relative to the current source directory.- Added in version 3.19:
<dirs>may reference a binary directory.
- Added in version 3.19:
TARGET_DIRECTORY <targets>...โ The source file property will be set in each of the directory scopes where any of the specified<targets>were created (the<targets>must therefore already exist).
- See also the
set_source_files_properties()command.
- Added in version 3.18: Visibility can be set in other directory scopes using one or both of the following sub-options:
INSTALLโ Added in version 3.1.- Scope may name zero or more installed file paths. These are made available to CPack to influence deployment.
- Both the property key and value may use generator expressions. Specific properties may apply to installed files and/or directories.
- Path components have to be separated by forward slashes, must be normalized and are case sensitive. so no
\shenanigans, we're not doing that today ๐ - To reference the installation prefix itself with a relative path use
.. - Currently installed file properties are only defined for the
WIXgenerator where the given paths are relative to the installation prefix.
TESTโ Scope is limited to the directory the command is called in. It may name zero or more existing tests. See also commandset_tests_properties().- Test property values may be specified using generator expressions for tests created by the
add_test(NAME)signature. - Added in version 3.28: Visibility can be set in other directory scopes using the following sub-option:
DIRECTORY <dir>โ The test property will be set in the<dir>directory's scope. CMake must already know about this directory, either by having added it through a call toadd_subdirectory()or it being the top level source directory. Relative paths are treated as relative to the current source directory.<dir>may reference a binary directory.
- Test property values may be specified using generator expressions for tests created by the
CACHEโ Scope must name zero or more existing cache entries.
The required PROPERTY option is immediately followed by the name of the property to set. Remaining arguments are used to compose the property value in the form of a semicolon-separated list. โจ
If the APPEND option is given the list is appended to any existing property value (except that empty values are ignored and not appended โ they get ghosted ๐ป). If the APPEND_STRING option is given the string is appended to any existing property value as string, i.e. it results in a longer string and not a list of strings. When using APPEND or APPEND_STRING with a property defined to support INHERITED behavior (see define_property()), no inheriting occurs when finding the initial value to append to. If the property is not already directly set in the nominated scope, the command will behave as though APPEND or APPEND_STRING had not been given.
Note: The GENERATED source file property may be globally visible. See its documentation for details. iykyk ๐ซถ
See Also
define_property()get_property()- The
cmake-properties(7)manual for a list of properties in each scope.
๐ site_name
Set the given variable to the name of the computer. literally just "who am i" but as a variable ๐ฅ๏ธโจ
site_name(variable)
On UNIX-like platforms, if the variable HOSTNAME is set, its value will be executed as a command expected to print out the host name, much like the hostname command-line tool. yes bestie it executes it, that's the assignment, don't @ me.
๐ string
String operations. the whole buffet, one command. ๐
Synopsis
Search and Replace
string(FIND <string> <substring> <out-var> [...])
string(REPLACE <match-string> <replace-string> <out-var> <input>...)
string(REGEX MATCH <match-regex> <out-var> <input>...)
string(REGEX MATCHALL <match-regex> <out-var> <input>...)
string(REGEX REPLACE <match-regex> <replace-expr> <out-var> <input>...)
Manipulation
string(APPEND <string-var> [<input>...])
string(PREPEND <string-var> [<input>...])
string(CONCAT <out-var> [<input>...])
string(JOIN <glue> <out-var> [<input>...])
string(TOLOWER <string> <out-var>)
string(TOUPPER <string> <out-var>)
string(LENGTH <string> <out-var>)
string(SUBSTRING <string> <begin> <length> <out-var>)
string(STRIP <string> <out-var>)
string(GENEX_STRIP <string> <out-var>)
string(REPEAT <string> <count> <out-var>)
string(REGEX QUOTE <out-var> <input>...)
Comparison
string(COMPARE <op> <string1> <string2> <out-var>)
Hashing
string(<HASH> <out-var> <input>)
Generation
string(ASCII <number>... <out-var>)
string(HEX <string> <out-var>)
string(CONFIGURE <string> <out-var> [...])
string(MAKE_C_IDENTIFIER <string> <out-var>)
string(RANDOM [<option>...] <out-var>)
string(TIMESTAMP <out-var> [<format string>] [UTC])
string(UUID <out-var> ...)
JSON
string(JSON <out-var> [ERROR_VARIABLE <error-var>]
{GET | GET_RAW | TYPE | LENGTH}
<json-string> [<member|index> ...])
string(JSON <out-var> [ERROR_VARIABLE <error-var>]
REMOVE
<json-string> <member|index> [<member|index> ...])
string(JSON <out-var> [ERROR_VARIABLE <error-var>]
MEMBER <json-string>
[<member|index> ...] <index>)
string(JSON <out-var> [ERROR_VARIABLE <error-var>]
SET <json-string>
<member|index> [<member|index> ...] <value>)
string(JSON <out-var> [ERROR_VARIABLE <error-var>]
EQUAL <json-string1> <json-string2>)
string(JSON <out-var> [ERROR_VARIABLE <error-var>]
PARTIAL_EQUAL <json-string1> <json-string2>)
string(JSON <out-var> [ERROR_VARIABLE <error-var>]
STRING_ENCODE <string>)
๐ Search and Replace
Search and Replace With Plain Strings
string(FIND <string> <substring> <output_variable> [REVERSE])
Return the position where the given <substring> was found in the supplied <string>. If the REVERSE flag was used, the command will search for the position of the last occurrence of the specified <substring>. If the <substring> is not found, a position of -1 is returned.
The string(FIND) subcommand treats all strings as ASCII-only characters. The index stored in <output_variable> will also be counted in bytes, so strings containing multi-byte characters may lead to unexpected results. โ ๏ธ multi-byte besties, check yourselves before you wreck yourselves.
string(REPLACE <match_string> <replace_string> <output_variable> <input> [<input>...])
Replace all occurrences of <match_string> in the <input> with <replace_string> and store the result in the <output_variable>.
Search and Replace With Regular Expressions
string(REGEX MATCH <regular_expression> <output_variable> <input> [<input>...])
Match the <regular_expression> once and store the match in the <output_variable>. All <input> arguments are concatenated before matching. Regular expressions are specified in the subsection just below. one (1) match, that's the whole vibe.
string(REGEX MATCHALL <regular_expression> <output_variable> <input> [<input>...])
Match the <regular_expression> as many times as possible and store the matches in the <output_variable> as a list. All <input> arguments are concatenated before matching. collect them all like they're Pokรฉmon ๐ฅ
string(REGEX REPLACE <regular_expression> <replacement_expression> <output_variable> <input> [<input>...])
Match the <regular_expression> as many times as possible and substitute the <replacement_expression> for the match in the output. All <input> arguments are concatenated before matching.
The <replacement_expression> may refer to parenthesis-delimited subexpressions of the match using \1, \2, ..., \9. Note that two backslashes (\\1) are required in CMake code to get a backslash through argument parsing. fr fr, the escaping will humble you. ๐ญ
okay so the ^ anchor literally got a glow-up in 4.1: it matches only at the beginning of the input string now, not at the start of every repeated search. The way that's a whole personality change ๐ญ โ go peek at policy CMP0186 if you need the receipts.
Zero-length matches are allowed in MATCHALL and REPLACE now. Bestie, they used to throw an error for that. Growth. ๐ฑ
And your replacement expression can reference subexpressions that didn't match anything. Previously? error. Now? it just vibes. ๐
๐ฆ Regex Specification ๐ฆ
These characters are the main characters of regex โ they have special meaning:
^โ matches at beginning of input.$โ matches at end of input..โ matches any single character.\<char>โ matches the single character specified by<char>. Use this to match special regex characters, e.g.\.for a literal., or\\for a literal backslash\. Escaping a non-special character is unnecessary but allowed, e.g.\amatchesa.[ ]โ matches any character(s) inside the brackets. To match a literal], make it the first character, e.g.,[]ab].[^ ]โ matches any character(s) not inside the brackets. To not match a literal], make it the first character, e.g.,[^]ab].-โ inside brackets, specifies an inclusive range between the characters on either side, e.g.,[a-f]is[abcdef]. To match a literal-using brackets, make it the first or the last character, e.g.,[+*/-]matches basic mathematical operators.*โ matches preceding pattern zero or more times.+โ matches preceding pattern one or more times.?โ matches preceding pattern zero or once only.|โ matches a pattern on either side of the|.()โ saves a matched subexpression, which can be referenced in theREGEX REPLACEoperation.
Added in version 3.9: All regular expression-related commands โ including, like,if(MATCHES)โ save subgroup matches in the variablesCMAKE_MATCH_<n>for<n>0..9. No cap, group chat memory unlocked. ๐ซถ
Precedence tea โ: *, + and ? outrank concatenation. | sits below concatenation. So the regex ^ab+d$ matches abbd but not ababd, and the regex ^(ab|cd)$ matches ab but not abd. Slay, that's just how it eats. ๐ฅ
CMake language Escape Sequences like \t, \r, \n, and \\ may be used to construct literal tabs, carriage returns, newlines, and backslashes (respectively) to pass in a regex. For example:
- The quoted argument
"[ \t\r\n]"specifies a regex that matches any single whitespace character. - The quoted argument
"[/\\]"specifies a regex that matches a single forward slash/or backslash\. - The quoted argument
"[A-Za-z0-9_]"specifies a regex that matches any single "word" character in the C locale. - The quoted argument
"\\(\\a\\+b\\)"specifies a regex that matches the exact string(a+b). Each\\is parsed in a quoted argument as just\, so the regex itself is actually\(\a\+\b\). This can alternatively be specified in a Bracket Argument without having to escape the backslashes, e.g.[[\(\a\+\b\)]].
๐ Manipulation ๐
string(APPEND <string_variable> [<input>...])โ Added in version 3.4. Append all the<input>arguments to the string. Pile it on, bestie ๐string(PREPEND <string_variable> [<input>...])โ Added in version 3.10. Prepend all the<input>arguments to the string. Front of the line energy. ๐string(CONCAT <output_variable> [<input>...])โ Concatenate all the<input>arguments together and store the result in the named<output_variable>.string(JOIN <glue> <output_variable> [<input>...])โ Added in version 3.12. Join all the<input>arguments together using the<glue>string and store the result in the named<output_variable>.
Bestie, to join a list's elements, prefer theJOINoperator from thelist()command. That one lets the elements have special characters like;in them. iykyk ๐ง
string(TOLOWER <string> <output_variable>)โ Convert<string>to lower characters. lowercase aesthetic fr fr.string(TOUPPER <string> <output_variable>)โ Convert<string>to upper characters. LOUDER. ๐ฃstring(LENGTH <string> <output_variable>)โ Store in an<output_variable>a given string's length in bytes. Note that this means if<string>contains multi-byte characters, the result stored in<output_variable>will not be the number of characters. Bytes โ characters, don't let it gaslight you. ๐string(SUBSTRING <string> <begin> <length> <output_variable>)โ Store in an<output_variable>a substring of a given<string>. If<length>is-1the remainder of the string starting at<begin>will be returned.
Changed in version 3.2: If<string>is shorter than<length>then the end of the string is used instead. Previous versions of CMake reported an error in this case.
Both <begin> and <length> are counted in bytes, so care must be exercised if <string> could contain multi-byte characters. ๐
string(STRIP <string> <output_variable>)โ Store in an<output_variable>a substring of a given<string>with leading and trailing spaces removed. Trim the toxic energy โจstring(GENEX_STRIP <string> <output_variable>)โ Added in version 3.1. Strip any generator expressions from the input<string>and store the result in the<output_variable>.string(REPEAT <string> <count> <output_variable>)โ Added in version 3.15. Produce the output string as the input<string>repeated<count>times. Spam that group chat ๐string(REGEX QUOTE <out-var> <input>...)โ Added in version 4.2. Store in an<out-var>a regular expression matching the<input>. All characters that have special meaning in a regular expression are escaped, such that the output string can be used as part of a regular expression to match the input literally. Escape room but make it regex ๐
๐ Comparison ๐
string(COMPARE LESS <string1> <string2> <output_variable>)string(COMPARE GREATER <string1> <string2> <output_variable>)string(COMPARE EQUAL <string1> <string2> <output_variable>)string(COMPARE NOTEQUAL <string1> <string2> <output_variable>)string(COMPARE LESS_EQUAL <string1> <string2> <output_variable>)string(COMPARE GREATER_EQUAL <string1> <string2> <output_variable>)
Compare the strings and store true or false in the <output_variable>. Simple as that, bestie ๐
Added in version 3.7: Added theLESS_EQUALandGREATER_EQUALoptions. The glow-up we deserved. ๐
๐ฅ Hashing ๐ฅ
string(<HASH> <output_variable> <input>)โ Compute a cryptographic hash of the<input>string.
The supported <HASH> algorithm names are:
MD5โ Message-Digest Algorithm 5, RFC 1321.SHA1โ US Secure Hash Algorithm 1, RFC 3174.SHA224โ US Secure Hash Algorithms, RFC 4634.SHA256โ US Secure Hash Algorithms, RFC 4634.SHA384โ US Secure Hash Algorithms, RFC 4634.SHA512โ US Secure Hash Algorithms, RFC 4634.SHA3_224โ Keccak SHA-3.SHA3_256โ Keccak SHA-3.SHA3_384โ Keccak SHA-3.SHA3_512โ Keccak SHA-3.
Added in version 3.8: Added the SHA3_* hash algorithms. They're giving new-gen cryptography. ๐ธ
๐ Generation ๐
string(ASCII <number> [<number> ...] <output_variable>)โ Convert all numbers into corresponding ASCII characters.string(HEX <string> <output_variable>)โ Added in version 3.18. Convert each byte in the input<string>to its hexadecimal representation and store the concatenated hex digits in the<output_variable>. Letters in the output (athroughf) are in lowercase. lowkey aesthetic. ๐string(CONFIGURE <string> <output_variable> [@ONLY] [ESCAPE_QUOTES])โ Transform a<string>likeconfigure_file()transforms a file.string(MAKE_C_IDENTIFIER <string> <output_variable>)โ Convert each non-alphanumeric character in the input<string>to an underscore and store the result in the<output_variable>. If the first character of the<string>is a digit, an underscore will also be prepended to the result. Cute, legal, C-ified ๐string(RANDOM [LENGTH <length>] [ALPHABET <alphabet>] [RANDOM_SEED <seed>] <output_variable>)โ Return a random string of given<length>consisting of characters from the given<alphabet>. Default length is5characters and default alphabet is all numbers and upper and lower case letters. If an integerRANDOM_SEEDis given, its value will be used to seed the random number generator. Chaos, but make it reproducible ๐ฒstring(TIMESTAMP <output_variable> [<format_string>] [UTC])โ Write a string representation of the current date and/or time to the<output_variable>.
If the command is unable to obtain a timestamp, the <output_variable> will be set to the empty string "".
The optional UTC flag requests the current date/time representation to be in Coordinated Universal Time (UTC) rather than local time. ๐
The optional <format_string> may contain the following format specifiers:
%%โ Added in version 3.8. A literal percent sign (%).%dโ The day of the current month (01-31).%Hโ The hour on a 24-hour clock (00-23).%Iโ The hour on a 12-hour clock (01-12).%jโ The day of the current year (001-366).%mโ The month of the current year (01-12).%bโ Added in version 3.7. Abbreviated month name (e.g.Oct).%Bโ Added in version 3.10. Full month name (e.g.October).%Mโ The minute of the current hour (00-59).%sโ Added in version 3.6. Seconds since midnight (UTC) 1-Jan-1970 (UNIX time).%Sโ The second of the current minute.60represents a leap second. (00-60)%fโ Added in version 3.23. The microsecond of the current second (000000-999999).%Uโ The week number of the current year (00-53).%Vโ Added in version 3.22. The ISO 8601 week number of the current year (01-53).%wโ The day of the current week.0is Sunday. (0-6)%aโ Added in version 3.7. Abbreviated weekday name (e.g.Fri).%Aโ Added in version 3.10. Full weekday name (e.g.Friday).%yโ The last two digits of the current year (00-99).%Yโ The current year.%zโ Added in version 3.26. The offset of the time zone from UTC, in hours and minutes, with format+hhmmor-hhmm.%Zโ Added in version 3.26.
- The time zone name.
Unknown format specifiers don't throw hands โ they just get ignored and copied to the output as-is. ๐
If you don't pass an explicit <format_string>, it lowkey defaults to:
%Y-%m-%dT%H:%M:%Sfor local time.%Y-%m-%dT%H:%M:%SZfor UTC.
Added in version 3.8: if the SOURCE_DATE_EPOCH environment variable is set, its value gets used instead of the current time. See <https://reproducible-builds.org/specs/source-date-epoch/> for the full tea. ๐ซถ
string(UUID <output_variable> NAMESPACE <namespace> NAME <name> TYPE
<MD5|SHA1> [UPPER])
Added in version 3.1.
Makes a universally unique identifier (aka a GUID, yes bestie, the same thing) as per RFC4122, built from the hash of <namespace> (which itself has to be a valid UUID, no faking it) combined with <name>. The hash algorithm is either MD5 (that's a Version 3 UUID) or SHA1 (Version 5 UUID, my beloved โจ). A UUID looks like xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx where every x is a lower case hexadecimal character. If you need it shouty, the optional UPPER flag gives you the uppercase representation. ๐
JSON ๐ฆ
Added in version 3.19.
Functionality for querying a JSON string. Yes, CMake does JSON now, we're thriving.
Note: in each of the following JSON-related subcommands, if the optionalERROR_VARIABLEargument is given, errors get reported in<error-variable>and the<out-var>is set to<member|index>-[<member|index>...]-NOTFOUNDwith the path elements up to the point where the error happened, or justNOTFOUNDif there's no relevant path. If an error occurs but theERROR_VARIABLEoption isn't there, you get a fatal error message โ like, the whole thing dies ๐ญ. And if nothing goes wrong,<error-variable>gets set toNOTFOUND.
In the following subcommands, write the <json-string> argument as a Quoted Argument <#quoted-argument> so the entire JSON string gets passed as a single argument even if it's full of semicolons. Semicolons are menace behavior, protect yourself. ๐
GET
string(JSON <out-var> [ERROR_VARIABLE <error-variable>] GET
<json-string> [<member|index> ...])
Grabs an element out of <json-string> at the location given by the list of <member|index> arguments. Array and object elements come back as a JSON string. Boolean elements come back as ON or OFF. Null elements come back as an empty string. Number and string types come back as strings. It's giving type flattening, but make it fashion. ๐
GET_RAW
string(JSON <out-var> [ERROR_VARIABLE <error-variable>] GET_RAW
<json-string> [<member|index> ...])
Added in version 4.3.
Grabs an element out of <json-string> at the location given by the list of <member|index> arguments. Similar to GET, but it does not convert number, string, boolean, or null elements. Raw dogging the JSON, respectfully. ๐
TYPE
string(JSON <out-var> [ERROR_VARIABLE <error-variable>] TYPE
<json-string> [<member|index> ...])
Gets the type of an element in <json-string> at the location given by the list of <member|index> arguments. <out-var> gets set to one of NULL, NUMBER, STRING, BOOLEAN, ARRAY, or OBJECT. Six options, all iconic. ๐
MEMBER
string(JSON <out-var> [ERROR_VARIABLE <error-var>] MEMBER <json-string>
[<member|index> ...] <index>)
Gets the name of the <index>-th member in <json-string> at the location given by the list of <member|index> arguments. Requires an element of object type, so don't try this on an array bestie, it will not slay. ๐
LENGTH
string(JSON <out-var> [ERROR_VARIABLE <error-variable>] LENGTH
<json-string> [<member|index> ...])
Gets the length of an element in <json-string> at the location given by the list of <member|index> arguments. Requires an element of array or object type โ those are the only two things that even have a length, no cap.
REMOVE
string(JSON <out-var> [ERROR_VARIABLE <error-variable>] REMOVE
<json-string> <member|index> [<member|index> ...])
Removes an element from <json-string> at the location given by the list of <member|index> arguments. The JSON string without the removed element gets stored in <out-var>. It's giving "you're not invited to the group chat anymore". ๐ซถ
SET
string(JSON <out-var> [ERROR_VARIABLE <error-variable>] SET
<json-string> <member|index> [<member|index> ...] <value>)
Sets an element in <json-string> at the location given by the list of <member|index> arguments to <value>. The contents of <value> should be valid JSON โ fr fr, don't be out here passing vibes. If <json-string> is an array, you can append <value> to the end of the array by using a number greater than or equal to the array length as the <member|index> argument. โจ
EQUAL
string(JSON <out-var> [ERROR_VARIABLE <error-var>] EQUAL <json-string1>
<json-string2>)
Compares the two JSON objects given by <json-string1> and <json-string2> for equality. The contents of <json-string1> and <json-string2> should be valid JSON. <out-var> gets set to a true value if the JSON objects are considered equal, or a false value otherwise. Simple, clean, no drama. ๐
PARTIAL_EQUAL
string(JSON <out-var> [ERROR_VARIABLE <error-var>] PARTIAL_EQUAL
<json-pattern> <json-actual>)
Added in version 4.4.
Compares two JSON values using partial equality. The first argument (<json-pattern>) is treated as a pattern to match against the second argument (<json-actual>), which is treated as the complete JSON value. The contents of <json-pattern> and <json-actual> must be valid JSON.
<out-var> gets set to a true value if <json-pattern> is contained within <json-actual> according to the rules below, or a false value otherwise.
Heads up โ ๏ธ: partial equality is not symmetric. In general, PARTIAL_EQUAL(A, B) and PARTIAL_EQUAL(B, A) may produce different results. Yes, order matters, it's that kind of function.
Matching rules:
- Scalars (null, number, string, boolean) must match exactly. No rounding, no "close enough".
- Objects match if every member in
<json-pattern>exists in<json-actual>and the corresponding values also match recursively. Extra members in<json-actual>are ignored โ they're just bonus content, we don't gatekeep. - Arrays match if every element in
<json-pattern>matches a distinct element in<json-actual>recursively. Once an element in<json-actual>successfully matches an element in<json-pattern>, it is consumed and cannot be reused to match any subsequent elements. Array element order is not significant. Extra elements in<json-actual>are ignored. So it's like, one dance partner each, periodt. ๐ - Type differences do not match (for example, an object does not match an array, and a string does not match a number). Obviously, babe.
STRING_ENCODE
string(JSON <out-var> [ERROR_VARIABLE <error-var>] STRING_ENCODE
<string>)
Added in version 4.3.
Turns a raw string into a JSON string surrounded by quotes. Special characters get properly escaped inside the JSON string โ no more broken quotes ruining your whole build. ๐ง
unset
Unset a variable, cache variable, or environment variable. Three flavors, pick your fighter.
Unset Normal Variable
unset(<variable> [PARENT_SCOPE])
Removes a normal variable from the current scope, causing it to become undefined. Poof. Gone. Ghosted. ๐ป
If PARENT_SCOPE is present then the variable gets removed from the scope above the current scope. See the same option in the set() <#command:set> command for further details.
Note: when evaluating Variable References <#variable-references> of the form${VAR}, CMake first searches for a normal variable with that name. If no such normal variable exists, CMake then searches for a cache entry with that name. Because of this, unsetting a normal variable can expose a cache variable that was previously hidden โ like pulling back the curtain and finding a whole other variable living there ๐ญ. To force a variable reference of the form${VAR}to return an empty string, useset(<variable> ""), which clears the normal variable but leaves it defined. Different vibe entirely.
Unset Cache Entry
unset(CACHE{<variable>})
Added in version 4.2.
Removes <variable> from the cache, causing it to become undefined.
unset(<variable> CACHE)
This signature is supported for compatibility purpose. Use preferably the other one. Yes, the older one is still here, living its legacy era, but we're gently nudging you toward the newer form. ๐
Unset Environment Variable
unset(ENV{<variable>})
Removes <variable> from the currently available Environment Variables <#manual:cmake-env-variables(7)>. Subsequent calls of $ENV{<variable>} will return the empty string.
This command affects only the current CMake process โ not the process from which CMake was called, nor the system environment at large, nor the environment of subsequent build or test processes. So like, it's a local vibe, not a global one. Keep that in mind before you blame CMake for your shell looking weird. ๐
See Also
set()<#command:set>
variable_watch
Watch the CMake variable for change. It's giving surveillance but make it helpful. ๐โจ
variable_watch(<variable> [<command>])
If the specified <variable> changes and no <command> is given, a message gets printed to inform you about the change.
If <command> is given, that command gets executed instead. The command receives the following arguments: COMMAND(<variable> <access> <value> <current_list_file> <stack>)
<variable> : Name of the variable being accessed.
<access> : One of READ_ACCESS, UNKNOWN_READ_ACCESS, MODIFIED_ACCESS, UNKNOWN_MODIFIED_ACCESS, or REMOVED_ACCESS. The UNKNOWN_ values are only used when the variable has never been set. Once set, they are never used again during the same CMake run, even if the variable is later unset. One and done, no takebacks. ๐
<value> : The value of the variable. On a modification, this is the new (modified) value of the variable. On removal, the value is empty. Sad little empty string.
<current_list_file> : Full path to the file doing the access.
<stack> : List of absolute paths of all files currently on the stack of file inclusion, with the bottom-most file first and the currently processed file (that is, current_list_file) last. Bottom to top, like a stack of pancakes. ๐ฅ
Note that for some accesses such as list(APPEND) <#append>, the watcher runs twice โ first with a read access and then with a write one. Also note that an if(DEFINED) <#defined> query on the variable does not register as an access and the watcher is not executed. Sneaky little query, flying under the radar. ๐ฆ
Only non-cache variables can be watched using this command. Access to cache variables is never watched. However, the existence of a cache variable var causes accesses to the non-cache variable var to not use the UNKNOWN_ prefix, even if a non-cache variable var has never existed. Yeah, it's messy, that's just how it is bestie. ๐
while
Evaluate a group of commands while a condition is true. The original loop-de-loop. ๐
while(<condition>)
<commands>
endwhile()
All commands between while and the matching endwhile() <#command:endwhile> are recorded without being invoked โ they're just sitting there, waiting, main character energy but no screentime yet. Once the endwhile() <#command:endwhile> is evaluated, the recorded list of commands gets invoked as long as the <condition> is true. โจ
The <condition> has the same syntax and is evaluated using the same logic as described at length for the if() <#command:if> command. So go read that one, iykyk. ๐ซถ
The commands break() and continue() are literally your escape hatches from the normal control flow โ think of them as the "bestie I gotta go" of CMake loops. ๐จ
Per legacy (yes, the old-school vibes), the endwhile() command admits an optional <condition> argument. If you use it, it must be a verbatim repeat of the argument of the opening while command. No paraphrasing, no remixing โ copy it exactly, periodt. ๐
๐ See Also
break()continue()foreach()endwhile()
๐ ๏ธ PROJECT COMMANDS ๐ ๏ธ
Okay so these commands are available only in CMake projects. Not in script mode, bestie โ projects only. ๐
๐ท๏ธ add_compile_definitions
Added in version 3.12. โจ
Add preprocessor definitions to the compilation of source files. It's giving "let me tell the compiler about my lore" energy.
add_compile_definitions(<definition> ...)
Adds preprocessor definitions to the compiler command line. Fr fr, that's the whole bit.
The preprocessor definitions get added to the COMPILE_DEFINITIONS directory property for the current CMakeLists file. They're also added to the COMPILE_DEFINITIONS target property for each target in the current CMakeLists file. Double the property, double the slay. ๐
Definitions are specified using the syntax VAR or VAR=value. Function-style definitions are not supported, sorry bestie, that's just not on the menu. ๐ CMake will automatically escape the value correctly for the native build system โ note that CMake language syntax may require escapes to specify some values, so like, watch out for that.
Added in version 3.26: any leading -D on an item will be removed. Iconic behaviour, honestly.
Arguments to add_compile_definitions may use generator expressions with the syntax $<...>. See the cmake-generator-expressions(7) manual for available expressions. See the cmake-buildsystem(7) manual for more on defining buildsystem properties. ๐
๐ See Also
- The command
target_compile_definitions()adds target-specific definitions. ๐ฏ
โ๏ธ add_compile_options
Add options to the compilation of source files. Lowkey the workhorse of the whole buildsystem. ๐ฅ
add_compile_options(<option> ...)
Adds options to the COMPILE_OPTIONS directory property. These options are used when compiling targets from the current directory and below. It trickles down, main character energy. ๐
Note: these options are not used when linking. Like, at all. See the add_link_options() command for that one. ๐
๐ง Arguments
Arguments to add_compile_options may use generator expressions with the syntax $<...>. See the cmake-generator-expressions(7) manual for available expressions. See the cmake-buildsystem(7) manual for more on defining buildsystem properties. Same deal as before, iykyk.
๐งน Option De-duplication
So here's the tea โ โ the final set of options used for a target is constructed by accumulating options from the current target and the usage requirements of its dependencies. The set of options is de-duplicated to avoid repetition. Clean, tidy, no duplicates.
Added in version 3.12: while this is beneficial for individual options, the de-duplication step can break up option groups. ๐ญ For example, -option A -option B becomes -option A B. Not the vibe.
One may specify a group of options using shell-like quoting along with a SHELL: prefix. The SHELL: prefix is dropped, and the rest of the option string is parsed using the separate_arguments() UNIX_COMMAND mode. For example, "SHELL:-option A" "SHELL:-option B" becomes -option A -option B. Slay, group preserved. ๐ซถ
๐ธ Example
Since different compilers support different options, a typical use of this command is in a compiler-specific conditional clause:
if (MSVC)
# warning level 4
add_compile_options(/W4)
else()
# additional warnings
add_compile_options(-Wall -Wextra -Wpedantic)
endif()
To set per-language options, use the $<COMPILE_LANGUAGE> or $<COMPILE_LANGUAGE:languages> generator expressions. ๐ฆ
๐ See Also
- This command can be used to add any options. However, for adding preprocessor definitions and include directories it is recommended to use the more specific commands
add_compile_definitions()andinclude_directories(). ๐ - The command
target_compile_options()adds target-specific options. ๐ฏ - This command adds compile options for all languages. Use the
COMPILE_LANGUAGEgenerator expression to specify per-language compile options. ๐ - The source file property
COMPILE_OPTIONSadds options to one source file. ๐ add_link_options()adds options for linking. ๐CMAKE_<LANG>_FLAGSandCMAKE_<LANG>_FLAGS_<CONFIG>add language-wide flags passed to all invocations of the compiler. This includes invocations that drive compiling and those that drive linking. Literally all of them. ๐
๐งฉ add_custom_command
Add a custom build rule to the generated build system. This one's a big deal, bestie โ buckle up. ๐ข
๐ Synopsis
Generating Files:
add_custom_command(OUTPUT <output1> [<output2> ...]
COMMAND <command1> [ARGS] [<args1>...]
[...])
Build Events:
add_custom_command(TARGET <target>
PRE_BUILD | PRE_LINK | POST_BUILD
[...])
๐งฑ Generating Files
add_custom_command(OUTPUT <output1> [<output2> ...] COMMAND <command1>
[ARGS] [<args1>...] [...])
Add a custom command to produce an output:
add_custom_command(OUTPUT <output1> [<output2> ...]
COMMAND <command1> [ARGS] [<args1>...]
[COMMAND <command2> [ARGS] [<args2>...]] ...
[MAIN_DEPENDENCY depend]
[DEPENDS <depends>...]
[BYPRODUCTS <files>...]
[IMPLICIT_DEPENDS <lang1> <depend1>
[<lang2> <depend2>] ...]
[WORKING_DIRECTORY <dir>]
[COMMENT <comment>]
[DEPFILE <depfile>]
[JOB_POOL <job_pool>]
[JOB_SERVER_AWARE <bool>]
[VERBATIM] [APPEND] [USES_TERMINAL]
[CODEGEN]
[COMMAND_EXPAND_LISTS]
[DEPENDS_EXPLICIT_ONLY])
This defines a command to generate specified OUTPUT file(s). A target created in the same directory (CMakeLists.txt file) that specifies any output of the custom command as a source file is given a rule to generate the file using the command at build time. ๐๏ธ
โ ๏ธ Do not list the output in more than one independent target that may build in parallel, or the instances of the rule may conflict. Instead, use the add_custom_target() command to drive the command and make the other targets depend on that one. See the Example: Generating Files for Multiple Targets below. ๐
The options are:
APPENDโ Append theCOMMANDandDEPENDSoption values to the custom command for the first output specified. There must have already been a previous call to this command with the same output.
If the previous call specified the output via a generator expression, the output specified by the current call must match in at least one configuration after evaluating generator expressions. In this case, the appended commands and dependencies apply to all configurations. ๐
The COMMENT, MAIN_DEPENDENCY, and WORKING_DIRECTORY options are currently ignored when APPEND is given, but may be used in the future. ๐ (Read: don't count on them doing anything rn, but also don't be surprised later.)
BYPRODUCTSโ Added in version 3.2. โจ
Specify the files the command is expected to produce but whose modification time may or may not be newer than the dependencies. If a byproduct name is a relative path it will be interpreted relative to the build tree directory corresponding to the current source directory. Each byproduct file will be marked with the GENERATED source file property automatically. ๐ท๏ธ
See policy CMP0058 for the motivation behind this feature. ๐
Explicit specification of byproducts is supported by the Ninja generator to tell the ninja build tool how to regenerate byproducts when they are missing. It is also useful when other build rules (e.g. custom commands) depend on the byproducts. Ninja requires a build rule for any generated file on which another rule depends โ even if there are order-only dependencies to ensure the byproducts will be available before their dependents build. ๐ฅท
The Makefile Generators will remove BYPRODUCTS and other GENERATED files during make clean. ๐งน
This keyword cannot be used with APPEND (see policy CMP0175). All byproducts must be set in the first call to add_custom_command(OUTPUT...) for the output files. No sneaking them in later, bestie. ๐ซ
Added in version 3.20: arguments to BYPRODUCTS may use a restricted set of generator expressions. Target-dependent expressions are not permitted. ๐
Changed in version 3.28: in targets using File Sets, custom command byproducts are now considered private unless they are listed in a non-private file set. See policy CMP0154. ๐
COMMANDโ Specify the command-line(s) to execute at build time. At least oneCOMMANDwould normally be given, but certain patterns may omit it, such as adding commands in separate calls usingAPPEND. ๐งต
okay so if you pass more than one COMMAND, they all run in order โ but โจheads upโจ they are not necessarily glued together into one stateful shell or batch script. So don't expect variable carryover, bestie, it's not that kind of party. Wanna run a whole actual script? Use the configure_file() command or the file(GENERATE) command to create it, then hand COMMAND the job of launching it. Iconic workaround, honestly.
The optional ARGS argument is just there for backward compatibility and will be ignored. ๐ yes literally ignored, like that one guy in the group chat.
If COMMAND names an executable target (one made by the add_executable() command), CMake will automatically swap in the location of the executable built at build time โ but only if either of these is true:
- The target is not being cross-compiled (i.e. the
CMAKE_CROSSCOMPILINGvariable is not set to true). - Added in version 3.6: The target is being cross-compiled and an emulator is provided (i.e. its
CROSSCOMPILING_EMULATORtarget property is set). In that case, the contents ofCROSSCOMPILING_EMULATORget prepended to the command, right before the location of the target executable. ๐ง
If neither of those conditions is met, CMake just assumes the command name is a program found on the PATH at build time. Simple as that, no cap.
Arguments to COMMAND may use generator expressions. Use the TARGET_FILE generator expression when you want to point at a target's location later in the command line โ like, as a command argument rather than as the thing being executed. Big difference, iykyk. ๐
And whenever one of these target-based generator expressions shows up as the command to execute or gets mentioned in a command argument, a target-level dependency gets added automatically, so the mentioned target builds before any target using this custom command (see policy CMP0112). The VIP list ๐
:
TARGET_FILETARGET_LINKER_FILETARGET_SONAME_FILETARGET_PDB_FILE
๐ซถ Important lil caveat: this target-level dependency does NOT add a file-level dependency that would make the custom command re-run every time the executable gets recompiled. If you want that, list the target names with the DEPENDS option. Different tool, different job, bestie.
COMMENT ๐ฌ
Displays the given message before the commands get executed at build time. It'll be ignored if APPEND is given โ though a future version might actually use it, so, watch this space ๐.
Added in version 3.26: Arguments to COMMENT may use generator expressions. Slay.
DEPENDS ๐
Specifies the files your command depends on. Each argument gets converted into a dependency like this:
- If the argument is the name of a target (created by the
add_custom_target(),add_executable(), oradd_library()command), a target-level dependency is created to make sure that target is built before any target using this custom command. Plus โ if the target is an executable or a library โ a file-level dependency is created so the custom command re-runs whenever the target recompiles. ๐ฅ
Changed in version 4.4: Previously an executable target could be specified using the name of the target with .exe appended. This is no longer allowed. See policy CMP0212.
- If the argument is an absolute path, a file-level dependency is created on that path.
- If the argument is the name of a source file that's been added to a target, or on which a source file property has been set, a file-level dependency is created on that source file.
- If the argument is a relative path and it exists in the current source directory, a file-level dependency is created on that file in the current source directory.
- Otherwise, a file-level dependency is created on that path relative to the current binary directory. ๐
If any dependency is an OUTPUT of another custom command in the same directory (CMakeLists.txt file), CMake automatically brings that other custom command into the target in which this command is built. It's giving teamwork, honestly.
Added in version 3.16: A target-level dependency is added if any dependency is listed as BYPRODUCTS of a target, or of any of its build events, in the same directory โ just to make sure the byproducts will be available. ๐ฆ
If DEPENDS is not specified, the command runs whenever the OUTPUT is missing. And if the command doesn't actually create the OUTPUTโฆ ๐ซ the rule will always run. Forever. Every single time. Not a vibe, but that's the deal.
Added in version 3.1: Arguments to DEPENDS may use generator expressions.
COMMAND_EXPAND_LISTS ๐
Added in version 3.8.
Lists inside COMMAND arguments get expanded โ including the ones created with generator expressions โ which lets COMMAND arguments like the following actually expand properly:
${CC} "-I$<JOIN:$<TARGET_PROPERTY:foo,INCLUDE_DIRECTORIES>,;-I>" foo.cc
โ ๏ธ This keyword cannot be used withAPPEND(see policyCMP0175). If the appended commands need this option set, it has to be set on the first call toadd_custom_command(OUTPUT...)for the output files. No exceptions, bestie.
CODEGEN โก
Added in version 3.31.
Adds the custom command to a global codegen target that you can use to execute the custom command while dodging the majority of the build graph. Speedrun strats, basically. ๐ฅ
This option is supported only by the Ninja Generators and the Makefile Generators, and is ignored by other generators. Also, it's allowed only if policy CMP0171 is set to NEW.
โ ๏ธ This keyword cannot be used withAPPEND(see policyCMP0175). It can only be set on the first call toadd_custom_command(OUTPUT...)for the output files.
IMPLICIT_DEPENDS ๐
Requests scanning of implicit dependencies of an input file. The language you give specifies the programming language whose corresponding dependency scanner should be used. Currently only the C and CXX language scanners are supported. And yes, the language has to be specified for every file in the IMPLICIT_DEPENDS list โ no skipping, bestie. Dependencies discovered from the scanning get added to those of the custom command at build time.
Note that the IMPLICIT_DEPENDS option is currently supported only for Makefile generators and will be ignored by other generators. ๐ญ
Note: This option cannot be specified at the same time as the DEPFILE option. Pick a lane, queen.
JOB_POOL ๐
Added in version 3.15.
Specifies a pool for the Ninja generator. Incompatible with USES_TERMINAL, which implies the console pool โ so yeah, those two are not friends. ๐ And using a pool that isn't defined by JOB_POOLS causes an error by ninja at build time. You've been warned.
โ ๏ธ This keyword cannot be used withAPPEND(see policyCMP0175). Job pools can only be specified in the first call toadd_custom_command(OUTPUT...)for the output files.
JOB_SERVER_AWARE ๐๏ธ
Added in version 3.28.
Specifies that the command is GNU Make job server aware. Fancy.
For the Unix Makefiles, MSYS Makefiles, and MinGW Makefiles generators, this adds the + prefix to the recipe line. See the GNU Make Documentation (https://www.gnu.org/software/make/manual/html_node/MAKE-Variable.html) for more info, iykyk.
This option is silently ignored by other generators. ๐คซ
โ ๏ธ This keyword cannot be used withAPPEND(see policyCMP0175). Job server awareness can only be specified in the first call toadd_custom_command(OUTPUT...)for the output files.
MAIN_DEPENDENCY ๐
Specifies the primary input source file to the command. It's treated just like any value given to the DEPENDS option, but it also suggests to the Visual Studio Generators where to hang the custom command. Helpful lil hint ๐.
Each source file may have at most one command specifying it as its main dependency. A compile command (i.e. for a library or an executable) counts as an implicit main dependency, and that one gets silently overwritten by a custom command specification. Not me being territorial about my main dependency ๐ญ.
This option is currently ignored if APPEND is given, but a future version may use it. So likeโฆ stay tuned, bestie.
OUTPUT
Okay so this is where you tell CMake which files your command is expected to produce ๐
. Every output file automatically gets the GENERATED source file property slapped on it. And listen โ if your command doesn't actually write a real file to disk? Mark it with the SYMBOLIC source file property, bestie, or things get weird.
If an output file name is a relative path, its absolute path gets figured out by interpreting it relative to:
- the build directory corresponding to the current source directory (
CMAKE_CURRENT_BINARY_DIR), or - the current source directory (
CMAKE_CURRENT_SOURCE_DIR).
The path in the build directory is preferred unless the path in the source tree is mentioned as an absolute source file path elsewhere in the current directory.
The output file path may not contain < or > characters. (Rude, but okay.)
Added in version 3.20: Arguments to OUTPUT may use a restricted set of generator expressions. Target-dependent expressions are not permitted. ๐ซ
Changed in version 3.28: In targets using File Sets, custom command outputs are now considered private unless they are listed in a non-private file set. See policy CMP0154.
Changed in version 3.30: The output file path may now use#characters, except when using theBorland Makefilesgenerator.
USES_TERMINAL
Added in version 3.2. โญ
The command gets direct access to the terminal if possible. With the Ninja generator, this drops the command into the console pool (JOB_POOLS). Very main character of it honestly.
This keyword cannot be used with APPEND (see policy CMP0175). If the appended commands need access to the terminal, it must be set on the first call to add_custom_command(OUTPUT...) for the output files. First-call-only, no takebacks ๐ซถ.
VERBATIM
All arguments to the commands get escaped properly for the build tool so that the invoked command receives each argument unchanged. Note that one level of escapes is still used by the CMake language processor before add_custom_command even sees the arguments โ layers, babe, it's giving onions ๐ง
.
Use of VERBATIM is recommended as it enables correct behavior. When VERBATIM is not given, the behavior is platform specific because there is no protection of tool-specific special characters. Lowkey a vibes-based gamble without it ๐ญ.
This keyword cannot be used with APPEND (see policy CMP0175). If the appended commands need to be treated as VERBATIM, it must be set on the first call to add_custom_command(OUTPUT...) for the output files.
WORKING_DIRECTORY
Execute the command with the given current working directory. If it's a relative path, it gets interpreted relative to the build tree directory corresponding to the current source directory. If not specified, it's set to CMAKE_CURRENT_BINARY_DIR.
This option is currently ignored if APPEND is given, but a future version may use it. So likeโฆ don't rely on it being ignored forever, bestie ๐.
Added in version 3.13: Arguments to WORKING_DIRECTORY may use generator expressions.
DEPFILE
Added in version 3.7.
Specify a depfile which holds dependencies for the custom command. It's usually emitted by the custom command itself. This keyword may only be used if the generator supports it, as detailed below. ๐
The expected format, compatible with what is generated by gcc with the option -M, is independent of the generator or platform.
The formal syntax, as specified using BNF notation with the regular extensions, is the following:
depfile ::= rule*
rule ::= targets (':' (separator dependencies?)?)? eol
targets ::= target (separator target)* separator*
target ::= pathname
dependencies ::= dependency (separator dependency)* separator*
dependency ::= pathname
separator ::= (space | line_continue)+
line_continue ::= '\' eol
space ::= ' ' | '\t'
pathname ::= character+
character ::= std_character | dollar | hash | whitespace
std_character ::= <any character except '$', '#' or ' '>
dollar ::= '$$'
hash ::= '\#'
whitespace ::= '\ '
eol ::= '\r'? '\n'
Note: As part of pathname, any slash and backslash is interpreted as a directory separator.
Added in version 3.7: TheNinjagenerator supportsDEPFILEsince the keyword was first added.
Added in version 3.17: Added theNinja Multi-Configgenerator, which included support for theDEPFILEkeyword.
Added in version 3.20: Added support for Makefile Generators.
Note:DEPFILEcannot be specified at the same time as theIMPLICIT_DEPENDSoption for Makefile Generators. Pick a lane, diva ๐.
Added in version 3.21: Added support for Visual Studio Generators with VS 2012 and above, and for the Xcode generator. Support for generator expressions was also added.
Added in version 3.29: The Ninja Generators will now incorporate the dependencies into its "deps log" database if the file is not listed inOUTPUTSorBYPRODUCTS.
Using DEPFILE with generators other than those listed above is an error. Not a vibe check failure โ an actual error ๐จ.
If the DEPFILE argument is relative, it should be relative to CMAKE_CURRENT_BINARY_DIR, and any relative paths inside the DEPFILE should also be relative to CMAKE_CURRENT_BINARY_DIR. See policy CMP0116, which is always NEW for Makefile Generators, Visual Studio Generators, and the Xcode generator.
This keyword cannot be used with APPEND (see policy CMP0175). Depfiles can only be set on the first call to add_custom_command(OUTPUT...) for the output files.
DEPENDS_EXPLICIT_ONLY
Added in version 3.27.
Indicates that the command's DEPENDS argument represents all files required by the command and implicit dependencies are not required. Like, she's self-sufficient, she doesn't need your charity ๐
.
Without this option, if any target uses the output of the custom command, CMake will consider that target's dependencies as implicit dependencies for the custom command in case this custom command requires files implicitly created by those targets.
This option can be enabled on all custom commands by setting CMAKE_ADD_CUSTOM_COMMAND_DEPENDS_EXPLICIT_ONLY to ON.
This keyword cannot be used with APPEND (see policy CMP0175). It can only be set on the first call to add_custom_command(OUTPUT...) for the output files.
Only the Ninja Generators actually use this information to remove unnecessary implicit dependencies. Everyone else is just nodding along politely ๐.
See also the OPTIMIZE_DEPENDENCIES target property, which may provide another way for reducing the impact of target dependencies in some scenarios.
๐ Examples: Generating Files ๐
Custom commands may be used to generate source files. For example, the code:
add_custom_command(
OUTPUT out.c
COMMAND someTool -i ${CMAKE_CURRENT_SOURCE_DIR}/in.txt
-o out.c
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/in.txt
VERBATIM)
add_library(myLib out.c)
adds a custom command to run someTool to generate out.c and then compile the generated source as part of a library. The generation rule will re-run whenever in.txt changes. Obsessed with a self-updating pipeline, honestly โจ.
Added in version 3.20: One may use generator expressions to specify per-configuration outputs. For example, the code:
add_custom_command(
OUTPUT "out-$<CONFIG>.c"
COMMAND someTool -i ${CMAKE_CURRENT_SOURCE_DIR}/in.txt
-o "out-$<CONFIG>.c"
-c "$<CONFIG>"
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/in.txt
VERBATIM)
add_library(myLib "out-$<CONFIG>.c")
so this one ๐
adds a custom command that runs someTool to generate out-<config>.c โ where <config> is the build configuration โ and then compiles the generated source as part of a library. it's giving "generate per-config, compile per-config," we love a two-for-one.
Added in version 3.31: use the CODEGEN option to add a custom command's outputs to the builtin codegen target. this is lowkey iconic when you want generated code available for static analysis without building the entire project. like so:
add_executable(someTool someTool.c)
add_custom_command(
OUTPUT out.c
COMMAND someTool -o out.c
CODEGEN)
add_library(myLib out.c)
a user may build the codegen target to generate out.c. someTool is built as a dependency, but myLib is not built at all. periodt. ๐
๐ธ Example: Generating Files for Multiple Targets ๐ธ
okay so if multiple independent targets need the same custom command output, it must be attached to a single custom target that they all depend on. no cap. consider this:
add_custom_command(
OUTPUT table.csv
COMMAND makeTable -i ${CMAKE_CURRENT_SOURCE_DIR}/input.dat
-o table.csv
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/input.dat
VERBATIM)
add_custom_target(generate_table_csv DEPENDS table.csv)
add_custom_command(
OUTPUT foo.cxx
COMMAND genFromTable -i table.csv -case foo -o foo.cxx
DEPENDS table.csv # file-level dependency
generate_table_csv # target-level dependency
VERBATIM)
add_library(foo foo.cxx)
add_custom_command(
OUTPUT bar.cxx
COMMAND genFromTable -i table.csv -case bar -o bar.cxx
DEPENDS table.csv # file-level dependency
generate_table_csv # target-level dependency
VERBATIM)
add_library(bar bar.cxx)
so foo.cxx is needed only by target foo and bar.cxx is needed only by target bar, but both targets need table.csv, transitively. ๐ซถ and since foo and bar are independent targets that may build concurrently, we prevent them from racing to generate table.csv by placing its custom command in a separate target, generate_table_csv. the custom commands generating foo.cxx and bar.cxx each specify a target-level dependency on generate_table_csv, so the targets using them โ foo and bar โ will not build until after target generate_table_csv is built. no race condition, no tears, we love to see it. โจ
๐ Build Events ๐
add_custom_command(TARGET <target> PRE_BUILD | PRE_LINK | POST_BUILD
[...])
add a build event to a target such as a library or executable. this is useful for performing an operation before or after building the target. the command becomes part of the target and will only execute when the target itself is built. if the target is already built, the command will not execute. ๐
add_custom_command(TARGET <target>
PRE_BUILD | PRE_LINK | POST_BUILD
COMMAND <command1> [ARGS] [<args1>...]
[COMMAND <command2> [ARGS] [<args2>...]] ...
[BYPRODUCTS <files>...]
[WORKING_DIRECTORY <dir>]
[COMMENT <comment>]
[VERBATIM]
[COMMAND_EXPAND_LISTS]
[USES_TERMINAL])
this defines a new command that will be associated with building the specified <target>. and heads up bestie: the <target> must be defined in the current directory โ targets defined in other directories may not be specified. ๐
when the command will happen is determined by which of the following is specified:
PRE_BUILD
this option has unique behavior for the Visual Studio Generators. when using one of the Visual Studio generators, the command will run before any other rules are executed within the target. with all other generators, this option behaves the same as PRE_LINK instead. because of this, it is recommended to avoid using PRE_BUILD except when it is known that a Visual Studio generator is being used. iykyk. ๐
PRE_LINK
run after sources have been compiled but before linking the binary or running the librarian or archiver tool of a static library. this is not defined for targets created by the add_custom_target() command.
POST_BUILD
run after all other rules within the target have been executed. the grand finale vibe. ๐
projects should always specify one of the above three keywords when using the TARGET form. see policy CMP0175.
all other keywords shown in the signature above have the same meaning as they do for the add_custom_command(OUTPUT) form of the command. at least one COMMAND must be given, see policy CMP0175. โ
note: because generator expressions can be used in custom commands, it is possible to define COMMAND lines or whole custom commands which evaluate to empty strings for certain configurations. for Visual Studio Generators these command lines or custom commands will be omitted for the specific configuration and no "empty-string-command" will be added. ๐
this allows adding individual build events for every configuration. slay.
Added in version 3.21: support for target-dependent generator expressions.
Added in version 3.29: the <target> may be an ALIAS target.
๐ฆ Examples: Build Events ๐ฆ
a POST_BUILD event may be used to post-process a binary after linking. for example, this code:
add_executable(myExe myExe.c)
add_custom_command(
TARGET myExe POST_BUILD
COMMAND someHasher -i "$<TARGET_FILE:myExe>"
-o "$<TARGET_FILE:myExe>.hash"
VERBATIM)
will run someHasher to produce a .hash file next to the executable after linking. cute, useful, iconic. โจ
Added in version 3.20: one may use generator expressions to specify per-configuration byproducts. for example, this code:
add_library(myPlugin MODULE myPlugin.c)
add_custom_command(
TARGET myPlugin POST_BUILD
COMMAND someHasher -i "$<TARGET_FILE:myPlugin>"
--as-code "myPlugin-hash-$<CONFIG>.c"
BYPRODUCTS "myPlugin-hash-$<CONFIG>.c"
VERBATIM)
add_executable(myExe myExe.c "myPlugin-hash-$<CONFIG>.c")
will run someHasher after linking myPlugin โ e.g. to produce a .c file containing code to check the hash of myPlugin that the myExe executable can use to verify it before loading. honestly? that's main character behavior. ๐
๐ Ninja Multi-Config ๐
Added in version 3.20: add_custom_command supports the Ninja Multi-Config generator's cross-config capabilities. see the generator documentation for more information. go read it bestie, it's worth it. ๐ซถ
๐ See Also ๐
add_custom_target()
๐ add_custom_target ๐
add a target with no output so it will always be built. yes, always. it never gets to rest. ๐ญ
add_custom_target(Name [ALL] [command1 [<args1>...]]
[COMMAND command2 [<args2>...]] ...
[DEPENDS <depend>...]
[BYPRODUCTS <file>...]
[WORKING_DIRECTORY <dir>]
[COMMENT <comment>]
[JOB_POOL <job_pool>]
[JOB_SERVER_AWARE <bool>]
[VERBATIM] [USES_TERMINAL]
[COMMAND_EXPAND_LISTS]
[SOURCES <source>...])
adds a target with the given name that executes the given commands. the target has no output file and is always considered out of date even if the commands try to create a file with the name of the target. ๐ use the add_custom_command() command to generate a file with dependencies. by default nothing depends on the custom target โ it's giving independent queen energy โ so use the add_dependencies() command to add dependencies to or from other targets.
the options are:
ALLโ indicate that this target should be added to the default build target so that it will be run every time (the command cannot be calledALL). ๐ฅBYPRODUCTSโ Added in version 3.2. specify the files the command is expected to produce but whose modification time may or may not be updated on subsequent builds. if a byproduct name is a relative path it will be interpreted relative to the build tree directory corresponding to the current source directory. each byproduct file will be marked with theGENERATEDsource file property automatically. โจ
see policy CMP0058 for the motivation behind this feature. fr fr, go read the policy.
explicit specification of byproducts is supported by the Ninja generator to tell the ninja build tool how to regenerate byproducts when they are missing. it's also useful when other build rules (e.g. custom commands) depend on the byproducts. ninja requires a build rule for any generated file on which another rule depends โ even if there are order-only dependencies โ to ensure the byproducts will be available before their dependents build. no shortcuts, no vibes-based builds. ๐
the Makefile Generators will remove BYPRODUCTS and other GENERATED files during make clean. bye bestie ๐ซถ
Added in version 3.20: arguments to BYPRODUCTS may use a restricted set of generator expressions. target-dependent expressions are not permitted. ๐
Changed in version 3.28: in custom targets using File Sets, byproducts are now considered private unless they are listed in a non-private file set. see policy CMP0154.
COMMANDโ tells CMake the command-line(s) to run at build time ๐ . If you give more than oneCOMMAND, they run in order, but they are not necessarily stitched together into one stateful shell or batch script (so like, no, variable you set in one doesn't carry over to the next, bestie). If you want a full script, use theconfigure_file()command or thefile(GENERATE)command to create one, then specify aCOMMANDto launch it ๐ซถ.
If COMMAND names an executable target (i.e. one created by the add_executable() command), CMake automatically swaps in the location of the executable built at build time if either of these is true:
- The target is not being cross-compiled (i.e. the
CMAKE_CROSSCOMPILINGvariable is not set to true). - Added in version 3.6: The target is being cross-compiled and an emulator is provided (i.e. its
CROSSCOMPILING_EMULATORtarget property is set). In this case, the contents ofCROSSCOMPILING_EMULATORget prepended to the command, before the location of the target executable.
If neither of those is the case, CMake assumes the command name is a program to be found on the PATH at build time ๐.
Arguments to COMMAND can use generator expressions. Use the TARGET_FILE generator expression when you want to refer to a target's location later in the command line (i.e. as a command argument rather than as the command to execute) ๐.
Whenever one of these target-based generator expressions is used as a command to execute, or shows up in a command argument, a target-level dependency gets added automatically so the mentioned target builds before this custom target (see policy CMP0112):
TARGET_FILETARGET_LINKER_FILETARGET_SONAME_FILETARGET_PDB_FILE
The command and arguments are optional โ if you don't specify them, an empty target gets created ๐.
COMMENTโ shows the given message before the commands run at build time ๐ฌ.
Added in version 3.26: Arguments to COMMENT can use generator expressions.
DEPENDSโ references files and outputs of custom commands created withadd_custom_command()command calls in the same directory (theCMakeLists.txtfile). They get brought up to date when the target is built โจ.
Changed in version 3.16: A target-level dependency gets added if any dependency is a byproduct of a target, or of any of its build events, in the same directory โ this makes sure the byproducts are available before this target builds.
Use the add_dependencies() command to add dependencies on other targets ๐ซก.
COMMAND_EXPAND_LISTSโ Added in version 3.8. Lists inCOMMANDarguments get expanded, including the ones created with generator expressions, which letsCOMMANDarguments like
${CC} "-I$<JOIN:$<TARGET_PROPERTY:foo,INCLUDE_DIRECTORIES>,;-I>" foo.cc
expand properly ๐ฆ.
JOB_POOLโ Added in version 3.15. Specifies a pool for theNinjagenerator. Incompatible withUSES_TERMINAL, which implies the console pool ๐ซ. Using a pool that isn't defined byJOB_POOLScauses an error by ninja at build time.JOB_SERVER_AWAREโ Added in version 3.28. Says the command is GNU Make job server aware ๐ท.
For the Unix Makefiles, MSYS Makefiles, and MinGW Makefiles generators this adds the + prefix to the recipe line. See the GNU Make Documentation for more info.
This option is silently ignored by other generators ๐คซ.
SOURCESโ specifies additional source files to include in the custom target. They get added to IDE project files so editing is comfy, even if they have no build rules ๐.VERBATIMโ all arguments to the commands get escaped properly for the build tool, so the invoked command receives each argument unchanged ๐ฏ. Note that one level of escapes is still used by the CMake language processor beforeadd_custom_targeteven sees the arguments. UsingVERBATIMis recommended, because it enables correct behavior. WhenVERBATIMisn't given, the behavior is platform specific, since there's no protection of tool-specific special characters ๐ฌ.USES_TERMINALโ Added in version 3.2. The command gets direct access to the terminal if possible. With theNinjagenerator, this places the command in the console pool ๐ฅ๏ธ.WORKING_DIRECTORYโ executes the command with the given current working directory. If it's a relative path, it's interpreted relative to the build tree directory corresponding to the current source directory. If it's not specified, it's set toCMAKE_CURRENT_BINARY_DIR๐.
Added in version 3.13: Arguments to WORKING_DIRECTORY can use generator expressions.
๐ Ninja Multi-Config ๐
Added in version 3.20: add_custom_target supports the Ninja Multi-Config generator's cross-config capabilities. Peep the generator documentation for the deets ๐.
๐ See Also ๐
add_custom_command()
๐ฏ add_definitions ๐ฏ
Adds -D define flags to the compilation of source files, slay ๐
.
add_definitions(-DFOO -DBAR ...)
This adds definitions to the compiler command line for targets in the current directory โ whether they were added before or after this command is invoked โ and for the ones in sub-directories added after. You can use this command to add any flags, but its whole personality is meant to be preprocessor definitions โจ.
Note: this command has been superseded by alternatives, bestie: - Useadd_compile_definitions()to add preprocessor definitions. - Useinclude_directories()to add include directories. - Useadd_compile_options()to add other options.
Flags beginning in -D or /D that look like preprocessor definitions get automatically added to the COMPILE_DEFINITIONS directory property for the current directory ๐. Definitions with non-trivial values may be left in the set of flags instead of being converted, for reasons of backwards compatibility. See the documentation of the directory, target, and source file COMPILE_DEFINITIONS properties for details on adding preprocessor definitions to specific scopes and configurations ๐ซถ.
๐ See Also ๐
- The
cmake-buildsystem(7)manual for more on defining buildsystem properties.
๐ง add_dependencies ๐ง
Adds a dependency between top-level targets. It's giving glue but make it build-graph ๐.
add_dependencies(<target> <target-dependency>...)
Makes a top-level <target> depend on other top-level targets, so they build before <target> does โณ. A top-level target is one created by one of the add_executable(), add_library(), or add_custom_target() commands โ but not targets generated by CMake itself, like install ๐
.
Dependencies added to an imported target or an interface library are followed transitively in its place, since the target itself doesn't build ๐ซก.
Added in version 3.3: Allows adding dependencies to interface libraries.
Added in version 3.8: Dependencies populate the MANUALLY_ADDED_DEPENDENCIES property of <target>.
Changed in version 3.9: The Ninja Generators use weaker ordering than other generators in order to improve available concurrency ๐ฅ. They only guarantee that the dependencies' custom commands are finished before sources in <target> start compiling โ this makes sure generated sources are available.
Changed in version 4.1: The command may be called with no dependencies. Previously, at least one dependency was required ๐.
๐ See Also ๐
- The
DEPENDSoption of theadd_custom_target()andadd_custom_command()commands, for adding file-level dependencies in custom rules. - The
OBJECT_DEPENDSsource file property, for adding file-level dependencies to object files.
๐ add_executable ๐
Adds an executable to the project using the specified source files. Main character energy fr fr ๐ .
๐ Normal Executables ๐
add_executable(<name> <options>... <sources>...)
Adds an executable target called <name> to be built from the source files listed in the command invocation ๐.
The options are:
WIN32โ sets theWIN32_EXECUTABLEtarget property automatically. See that target property's documentation for the deets.MACOSX_BUNDLEโ sets theMACOSX_BUNDLEtarget property automatically. See that target property's documentation for the deets.EXCLUDE_FROM_ALLโ sets theEXCLUDE_FROM_ALLtarget property automatically. See that target property's documentation for the deets.
The <name> corresponds to the logical target name and must be globally unique within a project โ ๏ธ. The actual file name of the executable that gets built is constructed based on the conventions of the native platform (like <name>.exe, or just <name>) ๐ฆ.
okay so back to add_executable for a sec because there's more tea โ
Added in version 3.1: the source args you pass to add_executable can absolutely use "generator expressions" with the syntax $<...>. go check the cmake-generator-expressions(7) manual for the full menu of expressions you can use ๐ฆ
Added in version 3.11: you can literally skip the source files entirely if you're gonna add them later with target_sources(). no cap, it's allowed โจ
So by default the executable file gets created in the build tree directory that corresponds to the source tree directory where you invoked the command. if you want to move it somewhere else, peep the docs for the RUNTIME_OUTPUT_DIRECTORY target property. and if you wanna change the <name> part of the final file name, look at the OUTPUT_NAME target property ๐
See the cmake-buildsystem(7) manual for more on defining buildsystem properties โ it's giving essential reading ngl.
Also see HEADER_FILE_ONLY for what to do if some of your sources are pre-processed and you still want the original sources reachable from inside your IDE ๐ซถ
Imported Executables
add_executable(<name> IMPORTED [GLOBAL])
Adds an IMPORTED executable target so you can reference an executable file that lives outside the project. the target name can be referenced just like any target built inside the project โ except by default it's only visible in the directory where it was created, and below. scoped vibes ๐
The options are:
GLOBALโ makes the target name globally visible. that's it, that's the whole option ๐
No rules get generated to build imported targets, and the IMPORTED target property is True. imported executables are super handy for conveniently referencing stuff from commands like add_custom_command() ๐ฅ
You spell out the details of the imported executable by setting properties whose names begin in IMPORTED_. The most important one is IMPORTED_LOCATION (and its per-configuration version IMPORTED_LOCATION_<CONFIG>) which specifies the location of the main executable file on disk. see the docs for the IMPORTED_* properties for more, bestie ๐
Alias Executables
add_executable(<name> ALIAS <target>)
Creates an Alias Target, so that <name> can be used to refer to <target> in commands that come after. iconic behaviour honestly. the <name> does not show up in the generated buildsystem as a make target. and heads up โ the <target> may not itself be an ALIAS ๐
Added in version 3.15... wait no, Added in version 3.11: an ALIAS can target a GLOBAL Imported Target โจ
Added in version 3.18: an ALIAS can target a non-GLOBAL Imported Target. that kind of alias is scoped to the directory where it's created plus subdirectories. you can check whether an alias is global or not with the ALIAS_GLOBAL target property ๐
ALIAS targets can be used as targets to read properties from, and as executables for custom commands and custom targets. they can also be tested for existence with the regular if(TARGET) subcommand ๐ฏ
but bestie, listen โ the <name> may not be used to modify properties of <target>. like, it may not be used as the operand of set_property(), set_target_properties(), target_link_libraries(), etc. and an ALIAS target may not be installed or exported. it's a read-only situationship, periodt ๐
See Also
add_library()๐ซถ
๐ธ add_library ๐ธ
Adds a library to the project using the source files you specify. let's go ๐
Normal Libraries
add_library(<name> [<type>] [EXCLUDE_FROM_ALL] <sources>...)
Adds a library target called <name> to be built from the source files you list in the command invocation. easy โจ
The optional <type> tells CMake what kind of library to create:
STATICโ a Static Library: an archive of object files for use when linking other targets.SHAREDโ a Shared Library: a dynamic library that may be linked by other targets and loaded at runtime.MODULEโ a Module Library: a plugin that may not be linked by other targets, but may be dynamically loaded at runtime usingdlopen-like functionality.
If you don't give a <type>, the default is STATIC or SHARED based on the value of the BUILD_SHARED_LIBS variable ๐
The options are:
EXCLUDE_FROM_ALLโ sets theEXCLUDE_FROM_ALLtarget property automatically. see the docs for that target property for the details ๐
The <name> corresponds to the logical target name and must be globally unique within a project. the actual file name of the library that gets built is constructed based on conventions of the native platform (think lib<name>.a or <name>.lib) ๐
Added in version 3.1: source args to add_library may use "generator expressions" with the syntax $<...>. see the cmake-generator-expressions(7) manual for the available expressions ๐ฆ
Added in version 3.11: the source files can be omitted if you're adding them later with target_sources() ๐
For SHARED and MODULE libraries, the POSITION_INDEPENDENT_CODE target property is set to ON automatically. and a SHARED library may be marked with the FRAMEWORK target property to create an macOS Framework ๐
Added in version 3.8: a STATIC library may be marked with the FRAMEWORK target property to create a static Framework ๐ธ
Important warning: if a library does not export any symbols, it must not be declared as a SHARED library. like, for example, a Windows resource DLL or a managed C++/CLI DLL that exports no unmanaged symbols would need to be a MODULE library instead. why? because CMake expects a SHARED library to always have an associated import library on Windows. it's a whole thing ๐ญ
By default the library file gets created in the build tree directory corresponding to the source tree directory where the command was invoked. see the docs for the ARCHIVE_OUTPUT_DIRECTORY, LIBRARY_OUTPUT_DIRECTORY, and RUNTIME_OUTPUT_DIRECTORY target properties to change that location. and see OUTPUT_NAME to change the <name> part of the final file name ๐
See the cmake-buildsystem(7) manual for more on defining buildsystem properties.
Also see HEADER_FILE_ONLY on what to do if some sources are pre-processed and you want the original sources reachable from within your IDE ๐ซถ
Changed in version 3.30: on platforms that do not support shared libraries, add_library now fails on calls creating SHARED libraries instead of automatically converting them to STATIC libraries like it used to. so if that's you, mind the vibe check. see policy CMP0164 ๐
Object Libraries
add_library(<name> OBJECT <sources>...)
Adds an Object Library to compile source files without archiving or linking their object files into a library. it's giving "just compile, no commitment" โจ
Other targets created by add_library or add_executable() may reference those objects using an expression of the form $<TARGET_OBJECTS:objlib> as a source, where objlib is the object library name. for example:
add_library(... $<TARGET_OBJECTS:objlib> ...)
add_executable(... $<TARGET_OBJECTS:objlib> ...)
will include objlib's object files in a library and an executable, along with the ones compiled from their own sources. obsessed ๐ซถ
Object libraries may contain only sources that compile, header files, and other files that wouldn't affect linking of a normal library (like .txt). they may contain custom commands generating such sources, but not PRE_BUILD, PRE_LINK, or POST_BUILD commands ๐ซ
Also, some native build systems (such as Xcode) may not like targets that have only object files, so consider adding at least one real source file to any target that references $<TARGET_OBJECTS:objlib>. little pro move for you ๐
Added in version 3.12: object libraries can be linked to with target_link_libraries() ๐ฅ
Interface Libraries
add_library(<name> INTERFACE)
Adds an Interface Library target that may specify usage requirements for dependents but does not compile sources and does not produce a library artifact on disk. it's the main character of vibes-only targets ๐
An interface library with no source files isn't included as a target in the generated buildsystem. however, it may have properties set on it, and it may be installed and exported. typically you populate INTERFACE_* properties on an interface target using these commands:
set_property(),target_link_libraries(INTERFACE),target_link_options(INTERFACE),target_include_directories(INTERFACE),target_compile_options(INTERFACE),target_compile_definitions(INTERFACE), andtarget_sources(INTERFACE),
and then you use it as an argument to target_link_libraries() just like any other target ๐
Added in version 3.15: an interface library can have PUBLIC_HEADER and PRIVATE_HEADER properties. the headers specified by those properties can be installed using the install(TARGETS) command ๐
add_library(<name> INTERFACE [EXCLUDE_FROM_ALL] <sources>...)
Added in version 3.19.
Adds an Interface Library target with source files (in addition to usage requirements and properties as documented by the signature above). source files may be listed directly in the add_library call, or added later by calls to target_sources() with the PRIVATE or PUBLIC keywords ๐
Okay so if an interface library has actual source files (like when the SOURCES target property is set) or header sets (when HEADER_SETS is set), it's gonna show up in the generated buildsystem as a real build target โ basically the same energy as a target defined by add_custom_target(). It doesn't compile any sources, but it does carry build rules for custom commands made by add_custom_command(). ๐
The options are:
EXCLUDE_FROM_ALLโ auto-sets theEXCLUDE_FROM_ALLtarget property for you. Go read that target property's docs for the full tea. ๐ซ
Note: In most command signatures where theINTERFACEkeyword shows up, the items listed after it only become part of that target's usage requirements โ they're not part of the target's own settings. But in this signature ofadd_library,INTERFACErefers to the library type only, periodt. Sources listed after it in theadd_librarycall arePRIVATEto the interface library and do not appear in itsINTERFACE_SOURCEStarget property. ๐
โจ add_library(<name> INTERFACE SYMBOLIC) โจ
Added in version 4.2.
Adds a symbolic Interface Library target. Symbolic interface libraries are lowkey iconic for representing optional components or features in a package. They have no usage requirements, do not compile sources, and do not produce a library artifact on disk โ but they may be exported and installed. They can also be tested for existence with the regular if(TARGET) subcommand. ๐
A symbolic interface library may be used as a linkable target to enforce the presence of optional components in a dependency. For example, if a library libgui may or may not provide a feature widget, a consumer package can link against widget to express that it requires this component to be available. This lets find_package() calls that declare required components be validated by linking against the corresponding symbolic targets. Fr fr, it's giving dependency validation. ๐
A symbolic interface library has the SYMBOLIC target property set to true.
๐ธ Imported Libraries ๐ธ
add_library(<name> <type> IMPORTED [GLOBAL])
Adds an IMPORTED library target called <name>. The target name may be referenced like any target built within the project, except that by default it is visible only in the directory in which it is created, and below. (Scoped visibility, we love to see it. โจ)
The <type> must be one of:
STATIC,SHARED,MODULE,UNKNOWNโ references a library file located outside the project. TheIMPORTED_LOCATIONtarget property (or its per-configuration variantIMPORTED_LOCATION_<CONFIG>) specifies the location of the main library file on disk:- For a
SHAREDlibrary on most non-Windows platforms, the main library file is the.soor.dylibfile used by both linkers and dynamic loaders. If the referenced library file has aSONAME(or on macOS, has aLC_ID_DYLIBstarting in@rpath/), the value of that field should be set in theIMPORTED_SONAMEtarget property. If the referenced library file does not have aSONAME, but the platform supports it, then theIMPORTED_NO_SONAMEtarget property should be set. ๐ง - For a
SHAREDlibrary on Windows, theIMPORTED_IMPLIBtarget property (or its per-configuration variantIMPORTED_IMPLIB_<CONFIG>) specifies the location of the DLL import library file (.libor.dll.a) on disk, and theIMPORTED_LOCATIONis the location of the.dllruntime library (and is optional, but needed by theTARGET_RUNTIME_DLLSgenerator expression). ๐ช
- For a
Additional usage requirements may be specified in INTERFACE_* properties.
An UNKNOWN library type is typically only used in the implementation of Find Modules. It lets the path to an imported library (often found using the find_library() command) be used without having to know what type of library it is. This is especially useful on Windows where a static library and a DLL's import library both have the same file extension. ๐ญ
OBJECTโ references a set of object files located outside the project. TheIMPORTED_OBJECTStarget property (or its per-configuration variantIMPORTED_OBJECTS_<CONFIG>) specifies the locations of object files on disk. Additional usage requirements may be specified inINTERFACE_*properties.INTERFACEโ does not reference any library or object files on disk, but may specify usage requirements inINTERFACE_*properties.
The options are:
GLOBALโ makes the target name globally visible. ๐
No rules are generated to build imported targets, and the IMPORTED target property is True. Imported libraries are useful for convenient reference from commands like target_link_libraries(). ๐
Details about the imported library are specified by setting properties whose names begin in IMPORTED_ and INTERFACE_. See the documentation of such properties for more info.
๐ฆ Alias Libraries ๐ฆ
add_library(<name> ALIAS <target>)
Creates an Alias Target, such that <name> can be used to refer to <target> in subsequent commands. The <name> does not appear in the generated buildsystem as a make target. The <target> may not be an ALIAS. No cap.
Added in version 3.11: An ALIAS can target a GLOBAL Imported Target.
Added in version 3.18: AnALIAScan target a non-GLOBAL Imported Target. Such an alias is scoped to the directory in which it is created and below. TheALIAS_GLOBALtarget property can be used to check if the alias is global or not.
ALIAS targets can be used as linkable targets and as targets to read properties from. They can also be tested for existence with the regular if(TARGET) subcommand. The <name> may not be used to modify properties of <target> โ that is, it may not be used as the operand of set_property(), set_target_properties(), target_link_libraries() etc. An ALIAS target may not be installed or exported. ๐ซ
๐ See Also ๐
add_executable()
๐ฅ add_link_options ๐ฅ
Added in version 3.13.
Adds options to the link step for executable, shared library or module library targets in the current directory and below that are added after this command is invoked. Iconic behaviour, honestly.
add_link_options(<option> ...)
This command can be used to add any link options, but alternative commands exist to add libraries (target_link_libraries() or link_libraries()). See the documentation of the directory and target LINK_OPTIONS properties. ๐
Note: This command cannot be used to add options for static library targets, since they do not use a linker. To add archiver or MSVC librarian flags, see the STATIC_LIBRARY_OPTIONS target property. ๐
Arguments to add_link_options may use generator expressions with the syntax $<...>. See the cmake-generator-expressions(7) manual for available expressions. See the cmake-buildsystem(7) manual for more on defining buildsystem properties. โจ
๐ Host And Device Specific Link Options ๐
Added in version 3.18: When a device link step is involved โ which is controlled byCUDA_SEPARABLE_COMPILATIONandCUDA_RESOLVE_DEVICE_SYMBOLSproperties and policyCMP0105โ the raw options will be delivered to the host and device link steps (wrapped in-Xcompileror equivalent for device link). Options wrapped with the$<DEVICE_LINK:...>generator expression will be used only for the device link step. Options wrapped with the$<HOST_LINK:...>generator expression will be used only for the host link step. Two vibes, two lanes. ๐ฃ๏ธ
๐ Option De-duplication ๐
The final set of options used for a target is constructed by accumulating options from the current target and the usage requirements of its dependencies. The set of options is de-duplicated to avoid repetition. (No repeats, we're not doing that. ๐ )
Added in version 3.12: While beneficial for individual options, the de-duplication step can break up option groups. For example,-option A -option Bbecomes-option A B. One may specify a group of options using shell-like quoting along with aSHELL:prefix. TheSHELL:prefix is dropped, and the rest of the option string is parsed using theseparate_arguments()UNIX_COMMANDmode. For example,"SHELL:-option A" "SHELL:-option B"becomes-option A -option B. Slay, grouping preserved. ๐ซถ
โญ Handling Compiler Driver Differences โญ
To pass options to the linker tool, each compiler driver has its own syntax. The LINKER: prefix and , separator can be used to specify, in a portable way, options to pass to the linker tool. LINKER: is replaced by the appropriate driver option and , by the appropriate driver separator. The driver prefix and driver separator are given by the values of the CMAKE_<LANG>_LINKER_WRAPPER_FLAG and CMAKE_<LANG>_LINKER_WRAPPER_FLAG_SEP variables. Portability ate and left no crumbs. ๐
For example, "LINKER:-z,defs" becomes -Xlinker -z -Xlinker defs for Clang and -Wl,-z,defs for GNU GCC. โจ
The LINKER: prefix can be specified as part of a SHELL: prefix expression.
The LINKER: prefix supports, as an alternative syntax, specification of arguments using the SHELL: prefix and space as separator. The previous example then becomes "LINKER:SHELL:-z defs". ๐ซถ
Note: specifying theSHELL:prefix anywhere other than at the beginning of theLINKER:prefix is not supported. like, don't do it bestie, it's not gonna work ๐
๐ See Also
link_libraries()target_link_libraries()target_link_options()CMAKE_<LANG>_FLAGSandCMAKE_<LANG>_FLAGS_<CONFIG>add language-wide flags passed to all invocations of the compiler. This includes invocations that drive compiling and those that drive linking.- Added in version 4.3:
CMAKE_<LANG>_LINK_FLAGSandCMAKE_<LANG>_LINK_FLAGS_<CONFIG>add language-wide flags passed to all invocations of the compiler which drive linking.
๐ฆ add_subdirectory
Add a subdirectory to the build. yes literally that's the whole vibe ๐
add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL] [SYSTEM])
Adds a subdirectory to the build. The source_dir specifies the directory in which the source CMakeLists.txt and code files are located. If it's a relative path, it will be evaluated with respect to the current directory (the typical usage), but it may also be an absolute path. The binary_dir specifies the directory in which to place the output files. If it's a relative path, it will be evaluated with respect to the current output directory, but it may also be an absolute path. If binary_dir is not specified, the value of source_dir, before expanding any relative path, will be used (the typical usage). The CMakeLists.txt file in the specified source directory will be processed immediately by CMake before processing in the current input file continues beyond this command. iconic behavior ngl ๐
If the EXCLUDE_FROM_ALL argument is provided then the EXCLUDE_FROM_ALL property will be set on the added directory. This will exclude the directory from a default build. See the directory property EXCLUDE_FROM_ALL for full details.
Added in version 3.25: if the SYSTEM argument is provided, the SYSTEM directory property of the subdirectory will be set to true. This property is used to initialize the SYSTEM property of each non-imported target created in that subdirectory. slay ๐
๐ธ add_test
Add a test to the project to be run by ctest(1). we love a test suite that runs itself ๐ง
add_test(NAME <name> COMMAND <command> [<arg>...]
[CONFIGURATIONS <config>...]
[WORKING_DIRECTORY <dir>]
[COMMAND_EXPAND_LISTS]
[BUILD_DEPENDS <dependencies>...])
Adds a test called <name>. The test name may contain arbitrary characters, expressed as a Quoted Argument or Bracket Argument if necessary. See policy CMP0110. (yes, arbitrary characters, go off, name your test whatever unhinged thing you want โจ)
CMake only generates tests if the enable_testing() command has been invoked. The CTest module invokes enable_testing automatically unless BUILD_TESTING is set to OFF. so like, the module's got you covered unless you specifically said no ๐ซถ
Tests added with the add_test(NAME) signature support using generator expressions in test properties set by set_property(TEST) or set_tests_properties(). Test properties may only be set in the directory the test is created in. periodt, no setting them from across the repo ๐
add_test options are:
COMMANDโ specify the test command-line.
If <command> specifies an executable target created by add_executable():
- It will automatically be replaced by the location of the executable created at build time.
- Added in version 3.3: the target's
CROSSCOMPILING_EMULATOR, if set, will be used to run the command on the host:
<emulator> <command>
- Changed in version 3.29: the emulator is used only when cross-compiling. See policy
CMP0158. - Added in version 3.29: the target's
TEST_LAUNCHER, if set, will be used to launch the command:
<launcher> <command>
If the CROSSCOMPILING_EMULATOR is also set, both are used:
<launcher> <emulator> <command>
- Added in version 4.4: when the
CMAKE_TEST_BUILD_DEPENDSvariable is enabled, the Ninja Generators generate a convenience build target namedtest_prep/<name>that depends on the test executable target. Building this target ensures the executable is up-to-date before the test runs. ๐โโ๏ธ
Additionally, targets referenced by the test command via generator expressions are added as dependencies of the test_prep/<name> target.
If multiple tests in different directories share the same name, their dependencies are merged into a single test_prep/<name> target.
Tests with names that are not valid target names are excluded from this behavior.
The BUILD_DEPENDS keyword can be used to add explicit build dependencies.
The command may be specified using generator expressions.
CONFIGURATIONSโ restrict execution of the test only to the named configurations. like, this test is for these configs only, don't @ me ๐WORKING_DIRECTORYโ set the test propertyWORKING_DIRECTORYin which to execute the test. If not specified, the test will be run inCMAKE_CURRENT_BINARY_DIR. The working directory may be specified using generator expressions. ๐BUILD_DEPENDSโ Added in version 4.4.
Specify a list of targets or files that must be built before the test can run. Each dependency is added to the test_prep/<name> build target described above when CMAKE_TEST_BUILD_DEPENDS is enabled with the Ninja Generators. The test name must be a valid target name in order to list build dependencies with this keyword. no valid target name, no deps, that's the rule ๐
COMMAND_EXPAND_LISTSโ Added in version 3.16.
Lists in COMMAND arguments will be expanded, including those created with generator expressions. ๐
If the test command exits with code 0 the test passes. Non-zero exit code is a "failed" test. The test property WILL_FAIL inverts this logic. Note that system-level test failures such as segmentation faults or heap errors will still fail the test even if WILL_FAIL is true. (yep, a segfault is a segfault, you can't gaslight ctest into thinking it's fine ๐) Output written to stdout or stderr is captured by ctest(1) and only affects the pass/fail status via the PASS_REGULAR_EXPRESSION, FAIL_REGULAR_EXPRESSION, or SKIP_REGULAR_EXPRESSION test properties.
Added in version 3.16: added SKIP_REGULAR_EXPRESSION property.
Example usage:
add_test(NAME mytest
COMMAND testDriver --config $<CONFIG>
--exe $<TARGET_FILE:myexe>)
This creates a test mytest whose command runs a testDriver tool passing the configuration name and the full path to the executable file produced by target myexe. cute right? look at those generator expressions go ๐ญ๐
The command syntax above is recommended over the older, less flexible form:
add_test(<name> <command> [<arg>...])
Add a test called <name> with the given command-line.
Unlike the above NAME signature, target names are not supported in the command-line. Furthermore, tests added with this signature do not support generator expressions in the command-line or test properties, and the TEST_LAUNCHER and CROSSCOMPILING_EMULATOR target properties are not supported. it's giving legacy, it's giving old money, but like... lowkey don't use it ๐
โญ aux_source_directory
Find all source files in a directory. ๐ต๏ธโโ๏ธ
aux_source_directory(<dir> <variable>)
Collects the names of all the source files in the specified directory and stores the list in the <variable> provided. This command is intended to be used by projects that use explicit template instantiation. Template instantiation files can be stored in a Templates subdirectory and collected automatically using this command to avoid manually listing all instantiations. bless, no giant hand-typed lists ๐ซถ
It is tempting to use this command to avoid writing the list of source files for a library or executable target. While this seems to work, there is no way for CMake to generate a build system that knows when a new source file has been added. Normally the generated build system knows when it needs to rerun CMake because the CMakeLists.txt file is modified to add a new source. When the source is just added to the directory without modifying this file, one would have to manually rerun CMake to generate a build system incorporating the new file.
so like... it works until the day it doesn't bestie ๐ญ you'll add a file, nothing happens, and you'll be sitting there like "hello???" โ that's the trap. ngl just list your sources ๐
๐ build_command
Get a command line to build the current project. This is mainly intended for internal use by the CTest module. it's an inside-job kind of command โจ
build_command(<variable>
[CONFIGURATION <config>]
[PARALLEL_LEVEL <parallel>]
[TARGET <target>]
[PROJECT_NAME <projname>] # legacy, causes warning
)
Sets the given <variable> to a command-line string of the form:
<cmake> --build . [--config <config>] [--parallel <parallel>] [--target <target>...]
where <cmake> is the location of the cmake(1) command-line tool, and <config>, <parallel> and <target> are the values provided to the CONFIGURATION, PARALLEL_LEVEL and TARGET options, if any. In CMake versions prior to 4.0, a trailing -- -i option was added for Makefile Generators if policy CMP0061 was not set to NEW.
psst โ that PROJECT_NAME option is legacy and causes a warning ๐ you've been warned, bestie ๐
When you invoke it, that cmake --build command line is literally gonna launch the underlying build system tool for you. ๐ ๏ธ
Added in version 3.21: the PARALLEL_LEVEL argument can be used to set the --parallel flag. Go off, parallelism. ๐ฅ
build_command(<cachevariable> <makecommand>)
Okay so this second signature is deprecated ๐ but still available for backwards compatibility โ use the first signature instead, bestie, fr fr.
It sets the given <cachevariable> to a command-line string just like the above, but without the --target option. The <makecommand> is ignored, but it should be the full path to devenv, nmake, make or one of the end user build tools for legacy invocations.
Note: in CMake versions prior to 3.0, this command returned a command line that directly invokes the native build tool for the current generator. Their implementation of the PROJECT_NAME option had no useful effects, so CMake now warns on use of the option. ๐
๐ฆ cmake_file_api
Added in version 3.27.
This one lets you interact with the CMake file API โ cmake-file-api(7), iykyk. โจ
cmake_file_api(QUERY ...)
The QUERY subcommand adds a file API query for the current CMake invocation. It's giving very "let me just ask nicely" energy:
cmake_file_api(
QUERY
API_VERSION <version>
[CODEMODEL <versions>...]
[CACHE <versions>...]
[CMAKEFILES <versions>...]
[TOOLCHAINS <versions>...]
)
API_VERSION must always be given โ no skipping it, queen. ๐ Currently, the only supported value for <version> is 1. See API v1 for the deets on reply content and location.
Each of the optional keywords CODEMODEL, CACHE, CMAKEFILES and TOOLCHAINS correspond to one of the object kinds that can be requested by the project. The configureLog object kind cannot be set with this command, since it must be set before CMake starts reading the top level CMakeLists.txt file. Respect the ordering, bestie. ๐ธ
For each of the optional keywords, the <versions> list must contain one or more version values of the form major or major.minor, where major and minor are integers. Projects should list the versions they accept in their preferred order, because only the first supported value from the list will be selected. The command will ignore versions with a major version higher than any major version it supports for that object kind. It will raise an error if it encounters an invalid version number, or if none of the requested versions is supported โ so like, list a real one, okay? ๐ญ
For each type of object kind requested, a query equivalent to a shared, stateless query will be added internally. No query file will be created in the file system. The reply will be written to the file system at generation time. ๐
It is not an error to add a query for the same thing more than once, whether from query files or from multiple calls to cmake_file_api(QUERY). The final set of queries will be a merged combination of all queries specified on disk and queries submitted by the project. Slay, merging. ๐ง
Example
A project may want to use replies from the file API at build time to implement some form of verification task. Instead of relying on something outside of CMake to create a query file, the project can use cmake_file_api(QUERY) to request the required information for the current run. It can then create a custom command to run at build time, knowing that the requested information should always be available. Obsessed with the foresight honestly. ๐
cmake_file_api(
QUERY
API_VERSION 1
CODEMODEL 2.3
TOOLCHAINS 1
)
add_custom_target(verify_project
COMMAND ${CMAKE_COMMAND}
-D BUILD_DIR=${CMAKE_BINARY_DIR}
-D CONFIG=$<CONFIG>
-P ${CMAKE_CURRENT_SOURCE_DIR}/verify_project.cmake
)
๐ง cmake_instrumentation
Added in version 4.3.
This enables interacting with the CMake Instrumentation API โ cmake-instrumentation(7). It basically allows for configuring instrumentation at the project-level. Main character energy for your build. ๐
cmake_instrumentation(
API_VERSION <version>
DATA_VERSION <version>
[HOOKS <hooks>...]
[OPTIONS <options>...]
[CALLBACK <callback>]
[CUSTOM_CONTENT <name> <type> <content>]
)
API_VERSION and DATA_VERSION must always be given. No exceptions, periodt.
API_VERSION is an integer. Currently, the only supported value is 1. See API v1 for details.
DATA_VERSION is a version value of the form major or major.minor. Currently, the maximum supported version is 1.1. See Data Version for details.
Each of the optional keywords HOOKS, OPTIONS, and CALLBACK correspond to one of the parameters to the v1 Query Files. The CALLBACK keyword can be provided multiple times to create multiple callbacks. Stack 'em up. ๐
Whenever cmake_instrumentation is invoked, a query file is generated in <build>/.cmake/instrumentation/v1/query/generated โ that's the path, write it down โ to enable instrumentation with the provided arguments. โจ
Custom CMake Content
The CUSTOM_CONTENT argument specifies certain data from configure time to include in each v1 CMake Content File. This may be used to associate instrumentation data with certain information about its configuration, such as the optimization level or whether it is part of a coverage build. Lowkey so useful. ๐ฅ
CUSTOM_CONTENT expects name, type and content arguments.
name is a specifier to identify the content being reported.
type specifies how the content should be interpreted. Supported values are:
STRINGโ thecontentis a string.BOOLโ thecontentshould be interpreted as a boolean. It will be true under the same conditions thatif()would be true for the given value.LISTโ thecontentis a CMake;separated list that should be parsed.JSONโ thecontentshould be parsed as a JSON string. This can be a number such as1or5.0, a quoted string such as\"string\", a boolean valuetrue/false, or a JSON object such as{ \"key\" : \"value\" }that may be constructed usingstring(JSON ...)commands.
content is the actual content to report. ๐ซถ
Example
The following example shows an invocation of the command and its equivalent JSON query file:
cmake_instrumentation(
API_VERSION 1
DATA_VERSION 1.0
HOOKS postGenerate preCMakeBuild postCMakeBuild
OPTIONS staticSystemInformation dynamicSystemInformation compileTrace trace
CALLBACK ${CMAKE_COMMAND} -P /path/to/handle_data.cmake
CALLBACK ${CMAKE_COMMAND} -P /path/to/handle_data_2.cmake
CUSTOM_CONTENT myString STRING string
CUSTOM_CONTENT myList LIST "item1;item2"
CUSTOM_CONTENT myObject JSON "{ \"key\" : \"value\" }"
)
{
"version": 1,
"hooks": [
"postGenerate", "preCMakeBuild", "postCMakeBuild"
],
"options": [
"staticSystemInformation", "dynamicSystemInformation", "compileTrace", "trace"
],
"callbacks": [
"/path/to/cmake -P /path/to/handle_data.cmake",
"/path/to/cmake -P /path/to/handle_data_2.cmake"
]
}
This will also result in the following content included in each v1 CMake Content File:
"custom": {
"myString": "string",
"myList": [
"item1", "item2"
],
"myObject": {
"key": "value"
}
}
๐ธ create_test_sourcelist
Create a test driver program that links together many small tests into a single executable. This is useful when building static executables with large libraries to shrink the total required size. Tiny exe, big slay. ๐
create_test_sourcelist(<sourceListName> <driverName> <test>... <options>...)
Generate a test driver source file from a list of individual test sources and provide a combined list of sources that can be built as an executable.
The options are:
<sourceListName>โ the name of a variable in which to store the list of source files needed to build the test driver. The list will contain the<test>...sources and the generated<driverName>source.
Changed in version 3.29: the test driver source is listed by absolute path in the build tree. Previously it was listed only as <driverName>.
<driverName>โ name of the test driver source file to be generated into the build tree. The source file will contain amain()program entry point that dispatches to whatever test is named on the command line. Very "you're the one in charge" of it. ๐<test>...โ test source files to be added to the driver binary. Each test source file must have a function in it that is the same name as the file with the extension removed. For example, afoo.cxxtest source might contain:
int foo(int argc, char** argv)
EXTRA_INCLUDE <header>โ specify a header file to#includein the generated test driver source.FUNCTION <function>โ specify a function to be called with pointers toargcandargv. The function may be provided in theEXTRA_INCLUDEheader:
void function(int* pargc, char*** pargv)
This can be used to add extra command line processing to each test. Fancy. โจ
Additionally, some CMake variables affect test driver generation:
CMAKE_TESTDRIVER_BEFORE_TESTMAINโ code to be placed directly before calling each test's function.CMAKE_TESTDRIVER_AFTER_TESTMAINโ code to be placed directly after the call to each test's function.
The generated test driver supports the following command-line arguments:
<name>โ run the test with the exact name<name>(case-insensitive).-R <substr>โ run the first test whose name contains<substr>(case-insensitive).-A [<skip_test>...]โ Added in version 3.21: run all tests and print results in TAP format (that's the Test Anything Protocol,https://testanything.org/, iykyk ๐ฆ). Any additional arguments after-Aare interpreted as exact test names to skip.-Nโ Added in version 4.4: list all available test names (one per line) and exit. Literally just the list and dip. ๐
Example ๐
okay so here's the whole vibe in one go โ this is literally how you'd wire discovery into a suite you built with create_test_sourcelist:
create_test_sourcelist(SRCS main.c test1.c test2.c)
add_executable(MyTests ${SRCS})
discover_tests(COMMAND MyTests
DISCOVERY_ARGS -N
DISCOVERY_MATCH "^(.+)$"
TEST_NAME "${PROJECT_NAME}.\\1"
TEST_ARGS "\\1"
)
bestie that's it, that's the post ๐
See Also ๐ซถ
discover_tests()
define_property ๐
Define and document custom properties.
define_property(<GLOBAL | DIRECTORY | TARGET | SOURCE |
TEST | VARIABLE | CACHED_VARIABLE>
PROPERTY <name> [INHERITED]
[BRIEF_DOCS <brief-doc> [<docs>...]]
[FULL_DOCS <full-doc> [<docs>...]]
[INITIALIZE_FROM_VARIABLE <variable>])
okay so this one defines one property in a scope, and then you get to use it with set_property() and get_property(). Lowkey its main character era is all about how a property gets initialized or inherited โ like, that's the whole point now. Historically this command also glued documentation onto a property, but ngl that's not really considered a primary use case anymore, so don't come here expecting a docs generator.
The first argument decides the kind of scope the property lives in, and it has to be exactly one of these:
GLOBALโ associated with the global namespace.DIRECTORYโ associated with one directory.TARGETโ associated with one target.SOURCEโ associated with one source file.TESTโ associated with a test named withadd_test().VARIABLEโ documents a CMake language variable.CACHED_VARIABLEโ documents a CMake cache variable.
โจ heads up bestie: unlikeset_property()andget_property(), you do not hand over an actual scope here. No real directory, no real target, none of that. Only the kind of scope matters. it's giving "concept, not instance".
The required PROPERTY option comes immediately followed by the name of the property you're defining.
If you pass the INHERITED option, then get_property() will chain up to the next higher scope whenever the property you asked for isn't set in the scope you gave it. The chaining goes like this:
DIRECTORYscope chains to its parent directory's scope, and keeps walking up parent directories until some directory has the property set โ or until there are literally no more parents. If it's still not found at the top level directory, it chains to theGLOBALscope.TARGET,SOURCEandTESTproperties chain toDIRECTORYscope, and from there keep chaining up the directories and so on, as needed.
โ ๏ธ but listen โ this scope chaining behavior only applies to calls toget_property(),get_directory_property(),get_target_property(),get_source_file_property()andget_test_property(). There is no inheriting behavior when setting properties, so usingAPPENDorAPPEND_STRINGwith theset_property()command will not consider inherited values when working out the contents to append to. fr fr, that's a trap.
The BRIEF_DOCS and FULL_DOCS options are followed by strings that get associated with the property as its brief and full documentation. CMake doesn't use this documentation for anything other than making it available to the project through the corresponding options of the get_property() command.
๐ฆ Changed in version 3.23: TheBRIEF_DOCSandFULL_DOCSoptions are optional.
๐ฅ Added in version 3.23: TheINITIALIZE_FROM_VARIABLEoption specifies a variable from which the property should be initialized. It can only be used with target properties. The<variable>name must end with the property name and must not begin withCMAKE_or_CMAKE_. The property name must contain at least one underscore. It is recommended that the property name have a prefix specific to the project.
Property Redefinition ๐
So once a property is defined for a particular type of scope, it cannot be redefined. Any attempt to redefine an existing property by calling define_property() with the same scope type and property name gets silently ignored โ no error, no drama, just vibes and nothing happening. Defining the same property name for two different kinds of scope? Totally valid, slay.
You can use get_property() to figure out whether a property is already defined for a particular kind of scope, and if it is, to examine its definition. Like this:
# Initial definition
define_property(TARGET PROPERTY MY_NEW_PROP
BRIEF_DOCS "My new custom property"
)
# Later examination
get_property(my_new_prop_exists
TARGET NONE
PROPERTY MY_NEW_PROP
DEFINED
)
if(my_new_prop_exists)
get_property(my_new_prop_docs
TARGET NONE
PROPERTY MY_NEW_PROP
BRIEF_DOCS
)
# ${my_new_prop_docs} is now set to "My new custom property"
endif()
See Also โจ
get_property()set_property()
discover_tests ๐ฅ
๐ Added in version 4.4.
Register tests with names and properties discovered at test time by ctest(1).
discover_tests(COMMAND <command> [<arg>...] [COMMAND_EXPAND_LISTS]
[CONFIGURATIONS <config>...]
DISCOVERY_ARGS <arg>...
DISCOVERY_MATCH <regex>
[DISCOVERY_PROPERTIES <key> <value> [<key> <value>]...]
TEST_NAME <replacement>
TEST_ARGS <replacement>...
[TEST_PROPERTIES <key> <replacement> [<key> <replacement>]...]
)
okay so this is not "define one test at configure time" energy at all. This command configures test discovery. During test execution, ctest(1) runs the discovery command you gave it, parses the output, and then registers one or more tests based on the regular expression and replacement strings you provided. it's giving "surprise, here are your tests" ๐
Here are the discover_tests options:
COMMANDโ Specify the command-line used for test discovery.
The command is executed by ctest(1) at test time (not by CMake at configure time). With DISCOVERY_ARGS appended, it must print the list of available tests in a format that DISCOVERY_MATCH matches.
If <command> specifies an executable target created by add_executable():
- It will automatically be replaced by the location of the executable created at build time.
- The target's
CROSSCOMPILING_EMULATOR, if set, will be used to run the command on the host:<emulator> <command>. The emulator is used only when cross-compiling โ that'sCMAKE_CROSSCOMPILING, iykyk. - The target's
TEST_LAUNCHER, if set, will be used to launch the command:<launcher> <command>. If theCROSSCOMPILING_EMULATORis also set, both are used:<launcher> <emulator> <command>.
The command may be specified using generator expressions.
COMMAND_EXPAND_LISTSโ Lists inCOMMANDarguments will be expanded, including those created with generator expressions.CONFIGURATIONSโ Restrict the test discovery only to the named configurations.DISCOVERY_ARGSโ Additional arguments passed toCOMMANDwhen performing discovery.DISCOVERY_MATCHโ Regular expression used to parse each line produced by the discovery command. Capturing groups may be referenced byTEST_NAME,TEST_ARGS, and values inTEST_PROPERTIESusing\1,\2, etc.DISCOVERY_PROPERTIESโ Specify properties for the discovery run itself.TEST_NAMEโ Replacement string used to generate the test name for each discovered test. It may reference capture groups fromDISCOVERY_MATCH.TEST_ARGSโ Replacement strings used to generate the arguments passed to the discovered test. Each argument may reference capture groups fromDISCOVERY_MATCH.TEST_PROPERTIESโ Specify test properties to set on each discovered test. Values are replacement strings and may reference capture groups fromDISCOVERY_MATCH.
CTest executes the discovery step to obtain the list of tests, and then runs each discovered test using the command-line produced by COMMAND together with TEST_ARGS. The pass/fail behavior of each discovered test follows the usual CTest rules โ exit code 0 indicates success unless inverted by the WILL_FAIL property. Output written to stdout or stderr is captured by ctest(1) and only affects the pass/fail status via the PASS_REGULAR_EXPRESSION, FAIL_REGULAR_EXPRESSION, or SKIP_REGULAR_EXPRESSION test properties. no extra chaos, just the rules ๐
Example usage:
discover_tests(COMMAND testDriver --exe $<TARGET_FILE:myexe>
DISCOVERY_ARGS --list-tests
DISCOVERY_MATCH "^([^,]+),([^,]+),([^,]+),(.*)$"
TEST_NAME "${PROJECT_NAME}.\\1.\\2"
TEST_ARGS --run-test "\\1.\\2"
TEST_PROPERTIES
PROCESSORS "\\3"
LABELS "\\4"
)
This example configures discovery by running testDriver --list-tests. For each line of output that matches DISCOVERY_MATCH, a test name is generated using TEST_NAME, the per-test command-line is generated using TEST_ARGS, and test properties are populated from the remaining capture groups. honestly? iconic. ๐
enable_language ๐
Enable languages (CXX/C/OBJC/OBJCXX/Fortran/etc)
enable_language(<lang>... [OPTIONAL])
Enables support for the named languages in CMake. This is the same as the project() command, except it does not create any of the extra variables that project() creates. so like, same energy, less baggage ๐ซถ
The supported languages are:
CCXXโ C++CSharpโ Added in version 3.8. C#CUDAโ Added in version 3.8.OBJCโ Added in version 3.16. Objective-COBJCXXโ Added in version 3.16. Objective-C++FortranHIPโ Added in version 3.21.ISPCโ Added in version 3.18.Swiftโ Added in version 3.15.ASMโ Assembly language supported by the C compiler.
๐ If enablingASM, list it last so that CMake can check whether theCorCXXcompiler supports assembly.
ASM_NASMโ Netwide AssemblerASM_MARMASMโ Added in version 3.26. Microsoft Assembler (ARM, ARM64)ASM_MASMโ Microsoft Assembler (x86, x64)
โจ ASM_POASM
Added in version 4.4. ๐ซถ
Pelles C toolchain assembler. That's the whole vibe, bestie โ it's just the assembler that comes with the Pelles C toolchain. Slay.
๐ธ ASM-ATT
Okay so before you go wild calling enable_language() wherever your heart desires, here are the rules โ and they are not optional, fr fr:
- It must be called in file scope โ not inside a
function()call and not inside ablock(). Periodt. - It must not be called before the first call to
project(). Go check policyCMP0165for the receipts. - It must be called in the highest directory common to all targets using the named language โ whether those targets use it directly for compiling sources, or indirectly through link dependencies. Honestly? Easiest glow-up move is to just enable all the languages you need in the top-level directory of your project. No cap.
The OPTIONAL keyword is literally just a placeholder for future implementation and does not currently work. ๐ Instead, you can use the CheckLanguage module to verify support before enabling. Iconic workaround behavior.
๐ enable_testing
Enables testing for the current directory and everything below it:
enable_testing()
You should invoke this in the top-level source directory because ctest(1) expects to find a test file in the top-level build directory. Like, it's just what ctest looks for. ๐
This command is also automatically invoked when the CTest module is included โ unless the BUILD_TESTING option is turned off. Sneaky but iconic.
And the restrictions on where you can call enable_testing():
- It must be called in file scope โ not in a
function()call, and not inside ablock().
๐ Examples
In the following example, this command is conditionally called depending on how the project is used. Say the Example project gets added via the FetchContent module as a subdirectory of a parent project that defines its own tests โ then testing for the Example project is disabled. Clean. ๐ง
CMakeLists.txt
project(Example)
option(Example_ENABLE_TESTING "Enable testing" ${PROJECT_IS_TOP_LEVEL})
if(Example_ENABLE_TESTING)
enable_testing()
endif()
# ...
if(Example_ENABLE_TESTING)
add_test(...)
endif()
๐ฆ See Also
- The
add_test()command. Go look at it, iykyk.
๐ export
Export targets or packages so outside projects can use them directly from the current project's build tree โ no installation required. โจ
And if you do want to export from an install tree, go see the install(EXPORT) command instead.
โญ Synopsis
export(TARGETS <target>... [...])
export(EXPORT <export-name> [...])
export(PACKAGE <PackageName>)
export(SETUP <export-name> [...])
export(PACKAGE_INFO <package-name> [...])
export(SBOM <sbom-name> [...])
๐ Exporting Targets
export(TARGETS <target>... [NAMESPACE <namespace>]
[APPEND] FILE <filename> [EXPORT_LINK_INTERFACE_LIBRARIES]
[CXX_MODULES_DIRECTORY <directory>])
Creates a file <filename> that outside projects can include to import the targets named by <target>... from the current project's build tree. This is genuinely so useful when cross-compiling โ you build utility executables that run on the host platform in one project, then import them into another project being compiled for the target platform. Main character energy for the host. ๐ซถ
The file this command creates is specific to the build tree and should never be installed. Like, ever. If you want to export from an install tree, that's the install(EXPORT) command's whole thing.
The options are:
NAMESPACE <namespace>โ Prepends the<namespace>string to all target names written to the file.APPENDโ Appends to the file instead of overwriting it. Perfect for incrementally exporting multiple targets into the same file, one at a time.EXPORT_LINK_INTERFACE_LIBRARIESโ Includes the contents of the properties named with the pattern(IMPORTED_)?LINK_INTERFACE_LIBRARIES(_<CONFIG>)?in the export, even when policyCMP0022isNEW. Useful for supporting consumers still running CMake versions older than2.8.12. Respect the elders. ๐CXX_MODULES_DIRECTORY <directory>โ Added in version 3.28. Exports C++ module properties to files under the given directory. Each file gets named according to the target's export name (without any namespace), and these files are automatically included from the export file. Auto-magic, love that. โจ
This signature requires all targets to be listed explicitly. And ngl, if a library target is included in the export but a target it links to is not included, the behavior is unspecified โ so don't do that. ๐ If you want to automatically export the same targets from the build tree that install(EXPORT) would from an install tree, go use the export(EXPORT) signature.
Note: Object Libraries under Xcode have special handling if multiple architectures are listed in CMAKE_OSX_ARCHITECTURES. In that case they get exported as Interface Libraries with no object files available to clients. Which is honestly sufficient to satisfy transitive usage requirements of other targets that link to the object libraries in their implementation. It works, bestie.
This command exports all Build Configurations from the build tree. If you need to map configurations of dependent projects to the exported configurations, see the CMAKE_MAP_IMPORTED_CONFIG_<CONFIG> variable.
๐ Exporting Targets to Android.mk
export(TARGETS <target>... ANDROID_MK <filename>)
Added in version 3.7.
This signature exports CMake built targets to the android ndk build system by creating an Android.mk file that references the prebuilt targets. The Android NDK supports prebuilt libraries โ both static and shared โ which lets CMake build a project's libraries and hand them over to an ndk build system, complete with transitive dependencies, include flags and defines required to use those libraries. Literally giving it everything it needs. ๐
The signature takes a list of targets and drops them into the Android.mk file specified by the <filename> you give it. You can only use this signature if policy CMP0022 is NEW for all the targets given โ if that policy is OLD for even one of them, an error gets issued. No exceptions, periodt.
๐ง Exporting Targets matching install(EXPORT)
export(EXPORT <export-name> [NAMESPACE <namespace>] [FILE <filename>]
[CXX_MODULES_DIRECTORY <directory>] [EXPORT_PACKAGE_DEPENDENCIES])
Creates a file <filename> that outside projects can include to import targets from the current project's build tree. It's the same as the export(TARGETS) signature, except you don't list the targets explicitly โ instead it exports the targets associated with the installation export <export-name>. Those target installations get associated with the export <export-name> using the EXPORT option of the install(TARGETS) command.
EXPORT_PACKAGE_DEPENDENCIESโ > Note: Experimental. Gated byCMAKE_EXPERIMENTAL_EXPORT_PACKAGE_DEPENDENCIES. Specifies thatfind_dependency()calls should be exported. Seeinstall(EXPORT)for the details on how this works.
๐ Exporting Targets to the Common Package Specification
export(PACKAGE_INFO <package-name> EXPORT <export-name>
[PROJECT <project-name>|NO_PROJECT_METADATA]
[APPENDIX <appendix-name>]
[LOWER_CASE_FILE]
[VERSION <version>
[COMPAT_VERSION <version>]
[VERSION_SCHEMA <string>]]
[DEFAULT_TARGETS <target>...]
[DEFAULT_CONFIGURATIONS <config>...]
[LICENSE <license-string>]
[DEFAULT_LICENSE <license-string>]
[DESCRIPTION <description-string>]
[HOMEPAGE_URL <url-string>]
[CXX_MODULES_DIRECTORY <directory>])
Added in version 4.3.
Creates a file in the Common Package Specification (https://cps-org.github.io/cps/) that outside projects can include to import targets named by <target>... from the current project's build tree. If you want to export targets from an install tree, see the install(PACKAGE_INFO) command. The imported targets are implicitly in the namespace <package-name>. ๐
The default file name is <package-name>[-<appendix-name>].cps. If you pass the LOWER_CASE_FILE option, the file name uses the package name converted to lower case. Files get written to the cps/<package-name> subdirectory of the current build directory.
For a description of all the other options, go see install(PACKAGE_INFO).
๐ฅ Exporting Software Bill of Materials (SBOM) Documents
export(SBOM <sbom-name> EXPORTS <export-names>...
[FORMAT <string>]
[PROJECT <project-name>|NO_PROJECT_METADATA]
[VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]
[LICENSE <license-string>]
[DESCRIPTION <description-string>]
[HOMEPAGE_URL <url-string>]
[PACKAGE_URL <url-string>])
Added in version 4.3.
Note: Experimental. Gated by CMAKE_EXPERIMENTAL_GENERATE_SBOM.
Generates a software bill of materials (SBOM) document describing the targets in the listed <export-names> export sets and their dependencies in the build tree. Targets from all the listed exports get aggregated into one document. The generated SBOM is written to the sbom/<sbom-name> subdirectory of the current build directory.
See install(SBOM) for the details about the supported SBOM formats and a description of all the other options. ๐ฆ
๐ Exporting Packages
export(PACKAGE <PackageName>)
Stores the current build directory in the CMake user package registry for package <PackageName>. The find_package() command may consider that directory while searching for package <PackageName>, which helps dependent projects find and use a package from the current project's build tree without any help from the user. Self-sufficient queen behavior. ๐
Note that the entry in the package registry this command creates only works in conjunction with a package configuration file (<PackageName>Config.cmake) that works with the build tree. And in some cases โ packaging, for example, and system-wide installations โ writing the user package registry is just not desirable. Read the room.
Changed in version 3.1: If the CMAKE_EXPORT_NO_PACKAGE_REGISTRY variable is enabled, the export(PACKAGE) command will do nothing. Literally nothing. It's giving ghosted. ๐
okay so quick glow-up era for export(PACKAGE) โ Changed in version 3.15: by default the export(PACKAGE) command literally does nothing now (peep policy CMP0090) ๐ because populating the user package registry has effects outside the source and build trees, which is giving "side effects you didn't ask for" energy. If you actually want build directories added to the CMake user package registry, set the CMAKE_EXPORT_PACKAGE_REGISTRY variable. That's the whole vibe check. โจ
๐ธ Configuring Exports ๐ธ
export(SETUP <export-name> [...])
export(SETUP <export-name>
[PACKAGE_DEPENDENCY <dep>
[ENABLED (<bool-true>|<bool-false>|AUTO)]
[EXTRA_ARGS <args>...]
] [...]
[TARGET <target>
[XCFRAMEWORK_LOCATION <location>]
] [...]
)
Added in version 3.29. This is how you configure the params of an export, bestie. The arguments are:
PACKAGE_DEPENDENCY <dep>โ specify a package dependency to configure. This changes howfind_dependency()calls get written duringexport(EXPORT)andinstall(EXPORT).<dep>is the name of a package to export. It accepts these extra args:
Note: this one's Experimental. It's gated by CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_DEPENDENCIES, so like... gatekept, iykyk.
ENABLEDโ manually control whether the dependency gets exported or not. Takes these values:<bool-true>โ any value CMake recognizes as "true". Always export the dependency, even if no exported targets depend on it. You can use this to manually addfind_dependency()calls to the export. ๐<bool-false>โ any value CMake recognizes as "false". Never export the dependency, even if an exported target does depend on it. ๐AUTOโ only export the dependency if an exported target depends on it. The chill, lowkey option. ๐ฆ
EXTRA_ARGS <args>โ extra arguments to pass tofind_dependency()after theREQUIREDargument.
TARGET <target>โ specify a target to configure in this export. It takes this extra arg:XCFRAMEWORK_LOCATIONโ specify the location of an.xcframeworkwhich contains the library from this target. If you specify it, the generated code will check to see if the.xcframeworkexists, and if it does, it'll use the.xcframeworkas its imported location instead of the installed library. ๐
๐ fltk_wrap_ui ๐
Create FLTK user interfaces Wrappers.
fltk_wrap_ui(resultingLibraryName source1
source2 ... sourceN)
Produce .h and .cxx files for all the .fl and .fld files listed. The resulting .h and .cxx files get added to a variable named resultingLibraryName_FLTK_UI_SRCS โ and that variable should be added to your library. That's it, that's the whole job. โจ
๐ get_source_file_property ๐
Get a property for a source file.
get_source_file_property(<variable> <file>
[DIRECTORY <dir> | TARGET_DIRECTORY <target>]
<property>)
Gets a property from a source file, and the value of the property gets stored in the specified <variable>. If <file> isn't a source file, or the source property just isn't found, <variable> will be set to NOTFOUND. ๐ญ And if the source property was defined to be an INHERITED property (see define_property()), the search will include the relevant parent scopes, exactly as described for the define_property() command.
By default, the source file's property gets read from the current source directory's scope. Periodt.
Added in version 3.18: directory scope can be overridden with one of these sub-options:
DIRECTORY <dir>โ the source file property gets read from the<dir>directory's scope. CMake must already know about that source directory, either by having added it through a call toadd_subdirectory()or by<dir>being the top level source directory. Relative paths are treated as relative to the current source directory. ๐ซถTARGET_DIRECTORY <target>โ the source file property gets read from the directory scope in which<target>was created (<target>must therefore already exist, no cap).
Use set_source_files_properties() to set property values. Source file properties usually control how the file is built. One property that's always there is LOCATION. ๐
Note: the GENERATED source file property may be globally visible. See its documentation for the details, bestie.
โญ See Also โญ
define_property()- the more general
get_property()command set_source_files_properties()
๐ get_target_property ๐
Get a property from a target.
get_target_property(<variable> <target> <property>)
Get a property from a target โ the value of the property gets stored in the specified <variable>. If the target property isn't found, <variable> will be set to <variable>-NOTFOUND. Yes, literally the variable name plus -NOTFOUND. ๐ญ If the target property was defined to be an INHERITED property (see define_property()), the search will include the relevant parent scopes, as described for the define_property() command.
Use set_target_properties() to set target property values. Properties usually control how a target is built, but some of them query the target instead. This command can get properties for any target created so far โ the targets do not need to be in the current CMakeLists.txt file. Main character energy: it'll reach across files for you. ๐
๐ See Also ๐
define_property()- the more general
get_property()command set_target_properties()- Properties on Targets for the list of properties known to CMake
๐ง get_test_property ๐ง
Get a property of the test.
get_test_property(<test> <property> [DIRECTORY <dir>] <variable>)
Get a property from the test, and the value of the property gets stored in the specified <variable>. If <test> isn't defined, or the test property isn't found, <variable> will be set to NOTFOUND. ๐ญ If the test property was defined to be an INHERITED property (see define_property()), the search will include the relevant parent scopes, as described for the define_property() command.
For a list of standard properties you can type cmake --help-property-list. Go off, it's free. โจ
Added in version 3.28: directory scope can be overridden with this sub-option:
DIRECTORY <dir>โ the test property gets read from the<dir>directory's scope. CMake must already know about that source directory, either by having added it through a call toadd_subdirectory()or by<dir>being the top level source directory. Relative paths are treated as relative to the current source directory. Also,<dir>may reference a binary directory. ๐ฆ
๐ See Also ๐
define_property()- the more general
get_property()command
๐ธ include_directories ๐ธ
Add include directories to the build.
include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...])
Add the given directories to those the compiler uses to search for include files. Relative paths are interpreted as relative to the current source directory. ๐
The include directories get added to the INCLUDE_DIRECTORIES directory property for the current CMakeLists file. They're also added to the INCLUDE_DIRECTORIES target property for each target in the current CMakeLists file. And the target property values are the ones actually used by the generators, so like... that's the real ones. ๐
By default the directories you specify are appended onto the current list of directories. This default behavior can be changed by setting CMAKE_INCLUDE_DIRECTORIES_BEFORE to ON. And by using AFTER or BEFORE explicitly, you can pick between appending and prepending, independent of the default. Choose your fighter. ๐
If the SYSTEM option is given, the compiler will be told the directories are meant as system include directories on some platforms. Signaling this setting might achieve effects such as the compiler skipping warnings, or these fixed-install system files not being considered in dependency calculations โ see compiler docs for the deets.
Arguments to include_directories may use generator expressions with the syntax $<...>. See the cmake-generator-expressions(7) manual for available expressions. See the cmake-buildsystem(7) manual for more on defining buildsystem properties. ๐
Note: prefer the target_include_directories() command to add include directories to individual targets and optionally propagate/export them to dependents. Like, fr fr, that's the modern way.
๐ซถ See Also ๐ซถ
target_include_directories()
๐ฅ include_external_msproject ๐ฅ
Include an external Microsoft project file in the solution file produced by Visual Studio Generators. Ignored on other generators. ๐
include_external_msproject(projectname location
[TYPE projectTypeGUID]
[GUID projectGUID]
[PLATFORM platformName]
dep1 dep2 ...)
Includes an external Microsoft project in the generated solution file. This will create a target named [projectname] โ and you can use that in the add_dependencies() command to make things depend on the external project. ๐ฆ
TYPE, GUID and PLATFORM are optional parameters that let you specify the type of project, the id (GUID) of the project, and the name of the target platform. This is useful for projects requiring values other than the default (e.g. WIX projects). โจ
Added in version 3.9: if the imported project has different configuration names than the current project, set the MAP_IMPORTED_CONFIG_<CONFIG> target property to specify the mapping. Matching fits, no cap. ๐
๐ธ include_regular_expression ๐ธ
okay so this one is literally just setting the regex vibe for dependency checking, bestie โ nothing scary.
include_regular_expression(regex_match [regex_complain])
It sets the regular expressions used in dependency checking. Only files matching regex_match get traced as dependencies. Only files matching regex_complain will generate warnings if they can't be found (and ngl, standard header paths are not searched โ so don't come for it when your system headers don't show up).
The default for regex_match is "^.*$" (match everything, she's generous ๐
). The default for regex_complain is "^$" (match the empty string only).
๐ install ๐
โจ Synopsis โจ
install(TARGETS <target>... [...])
install(IMPORTED_RUNTIME_ARTIFACTS <target>... [...])
install({FILES | PROGRAMS} <file>... [...])
install(DIRECTORY <dir>... [...])
install(SCRIPT <file> [...])
install(CODE <code> [...])
install(EXPORT <export-name> [...])
install(PACKAGE_INFO <package-name> [...])
install(RUNTIME_DEPENDENCY_SET <set-name> [...])
install(SBOM <sbom-name> [...])
๐ Introduction ๐
This command generates installation rules for a project. Install rules that you specify by calling install() inside a source directory are executed in order during installation. Periodt, order matters.
Changed in version 3.14: install rules in subdirectories added by calls to add_subdirectory() are interleaved with those in the parent directory, so they run in the order declared (see policy CMP0082). Cute, right? ๐ซถ
Changed in version 3.22: the environment variable CMAKE_INSTALL_MODE can override the default copying behavior of install(). iconique.
Changed in version 3.31: projects can enable INSTALL_PARALLEL to enable a parallel installation. When using the parallel install, subdirectories added by calls to add_subdirectory() are installed independently, and the order that install rules added in different subdirectories will run is not guaranteed. So likeโฆ chaos, but scheduled chaos ๐.
๐ Common Options ๐
There are multiple signatures for this command, bestie. Some of them define installation options for files and targets. Options common to multiple signatures are covered right here, but heads up: they're valid only for signatures that specify them. No sneaking them in elsewhere ๐ซ.
DESTINATION <dir>โ specifies the directory on disk to which a file will be installed.<dir>should be a relative path. An absolute path is allowed, but not recommended.- Added in version 4.4: the
CMD_INSTALL_ABSOLUTE_DESTINATIONdiagnostic can be enabled to warn or error out when an absolute destination is provided. - When a relative path is given, it is interpreted relative to the value of the
CMAKE_INSTALL_PREFIXvariable. The prefix can be relocated at install time using theDESTDIRmechanism explained in theCMAKE_INSTALL_PREFIXvariable documentation. - As absolute paths do not work with the
cmake --installcommand's--prefixoption, or with thecpackinstaller generators, it is strongly recommended to use relative paths throughout for best support by package maintainers. In particular, there is no need to make paths absolute by prependingCMAKE_INSTALL_PREFIXโ this prefix is used by default if theDESTINATIONis a relative path. so likeโฆ pls don't ๐. - If an absolute path (with a leading slash or drive letter) is given, it is used verbatim.
- Changed in version 3.31:
<dir>will be normalized according to the same normalization rules as thecmake_path()command.
- Added in version 4.4: the
PERMISSIONS <permission>...โ specify permissions for installed files. The valid permissions areOWNER_READ,OWNER_WRITE,OWNER_EXECUTE,GROUP_READ,GROUP_WRITE,GROUP_EXECUTE,WORLD_READ,WORLD_WRITE,WORLD_EXECUTE,SETUID, andSETGID. Permissions that don't make sense on certain platforms are just ignored on those platforms โ she's flexible like that โจ.- If this option is used multiple times in a single call, its list of permissions accumulates. If an
install(TARGETS)call uses<artifact-kind>arguments, a separate list of permissions is accumulated for each kind of artifact.
- If this option is used multiple times in a single call, its list of permissions accumulates. If an
CONFIGURATIONS <config>...โ specify a list of build configurations for which the install rule applies (Debug,Release, etc., iykyk).- If this option is used multiple times in a single call, its list of configurations accumulates. If an
install(TARGETS)call uses<artifact-kind>arguments, a separate list of configurations is accumulated for each kind of artifact.
- If this option is used multiple times in a single call, its list of configurations accumulates. If an
COMPONENT <component>โ specify an installation component name with which the install rule is associated, such asRuntimeorDevelopment. During component-specific installation, only install rules associated with the given component name will be executed. During a full installation, all components are installed unless marked withEXCLUDE_FROM_ALL. IfCOMPONENTis not provided, a default component"Unspecified"is created. The default component name may be controlled with theCMAKE_INSTALL_DEFAULT_COMPONENT_NAMEvariable.- Installation components can then be used by the
cmake --installcommand's--componentoption and theCPackComponentmodule. The global targetlist_install_componentslists all available components. shoutout to that target fr fr ๐
- Installation components can then be used by the
EXCLUDE_FROM_ALLโ Added in version 3.6. Specify that the file is excluded from a full installation and only installed as part of a component-specific installation.OPTIONALโ specify that it is not an error if the file to be installed does not exist. no drama, no vibe check failed ๐ .
Added in version 3.1: command signatures that install files may print messages during installation. Use the CMAKE_INSTALL_MESSAGE variable to control which messages are printed.
Added in version 3.11: many of the install() variants implicitly create the directories containing the installed files. If CMAKE_INSTALL_DEFAULT_DIRECTORY_PERMISSIONS is set, these directories will be created with the permissions specified. Otherwise, they will be created according to the umask rules on Unix-like platforms (the manual says "uname" โ that's a typo in the original, not me, don't @ me ๐ญ). Windows platforms are unaffected.
๐ Signatures ๐
install(TARGETS <target>... [...])โ install target Output Artifacts and associated files:
install(TARGETS <target>... [EXPORT <export-name>]
[RUNTIME_DEPENDENCIES <arg>...|RUNTIME_DEPENDENCY_SET <set-name>]
[<artifact-option>...]
[<artifact-kind> <artifact-option>...]...
[INCLUDES DESTINATION [<dir> ...]]
)
where the <artifact-option>... group may contain:
[DESTINATION <dir>]
[PERMISSIONS <permission>...]
[CONFIGURATIONS <config>...]
[COMPONENT <component>]
[NAMELINK_COMPONENT <component>]
[OPTIONAL] [EXCLUDE_FROM_ALL]
[NAMELINK_ONLY|NAMELINK_SKIP]
The first <artifact-option>... group applies to target Output Artifacts that do not have a dedicated group specified later in the same call.
Each <artifact-kind> <artifact-option>... group applies to Output Artifacts of the specified artifact kind:
ARCHIVEโ target artifacts of this kind include:- Static libraries (except on macOS when marked as
FRAMEWORK, see below); - DLL import libraries (on all Windows-based systems including Cygwin; they have extension
.lib, in contrast to the.dlllibraries that go toRUNTIME); - On AIX, the linker import file created for executables with
ENABLE_EXPORTSenabled. - On macOS, the linker import file created for shared libraries with
ENABLE_EXPORTSenabled (except when marked asFRAMEWORK, see below).
- Static libraries (except on macOS when marked as
LIBRARYโ target artifacts of this kind include:- Shared libraries, except
- DLLs (these go to
RUNTIME, see below), - on macOS when marked as
FRAMEWORK(see below).
- DLLs (these go to
- Module libraries.
- Shared libraries, except
RUNTIMEโ target artifacts of this kind include:- Executables (except on macOS when marked as
MACOSX_BUNDLE, seeBUNDLEbelow); - DLLs (on all Windows-based systems including Cygwin; note that the accompanying import libraries are of kind
ARCHIVE).
- Executables (except on macOS when marked as
OBJECTSโ Added in version 3.9. Object files associated with object libraries.FRAMEWORKโ both static and shared libraries marked with theFRAMEWORKproperty are treated asFRAMEWORKtargets on macOS.BUNDLEโ executables marked with theMACOSX_BUNDLEproperty are treated asBUNDLEtargets on macOS.PUBLIC_HEADERโ anyPUBLIC_HEADERfiles associated with a library are installed in the destination specified by thePUBLIC_HEADERargument on non-Apple platforms. Rules defined by this argument are ignored forFRAMEWORKlibraries on Apple platforms because the associated files are installed into the appropriate locations inside the framework folder. SeePUBLIC_HEADERfor details.PRIVATE_HEADERโ similar toPUBLIC_HEADER, but forPRIVATE_HEADERfiles. SeePRIVATE_HEADERfor details.RESOURCEโ similar toPUBLIC_HEADERandPRIVATE_HEADER, but forRESOURCEfiles. SeeRESOURCEfor details.FILE_SET <set-name>โ Added in version 3.23.
File sets are defined by the target_sources(FILE_SET) command, okay? So if the file set <set-name> exists and it's PUBLIC or INTERFACE, any files in the set of type HEADERS get installed under the destination (see below, bestie, it's literally right there ๐). Other types do not have any default destination, so the DESTINATION option must be specified for each FILE_SET. The directory structure relative to the file set's base directories is preserved โ no cap. For example, a file added to the file set as /blah/include/myproj/here.h with a base directory /blah/include would be installed to myproj/here.h below the destination. Obsessed with the path math tbh ๐
CXX_MODULES_BMIโ Added in version 3.28. Any module files from C++ modules fromPUBLICsources in a file set of typeCXX_MODULESwill be installed to the givenDESTINATION. All modules are placed directly in the destination as no directory structure is derived from the names of the modules. An emptyDESTINATIONmay be used to suppress installing these files (for use in generic code). ๐ง
For regular executables, static libraries and shared libraries, the DESTINATION argument is not required. For these target types, when DESTINATION is omitted, a default destination will be taken from the appropriate variable from GNUInstallDirs, or set to a built-in default value if that variable is not defined. The same is true for file sets of type HEADERS, and the public and private headers associated with the installed targets through the PUBLIC_HEADER and PRIVATE_HEADER target properties. A destination must always be provided for module libraries, Apple bundles and frameworks. A destination can be omitted for interface and object libraries, but they are handled differently (see the discussion of this topic toward the end of this section). โจ
For shared libraries on DLL platforms, if neither RUNTIME nor ARCHIVE destinations are specified, both the RUNTIME and ARCHIVE components are installed to their default destinations. If either a RUNTIME or ARCHIVE destination is specified, the component is installed to that destination, and the other component is not installed. If both RUNTIME and ARCHIVE destinations are specified, then both components are installed to their respective destinations. It's giving "choose your fighter" but make it install components ๐
Here's the target types with their associated variables and built-in defaults that apply when no destination is given (the original was a whole table, so have it as a lil list instead, same facts, cuter packaging ๐):
RUNTIMEโGNUInstallDirsvariable:${CMAKE_INSTALL_BINDIR}โ Built-In Default:binLIBRARYโGNUInstallDirsvariable:${CMAKE_INSTALL_LIBDIR}โ Built-In Default:libARCHIVEโGNUInstallDirsvariable:${CMAKE_INSTALL_LIBDIR}โ Built-In Default:libPRIVATE_HEADERโGNUInstallDirsvariable:${CMAKE_INSTALL_INCLUDEDIR}โ Built-In Default:includePUBLIC_HEADERโGNUInstallDirsvariable:${CMAKE_INSTALL_INCLUDEDIR}โ Built-In Default:includeFILE_SET(typeHEADERS) โGNUInstallDirsvariable:${CMAKE_INSTALL_INCLUDEDIR}โ Built-In Default:include
Projects wishing to follow the common practice of installing headers into a project-specific subdirectory may prefer using file sets with appropriate paths and base directories. Otherwise, they must provide a DESTINATION instead of being able to rely on the above (see next example below). ๐
To make packages compliant with distribution filesystem layout policies, if projects must specify a DESTINATION, it is strongly recommended that they use a path that begins with the appropriate relative GNUInstallDirs variable. This allows package maintainers to control the install destination by setting the appropriate cache variables. The following example shows a static library being installed to the default destination provided by GNUInstallDirs, but with its headers installed to a project-specific subdirectory without using file sets โ slay, look at it go:
add_library(mylib STATIC ...)
set_target_properties(mylib PROPERTIES PUBLIC_HEADER mylib.h)
include(GNUInstallDirs)
install(TARGETS mylib
PUBLIC_HEADER
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/myproj
)
In addition to the common options listed above, each target can accept the following additional arguments ๐:
NAMELINK_COMPONENTโ Added in version 3.12. On some platforms a versioned shared library has a symbolic link such as:
lib<name>.so -> lib<name>.so.1
where lib<name>.so.1 is the soname of the library and lib<name>.so is a "namelink" allowing linkers to find the library when given -l<name>. The NAMELINK_COMPONENT option is similar to the COMPONENT option, but it changes the installation component of a shared library namelink if one is generated. If not specified, this defaults to the value of COMPONENT. It is an error to use this parameter outside of a LIBRARY block. ๐ญ
Changed in version 3.27: This parameter is also usable for an ARCHIVE block to manage the linker import file created, on macOS, for shared libraries with ENABLE_EXPORTS enabled.
See the Example: Install Targets with Per-Artifact Components for an example using NAMELINK_COMPONENT.
This option is typically used for package managers that have separate runtime and development packages. For example, on Debian systems, the library is expected to be in the runtime package, and the headers and namelink are expected to be in the development package.
See the VERSION and SOVERSION target properties for details on creating versioned shared libraries.
NAMELINK_ONLYโ This option causes the installation of only the namelink when a library target is installed. On platforms where versioned shared libraries do not have namelinks or when a library is not versioned, theNAMELINK_ONLYoption installs nothing. It is an error to use this parameter outside of aLIBRARYblock. ๐ซถ
Changed in version 3.27: This parameter is also usable for an ARCHIVE block to manage the linker import file created, on macOS, for shared libraries with ENABLE_EXPORTS enabled.
When NAMELINK_ONLY is given, either NAMELINK_COMPONENT or COMPONENT may be used to specify the installation component of the namelink, but COMPONENT should generally be preferred.
NAMELINK_SKIPโ Similar toNAMELINK_ONLY, but it has the opposite effect: it causes the installation of library files other than the namelink when a library target is installed. When neitherNAMELINK_ONLYorNAMELINK_SKIPare given, both portions are installed. On platforms where versioned shared libraries do not have symlinks or when a library is not versioned,NAMELINK_SKIPinstalls the library. It is an error to use this parameter outside of aLIBRARYblock. ๐
Changed in version 3.27: This parameter is also usable for an ARCHIVE block to manage the linker import file created, on macOS, for shared libraries with ENABLE_EXPORTS enabled.
If NAMELINK_SKIP is specified, NAMELINK_COMPONENT has no effect. It is not recommended to use NAMELINK_SKIP in conjunction with NAMELINK_COMPONENT. ๐
The install(TARGETS) command can also accept the following options at the top level ๐:
EXPORTโ This option associates the installed target files with an export called<export-name>. It must appear before any target options. To actually install the export file itself, callinstall(EXPORT), documented below. See documentation of theEXPORT_NAMEtarget property to change the name of the exported target. โญINCLUDES DESTINATIONโ drop a list of directories here and they get added to theINTERFACE_INCLUDE_DIRECTORIEStarget property of the<targets>when they're exported by theinstall(EXPORT)command. If you hand it a relative path it's treated as relative to$<INSTALL_PREFIX>. And lowkey this one's special: unlike the otherDESTINATIONarguments on the variousinstall()subcommands, paths afterINCLUDES DESTINATIONare used as given โ not normalized, not even assumed to be normalized, though ngl it's recommended you give them in normalized form (peep Normalization).RUNTIME_DEPENDENCY_SET <set-name>โ โจAdded in version 3.21.โจ This makes all the runtime dependencies of your installed executable, shared library, and module targets get dumped into the runtime dependency set you name. Then you can install that whole set with aninstall(RUNTIME_DEPENDENCY_SET)command. Heads up tho: this keyword andRUNTIME_DEPENDENCIESare mutually exclusive โ pick one, bestie.RUNTIME_DEPENDENCIES <arg>...โ โจAdded in version 3.21.โจ This one takes all the runtime dependencies of your installed executable, shared library, and module targets and installs them right alongside the targets themselves. TheRUNTIME,LIBRARY,FRAMEWORK, and generic arguments are what decide the properties (DESTINATION,COMPONENT, etc.) of how those deps get installed.
It's semantically equivalent to these two calls, fr fr:
install(TARGETS ... RUNTIME_DEPENDENCY_SET <set-name>)
install(RUNTIME_DEPENDENCY_SET <set-name> <arg>...)
where <set-name> is a randomly generated set name. Your <arg>... can be any of these keywords that install(RUNTIME_DEPENDENCY_SET) supports:
DIRECTORIESPRE_INCLUDE_REGEXESPRE_EXCLUDE_REGEXESPOST_INCLUDE_REGEXESPOST_EXCLUDE_REGEXESPOST_INCLUDE_FILESPOST_EXCLUDE_FILES
And again: RUNTIME_DEPENDENCIES and RUNTIME_DEPENDENCY_SET are mutually exclusive. No mixing ๐
.
Interface Libraries can totally be listed among the targets you install. They install literally no artifacts, but they will be included in an associated EXPORT. And if Object Libraries get listed but you give them no destination for their object files, they get exported as Interface Libraries instead โ which is exactly enough to satisfy the transitive usage requirements of other targets that link to those object libraries in their implementation. It's giving "play your position."
Installing a target with theEXCLUDE_FROM_ALLtarget property set toTRUEhas undefined behavior. Not a vibe. Don't do it.
โจAdded in version 3.3:โจ An install destination passed as a DESTINATION argument can use "generator expressions" with the syntax $<...>. Go check the cmake-generator-expressions(7) manual for which expressions you've got. ๐ฆ
โจAdded in version 3.13:โจ install(TARGETS) can install targets that were created in other directories. But when you're using cross-directory install rules like that, running make install (or similar) from a subdirectory will not guarantee that targets from other directories are up-to-date. Use target_link_libraries() or add_dependencies() to make sure those out-of-directory targets get built before the subdirectory-specific install rules run. Main-character targets need a schedule, okay?
๐ install(IMPORTED_RUNTIME_ARTIFACTS <target>... [...]) ๐
โจAdded in version 3.21.โจ Install the runtime artifacts of imported targets, babes:
install(IMPORTED_RUNTIME_ARTIFACTS <target>...
[RUNTIME_DEPENDENCY_SET <set-name>]
[[LIBRARY|RUNTIME|FRAMEWORK|BUNDLE]
[DESTINATION <dir>]
[PERMISSIONS <permission>...]
[CONFIGURATIONS <config>...]
[COMPONENT <component>]
[OPTIONAL] [EXCLUDE_FROM_ALL]
]...
)
The IMPORTED_RUNTIME_ARTIFACTS form sets up rules for installing the runtime artifacts of imported targets. Projects do this when they wanna bundle outside executables or modules inside their own installation. The LIBRARY, RUNTIME, FRAMEWORK, and BUNDLE arguments mean the exact same thing they mean in TARGETS mode.
Important detail: only the runtime artifacts of imported targets get installed โ except in the case of FRAMEWORK libraries, MACOSX_BUNDLE executables, and BUNDLE CFBundles. For example, headers and import libraries associated with DLLs are not installed. But for FRAMEWORK libraries, MACOSX_BUNDLE executables, and BUNDLE CFBundles, the entire directory gets installed. ๐
The RUNTIME_DEPENDENCY_SET option causes the runtime artifacts of the imported executable, shared library, and module library targets to be added to the <set-name> runtime dependency set. Then you can install that set with an install(RUNTIME_DEPENDENCY_SET) command. ๐
๐ธ install(FILES <file>... [...]) ๐ธ
๐ธ install(PROGRAMS <program>... [...]) ๐ธ
Note: if you're installing header files, consider using file sets defined by target_sources(FILE_SET) instead โ file sets associate headers with a target and they install as part of the target. Cleaner. Iconic. Do that.
Install files or programs:
install(<FILES|PROGRAMS> <file>...
TYPE <type> | DESTINATION <dir>
[PERMISSIONS <permission>...]
[CONFIGURATIONS <config>...]
[COMPONENT <component>]
[RENAME <name>] [OPTIONAL] [EXCLUDE_FROM_ALL])
The FILES form sets up rules for installing files for a project. File names given as relative paths are interpreted with respect to the current source directory. Files installed this way get permissions OWNER_WRITE, OWNER_READ, GROUP_READ, and WORLD_READ by default, if you don't pass a PERMISSIONS argument. ๐
The PROGRAMS form is identical to the FILES form, except the default permissions for the installed file also include OWNER_EXECUTE, GROUP_EXECUTE, and WORLD_EXECUTE. This form is meant for installing programs that aren't targets โ think shell scripts. Use the TARGETS form to install targets that are built within the project. โจ
The list of files you give to FILES or PROGRAMS may use "generator expressions" with the syntax $<...>. See the cmake-generator-expressions(7) manual for what's available. But bestie, watch out: if any item begins in a generator expression, it must evaluate to a full path. No half-paths, no games. ๐ญ
The optional RENAME <name> argument is how you give the installed file a name that's different from its original file name. Gatekeep, girlboss: renaming is only allowed when a single file is installed by the command. ๐ซถ
okay so literally: either a TYPE or a DESTINATION has to be provided โ but not both, bestie. ๐
A TYPE argument tells CMake the generic file type of the files being installed. Then a destination gets set automatically by taking the corresponding variable from the GNUInstallDirs module, or by using a built-in default if that variable is not defined. The little matchup list below has the supported file types plus their corresponding variables and built-in defaults. Projects can also hand over a DESTINATION argument instead of a file type if they want to explicitly define the install destination. โจ
Hereโs the type tea โ:
BINโGNUInstallDirsvariable${CMAKE_INSTALL_BINDIR}; built-in defaultbinSBINโGNUInstallDirsvariable${CMAKE_INSTALL_SBINDIR}; built-in defaultsbinLIBโGNUInstallDirsvariable${CMAKE_INSTALL_LIBDIR}; built-in defaultlibINCLUDEโGNUInstallDirsvariable${CMAKE_INSTALL_INCLUDEDIR}; built-in defaultincludeSYSCONFโGNUInstallDirsvariable${CMAKE_INSTALL_SYSCONFDIR}; built-in defaultetcSHAREDSTATEโGNUInstallDirsvariable${CMAKE_INSTALL_SHARESTATEDIR}; built-in defaultcomLOCALSTATEโGNUInstallDirsvariable${CMAKE_INSTALL_LOCALSTATEDIR}; built-in defaultvarRUNSTATEโGNUInstallDirsvariable${CMAKE_INSTALL_RUNSTATEDIR}; built-in default<LOCALSTATE dir>/runDATAโGNUInstallDirsvariable${CMAKE_INSTALL_DATADIR}; built-in default<DATAROOT dir>INFOโGNUInstallDirsvariable${CMAKE_INSTALL_INFODIR}; built-in default<DATAROOT dir>/infoLOCALEโGNUInstallDirsvariable${CMAKE_INSTALL_LOCALEDIR}; built-in default<DATAROOT dir>/localeMANโGNUInstallDirsvariable${CMAKE_INSTALL_MANDIR}; built-in default<DATAROOT dir>/manDOCโGNUInstallDirsvariable${CMAKE_INSTALL_DOCDIR}; built-in default<DATAROOT dir>/docLIBEXECโGNUInstallDirsvariable${CMAKE_INSTALL_LIBEXECDIR}; built-in defaultlibexec
Projects wishing to follow the common practice of installing headers into a project-specific subdirectory will need to provide a destination rather than rely on the above. Using file sets for headers instead of install(FILES) would be even better (see target_sources(FILE_SET)). ๐ซถ
Note that some of the typesโ built-in defaults use the DATAROOT directory as a prefix. The DATAROOT prefix is calculated similarly to the types, with CMAKE_INSTALL_DATAROOTDIR as the variable and share as the built-in default. You cannot use DATAROOT as a TYPE parameter; please use DATA instead. ๐ซ
To make packages compliant with distribution filesystem layout policies, if projects must specify a DESTINATION, it is strongly recommended that they use a path that begins with the appropriate relative GNUInstallDirs variable. This allows package maintainers to control the install destination by setting the appropriate cache variables. The following example shows how to follow this advice while installing an image to a project-specific documentation subdirectory:
include(GNUInstallDirs)
install(FILES logo.png
DESTINATION ${CMAKE_INSTALL_DOCDIR}/myproj
)
Added in version 3.4: An install destination given as a DESTINATION argument may use "generator expressions" with the syntax $<...>. See the cmake-generator-expressions(7) manual for available expressions. โจ
Added in version 3.20: An install rename given as a RENAME argument may use "generator expressions" with the syntax $<...>. See the cmake-generator-expressions(7) manual for available expressions. ๐
Added in version 3.31: The TYPE argument now supports type LIBEXEC. ๐ฅ
๐ง install(DIRECTORY <dir>... [...]) ๐ง
Note: To install a directory sub-tree of headers, consider using file sets defined by target_sources(FILE_SET) instead. File sets not only preserve directory structure, they also associate headers with a target and install as part of the target. ๐ซถ
Install the contents of one or more directories:
install(DIRECTORY <dir>...
TYPE <type> | DESTINATION <dir>
[FILE_PERMISSIONS <permission>...]
[DIRECTORY_PERMISSIONS <permission>...]
[USE_SOURCE_PERMISSIONS] [OPTIONAL] [MESSAGE_NEVER]
[CONFIGURATIONS <config>...]
[COMPONENT <component>] [EXCLUDE_FROM_ALL]
[FILES_MATCHING]
[<match-rule> <match-option>...]...
)
The DIRECTORY form installs contents of one or more directories to a given destination. The directory structure is copied verbatim to the destination. ๐ฆ
Either a TYPE or a DESTINATION must be provided, but not both. If no permissions is given, files will be given the default permissions specified in the FILES form of the command, and the directories will be given the default permissions specified in the PROGRAMS form of the command. ๐
The options are:
<dir>...โ the list of directories to be installed.- The last component of each directory name is appended to the destination directory, but a trailing slash may be used to avoid this because it leaves the last component empty.
- Directory names given as relative paths are interpreted with respect to the current source directory.
- If no input directory names are given, the destination directory will be created but nothing will be installed into it.
- Added in version 3.5: The source
<dir>...list may use "generator expressions" with the syntax$<...>. See thecmake-generator-expressions(7)manual for available expressions. ๐
Okay so picking right back up with TYPE <type> โ this is the glow-up where you tell CMake the generic file type of everything inside those directories you're installing. It then auto-sets a destination for you by grabbing the matching variable from GNUInstallDirs, or by falling back to a built-in default if that variable isn't defined (iconic of it, honestly). Peep the table below for the supported file types and their matching variables and built-in defaults. And if a project wants to be extra and spell it out explicitly, they can just hand over a DESTINATION argument instead of a file type. ๐
BINโ variable${CMAKE_INSTALL_BINDIR}, built-in defaultbinSBINโ variable${CMAKE_INSTALL_SBINDIR}, built-in defaultsbinLIBโ variable${CMAKE_INSTALL_LIBDIR}, built-in defaultlibINCLUDEโ variable${CMAKE_INSTALL_INCLUDEDIR}, built-in defaultincludeSYSCONFโ variable${CMAKE_INSTALL_SYSCONFDIR}, built-in defaultetcSHAREDSTATEโ variable${CMAKE_INSTALL_SHARESTATEDIR}, built-in defaultcomLOCALSTATEโ variable${CMAKE_INSTALL_LOCALSTATEDIR}, built-in defaultvarRUNSTATEโ variable${CMAKE_INSTALL_RUNSTATEDIR}, built-in default<LOCALSTATE dir>/runDATAโ variable${CMAKE_INSTALL_DATADIR}, built-in default<DATAROOT dir>INFOโ variable${CMAKE_INSTALL_INFODIR}, built-in default<DATAROOT dir>/infoLOCALEโ variable${CMAKE_INSTALL_LOCALEDIR}, built-in default<DATAROOT dir>/localeMANโ variable${CMAKE_INSTALL_MANDIR}, built-in default<DATAROOT dir>/manDOCโ variable${CMAKE_INSTALL_DOCDIR}, built-in default<DATAROOT dir>/docLIBEXECโ variable${CMAKE_INSTALL_LIBEXECDIR}, built-in defaultlibexec
Heads up bestie: some of these types' built-in defaults use the DATAROOT directory as a prefix. The DATAROOT prefix gets calculated the same way as the types themselves โ variable CMAKE_INSTALL_DATAROOTDIR, built-in default share. And no, you literally cannot use DATAROOT as a TYPE parameter ๐ซถ โ please use DATA instead.
Added in version 3.31: the LIBEXEC type. New drop, go use it. โจ
๐ DESTINATION <dir>
The destination directory, exactly as documented among the common options.
And listen โ to make packages compliant with distribution filesystem layout policies, if a project must specify a DESTINATION, it is strongly recommended that they use a path that begins with the appropriate relative GNUInstallDirs variable. This is the whole point: it lets package maintainers control the install destination by setting the appropriate cache variables. Respect the ecosystem, periodt. ๐
Added in version 3.4: the destination<dir>may use "generator expressions" with the syntax$<...>. See thecmake-generator-expressions(7)manual for the available expressions. The lore is deep, iykyk.
๐ FILE_PERMISSIONS <permission>...
Specify the permissions given to files in the destination, where the <permission> names are documented among the common options.
๐ DIRECTORY_PERMISSIONS <permission>...
Same energy, but for directories in the destination โ the <permission> names are documented among the common options.
๐ธ USE_SOURCE_PERMISSIONS
If specified, and FILE_PERMISSIONS is not, then file permissions will be copied straight from the source directory structure. Inherited ~ from your mother ~ ๐ง
๐ธ MESSAGE_NEVER
Added in version 3.1.
Disable file installation status output. That's it. Silence. Peace and quiet. ๐
๐ฆ FILES_MATCHING
You can drop this option before the first <match-rule> to disable installation of files (but not directories) that aren't matched by any expression. Like, filter the guest list but let all the venues in.
For example, this code:
install(DIRECTORY src/ DESTINATION doc/myproj
FILES_MATCHING PATTERN "*.png")
will extract and install images from a source tree. Slay. ๐ผ๏ธ
๐ <match-rule> <match-option>...
Installation of directories may be controlled with fine granularity using rules that match directories or files encountered within input directories. They may be used to apply certain options (see below) to a subset of the files and directories encountered. And like โ all files and directories are installed whether or not they are matched, unless you gave that FILES_MATCHING option above. No sneaky deletions.
The full path to each input file or directory, with forward slashes, may be matched by a <match-rule>:
โญ PATTERN <pattern>
Match complete file names using a globbing pattern. The portion of the full path matching the pattern must occur at the end of the file name and be preceded by a slash (which is not part of the pattern). Details matter, bestie.
โญ REGEX <regex>
Match any portion of the full path of a file with a regular expression. You may use / and $ to limit matching to the end of a path. Regex girlies rise. ๐ฅ
Each <match-rule> may be followed by <match-option> arguments. The match options apply to the files or directories matched by the rule. The match options are:
EXCLUDEโ exclude the matched file or directory from installation. Begone. ๐PERMISSIONS <permission>...โ override the permissions setting for the matched file or directory.
For example, this code:
install(DIRECTORY icons scripts/ DESTINATION share/myproj
PATTERN "CVS" EXCLUDE
PATTERN "scripts/*"
PERMISSIONS OWNER_EXECUTE OWNER_WRITE OWNER_READ
GROUP_EXECUTE GROUP_READ)
will install the icons directory to share/myproj/icons and the scripts directory to share/myproj. The icons will get default file permissions, the scripts will be given specific permissions, and any CVS directories will be excluded. Three different treatments in one call, the multitasking icon she is. ๐
๐ install(SCRIPT <file> [...])
๐ install(CODE <code> [...])
Invoke CMake scripts or code during installation:
install([[SCRIPT <file>] [CODE <code>]]
[ALL_COMPONENTS | COMPONENT <component>]
[EXCLUDE_FROM_ALL])
That's the whole vibe โ you're literally running a script or a chunk of code at install time. Use it wisely, and maybe don't put your whole personality in there. ๐ญ
Okay so real talk for a sec โ the SCRIPT form literally invokes the CMake script files you gave it, during installation. And if the script file name is a relative path, it gets interpreted with respect to the current source directory, iykyk. The CODE form invokes the CMake code you gave it, during installation too. That code has to be a single argument inside a double-quoted string, bestie. Like, for example:
install(CODE "message(\"Sample install message.\")")
which will print a message during installation. Cute, right? โจ
Added in version 3.21: when you pass the ALL_COMPONENTS option, the custom installation script code will be executed for every component of a component-specific installation. And heads up โ this option is mutually exclusive with the COMPONENT option. You can't have both, no cap. ๐
โโ๏ธ
Added in version 3.14: <file> or <code> may use "generator expressions" with the syntax $<...> (and in the case of <file>, this refers to their use in the file name, not the file's contents โ important distinction, don't get it twisted ๐
). Go peek at the cmake-generator-expressions(7) manual for all the available expressions.
๐ install(EXPORT <export-name> [...])
Install a CMake file exporting targets for dependent projects โ it's giving sharing is caring:
install(EXPORT <export-name> DESTINATION <dir>
[NAMESPACE <namespace>] [FILE <name>.cmake]
[PERMISSIONS <permission>...]
[CONFIGURATIONS <config>...]
[CXX_MODULES_DIRECTORY <directory>]
[EXPORT_LINK_INTERFACE_LIBRARIES]
[COMPONENT <component>]
[EXCLUDE_FROM_ALL]
[EXPORT_PACKAGE_DEPENDENCIES])
install(EXPORT_ANDROID_MK <export-name> DESTINATION <dir> [...])
So the EXPORT form generates and installs a CMake file that contains code to import targets from the installation tree into another project. Target installations get associated with the export <export-name> using the EXPORT option of the install(TARGETS) signature documented above. The NAMESPACE option will prepend <namespace> to the target names as they get written to the import file. By default the generated file is called <export-name>.cmake, but the FILE option lets you specify a different name โ and the value you give to FILE must be a file name with the .cmake extension. Non-negotiable. ๐ซถ
If a CONFIGURATIONS option is given, then the file will only be installed when one of the named configurations is installed. Also, the generated import file will reference only the matching target configurations. Check out the CMAKE_MAP_IMPORTED_CONFIG_<CONFIG> variable to map configurations of dependent projects to the installed configurations. The EXPORT_LINK_INTERFACE_LIBRARIES keyword, if present, causes the contents of the properties matching (IMPORTED_)?LINK_INTERFACE_LIBRARIES(_<CONFIG>)? to be exported, when policy CMP0022 is NEW.
Note: the installed<export-name>.cmakefile may come with additional per-configuration<export-name>-*.cmakefiles to be loaded by globbing. So do not use an export name that's the same as the package name in combination with installing a<package-name>-config.cmakefile โ otherwise the latter may be incorrectly matched by the glob and loaded. That's a real "oops" moment, and not the fun kind. ๐ญ
When a COMPONENT option is given, the listed <component> implicitly depends on all components mentioned in the export set. The exported <name>.cmake file will require each of the exported components to be present in order for dependent projects to build properly. Example time, because this one's a whole vibe: ๐ฆ
- A project may define components
RuntimeandDevelopment, with shared libraries going into theRuntimecomponent and static libraries and headers going into theDevelopmentcomponent. - The export set would also typically be part of the
Developmentcomponent, but it would export targets from both theRuntimeandDevelopmentcomponents. - Therefore, the
Runtimecomponent would need to be installed if theDevelopmentcomponent was installed, but not vice versa. - If the
Developmentcomponent was installed without theRuntimecomponent, dependent projects that try to link against it would get build errors. ๐ - Package managers, such as APT and RPM, typically handle this by listing the
Runtimecomponent as a dependency of theDevelopmentcomponent in the package metadata, ensuring that the library is always installed if the headers and CMake export file are present. Slay, honestly. ๐
Added in version 3.7: in addition to cmake language files, the EXPORT_ANDROID_MK mode may be used to specify an export to the android ndk build system. This mode accepts the same options as the normal export mode. The Android NDK supports the use of prebuilt libraries, both static and shared. This allows cmake to build the libraries of a project and make them available to an ndk build system complete with transitive dependencies, include flags and defines required to use the libraries. Very much the whole package. ๐ฆ
CXX_MODULES_DIRECTORY
Added in version 3.28.
Specify a subdirectory to store C++ module information for targets in the export set. This directory will be populated with files which add the necessary target property information to the relevant targets. Note that without this information, none of the C++ modules which are part of the targets in the export set will support being imported in consuming targets. So likeโฆ if you skip it, that's on you bestie. ๐
EXPORT_PACKAGE_DEPENDENCIES
Note: Experimental. Gated by CMAKE_EXPERIMENTAL_EXPORT_PACKAGE_DEPENDENCIES. (Yes, it's behind a gate โ behave accordingly. ๐ง)
Specify that find_dependency() calls should be exported. If this argument is specified, CMake examines all targets in the export set and gathers their INTERFACE link targets. If any such targets either were found with find_package() or have the EXPORT_FIND_PACKAGE_NAME property set, and such package dependency was not disabled by passing ENABLED OFF to export(SETUP), then a find_dependency() call is written with the target's corresponding package name, a REQUIRED argument, and any additional arguments specified by the EXTRA_ARGS argument of export(SETUP). And any package dependencies that were manually specified by passing ENABLED ON to export(SETUP) are also added, even if the exported targets don't depend on any targets from them. Generous behaviour, honestly. ๐
The find_dependency() calls are written in the following order:
- Any package dependencies that were listed in
export(SETUP)are written in the order they were first specified, regardless of whether or not they containINTERFACEdependencies of the exported targets. - Any package dependencies that contain
INTERFACElink dependencies of the exported targets and that were never specified inexport(SETUP)are written in the order they were first found.
The EXPORT form is useful to help outside projects use targets built and installed by the current project. For example, this code:
install(TARGETS myexe EXPORT myproj DESTINATION bin)
install(EXPORT myproj NAMESPACE mp_ DESTINATION lib/myproj)
install(EXPORT_ANDROID_MK myproj DESTINATION share/ndk-modules)
will install the executable myexe to <prefix>/bin and code to import it in the file <prefix>/lib/myproj/myproj.cmake and <prefix>/share/ndk-modules/Android.mk. An outside project may load this file with the include command and reference the myexe executable from the installation tree using the imported target name mp_myexe as if the target were built in its own tree. Literally main character energy for an executable. ๐ฅ
๐ install(PACKAGE_INFO <package-name> [...])
Added in version 4.3.
Installs a Common Package Specification ("CPS") file exporting targets for dependent projects โ it's the https://cps-org.github.io/cps/ spec, if you want the lore:
install(PACKAGE_INFO <package-name> EXPORT <export-name>
[PROJECT <project-name>|NO_PROJECT_METADATA]
[APPENDIX <appendix-name>]
[DESTINATION <dir>]
[LOWER_CASE_FILE]
[VERSION <version>
[COMPAT_VERSION <version>]
[VERSION_SCHEMA <string>]]
[DEFAULT_TARGETS <target>...]
[DEFAULT_CONFIGURATIONS <config>...]
[LICENSE <license-string>]
[DEFAULT_LICENSE <license-string>]
[DESCRIPTION <description-string>]
[HOMEPAGE_URL <url-string>]
[PERMISSIONS <permission>...]
[CONFIGURATIONS <config>...]
[CXX_MODULES_DIRECTORY <directory>]
[COMPONENT <component>]
[EXCLUDE_FROM_ALL])
The PACKAGE_INFO form generates and installs a Common Package Specification file which describes installed targets such that they can be consumed by another project. Target installations are associated with the export <export-name> using the EXPORT option of the install(TARGETS) signature documented above. Unlike install(EXPORT), this information is not expressed in CMake code, so it can be consumed by tools other than CMake. ๐ When imported into another CMake project, the imported targets will be prefixed with <package-name>::. By default, the generated file will be called <package-name>[-<appendix-name>].cps. If LOWER_CASE_FILE is given, the package name as it appears on disk (in both the file name and install destination) will be first converted to lower case. lowercase era fr fr. ๐
If DESTINATION is not specified, a platform-specific default is used.
Several options may be used to specify package metadata:
VERSION <version>โ the version of the package ๐ and yes, the<version>has to conform to the specified schema, no freestyling. Wanna know how that version actually gets used when a consumer asks for the package? Go read Version Selection (CPS), it's all laid out there.COMPAT_VERSION <version>โ the oldest version for which the package still provides compatibility. If you don't give it,COMPAT_VERSIONis implicitly taken to equal the package'sVERSION, which is basically saying "no backwards compatibility, we're thriving in the present" ๐.VERSION_SCHEMA <schema>โ the schema that the package's version number(s) follow (bothVERSIONandCOMPAT_VERSION, bestie, both of them). Here's the tea: if you don't provide this option, no schema gets written to the.cpsfile at all, but CPS says the schema is assumed to besimplein those cases. Peepversion_schemaathttps://cps-org.github.io/cps/schema.html#version-schemafor the deets and the list of officially supported schemas โ but โ ๏ธ be aware the spec may include schemas that CMake does not support. For the list thatfind_package()actually supports, see Version Selection (CPS).DEFAULT_TARGETS <target>...โ targets used when a consumer requests linking to the package name instead of to specific components. Like a little default friend group ๐ซถ.DEFAULT_CONFIGURATIONS <config>...โ an ordered list of configurations consumers should prefer when there's no exact match, and no mapping of the consumer's configuration onto the package's available configurations. If you skip this, CMake just falls back to the package's available configurations in an unspecified order (so, chaos, but legal chaos).LICENSE <license-string>โ Added in version 4.2. A System Package Data Exchange (SPDX) License Expression that describes the license(s) of the project as a whole โ and that includes documentation, resources, or other materials distributed with the project, in addition to software artifacts. Need identifiers? The SPDX License List athttps://spdx.org/licenses/has the commonly used licenses and their identifiers. The license of individual components comes from theSPDX_LICENSEproperty of their respective targets ๐.DEFAULT_LICENSE <license-string>โ Added in version 4.2. Also a System Package Data Exchange (SPDX) License Expression, except this one describes the license(s) of any components that do not otherwise specify their license(s). The fallback bestie ๐.DESCRIPTION <description-string>โ Added in version 4.1. An informational description of the project. Recommendation: keep it relatively short, usually no more than a few words. We are not writing a memoir here โจ.HOMEPAGE_URL <url-string>โ Added in version 4.1. An informational canonical home URL for the project. The main character address ๐.
So here's how the metadata inheritance thing works, and it's lowkey iconic: by default, if the <package-name> you specified matches the current CMake PROJECT_NAME, package metadata gets inherited from the project. Use the PROJECT <project-name> option if you want to inherit metadata from a different project. And if NO_PROJECT_METADATA is specified, that automatic inheritance is disabled entirely, periodt. Either way โ any metadata values you specify right there in the install command take precedence. Always ๐
.
Now, APPENDIX โ this one is a vibe. If APPENDIX is specified, instead of generating a top level package specification, the specified targets get exported as an appendix to the named package. Appendices let you separate less commonly used targets (along with their external dependencies) from the rest of a package. Why do we care? Because it lets consumers ignore transitive dependencies for targets they don't even use, and it also lets a single logical "package" be composed of artifacts produced by multiple build trees. Composed, like a fit ๐ฅ.
But appendices are not permitted to change basic package metadata. So none of PROJECT, VERSION, COMPAT_VERSION, VERSION_SCHEMA, DEFAULT_TARGETS or DEFAULT_CONFIGURATIONS may be specified in combination with APPENDIX. Don't even try it. Also, it's strongly recommended that your use of LOWER_CASE_FILE be consistent between the main package and any appendices ๐ซถ.
Note ๐ฆ โ Because it's intended to be portable across multiple build tools, CPS may not support all features that are allowed in CMake-script exports. Specifically? Support for generator expressions in interface properties is limited at this time to configuration-dependent expressions. That's the limit, bestie, respect it.
Note ๐ธ โ This is the recommended way to generate Common Package Specification package information for a project. But for distributors whose users may require CPS package information when making changes to the project's build files isn't practical, there's theCMAKE_INSTALL_EXPORTS_AS_PACKAGE_INFOvariable, which may be used to generate.cpsfiles frominstall(EXPORT)calls. Usage and caveats live in that variable's documentation โ go read it, iykyk.
๐ install(RUNTIME_DEPENDENCY_SET <set-name> [...])
Added in version 3.21. Okay so this one installs a runtime dependency set ๐ฆ:
install(RUNTIME_DEPENDENCY_SET <set-name>
[[LIBRARY|RUNTIME|FRAMEWORK]
[DESTINATION <dir>]
[PERMISSIONS <permission>...]
[CONFIGURATIONS <config>...]
[COMPONENT <component>]
[NAMELINK_COMPONENT <component>]
[OPTIONAL] [EXCLUDE_FROM_ALL]
]...
[PRE_INCLUDE_REGEXES <regex>...]
[PRE_EXCLUDE_REGEXES <regex>...]
[POST_INCLUDE_REGEXES <regex>...]
[POST_EXCLUDE_REGEXES <regex>...]
[POST_INCLUDE_FILES <file>...]
[POST_EXCLUDE_FILES <file>...]
[DIRECTORIES <dir>...]
)
What it does: installs a runtime dependency set that was previously created by one or more install(TARGETS) or install(IMPORTED_RUNTIME_ARTIFACTS) commands. The dependencies of targets belonging to a runtime dependency set go into the RUNTIME destination and component on DLL platforms, and into the LIBRARY destination and component on non-DLL platforms. macOS frameworks? Those land in the FRAMEWORK destination and component ๐.
Big important thing: targets built within the build tree will never be installed as runtime dependencies, nor will their own dependencies โ unless the targets themselves are installed with install(TARGETS). Like, that's the rule ๐ซถ.
The generated install script calls file(GET_RUNTIME_DEPENDENCIES) on the build-tree files to calculate the runtime dependencies. The build-tree executable files get passed as the EXECUTABLES argument, the build-tree shared libraries as the LIBRARIES argument, and the build-tree modules as the MODULES argument. On macOS, if one of the executables is a MACOSX_BUNDLE, that executable is passed as the BUNDLE_EXECUTABLE argument โ and heads up, at most one such bundle executable may be in the runtime dependency set on macOS. The MACOSX_BUNDLE property has no effect on other platforms. And ngl, file(GET_RUNTIME_DEPENDENCIES) only supports collecting runtime dependencies for Windows, Linux and macOS platforms, so install(RUNTIME_DEPENDENCY_SET) has that exact same limitation. No cap ๐.
The following sub-arguments get forwarded through as the corresponding arguments to file(GET_RUNTIME_DEPENDENCIES) โ for those that provide a non-empty list of directories, regular expressions or files, that is. They all support generator expressions:
DIRECTORIES <dir>...PRE_INCLUDE_REGEXES <regex>...PRE_EXCLUDE_REGEXES <regex>...POST_INCLUDE_REGEXES <regex>...POST_EXCLUDE_REGEXES <regex>...POST_INCLUDE_FILES <file>...POST_EXCLUDE_FILES <file>...
Note ๐ โ This command supersedes theinstall_targets()command and thePRE_INSTALL_SCRIPTandPOST_INSTALL_SCRIPTtarget properties. It also replaces theFILESforms of theinstall_files()andinstall_programs()commands. And the processing order of these install rules relative to the ones generated byinstall_targets(),install_files(), andinstall_programs()? Not defined. So don't be out here relying on an order that doesn't exist ๐.
๐ install(SBOM <sbom-name> [...])
Added in version 4.3.
Note ๐ง โ Experimental. Gated by CMAKE_EXPERIMENTAL_GENERATE_SBOM. Do not come for me if the experimental gate bites, that's just how it is.
Installs a Software Bill of Material, or "SBOM", which describes the project ๐:
install(SBOM <sbom-name> EXPORTS <export-names>...
[PROJECT <project-name>|NO_PROJECT_METADATA]
[DESTINATION <dir>]
[VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]
[LICENSE <license-string>]
[DESCRIPTION <description-string>]
[HOMEPAGE_URL <url-string>]
[PACKAGE_URL <url-string>]
[FORMAT <string>])
okay so the SBOM form? it literally generates a Software Bill of Material โ yes that's "Bill of Material," singular, we don't make the rules โ for a given project and installs it as part of the project installation. think of it as a machine-readable receipt: it describes the project's targets, the libraries they link, and all the related metadata like versions and license info. CMake currently generates SBOM files using the System Package Data Exchange <https://spdx.dev/> 3.0 specification in its JSON-LD representation, selected by the FORMAT option, but the interface is designed so that future CMake releases can support additional SBOM formats or schema versions. forward compatible, we love to see it ๐
Target installations get associated with each export <export-names> in the EXPORTS list using the EXPORTS option of the install(TARGETS) signature documented above. a single SBOM can cover multiple export sets โ targets from all listed exports get aggregated into one document, no gatekeeping. If DESTINATION isn't specified, a platform-specific default is used.
Several options may be used to specify package metadata:
VERSION <version>โ the package version, given as a series of non-negative integer components, i.e.<major>[.<minor>[.<patch>[.<tweak>]]]. Seeproject(VERSION)<#command:project> for more info, bestie.FORMAT <string>โ the format the SBOM should be exported in, and it has to be an expression of the form<format>[-<version>][+<representation>]. CMake currently supports the JSON-LD serialization of System Package Data Exchange <https://spdx.dev/> v3.0.1 (spdxorspdx-3.0.1+json), which is also the default ifFORMATis not specified. iconic default behavior honestly โจHOMEPAGE_URL <url-string>โ an informational canonical home URL for the project ๐PACKAGE_URL <url-string>โ an informational canonical package URL for the project ๐ฆLICENSE <license-string>โ a System Package Data Exchange <https://spdx.dev/> (SPDX) License Expression <https://spdx.github.io/spdx-spec/v3.0.1/annexes/spdx-license-expressions/> that describes the license(s) of the project as a whole โ and that includes documentation, resources, or other materials distributed with the project, on top of the software artifacts, not just the code. check the SPDX License List <https://spdx.org/licenses/> for a list of commonly used licenses and their identifiers, super handy.DESCRIPTION <description-string>โ an informational description of the project. it's recommended that this be a relatively short string, usually no more than a few words. like a bio, not a memoir ๐
By default, if the specified <sbom-name> matches the current CMake PROJECT_NAME <#variable:PROJECT_NAME>, the sbom metadata will be inherited from the project. the PROJECT <project-name> option lets you name a different project to inherit metadata from. and if NO_PROJECT_METADATA is specified, that automatic inheritance is switched off entirely. in any case, any metadata values specified in the install command will take precedence โ what you write in the install command wins, periodt ๐
โ ๏ธ heads up: an SBOM file cannot be generated for targets that have generator expressions in theirLINK_LIBRARIES<#prop_tgt:LINK_LIBRARIES> orINTERFACE_LINK_LIBRARIES<#prop_tgt:INTERFACE_LINK_LIBRARIES> properties โ unless those generator expressions are guarded byLINK_ONLY<#genex:LINK_ONLY>. no cap, that's the rule.
โจ Examples
Example: Install Targets with Per-Artifact Components
consider a project that defines targets with different artifact kinds:
add_executable(myExe myExe.c)
add_library(myStaticLib STATIC myStaticLib.c)
target_sources(myStaticLib PUBLIC FILE_SET HEADERS FILES myStaticLib.h)
add_library(mySharedLib SHARED mySharedLib.c)
target_sources(mySharedLib PUBLIC FILE_SET HEADERS FILES mySharedLib.h)
set_property(TARGET mySharedLib PROPERTY SOVERSION 1)
so we can call install(TARGETS) with <artifact-kind> arguments to specify different options for each kind of artifact:
install(TARGETS
myExe
mySharedLib
myStaticLib
RUNTIME # Following options apply to runtime artifacts.
COMPONENT Runtime
LIBRARY # Following options apply to library artifacts.
COMPONENT Runtime
NAMELINK_COMPONENT Development
ARCHIVE # Following options apply to archive artifacts.
COMPONENT Development
DESTINATION lib/static
FILE_SET HEADERS # Following options apply to file set HEADERS.
COMPONENT Development
)
This will:
- Install
myExeto<prefix>/bin, the defaultRUNTIMEartifact destination, as part of theRuntimecomponent. - On non-DLL platforms:
- Install
libmySharedLib.so.1to<prefix>/lib, the defaultLIBRARYartifact destination, as part of theRuntimecomponent. - Install the
libmySharedLib.so"namelink" (symbolic link) to<prefix>/lib, the defaultLIBRARYartifact destination, as part of theDevelopmentcomponent.
- Install
- On DLL platforms:
- Install
mySharedLib.dllto<prefix>/bin, the defaultRUNTIMEartifact destination, as part of theRuntimecomponent. - Install
mySharedLib.libto<prefix>/lib/static, the specifiedARCHIVEartifact destination, as part of theDevelopmentcomponent.
- Install
- Install
myStaticLibto<prefix>/lib/static, the specifiedARCHIVEartifact destination, as part of theDevelopmentcomponent. - Install
mySharedLib.handmyStaticLib.hto<prefix>/include, the default destination for a file set of typeHEADERS, as part of theDevelopmentcomponent.
slay, everything's where it should be ๐ธ
Example: Install Targets to Per-Config Destinations
Each install(TARGETS) call installs a given target output artifact <#output-artifacts> to at most one DESTINATION, but the install rule itself may be filtered by the CONFIGURATIONS option. so if you want to install to a different destination for each configuration, you need one call per configuration. for example, this code:
install(TARGETS myExe
CONFIGURATIONS Debug
RUNTIME
DESTINATION Debug/bin
)
install(TARGETS myExe
CONFIGURATIONS Release
RUNTIME
DESTINATION Release/bin
)
will install myExe to <prefix>/Debug/bin in the Debug configuration, and to <prefix>/Release/bin in the Release configuration. two calls, two vibes, zero confusion ๐
๐ ๏ธ Generated Installation Script
๐จ Note: use of this feature is not recommended. please consider using the cmake --install <#cmdoption-cmake-install> instead. like, genuinely.
The install() command generates a file, cmake_install.cmake, inside the build directory, which is used internally by the generated install target and by CPack. You can also invoke this script manually with cmake -P <#cmdoption-cmake-P>. This script accepts several variables:
COMPONENTโ set this variable to install only a single CPack component instead of all of them. for example, if you only want to install theDevelopmentcomponent, runcmake -DCOMPONENT=Development -P cmake_install.cmake.BUILD_TYPEโ set this variable to change the build type if you're using a multi-config generator. for example, to install with theDebugconfiguration, runcmake -DBUILD_TYPE=Debug -P cmake_install.cmake.DESTDIRโ this one is an environment variable rather than a CMake variable. it lets you change the installation prefix on UNIX systems. seeDESTDIR<#envvar:DESTDIR> for details. ๐ง
link_directories ๐ฆ
Add directories in which the linker will look for libraries.
link_directories([AFTER|BEFORE] directory1 [directory2 ...])
Adds the paths in which the linker should search for libraries. Relative paths given to this command are interpreted as relative to the current source directory, see CMP0015 <#policy:CMP0015>.
The command will apply only to targets created after it is called. so timing matters bestie โฐ
Added in version 3.13: The directories are added to the LINK_DIRECTORIES <#prop_dir:LINK_DIRECTORIES> directory property for the current CMakeLists.txt file, converting relative paths to absolute as needed. See the cmake-buildsystem(7) <#manual:cmake-buildsystem(7)> manual for more on defining buildsystem properties.
Added in version 3.13: By default the directories specified are appended onto the current list of directories. This default behavior can be changed by setting CMAKE_LINK_DIRECTORIES_BEFORE <#variable:CMAKE_LINK_DIRECTORIES_BEFORE> to ON. By using AFTER or BEFORE explicitly, you can select between appending and prepending, independent of the default. your call ๐
Added in version 3.13: Arguments to link_directories may use "generator expressions" with the syntax "$<...>". See the cmake-generator-expressions(7) <#manual:cmake-generator-expressions(7)> manual for available expressions.
๐ซถ Note: this command is rarely necessary and should be avoided where there are other choices. Prefer to pass full absolute paths to libraries where possible, since this ensures the correct library will always be linked. Thefind_library()<#command:find_library> command provides the full path, which can generally be used directly in calls totarget_link_libraries()<#command:target_link_libraries>. Situations where a library search path may be needed include: - Project generators like Xcode <#generator:Xcode> where the user can switch target architecture at build time, but a full path to a library cannot be used because it only provides one architecture (i.e. it is not a universal binary). - Libraries may themselves have other private library dependencies that expect to be found via RPATH mechanisms, but some linkers are not able to fully decode those paths (e.g. due to the presence of things like$ORIGIN).
If a library search path must be provided, prefer to localize the effect where possible by using the target_link_directories() <#command:target_link_directories> command rather than link_directories(). The target-specific command can also control how the search directories propagate to other dependent targets โ which is, honestly, the main character energy we want ๐โจ
See Also
target_link_directories()target_link_libraries()
link_libraries โ link libs to literally every target you add afterwards ๐ซถ
okay so this is the "set the vibe for the whole directory" version of linking:
link_libraries([item1 [item2 [...]]]
[[debug|optimized|general] <item>] ...)
It says: use these libraries (or flags) when linking any target created later in the current directory or below, by stuff like add_executable() or add_library(). For what the arguments actually mean, go look at target_link_libraries() โ same energy, different scope.
Note: bestie, target_link_libraries() should be preferred whenever possible. Library dependencies get chained automatically anyway, so specifying link libraries directory-wide is rarely needed. It's giving "why would you" energy. ๐ญ
project โ name your project, make it official โจ
Sets the name of the project.
Synopsis
project(<PROJECT-NAME> [<language-name>...])
project(<PROJECT-NAME>
[VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]
[COMPAT_VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]
[SPDX_LICENSE <license-string>]
[DESCRIPTION <description-string>]
[HOMEPAGE_URL <url-string>]
[LANGUAGES <language-name>...])
It sets the project name and stores it in PROJECT_NAME. And like, when you call it from the top-level CMakeLists.txt, it also stashes the project name in CMAKE_PROJECT_NAME. main character behavior, honestly ๐
It also sets these variables:
PROJECT_SOURCE_DIR,<PROJECT-NAME>_SOURCE_DIRโ absolute path to the source directory for the project ๐PROJECT_BINARY_DIR,<PROJECT-NAME>_BINARY_DIRโ absolute path to the binary directory for the project ๐PROJECT_IS_TOP_LEVEL,<PROJECT-NAME>_IS_TOP_LEVELโ Added in version 3.21. Boolean value indicating whether the project is top-level ๐
More variables get set by the optional arguments down in Options โ and where an option isn't given, its corresponding variable is set to the empty string. No vibes, just emptiness. ๐ซฅ
Heads up: variables of the form <name>_SOURCE_DIR and <name>_BINARY_DIR may also be set by other commands before project() is called (peep the FetchContent_MakeAvailable() command for one example). Projects should not rely on <PROJECT-NAME>_SOURCE_DIR or <PROJECT-NAME>_BINARY_DIR holding a particular value outside of the scope of the call to project() or one of its child scopes. Don't get attached, basically ๐
Changed in version 3.30: <PROJECT-NAME>_SOURCE_DIR, <PROJECT-NAME>_BINARY_DIR, and <PROJECT-NAME>_IS_TOP_LEVEL, if already set as normal variables when project(<PROJECT-NAME> ...) is called, are updated by the call. Cache entries by the same names are always set as before. See release notes for 3.30.3, 3.30.4, and 3.30.5 for the deets.
Changed in version 3.31: <PROJECT-NAME>_SOURCE_DIR, <PROJECT-NAME>_BINARY_DIR, and <PROJECT-NAME>_IS_TOP_LEVEL are always set as normal variables by project(<PROJECT-NAME> ...). See policy CMP0180. Cache entries by the same names are always set as before. slay, consistency ๐
Options
the options are, in order:
VERSION <version>โ Optional; may not be used unless policyCMP0048is set toNEW. ๐ค It takes a<version>argument made of non-negative integer components, i.e.<major>[.<minor>[.<patch>[.<tweak>]]], and sets these variables:PROJECT_VERSION,<PROJECT-NAME>_VERSIONPROJECT_VERSION_MAJOR,<PROJECT-NAME>_VERSION_MAJORPROJECT_VERSION_MINOR,<PROJECT-NAME>_VERSION_MINORPROJECT_VERSION_PATCH,<PROJECT-NAME>_VERSION_PATCHPROJECT_VERSION_TWEAK,<PROJECT-NAME>_VERSION_TWEAK
Added in version 3.12: when the project() command is called from the top-level CMakeLists.txt, the version also gets stored in the variable CMAKE_PROJECT_VERSION. ๐ฅ
COMPAT_VERSION <version>โ Added in version 4.3. Optional; requiresVERSIONalso be set. It takes a<version>argument made of non-negative integer components, i.e.<major>[.<minor>[.<patch>[.<tweak>]]], and sets:PROJECT_COMPAT_VERSION,<PROJECT-NAME>_COMPAT_VERSION
When project() is called from the top-level CMakeLists.txt, the compatibility version is also stored in the variable CMAKE_PROJECT_COMPAT_VERSION. ๐
SPDX_LICENSE <license-string>โ Added in version 4.3. Optional. Sets:PROJECT_SPDX_LICENSE,<PROJECT-NAME>_SPDX_LICENSE
...to <license-string>, which shall be a System Package Data Exchange (SPDX) License Expression that describes the license(s) of the project as a whole โ including documentation, resources, or other materials distributed with the project, in addition to software artifacts. Peep the SPDX License List for a list of commonly used licenses and their identifiers. And see the SPDX_LICENSE property for specifying the license(s) on individual software artifacts. ๐
Note: the project license is not used to initialize theSPDX_LICENSEproperty of individual targets. This is on purpose โ it allows the package license and default component license, which are specified when exporting package information, to stay meaningful. Only Common Package Specification exports make use of this information. The project license is inherited as the package license in some cases tho. Refer to thePROJECToption and related documentation of theexport()andinstall()commands for more info. iykyk ๐ง
DESCRIPTION <description-string>โ Added in version 3.9. Optional. Sets:PROJECT_DESCRIPTION,<PROJECT-NAME>_DESCRIPTION
...to <description-string>. Recommendation: keep it relatively short, usually no more than a few words. nobody's reading a novel in a description bestie โ๏ธ When project() is called from the top-level CMakeLists.txt, the description is also stored in the variable CMAKE_PROJECT_DESCRIPTION. Added in version 3.12: added the <PROJECT-NAME>_DESCRIPTION variable.
HOMEPAGE_URL <url-string>โ Added in version 3.12. Optional. Sets:PROJECT_HOMEPAGE_URL,<PROJECT-NAME>_HOMEPAGE_URL
...to <url-string>, which should be the canonical home URL for the project. ๐ When project() is called from the top-level CMakeLists.txt, the URL also is stored in the variable CMAKE_PROJECT_HOMEPAGE_URL.
LANGUAGES <language-name>...โ Optional. Can also be specified without theLANGUAGESkeyword per the first, short signature. Selects which programming languages are needed to build the project. The supported languages are:CCXXโ C++CSharpโ Added in version 3.8. C#CUDAโ Added in version 3.8.OBJCโ Added in version 3.16. Objective-COBJCXXโ Added in version 3.16. Objective-C++FortranHIPโ Added in version 3.21.ISPCโ Added in version 3.18.Swiftโ Added in version 3.15.ASMโ Assembly language supported by the C compiler. If enablingASM, list it last so that CMake can check whether the C orCXXcompiler supports assembly. order matters, bestie ๐จASM_NASMโ Netwide AssemblerASM_MARMASMโ Added in version 3.26. Microsoft Assembler (ARM, ARM64)ASM_MASMโ Microsoft Assembler (x86, x64)ASM_POASMโ Added in version 4.4. Pelles C toolchain assembler.ASM-ATT
By default C and CXX are enabled if no language options are given. Specify language NONE, or use the LANGUAGES keyword and list no languages, to skip enabling any languages. โ๏ธ
The variables set through the VERSION, COMPAT_VERSION, SPDX_LICENSE, DESCRIPTION and HOMEPAGE_URL options are intended for use as default values in package metadata and documentation. The export() and install() commands use these accordingly when generating Common Package Specification package descriptions. ๐๏ธ
Code Injection
okay this is the sneaky-fun part ๐ A bunch of variables can be defined by the user to specify files to include at different points during the execution of the project() command. Here's the outline of the steps performed during a project() call:
- Added in version 3.15: For every
project()call, regardless of the project name, include the file(s) and module(s) named byCMAKE_PROJECT_INCLUDE_BEFORE, if set. ๐ช - Added in version 3.17: If the
project()command specifies<PROJECT-NAME>as its project name, include the file(s) and module(s) named byCMAKE_PROJECT_<PROJECT-NAME>_INCLUDE_BEFORE, if set. - Set all the project-specific variables that the Synopsis and Options sections up above were yapping about. ๐
- For the very first
project()call only โ pay attention bestie, this is a one-time thing:- If
CMAKE_TOOLCHAIN_FILEis set, it gets read at least once. It may be read multiple times, and ngl it may also get read again later when languages are being enabled (see below). ๐ - The variables describing the host and target platforms get set. Language-specific variables might or might not be set at this point, depending on vibes. On the first run, the only language-specific variables that could possibly be defined are the ones a toolchain file set. On subsequent runs, language-specific variables cached from a previous run may be set. โจ
- Added in version 3.24: Every file listed in
CMAKE_PROJECT_TOP_LEVEL_INCLUDESgets included, if that variable is set. After that, CMake ignores the variable forever. Ghosted, basically. ๐ป
- If
- Enable whatever languages were specified in the call โ or the default languages if none were given. The toolchain file may be re-read when a language is enabled for the first time. ๐ฆ
- Added in version 3.15: For every
project()call, no matter what the project name is, include the file(s) and module(s) named byCMAKE_PROJECT_INCLUDE, if it's set. ๐ - If the
project()command specifies<PROJECT-NAME>as its project name, include the file(s) and module(s) named byCMAKE_PROJECT_<PROJECT-NAME>_INCLUDE, if it's set.
Usage ๐ฌ
The top-level CMakeLists.txt for a project must contain a literal, direct call to the project() command. Loading one through the include() command is not sufficient โ sorry, sneaky workaround, it doesn't count. ๐
If no such call exists, CMake issues a warning and pretends there's a project(Project) at the top just so it can enable the default languages (C and CXX). Close enough bestie ๐
Note: Call theproject()command near the top of the top-levelCMakeLists.txt, but after callingcmake_minimum_required(). It's majorly important to establish version and policy settings before invoking other commands whose behavior those settings may affect โ which is exactly whyproject()issues a warning if you don't keep that order. See also policyCMP0000. ๐
remove_definitions ๐งน
Removes compile definitions that were added by add_compile_definitions() or add_definitions():
remove_definitions([<definitions>...])
The arguments are:
<definitions>...โ zero or more compile definitions. Zero! Or more! Your call.
This command can also be used to remove any flags added by add_definitions(), but fr fr its intended job is removing preprocessor definitions passed with -D or /D. ๐งผ
Examples ๐ธ
In the following example, targets in the current directory scope will end up with only BAZ and QUUX compile definitions:
add_compile_definitions(FOO BAR BAZ -DQUUX)
# ...
remove_definitions(-DFOO -DBAR)
set_source_files_properties ๐
Source files can have properties that affect how they're built. Iconic. ๐
set_source_files_properties(<files> ...
[DIRECTORY <dirs> ...]
[TARGET_DIRECTORY <targets> ...]
PROPERTIES <prop1> <value1>
[<prop2> <value2>] ...)
Sets properties associated with source files using a key/value paired list. Very demure, very key-value. ๐
Added in version 3.18: By default, source file properties are only visible to targets added in the same directory (CMakeLists.txt). You can set visibility in other directory scopes using one or both of these options:
DIRECTORY <dirs>...โ the source file properties will be set in each of the<dirs>directories' scopes. CMake must already know about each of these source directories, either because they were added through a call toadd_subdirectory()or because it's the top level source directory. Relative paths are treated as relative to the current source directory. ๐TARGET_DIRECTORY <targets>...โ the source file properties will be set in each of the directory scopes where any of the specified<targets>were created. Which means the<targets>must already exist, obviously. ๐ฏ
Use get_source_file_property() to get property values back out. See also the set_property(SOURCE) command.
Note: The GENERATED source file property may be globally visible. Go read its docs for the details, iykyk. ๐
See Also ๐ซ
define_property()get_source_file_property()- Properties on Source Files โ that's where the full list of properties known to CMake lives ๐๏ธ
set_target_properties ๐ฏ
Targets can have properties that affect how they're built too. Equality! โ
set_target_properties(<targets> ...
PROPERTIES <prop1> <value1>
[<prop2> <value2>] ...)
Sets properties on targets. The syntax is: list all the targets you want to change, then hand over the values you want to set. You can use literally any prop/value pair you want and pull it back out later with the get_property() or get_target_property() command. ๐ซถ
Alias Targets do not support setting target properties. Not them. ๐
See Also ๐ซ
define_property()get_target_property()- the more general
set_property()command - Properties on Targets โ the full list of properties known to CMake ๐
set_tests_properties ๐งช
Set a property of the tests. Let's get testing bestie ๐
set_tests_properties(<tests>...
[DIRECTORY <dir>]
PROPERTIES <prop1> <value1>
[<prop2> <value2>]...)
Sets a property for the tests. If the test isn't found, CMake will report an error โ no quiet failing around here. ๐ญ
Test property values may be specified using generator expressions for tests created by the add_test(NAME) signature. Fancy. โจ
Added in version 3.28: Visibility can be set in other directory scopes using this option:
DIRECTORY <dir>โ the test properties will be set in the<dir>directory's scope. CMake must already know about this directory, either because it was added through a call toadd_subdirectory()or because it's the top level source directory. Relative paths are treated as relative to the current source directory. Also,<dir>may reference a binary directory. ๐
See Also ๐ซ
add_test()define_property()- the more general
set_property()command - Properties on Tests โ the full list of properties known to CMake ๐
source_group ๐๏ธ
Define a grouping for source files in IDE project generation. There are two different signatures to create source groups. Two! Choose your fighter. ๐ฅ
source_group(<name> [FILES <src>...] [REGULAR_EXPRESSION <regex>])
source_group(TREE <root> [PREFIX <prefix>] [FILES <src>...])
Defines a group into which sources will be placed in project files. The whole point here is setting up file tabs in Visual Studio. The group is scoped to the directory where the command is called, and it applies to sources in targets created in that directory. ๐๏ธ
The options are:
TREEโ Added in version 3.8. CMake will automatically detect, from the<src>files' paths, which source groups it needs to create, so that the structure of source groups mirrors the actual files-and-directories structure of the project. The paths of<src>files get cut so they're relative to<root>. The command fails if the paths withinsrcdon't start withroot. No cap, it will just error out. ๐ณPREFIXโ Added in version 3.8. The source group and files located directly in the<root>path will be placed in<prefix>source groups.FILESโ any source file specified explicitly will be placed in group<name>. Relative paths are interpreted with respect to the current source directory. Added in version 4.3: the arguments toFILESmay use generator expressions. ๐REGULAR_EXPRESSIONโ any source file whose name matches the regular expression will be placed in group<name>. ๐
If a source file matches multiple groups, the last group that explicitly lists the file with FILES wins โ if any group does. If no group explicitly lists the file, the last group whose regular expression matches the file wins. Last one standing, periodt. ๐
The <name> of the group and the <prefix> argument may contain forward slashes or backslashes to specify subgroups. Backslashes need to be escaped appropriately:
source_group(base/subdir ...)
source_group(outer\\inner ...)
source_group(TREE <root> PREFIX sources\\inc ...)
Added in version 3.18: you're allowed to use forward slashes (/) to specify subgroups. ๐ธ
For backwards compatibility, this short-hand signature:
source_group(<name> <regex>)
is equivalent to:
source_group(<name> REGULAR_EXPRESSION <regex>)
target_compile_definitions ๐ฅ
Add compile definitions to a target. Let's goooo ๐ฅ
target_compile_definitions(<target>
<INTERFACE|PUBLIC|PRIVATE> <definition>...
[<INTERFACE|PUBLIC|PRIVATE> <definition>... ...])
Specifies compile definitions to use when compiling a given <target>. The named <target> must have been created by a command such as add_executable() or add_library(), and it must not be an ALIAS target. Aliases stay unbothered. ๐
The INTERFACE, PUBLIC and PRIVATE keywords are required to specify the scope of the following arguments. PRIVATE and PUBLIC items will populate the COMPILE_DEFINITIONS property of <target>. PUBLIC and INTERFACE items will populate the INTERFACE_COMPILE_DEFINITIONS property of <target>. The following arguments specify the compile definitions themselves. Repeated calls for the same <target> append items in the order called. ๐
Added in version 3.11: you can also set INTERFACE items on IMPORTED targets. ๐ซถ
Ok so quick reminder before we dip: everything you pass to target_compile_definitions can use generator expressions with the syntax $<...>. Peep the cmake-generator-expressions(7) manual for the whole list of expressions you can use, and the cmake-buildsystem(7) manual if you wanna know more about defining buildsystem properties. ๐
Any leading -D on an item gets yeeted. Empty items are literally ignored. So these four are all the same thing, no cap:
target_compile_definitions(foo PUBLIC FOO)
target_compile_definitions(foo PUBLIC -DFOO) # -D removed
target_compile_definitions(foo PUBLIC "" FOO) # "" ignored
target_compile_definitions(foo PUBLIC -D FOO) # -D becomes "", then ignored
Definitions can optionally have values too, slay:
target_compile_definitions(foo PUBLIC FOO=1)
Heads up bestie: lots of compilers treat-DFOOas equivalent to-DFOO=1, but other tools out here may not recognize that in all circumstances (e.g. IntelliSense). ๐ So don't just assume everyone's on the same page.
โจ See Also โจ
add_compile_definitions()target_compile_features()target_compile_options()target_include_directories()target_link_libraries()target_link_directories()target_link_options()target_precompile_headers()target_sources()
๐ target_compile_features ๐
Added in version 3.1. ๐
Adds the compiler features you expect a target to need.
target_compile_features(<target>
{INTERFACE|PUBLIC|PRIVATE} <feature>...
[{INTERFACE|PUBLIC|PRIVATE} <feature>...]...)
So this one specifies the compiler features required when compiling a given target. If the feature isn't listed in the CMAKE_C_COMPILE_FEATURES, CMAKE_CUDA_COMPILE_FEATURES, or CMAKE_CXX_COMPILE_FEATURES variables, CMake will report an error. Rude but fair. And if using the feature needs an extra compiler flag โ like -std=gnu++11 for example โ that flag gets added automatically, no manual labor from you. ๐
The INTERFACE, PUBLIC and PRIVATE keywords are required, bestie, because they specify the scope of the features. PRIVATE and PUBLIC items populate the COMPILE_FEATURES property of <target>. PUBLIC and INTERFACE items populate the INTERFACE_COMPILE_FEATURES property of <target>. And repeating calls for the same <target>? They append items. Obsessed with the consistency.
Added in version 3.11: you're allowed to set INTERFACE items on IMPORTED targets. โจ
The named <target> must have been created by a command like add_executable() or add_library(), and it must not be an ALIAS target. Periodt.
Arguments to target_compile_features may use generator expressions with the syntax $<...>. See the cmake-generator-expressions(7) manual for available expressions, and the cmake-compile-features(7) manual for info on compile features plus a whole list of supported compilers. ๐ฆ
See Also
target_compile_definitions()target_compile_options()target_include_directories()target_link_libraries()target_link_directories()target_link_options()target_precompile_headers()target_sources()
๐ target_compile_options ๐
Adds compile options to a target. Career-defining behavior.
target_compile_options(<target> [BEFORE]
{INTERFACE|PUBLIC|PRIVATE} <item>...
[{INTERFACE|PUBLIC|PRIVATE} <item>...]...)
This adds options to the COMPILE_OPTIONS or INTERFACE_COMPILE_OPTIONS target properties. Those options get used when compiling the given <target>, which โ you guessed it โ must have been created by a command like add_executable() or add_library(), and must not be an ALIAS target. ๐ธ
๐ Note: these options are not used when linking the target. If that's what you need, the target_link_options() command is right there waiting for you.
Arguments
If BEFORE is specified, the content gets prepended to the property instead of appended. And yeah, see policy CMP0101 โ it affects whether BEFORE gets ignored in certain cases. ๐
The INTERFACE, PUBLIC and PRIVATE keywords are required to specify the scope of the following arguments. PRIVATE and PUBLIC items populate the COMPILE_OPTIONS property of <target>. PUBLIC and INTERFACE items populate the INTERFACE_COMPILE_OPTIONS property of <target>. The arguments after that are the actual compile options. Repeated calls for the same <target> append items in the order they were called โ order matters, iykyk.
Added in version 3.11: you can set INTERFACE items on IMPORTED targets. โจ
Arguments to target_compile_options may use generator expressions with the syntax $<...>. See the cmake-generator-expressions(7) manual for the available expressions, and the cmake-buildsystem(7) manual for more on defining buildsystem properties.
Option De-duplication
So the final set of options used for a target is built by accumulating options from the current target and the usage requirements of its dependencies. Then that set of options gets de-duplicated so nothing repeats. Clean. ๐ง
Added in version 3.12: ok so while de-duplication is great for individual options, the de-duplication step can break up option groups. Like, -option A -option B becomes -option A B. Not the vibe. ๐ญ So you can specify a group of options using shell-like quoting along with a SHELL: prefix. The SHELL: prefix gets dropped, and the rest of the option string is parsed using separate_arguments() in UNIX_COMMAND mode. For example, "SHELL:-option A" "SHELL:-option B" becomes -option A -option B. Slay, order preserved. ๐
See Also
- This command can be used to add any options. However, for adding preprocessor definitions and include directories, it's recommended to use the more specific commands
target_compile_definitions()andtarget_include_directories(). Bestie, use the right tool for the job. - For directory-wide settings, there's the
add_compile_options()command. - For file-specific settings, there's the source file property
COMPILE_OPTIONS. - This command adds compile options for all languages in a target. Use the
COMPILE_LANGUAGEgenerator expression to specify per-language compile options. ๐ target_compile_features()target_link_libraries()target_link_directories()target_link_options()target_precompile_headers()target_sources()CMAKE_<LANG>_FLAGSandCMAKE_<LANG>_FLAGS_<CONFIG>add language-wide flags passed to all invocations of the compiler. That includes invocations that drive compiling and those that drive linking. ๐- The
CheckCompilerFlagmodule, to check whether the compiler even supports a given flag. Very much a vibe check for your compiler.
๐ฆ target_include_directories ๐ฆ
Adds include directories to a target.
target_include_directories(<target> [SYSTEM] [AFTER|BEFORE]
{INTERFACE|PUBLIC|PRIVATE} <dir>...
[{INTERFACE|PUBLIC|PRIVATE} <dir>...]...)
Specifies the include directories to use when compiling a given target. The named <target> must have been created by a command such as add_executable() or add_library(), and must not be an ALIAS target. ๐
By using AFTER or BEFORE explicitly, you can pick between appending and prepending, independent of the default. Main character energy: you decide.
The INTERFACE, PUBLIC and PRIVATE keywords are required to specify the scope of the following arguments. PRIVATE and PUBLIC items populate the INCLUDE_DIRECTORIES property of <target>. PUBLIC and INTERFACE items populate the INTERFACE_INCLUDE_DIRECTORIES property of <target>. The arguments after the keyword are the include directories themselves. ๐
Added in version 3.11: INTERFACE items on IMPORTED targets? Allowed. โจ
Repeated calls for the same <target> append items in the order called.
If SYSTEM is specified, the compiler will be told the directories are meant as system include directories on some platforms. That can have effects like suppressing warnings or skipping the contained headers in dependency calculations (see your compiler's documentation, bestie). Additionally โ and this is the key bit โ system include directories are searched after normal include directories, regardless of the order you specified. ๐
If SYSTEM is used together with PUBLIC or INTERFACE, the INTERFACE_SYSTEM_INCLUDE_DIRECTORIES target property gets populated with the specified directories.
Arguments to target_include_directories may use generator expressions with the syntax $<...>. See the cmake-generator-expressions(7) manual for available expressions, and the cmake-buildsystem(7) manual for more on defining buildsystem properties. ๐ฅ
Specified include directories may be absolute paths or relative paths. A relative path gets interpreted as relative to the current source directory (i.e. CMAKE_CURRENT_SOURCE_DIR) and converted to an absolute path before it's stored in the associated target property. But if the path starts with a generator expression, it will always be assumed to be an absolute path (with one exception noted below) and will be used unmodified. โญ
Okay so real talk, include dirs hit different in the build tree vs the install tree โ that's just facts ๐
. The BUILD_INTERFACE and INSTALL_INTERFACE generator expressions are literally made for this: you use them to describe separate usage requirements depending on where the thing's gonna be used. ๐
Relative paths are allowed inside INSTALL_INTERFACE, and here's the tea โ they get interpreted as relative to the installation prefix. But relative paths should not be used in BUILD_INTERFACE expressions, because they will not be converted to absolute. ๐ญ Like, don't do it, bestie. Example time:
target_include_directories(mylib PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include/mylib>
$<INSTALL_INTERFACE:include/mylib> # <prefix>/include/mylib
)
๐ง Creating Relocatable Packages
So this is the part where we're all like "be careful, queen." Note that it is not advisable to populate the INSTALL_INTERFACE of the INTERFACE_INCLUDE_DIRECTORIES of a target with absolute paths to the include directories of dependencies. Bestie, that would hard-code into installed packages the include directory paths for dependencies as found on the machine the package was made on. ๐ Which is giving "works on my machine" energy, and we don't vibe with that.
The INSTALL_INTERFACE of the INTERFACE_INCLUDE_DIRECTORIES is only suitable for specifying the required include directories for headers provided with the target itself, not those provided by the transitive dependencies listed in its INTERFACE_LINK_LIBRARIES target property. Those dependencies should themselves be targets that specify their own header locations in INTERFACE_INCLUDE_DIRECTORIES. Slay, self-contained, iconic. ๐
Also, go read the Creating Relocatable Packages section of the cmake-packages(7) manual for discussion of additional care that must be taken when specifying usage requirements while creating packages for redistribution. It's the extra credit reading, iykyk. ๐
โจ See Also
include_directories()target_compile_definitions()target_compile_features()target_compile_options()target_link_libraries()target_link_directories()target_link_options()target_precompile_headers()target_sources()
๐ธ target_link_directories
Added in version 3.13, so like, she's newer but she's already everywhere. ๐
Add link directories to a target. Periodt.
target_link_directories(<target> [BEFORE]
{INTERFACE|PUBLIC|PRIVATE} <dir>...
[{INTERFACE|PUBLIC|PRIVATE} <dir>...]...)
Specifies the paths in which the linker should search for libraries when linking a given target. Each item can be an absolute or relative path, with the latter being interpreted as relative to the current source directory. These items will be added to the link command. ๐ ๏ธ
The named <target> must have been created by a command such as add_executable() or add_library() and must not be an ALIAS target. No aliases, we see you. ๐
The INTERFACE, PUBLIC and PRIVATE keywords are required to specify the scope of the items that follow them. PRIVATE and PUBLIC items will populate the LINK_DIRECTORIES property of <target>. PUBLIC and INTERFACE items will populate the INTERFACE_LINK_DIRECTORIES property of <target> (IMPORTED targets only support INTERFACE items, that's just the rule). Each item specifies a link directory and will be converted to an absolute path if necessary before adding it to the relevant property. Repeated calls for the same <target> append items in the order called. ๐
If BEFORE is specified, the content will be prepended to the relevant property instead of being appended. Front of the line, main character energy. โจ
Arguments to target_link_directories may use generator expressions with the syntax $<...>. See the cmake-generator-expressions(7) manual for available expressions. See the cmake-buildsystem(7) manual for more on defining buildsystem properties.
Note, and this part matters: this command is rarely necessary and should be avoided where there are other choices. Prefer to pass full absolute paths to libraries where possible, since this ensures the correct library will always be linked. Thefind_library()command provides the full path, which can generally be used directly in calls totarget_link_libraries(). Situations where a library search path may be needed include: - Project generators like Xcode where the user can switch target architecture at build time, but a full path to a library cannot be used because it only provides one architecture (i.e. it is not a universal binary). ๐ฅ - Libraries may themselves have other private library dependencies that expect to be found via RPATH mechanisms, but some linkers are not able to fully decode those paths (e.g. due to the presence of things like$ORIGIN). ๐ญ
๐ฆ See Also
link_directories()target_compile_definitions()target_compile_features()target_compile_options()target_include_directories()target_link_libraries()target_link_options()target_precompile_headers()target_sources()
๐ target_link_libraries
Specify libraries or flags to use when linking a given target and/or its dependents. Usage requirements from linked library targets will be propagated. Usage requirements of a target's dependencies affect compilation of its own sources. It's giving "everything is connected" and honestly? Obsessed. ๐
โญ Overview
This command has several signatures as detailed in subsections below. All of them have the general form:
target_link_libraries(<target> ... <item>... ...)
The named <target> must have been created by a command such as add_executable() or add_library() and must not be an ALIAS target. If policy CMP0079 is not set to NEW then the target must have been created in the current directory. Repeated calls for the same <target> append items in the order called. ๐
Added in version 3.13: the <target> doesn't have to be defined in the same directory as the target_link_libraries call. Glow-up fr fr. โจ
Each <item> may be:
- A library target name โ the generated link line will have the full path to the linkable library file associated with the target. The buildsystem will have a dependency to re-link
<target>if the library file changes. The named target must be created byadd_library()within the project or as an IMPORTED library. If it is created within the project an ordering dependency will automatically be added in the build system to make sure the named library target is up-to-date before the<target>links. If an imported library has theIMPORTED_NO_SONAMEtarget property set, CMake may ask the linker to search for the library instead of using the full path (e.g./usr/lib/libfoo.sobecomes-lfoo). The full path to the target's artifact will be quoted/escaped for the shell automatically. ๐ - A full path to a library file โ the generated link line will normally preserve the full path to the file. The buildsystem will have a dependency to re-link
<target>if the library file changes. There are some cases where CMake may ask the linker to search for the library (e.g./usr/lib/libfoo.sobecomes-lfoo), such as when a shared library is detected to have no SONAME field. In CMake versions prior to 4.0, see policyCMP0060for discussion of another case. If the library file is in a macOS framework, theHeadersdirectory of the framework will also be processed as a usage requirement. This has the same effect as passing the framework directory as an include directory. ๐
Added in version 3.28: the library file may point to a .xcframework folder on Apple platforms. If it does, the target will get the selected library's Headers directory as a usage requirement. ๐
Added in version 3.8: on Visual Studio Generators for VS 2010 and above, library files ending in .targets will be treated as MSBuild targets files and imported into generated project files. This is not supported by other generators. ๐ค
The full path to the library file will be quoted/escaped for the shell automatically. ๐ธ
- A plain library name โ the generated link line will ask the linker to search for the library (e.g.
foobecomes-lfooorfoo.lib). The library name/flag is treated as a command-line string fragment and will be used with no extra quoting or escaping. Lowkey the simplest one. ๐ฆ - A link flag โ item names starting with
-, but not-lor-framework, are treated as linker flags. Note that such flags will be treated like any other library link item for purposes of transitive dependencies, so they are generally safe to specify only as private link items that will not propagate to dependents. Link flags specified here are inserted into the link command in the same place as the link libraries. This might not be correct, depending on the linker. Use theLINK_OPTIONStarget property ortarget_link_options()command to add link flags explicitly. The flags will then be placed at the toolchain-defined flag position in the link command. ๐ ๏ธ
Added in version 3.13: LINK_OPTIONS target property and target_link_options() command. For earlier versions of CMake, use LINK_FLAGS property instead. ๐
The link flag is treated as a command-line string fragment and will be used with no extra quoting or escaping. Periodt. โจ
- A generator expression โ a
$<...>generator expression may evaluate to any of the above items, or to a semicolon-separated list of them. So if the...has any;characters in it, like after a${list}variable gets evaluated, bestie you must wrap it in an explicitly quoted argument"$<...>"so the command receives it as one single single <item>. No cap, this one matters.
Also, a generator expression can be a fragment of any of the above items, like foo$<1:_d>. Cute, right?
- A
debug,optimized, orgeneralkeyword right before another<item>โ the item after such a keyword only gets used for the matching build configuration. Thedebugkeyword = theDebugconfiguration (or whatever configurations are named in theDEBUG_CONFIGURATIONSglobal property, if that's set). Theoptimizedkeyword = all the other configurations. Thegeneralkeyword = all configurations, and it's purely optional, queen. These keywords get interpreted immediately by this command, which means they have no special meaning when a generator expression produces them. ๐
Alternatively, generator expressions like $<CONFIG> give you finer per-configuration linking of <item>. And if you want a more structured vibe, higher granularity is achievable by creating and linking to IMPORTED library targets with the IMPORTED_CONFIGURATIONS property set โ especially in find modules. iykyk.
Items containing ::, like Foo::Bar, are assumed to be IMPORTED or ALIAS library target names, and will throw an error if no such target exists. See policy CMP0028. โจ
See the CMAKE_LINK_LIBRARIES_STRATEGY variable and its corresponding LINK_LIBRARIES_STRATEGY target property for the deets on how CMake orders direct link dependencies on linker command lines.
See the cmake-buildsystem(7) manual for more on defining buildsystem properties.
๐ ๏ธ Handling Compiler Driver Differences
Added in version 4.0. โจ
Okay so to pass options to the linker tool, every compiler driver has its own little syntax situation. The LINKER: prefix and the , separator let you specify options for the linker tool in a portable way. LINKER: gets replaced by the appropriate driver option, and , gets replaced by the appropriate driver separator. Those two things are given by the values of the CMAKE_<LANG>_LINKER_WRAPPER_FLAG and CMAKE_<LANG>_LINKER_WRAPPER_FLAG_SEP variables. ๐ซถ
Example time: "LINKER:-z,defs" becomes -Xlinker -z -Xlinker defs for Clang, and -Wl,-z,defs for GNU GCC. Slay.
The LINKER: prefix also supports an alternative syntax โ specifying arguments using the SHELL: prefix and a space as the separator. So the previous example becomes "LINKER:SHELL:-z defs". ๐
โ ๏ธ Note: specifying theSHELL:prefix anywhere other than at the very beginning of theLINKER:prefix is not supported. Don't do it, bestie.
๐ Libraries for a Target and/or its Dependents
target_link_libraries(<target>
{INTERFACE|PUBLIC|PRIVATE} <item>...
[{INTERFACE|PUBLIC|PRIVATE} <item>...]...)
The PUBLIC, PRIVATE and INTERFACE scope keywords can specify both the link dependencies and the link interface in one command. Efficiency icon behavior.
- Libraries and targets following
PUBLICare linked to, and are made part of the link interface. - Libraries and targets following
PRIVATEare linked to, but are not made part of the link interface. - Libraries following
INTERFACEare appended to the link interface and are not used for linking<target>.
๐ธ Libraries for both a Target and its Dependents
target_link_libraries(<target> <item>...)
Library dependencies are transitive by default with this signature. The way that when this target gets linked into another target, the libraries linked to this target will show up on the link line for that other target too? Obsessed. This transitive "link interface" is stored in the INTERFACE_LINK_LIBRARIES target property, and it may be overridden by setting the property directly.
In CMake versions prior to 4.0, if CMP0022 is not set to NEW, transitive linking is built in but may be overridden by the LINK_INTERFACE_LIBRARIES property. Also, calls to other signatures of this command may set the property, which makes any libraries linked exclusively by this signature private. ๐
๐ Libraries for a Target and/or its Dependents (Legacy)
This signature is for compatibility only. Prefer the PUBLIC or PRIVATE keywords instead, fr fr.
target_link_libraries(<target>
<LINK_PRIVATE|LINK_PUBLIC> <lib>...
[<LINK_PRIVATE|LINK_PUBLIC> <lib>...]...)
The LINK_PUBLIC and LINK_PRIVATE modes can specify both the link dependencies and the link interface in one command.
Libraries and targets following LINK_PUBLIC are linked to, and are made part of the INTERFACE_LINK_LIBRARIES.
In CMake versions prior to 4.0, if policy CMP0022 is not NEW, they are also made part of the LINK_INTERFACE_LIBRARIES. Libraries and targets following LINK_PRIVATE are linked to, but are not made part of the INTERFACE_LINK_LIBRARIES (or LINK_INTERFACE_LIBRARIES).
๐ Libraries for Dependents Only (Legacy)
This signature is for compatibility only too. Prefer the INTERFACE mode instead. ๐
target_link_libraries(<target> LINK_INTERFACE_LIBRARIES <item>...)
The LINK_INTERFACE_LIBRARIES mode appends the libraries to the INTERFACE_LINK_LIBRARIES target property instead of using them for linking.
In CMake versions prior to 4.0, if policy CMP0022 is not NEW, then this mode also appends libraries to the LINK_INTERFACE_LIBRARIES and its per-configuration equivalent.
๐ง Linking Object Libraries
Added in version 3.12. โจ
Object Libraries may be used as the <target> (first) argument of target_link_libraries to specify dependencies of their sources on other libraries. For example, this code:
add_library(A SHARED a.c)
target_compile_definitions(A PUBLIC A)
add_library(obj OBJECT obj.c)
target_compile_definitions(obj PUBLIC OBJ)
target_link_libraries(obj PUBLIC A)
compiles obj.c with -DA -DOBJ and establishes usage requirements for obj that propagate to its dependents. Iconic.
Normal libraries and executables may link to Object Libraries to get their objects and usage requirements. Continuing the above example, this code:
add_library(B SHARED b.c)
target_link_libraries(B PUBLIC obj)
compiles b.c with -DA -DOBJ, creates shared library B with object files from b.c and obj.c, and links B to A. And furthermore, this code:
add_executable(main main.c)
target_link_libraries(main B)
compiles main.c with -DA -DOBJ and links executable main to B and A. The object library's usage requirements propagate transitively through B, but its object files do not. Wild, I know.
Object Libraries may "link" to other object libraries to get usage requirements, but since they don't have a link step, nothing is done with their object files. Continuing from the above example, the code:
add_library(obj2 OBJECT obj2.c)
target_link_libraries(obj2 PUBLIC obj)
add_executable(main2 main2.c)
target_link_libraries(main2 obj2)
compiles obj2.c with -DA -DOBJ, creates executable main2 with object files from main2.c and obj2.c, and links main2 to A.
In other words ๐ซถ โ when Object Libraries appear in a target's INTERFACE_LINK_LIBRARIES property they're treated as Interface Libraries, but when they appear in a target's LINK_LIBRARIES property their object files get included in the link too.
๐ฆ Linking Object Libraries via $<TARGET_OBJECTS>
Added in version 3.21. โจ
The object files associated with an object library may be referenced by the $<TARGET_OBJECTS> generator expression. Such object files get placed on the link line before all libraries, no matter what their relative order is. Also, an ordering dependency gets added to the build system to make sure the object library is up-to-date before the dependent target links. For example, this code:
add_library(obj3 OBJECT obj3.c)
target_compile_definitions(obj3 PUBLIC OBJ3)
add_executable(main3 main3.c)
target_link_libraries(main3 PRIVATE a3 $<TARGET_OBJECTS:obj3> b3)
links executable main3 with object files from main3.c and obj3.c followed by the a3 and b3 libraries. And note: main3.c is not compiled with usage requirements from obj3, such as -DOBJ3. ๐
This approach can be used to achieve transitive inclusion of object files in link lines as usage requirements. Continuing the above example, the code:
add_library(iface_obj3 INTERFACE)
target_link_libraries(iface_obj3 INTERFACE obj3 $<TARGET_OBJECTS:obj3>)
creates an interface library iface_obj3 that forwards the obj3 usage requirements and adds the obj3 object files to dependents' link lines. Then the code:
add_executable(use_obj3 use_obj3.c)
target_link_libraries(use_obj3 PRIVATE iface_obj3)
compiles use_obj3.c with -DOBJ3 and links executable use_obj3 with object files from use_obj3.c and obj3.c. Slay.
This also works transitively through a static library. Since a static library doesn't link, it does not consume the object files from object libraries referenced this way โ instead, the object files become transitive link dependencies of the static library. Continuing the above example, the code:
add_library(static3 STATIC static3.c)
target_link_libraries(static3 PRIVATE iface_obj3)
add_executable(use_static3 use_static3.c)
target_link_libraries(use_static3 PRIVATE static3)
compiles static3.c with -DOBJ3 and creates libstatic3.a using only its own object file. use_static3.c is compiled without -DOBJ3 because the usage requirement is not transitive through the private dependency of static3. However ๐ญ the link dependencies of static3 are propagated, including the iface_obj3 reference to $<TARGET_OBJECTS:obj3>. The use_static3 executable is created with object files from use_static3.c and obj3.c, and linked to library libstatic3.a. Chef's kiss. ๐
When using this approach, it's the project's responsibility to avoid linking multiple dependent binaries to iface_obj3, because they will all get the obj3 object files on their link lines. Like, every single one. No cap.
Note: Referencing$<TARGET_OBJECTS>intarget_link_librariescalls worked in versions of CMake prior to3.21for some cases, but it was not fully supported: - It did not place the object files before libraries on link lines. - It did not add an ordering dependency on the object library. - It did not work in Xcode with multiple architectures.
๐ Cyclic Dependencies of Static Libraries
Okay so the library dependency graph is normally acyclic (a DAG, bestie), but when you've got mutually-dependent STATIC libraries, CMake actually allows the graph to contain cycles (strongly connected components). When another target links to one of the libraries, CMake repeats the entire connected component. For example, this code:
add_library(A STATIC a.c)
add_library(B STATIC b.c)
target_link_libraries(A B)
target_link_libraries(B A)
add_executable(main main.c)
target_link_libraries(main A)
links main to A B A B. Iconic. And while one repetition is usually sufficient, pathological object file and symbol arrangements can require more. ๐ You can handle such cases by using the LINK_INTERFACE_MULTIPLICITY target property, or by manually repeating the component in the last target_link_libraries call. But honestly, if two archives are really so interdependent, they should probably just be combined into a single archive โ maybe by using Object Libraries. Periodt.
๐ฆ Creating Relocatable Packages
Note that it is not advisable to populate the INTERFACE_LINK_LIBRARIES of a target with absolute paths to dependencies. That would hard-code into installed packages the library file paths for dependencies as found on the machine the package was made on. Fr fr, that's a portability nightmare.
See the Creating Relocatable Packages section of the cmake-packages(7) manual for discussion of additional care that must be taken when specifying usage requirements while creating packages for redistribution. ๐ซถ
๐ See Also
target_compile_definitions()target_compile_features()target_compile_options()target_include_directories()target_link_directories()target_link_options()target_precompile_headers()target_sources()
๐ target_link_options
Added in version 3.13. โจ
Add options to the link step for an executable, shared library or module library target.
target_link_options(<target> [BEFORE]
{INTERFACE|PUBLIC|PRIVATE} <item>...
[{INTERFACE|PUBLIC|PRIVATE} <item>...]...)
The named <target> must have been created by a command such as add_executable() or add_library() and must not be an ALIAS target.
This command can be used to add any link options, but alternative commands exist to add libraries (target_link_libraries() or link_libraries()). See documentation of the directory and target LINK_OPTIONS properties.
Note: This command cannot be used to add options for static library targets, since they do not use a linker. To add archiver or MSVC librarian flags, see the STATIC_LIBRARY_OPTIONS target property.
If BEFORE is specified, the content will be prepended to the property instead of being appended.
The INTERFACE, PUBLIC and PRIVATE keywords are required to specify the scope of the following arguments. PRIVATE and PUBLIC items will populate the LINK_OPTIONS property of <target>. PUBLIC and INTERFACE items will populate the INTERFACE_LINK_OPTIONS property of <target>. The following arguments specify link options. Repeated calls for the same <target> append items in the order called.
Note:IMPORTEDtargets only supportINTERFACEitems.
Arguments to target_link_options may use generator expressions with the syntax $<...>. See the cmake-generator-expressions(7) manual for available expressions. See the cmake-buildsystem(7) manual for more on defining buildsystem properties.
๐ฅ๏ธ Host And Device Specific Link Options
Added in version 3.18: When a device link step is involved โ which is controlled by CUDA_SEPARABLE_COMPILATION and CUDA_RESOLVE_DEVICE_SYMBOLS properties and policy CMP0105 โ the raw options will be delivered to the host and device link steps (wrapped in -Xcompiler or equivalent for device link). Options wrapped with $<DEVICE_LINK:...> generator expression will be used only for the device link step. Options wrapped with $<HOST_LINK:...> generator expression will be used only for the host link step. Slay. ๐ฅ
๐งน Option De-duplication
The final set of options used for a target is constructed by accumulating options from the current target and the usage requirements of its dependencies. The set of options is de-duplicated to avoid repetition.
Added in version 3.12: While beneficial for individual options, the de-duplication step can break up option groups. For example, -option A -option B becomes -option A B. ๐ญ One may specify a group of options using shell-like quoting along with a SHELL: prefix. The SHELL: prefix is dropped, and the rest of the option string is parsed using the separate_arguments() UNIX_COMMAND mode. For example, "SHELL:-option A" "SHELL:-option B" becomes -option A -option B.
๐ Handling Compiler Driver Differences
To pass options to the linker tool, each compiler driver has its own syntax. The LINKER: prefix and , separator can be used to specify, in a portable way, options to pass to the linker tool. LINKER: is replaced by the appropriate driver option and , by the appropriate driver separator. The driver prefix and driver separator are given by the values of the CMAKE_<LANG>_LINKER_WRAPPER_FLAG and CMAKE_<LANG>_LINKER_WRAPPER_FLAG_SEP variables.
For example, "LINKER:-z,defs" becomes -Xlinker -z -Xlinker defs for Clang and -Wl,-z,defs for GNU GCC.
The LINKER: prefix can be specified as part of a SHELL: prefix expression.
The LINKER: prefix supports, as an alternative syntax, specification of arguments using the SHELL: prefix and space as separator. The previous example then becomes "LINKER:SHELL:-z defs".
Note: Specifying theSHELL:prefix anywhere other than at the beginning of theLINKER:prefix is not supported.
๐ See Also
target_compile_definitions()target_compile_features()target_compile_options()target_include_directories()target_link_libraries()target_link_directories()target_precompile_headers()target_sources()CMAKE_<LANG>_FLAGSandCMAKE_<LANG>_FLAGS_<CONFIG>add language-wide flags passed to all invocations of the compiler. This includes invocations that drive compiling and those that drive linking.- Added in version
4.3:CMAKE_<LANG>_LINK_FLAGSandCMAKE_<LANG>_LINK_FLAGS_<CONFIG>add language-wide flags passed to all invocations of the compiler which drive linking. - The
CheckLinkerFlagmodule to check whether a linker flag is supported by the compiler.
๐ target_precompile_headers
Added in version 3.16. ๐ฆ
Add a list of header files to precompile.
Precompiling header files can speed up compilation by creating a partially processed version of some header files, and then using that version during compilations rather than repeatedly parsing the original headers. It's literally giving efficiency. โญ
Main Form
target_precompile_headers(<target>
{INTERFACE|PUBLIC|PRIVATE} <header>...
[{INTERFACE|PUBLIC|PRIVATE} <header>...]...)
The command adds header files to the PRECOMPILE_HEADERS and/or INTERFACE_PRECOMPILE_HEADERS target properties of <target>. The named <target> must have been created by a command such as add_executable() or add_library() and must not be an ALIAS target.
The INTERFACE, PUBLIC and PRIVATE keywords are required to specify the scope of the following arguments. PRIVATE and PUBLIC items will populate the PRECOMPILE_HEADERS property of <target>. PUBLIC and INTERFACE items will populate the INTERFACE_PRECOMPILE_HEADERS property of <target> (IMPORTED targets only support INTERFACE items). Repeated calls for the same <target> will append items in the order called. ๐
Okay so real talk: projects should generally avoid using PUBLIC or INTERFACE for targets that are gonna be exported, or at the very least they should use the $<BUILD_INTERFACE:...> generator expression to stop precompile headers from popping up in an installed exported target. ๐
The whole vibe is that consumers of a target should typically be the ones in control of what precompile headers they use โ like, they should not have precompile headers forced on them by the targets being consumed (since precompile headers are not typically usage requirements). Rude otherwise, honestly.
There's one notable exception though, and it's actually kind of iconic: when an interface library gets created to define a commonly used set of precompile headers in one place, and then other targets link to that interface library privately. In that case the interface library exists specifically to propagate the precompile headers to its consumers, and the consumer is effectively still in control โ because it decides whether to link to the interface library or not. Queen behavior, truly. ๐
So, the list of header files gets used to generate a header file named cmake_pch.h|xx, and that is what's used to generate the precompiled header file (.pch, .gch, .pchi) artifact. The cmake_pch.h|xx header file is gonna be force included (-include for GCC, /FI for MSVC) to all source files, so bestieโฆ sources do not need to have #include "pch.h". It's handled. ๐ซถ
Header file names specified with angle brackets (e.g. <unordered_map>) or with explicit double quotes (escaped for the cmake-language(7) manual, e.g. [["other_header.h"]]) will be treated as is, and include directories must be available for the compiler to find them. Other header file names (e.g. project_header.h) are interpreted as being relative to the current source directory (e.g. CMAKE_CURRENT_SOURCE_DIR) and will be included by absolute path. Like this:
target_precompile_headers(myTarget
PUBLIC
project_header.h
PRIVATE
[["other_header.h"]]
<unordered_map>
)
Arguments to target_precompile_headers may use generator expressions with the syntax $<...>. Go check the cmake-generator-expressions(7) manual for the available expressions. โจ
The $<COMPILE_LANGUAGE:...> generator expression is particularly useful for specifying a language-specific header to precompile for only one language (e.g. CXX and not C). In that case, header file names that are not explicitly in double quotes or angle brackets must be specified by absolute path. Also โ and this is the part people forget โ when specifying angle brackets inside a generator expression, be sure to encode the closing > as $<ANGLE-R>. ๐ For example:
target_precompile_headers(mylib PRIVATE
"$<$<COMPILE_LANGUAGE:CXX>:${CMAKE_CURRENT_SOURCE_DIR}/cxx_only.h>"
"$<$<COMPILE_LANGUAGE:C>:<stddef.h$<ANGLE-R>>"
"$<$<COMPILE_LANGUAGE:CXX>:<cstddef$<ANGLE-R>>"
)
๐ Reusing Precompile Headers ๐
The command also supports a second signature, which you can use to say that one target reuses a precompiled header file artifact from another target instead of generating its own:
target_precompile_headers(<target> REUSE_FROM <other_target>)
This form sets the PRECOMPILE_HEADERS_REUSE_FROM property to <other_target> and adds a dependency such that <target> will depend on <other_target>. And CMake will halt with an error if the PRECOMPILE_HEADERS property of <target> is already set when the REUSE_FROM form is used. No take-backs, no double-dipping. ๐ซ
Note: theREUSE_FROMform requires the same set of compiler options, compiler flags and compiler definitions for both<target>and<other_target>. Some compilers (e.g. GCC) may issue a warning if the precompiled header file cannot be used (-Winvalid-pch). So likeโฆ keep them matching, bestie, or at least read the warning. ๐
๐ See Also ๐
- To disable precompile headers for specific targets, see the
DISABLE_PRECOMPILE_HEADERStarget property. - To prevent precompile headers from being used when compiling a specific source file, see the
SKIP_PRECOMPILE_HEADERSsource file property. target_compile_definitions()target_compile_features()target_compile_options()target_include_directories()target_link_libraries()target_link_directories()target_link_options()target_sources()
๐ฆ target_sources ๐ฆ
Added in version 3.1. โจ
Add sources to a target.
target_sources(<target>
{INTERFACE|PUBLIC|PRIVATE} <source>...
[{INTERFACE|PUBLIC|PRIVATE} <source>...]...)
Specifies sources to use when building a target and/or its dependents. The named <target> must have been created by a command such as add_executable() or add_library() or add_custom_target(), and it must not be an ALIAS target. The <source> items may use generator expressions.
Added in version 3.20: <target> can be a custom target. ๐
The INTERFACE, PUBLIC and PRIVATE keywords are required โ like, mandatory โ to specify the scope of the source file paths (<source>...) that follow them. So here's the breakdown:
PRIVATEandPUBLICsources will populate theSOURCESproperty of<target>, which are used when building the target itself.PUBLICandINTERFACEsources will populate theINTERFACE_SOURCESproperty of<target>, which are used when building dependents.
A target created by add_custom_target() can only have PRIVATE scope. Sorry, that's just the rules. ๐
Repeated calls for the same <target> append sources in the order called.
Added in version 3.3: allow exporting targets with INTERFACE_SOURCES. ๐
Added in version 3.11: allow setting INTERFACE sources on IMPORTED targets.
Changed in version 3.13: relative source file paths are interpreted as being relative to the current source directory (i.e. CMAKE_CURRENT_SOURCE_DIR). See policy CMP0076.
A path that begins with a generator expression is left unmodified. So when a target's SOURCE_DIR property differs from CMAKE_CURRENT_SOURCE_DIR, use absolute paths in generator expressions to make sure the sources are correctly assigned to the target. This is the classic oopsie:
# WRONG: starts with generator expression, but relative path used
target_sources(MyTarget PRIVATE "$<$<CONFIG:Debug>:dbgsrc.cpp>")
# CORRECT: absolute path used inside the generator expression
target_sources(MyTarget PRIVATE "$<$<CONFIG:Debug>:${CMAKE_CURRENT_SOURCE_DIR}/dbgsrc.cpp>")
See the cmake-buildsystem(7) manual for more on defining buildsystem properties. ๐
๐ธ File Sets ๐ธ
Added in version 3.23.
target_sources(<target>
[{INTERFACE|PUBLIC|PRIVATE}
[FILE_SET <set> [TYPE <type>] [BASE_DIRS <dirs>...] [FILES <files>...]]...
]...)
Adds a file set to a target, or adds files to an existing file set. Targets have zero or more named file sets. Each file set has a name, a type, a scope of INTERFACE, PUBLIC, or PRIVATE, one or more base directories, and files within those directories. The whole little package. ๐
Changed in version 4.4: a file may belong to at most one non-HEADERS file set in a target. See policy CMP0211.
The acceptable types include:
HEADERSโ sources intended to be used via a language's#includemechanism.SOURCESโ Added in version 4.4. Specifies sources to use when building a target and/or its dependents. With the scopePRIVATEandPUBLIC,<files>will populate theSOURCESproperty of<set>, which are used when building the target itself. With the scopePUBLICandINTERFACE,<files>will populate theINTERFACE_SOURCESproperty of<set>, which are used when building dependents. The sources specified by theINTERFACE_SOURCESproperty are propagated, transitively, to all the dependents. It's giving chain reaction. ๐ฅCXX_MODULESโ Added in version 3.28. Sources which contain C++ interface module or partition units (i.e., those using theexportkeyword). This file set type may not have anINTERFACEscope except onIMPORTEDtargets.
The optional default file sets are named after their type. The target may not be a custom target or, for HEADERS and CXX_MODULES types, a FRAMEWORK target. ๐ซ
Files in a PRIVATE or PUBLIC file set are marked as source files for the purposes of IDE integration. Additionally, files in HEADERS file sets have their HEADER_FILE_ONLY property set to TRUE. Files in an INTERFACE or PUBLIC file set can be installed with the install(TARGETS) command, and exported with the install(EXPORT) and export() commands. Slay, honestly. โจ
Each target_sources(FILE_SET) entry starts with INTERFACE, PUBLIC, or PRIVATE and accepts the following arguments:
FILE_SET <set>โ the name of the file set to create or add to. It must contain only letters, numbers and underscores. Names starting with a capital letter are reserved for built-in file sets predefined by CMake. The only predefined set names are those matching the acceptable types. All other set names must not start with a capital letter or underscore. Read the fine print, bestie. ๐TYPE <type>โ every file set is associated with a particular type of file. Only the types specified above may be used, and it is an error to specify anything else. As a special case, if the name of the file set is one of the types, the type does not need to be specified and theTYPE <type>arguments can be omitted. For all other file set names,TYPEis required. ๐ซถBASE_DIRS <dirs>...โ an optional list of base directories of the file set. Any relative path is treated as relative to the current source directory (i.e.CMAKE_CURRENT_SOURCE_DIR). If noBASE_DIRSare specified when the file set is first created, the value ofCMAKE_CURRENT_SOURCE_DIRis added. This argument supports generator expressions. ๐
Like, no two base directories for a file set may be sub-directories of each other โ periodt, that's the rule. And bestie, this requirement has to hold across all base directories added to a file set, not just the ones you threw in during a single call to target_sources(). The whole file set. Every time. ๐
FILES <files>...โ an optional list of files to add to the file set. Every single file has to live in one of the base directories, or in a subdirectory of one of them. This argument supports generator expressions <#manual:cmake-generator-expressions(7)> โจ
Okay so if you give relative paths, they're considered relative to CMAKE_CURRENT_SOURCE_DIR <#variable:CMAKE_CURRENT_SOURCE_DIR> at the moment target_sources() gets called. The one exception? A path starting with $< โ those get treated as relative to the target's source directory, after the generator expressions have been evaluated. iykyk ๐ซถ
The following target properties are set by target_sources(FILE_SET), but like... don't generally touch them directly, bestie. They're doing their own thing. ๐
For file sets of type HEADERS:
HEADER_SETS<#prop_tgt:HEADER_SETS>INTERFACE_HEADER_SETS<#prop_tgt:INTERFACE_HEADER_SETS>HEADER_SET<#prop_tgt:HEADER_SET>HEADER_SET_<NAME><#prop_tgt:HEADER_SET_<NAME>>HEADER_DIRS<#prop_tgt:HEADER_DIRS>HEADER_DIRS_<NAME><#prop_tgt:HEADER_DIRS_<NAME>>
For file sets of type SOURCES:
SOURCE_SETS<#prop_tgt:SOURCE_SETS>INTERFACE_SOURCE_SETS<#prop_tgt:INTERFACE_SOURCE_SETS>SOURCE_SET<#prop_tgt:SOURCE_SET>SOURCE_SET_<NAME><#prop_tgt:SOURCE_SET_<NAME>>SOURCE_DIRS<#prop_tgt:SOURCE_DIRS>SOURCE_DIRS_<NAME><#prop_tgt:SOURCE_DIRS_<NAME>>
For file sets of type CXX_MODULES:
CXX_MODULE_SETS<#prop_tgt:CXX_MODULE_SETS>INTERFACE_CXX_MODULE_SETS<#prop_tgt:INTERFACE_CXX_MODULE_SETS>CXX_MODULE_SET<#prop_tgt:CXX_MODULE_SET>CXX_MODULE_SET_<NAME><#prop_tgt:CXX_MODULE_SET_<NAME>>CXX_MODULE_DIRS<#prop_tgt:CXX_MODULE_DIRS>CXX_MODULE_DIRS_<NAME><#prop_tgt:CXX_MODULE_DIRS_<NAME>>
Target properties related to include directories also get modified by target_sources(FILE_SET), and here's exactly how ๐
INCLUDE_DIRECTORIES<#prop_tgt:INCLUDE_DIRECTORIES> โ if theTYPEisHEADERS, and the scope of the file set isPRIVATEorPUBLIC, then all of theBASE_DIRSof the file set get wrapped in$<BUILD_INTERFACE><#genex:BUILD_INTERFACE> and appended to this property. Slay. ๐INTERFACE_INCLUDE_DIRECTORIES<#prop_tgt:INTERFACE_INCLUDE_DIRECTORIES> โ if theTYPEisHEADERS, and the scope of the file set isINTERFACEorPUBLIC, then all of theBASE_DIRSof the file set get wrapped in$<BUILD_INTERFACE><#genex:BUILD_INTERFACE> and appended to this property. Same energy, different property. โจ
๐ฆ See Also ๐ฆ
add_executable()<#command:add_executable>add_library()<#command:add_library>target_compile_definitions()<#command:target_compile_definitions>target_compile_features()<#command:target_compile_features>target_compile_options()<#command:target_compile_options>target_include_directories()<#command:target_include_directories>target_link_libraries()<#command:target_link_libraries>target_link_directories()<#command:target_link_directories>target_link_options()<#command:target_link_options>target_precompile_headers()<#command:target_precompile_headers>
๐ง try_compile ๐ง
Try building some code. That's literally it. That's the vibe check. ๐ฅ
๐ Try Compiling Whole Projects ๐
try_compile(<compileResultVar> PROJECT <projectName>
SOURCE_DIR <srcdir>
[BINARY_DIR <bindir>]
[TARGET <targetName>]
[LOG_DESCRIPTION <text>]
[NO_CACHE]
[NO_LOG]
[CMAKE_FLAGS <flags>...]
[OUTPUT_VARIABLE <var>])
Added in version 3.25.
Try building a project, bestie. Build success returns TRUE and build failure returns FALSE in <compileResultVar>. Iconic behaviour ngl. โ
โ
In this form, <srcdir> should contain a complete CMake project with a CMakeLists.txt file and all sources. Heads up: the <bindir> and <srcdir> will not be deleted after this command runs โ they stick around. ๐ Specify <targetName> to build a specific target instead of the all or ALL_BUILD target. Scroll down for what the other options mean.
Changed in version 3.24: CMake variables describing platform settings, plus those listed by the CMAKE_TRY_COMPILE_PLATFORM_VARIABLES <#variable:CMAKE_TRY_COMPILE_PLATFORM_VARIABLES> variable, are propagated into the project's build configuration. See policy CMP0137 <#policy:CMP0137>. Before this, that only happened via the source file signature. glow-up fr ๐
Added in version 3.26: This command records a configure-log try_compile event <#try-compile-configure-log-event> if the NO_LOG option is not specified.
Added in version 3.30: If the PROPAGATE_TOP_LEVEL_INCLUDES_TO_TRY_COMPILE <#prop_gbl:PROPAGATE_TOP_LEVEL_INCLUDES_TO_TRY_COMPILE> global property is set to true, then CMAKE_PROJECT_TOP_LEVEL_INCLUDES <#variable:CMAKE_PROJECT_TOP_LEVEL_INCLUDES> is propagated into the project's build configuration. Spreading the love ๐ซถ
This command supports an alternate signature for CMake older than 3.25. The signature above is recommended for clarity, bestie โ trust.
try_compile(<compileResultVar> <bindir> <srcdir>
<projectName> [<targetName>]
[CMAKE_FLAGS <flags>...]
[OUTPUT_VARIABLE <var>])
๐ธ Try Compiling Source Files ๐ธ
try_compile(<compileResultVar>
[SOURCES_TYPE <type>]
{SOURCES <srcfile>... |
SOURCE_FROM_CONTENT <name> <content> |
SOURCE_FROM_VAR <name> <var> |
SOURCE_FROM_FILE <name> <path> }...
[LOG_DESCRIPTION <text>]
[NO_CACHE]
[NO_LOG]
[CMAKE_FLAGS <flags>...]
[COMPILE_DEFINITIONS <defs>...]
[LINK_OPTIONS <options>...]
[LINK_LIBRARIES <libs>...]
[LINKER_LANGUAGE <lang>]
[OUTPUT_VARIABLE <var>]
[COPY_FILE <fileName> [COPY_FILE_ERROR <var>]]
[<LANG>_STANDARD <std>]
[<LANG>_STANDARD_REQUIRED <bool>]
[<LANG>_EXTENSIONS <bool>]
)
Added in version 3.25.
Try building an executable or static library from one or more source files. The binary type is determined by the CMAKE_TRY_COMPILE_TARGET_TYPE <#variable:CMAKE_TRY_COMPILE_TARGET_TYPE> variable. Build success returns boolean true and build failure returns boolean false in <compileResultVar> (cached unless NO_CACHE is specified). ๐
In this form, you gotta provide one or more source files โ non-negotiable. And also, one of SOURCES and/or SOURCE_FROM_* must come before the other keywords. Order matters, bestie. ๐
If CMAKE_TRY_COMPILE_TARGET_TYPE <#variable:CMAKE_TRY_COMPILE_TARGET_TYPE> is unset or is set to EXECUTABLE, then the sources must include a definition for main and CMake will create a CMakeLists.txt file to build the source(s) as an executable. If CMAKE_TRY_COMPILE_TARGET_TYPE <#variable:CMAKE_TRY_COMPILE_TARGET_TYPE> is set to STATIC_LIBRARY, then a static library gets built instead and no main definition is required. For an executable, the generated CMakeLists.txt file would contain something like this:
add_definitions(<expanded COMPILE_DEFINITIONS from caller>)
include_directories(${INCLUDE_DIRECTORIES})
link_directories(${LINK_DIRECTORIES})
add_executable(cmTryCompileExec <srcfile>...)
target_link_options(cmTryCompileExec PRIVATE <LINK_OPTIONS from caller>)
target_link_libraries(cmTryCompileExec ${LINK_LIBRARIES})
CMake automatically generates, for each try_compile operation, a unique directory under ${CMAKE_BINARY_DIR}/CMakeFiles/CMakeScratch with an unspecified name. Those directories get cleaned automatically โ unless --debug-trycompile <#cmdoption-cmake-debug-trycompile> is passed to cmake. And directories left over from previous runs are also unconditionally cleaned at the beginning of any cmake execution. No clutter, we love to see it. ๐งนโจ
This command supports an alternate signature for CMake older than 3.25. Signature above is recommended for clarity, as always.
try_compile(<compileResultVar> <bindir> {<srcfile>|SOURCES <srcfile>...}
[CMAKE_FLAGS <flags>...]
[COMPILE_DEFINITIONS <defs>...]
[LINK_OPTIONS <options>...]
[LINK_LIBRARIES <libs>...]
[OUTPUT_VARIABLE <var>]
[COPY_FILE <fileName> [COPY_FILE_ERROR <var>]]
[<LANG>_STANDARD <std>]
[<LANG>_STANDARD_REQUIRED <bool>]
[<LANG>_EXTENSIONS <bool>]
)
In this version, try_compile will use <bindir>/CMakeFiles/CMakeTmp for its operation, and all such files get cleaned automatically. For debugging, --debug-trycompile <#cmdoption-cmake-debug-trycompile> can be passed to cmake to avoid this clean. But โ and this is the catch ๐ญ โ multiple sequential try_compile operations, if given the same <bindir>, will reuse this single output directory, such that you can only debug one such try_compile call at a time. So the newer signature is recommended to simplify debugging of multiple try_compile operations. Fr fr, save yourself the pain.
๐ Options ๐
The options for the above signatures are:
CMAKE_FLAGS <flags>...โ specify flags of the form-DVAR:TYPE=VALUE<#cmdoption-cmake-D> to be passed to thecmake(1)<#manual:cmake(1)> command-line used to drive the test build. The example up there shows how values for variablesCOMPILE_DEFINITIONS,INCLUDE_DIRECTORIES,LINK_DIRECTORIES,LINK_LIBRARIES, andLINK_OPTIONSare used. Compiler options can be passed in likeCMAKE_FLAGS -DCOMPILE_DEFINITIONS=-Werror. ๐COMPILE_DEFINITIONS <defs>...โ specify-Ddefinitionarguments to pass toadd_definitions()<#command:add_definitions> in the generated test project.COPY_FILE <fileName>โ copy the built executable or static library to the given<fileName>. Move it, girl. ๐ฆCOPY_FILE_ERROR <var>โ use afterCOPY_FILEto capture into variable<var>any error message encountered while trying to copy the file. So if the copy flops, you'll know. ๐LINK_LIBRARIES <libs>...โ specify libraries to be linked in the generated project. The list of libraries may refer to system libraries and to Imported Targets <#imported-targets> from the calling project.
If this option is specified, any -DLINK_LIBRARIES=... value given to the CMAKE_FLAGS option will be ignored. Sorry bestie, this one wins. ๐
Added in version 3.29: Alias targets to imported libraries are also supported. Periodt. โจ
LINK_OPTIONS <options>...โ Added in version 3.14.- (the link-step-options one โ picking up right where we left off ๐
) โ specify link step options to pass to
target_link_options()or to set theSTATIC_LIBRARY_OPTIONStarget property in the generated project, depending on theCMAKE_TRY_COMPILE_TARGET_TYPEvariable. iykyk, that variable is literally deciding the whole vibe here. LINKER_LANGUAGE<lang>โ Added in version 3.29. Sets theLINKER_LANGUAGEtarget property on the generated project. Okay so bestie, if you're mixing source files from different languages, set this to the language of the source file that holds the program entry point โ like,main. That's the one calling the shots. ๐LOG_DESCRIPTION<text>โ Added in version 3.26. Gives a non-empty text description of what the check is even for. It gets recorded in thecmake-configure-log(7)entry. Lowkey your future self will thank you.NO_CACHEโ Added in version 3.25. So<compileResultVar>gets stored in a normal variable instead of a cache entry. Why does that matter? Because<compileResultVar>is normally cached, which lets you use this super clean pattern to dodge re-running the test every single time CMake executes:
if(NOT DEFINED RESULTVAR)
# ...(check-specific setup code)...
try_compile(RESULTVAR ...)
# ...(check-specific logging and cleanup code)...
endif()
But if the guard variable and the result variable are not the same โ say the test is part of some bigger inspection โ then NO_CACHE is your girl, because it stops that intermediate result variable from leaking into the cache. no cap, that's the whole point. ๐ซถ
NO_LOGโ Added in version 3.26. Do not record acmake-configure-log(7)entry for this call. That's it. That's the whole vibe. ๐OUTPUT_VARIABLE<var>โ stores the output from the build process into the variable you name. โจSOURCE_FROM_CONTENT<name><content>โ Added in version 3.25. Writes<content>to a file named<name>inside the operation directory. The glow-up here: you can skip writing a separate source file when the file's contents are dynamically specified. The specified<name>is not allowed to contain path components, so keep it simple.SOURCE_FROM_CONTENTmay be specified multiple times. ๐SOURCE_FROM_FILE<name><path>โ Added in version 3.25. Copies<path>to a file named<name>in the operation directory. This consolidates files into the operation directory, which is genuinely useful if a source that already exists (i.e. as a stand-alone file in a project's source repository) needs to refer to other file(s) created bySOURCE_FROM_*. (Otherwise?SOURCESis usually more convenient โ fr fr.) The specified<name>is not allowed to contain path components.SOURCE_FROM_VAR<name><var>โ Added in version 3.25. Writes the contents of<var>to a file named<name>in the operation directory. It's the same asSOURCE_FROM_CONTENT, except it grabs the contents from the specified CMake variable instead of directly โ which slays when you're passing arguments through a function that wrapstry_compile. The specified<name>is not allowed to contain path components.SOURCE_FROM_VARmay be specified multiple times. ๐SOURCES_TYPE<type>โ Added in version 3.28. Classify your sources with this argument. Once you specify it, all subsequent sources get treated as that type until anotherSOURCES_TYPEshows up. Available types are:NORMALโ sources are not added to anyFILE_SETin the generated project.CXX_MODULEโ Added in version 3.28. sources are added to aFILE_SETof typeCXX_MODULESin the generated project.
The default type of sources is NORMAL. โญ
<LANG>_STANDARD<std>โ Added in version 3.8. Specifies theC_STANDARD,CXX_STANDARD,OBJC_STANDARD,OBJCXX_STANDARD, orCUDA_STANDARDtarget property of the generated project. pick your language, pick your standard, go off ๐<LANG>_STANDARD_REQUIRED<bool>โ Added in version 3.8. Specifies theC_STANDARD_REQUIRED,CXX_STANDARD_REQUIRED,OBJC_STANDARD_REQUIRED,OBJCXX_STANDARD_REQUIRED, orCUDA_STANDARD_REQUIREDtarget property of the generated project.<LANG>_EXTENSIONS<bool>โ Added in version 3.8. Specifies theC_EXTENSIONS,CXX_EXTENSIONS,OBJC_EXTENSIONS,OBJCXX_EXTENSIONS, orCUDA_EXTENSIONStarget property of the generated project.
๐ฆ Other Behavior Settings ๐ฆ
Added in version 3.4: If set, these variables get passed into the generated try_compile CMakeLists.txt so they can initialize compile target properties with default values:
CMAKE_CUDA_RUNTIME_LIBRARYCMAKE_ENABLE_EXPORTSCMAKE_EXECUTABLE_ENABLE_EXPORTSCMAKE_SHARED_LIBRARY_ENABLE_EXPORTSCMAKE_EXE_LINKER_FLAGSโ unless using CMake versions prior to 4.0 without policyCMP0056set toNEWCMAKE_<LANG>_LINK_FLAGSโ unless using CMake versions prior to 4.3 without policyCMP0210set toNEWCMAKE_LINK_SEARCH_START_STATICCMAKE_LINK_SEARCH_END_STATICCMAKE_MSVC_RUNTIME_LIBRARYCMAKE_POSITION_INDEPENDENT_CODECMAKE_WATCOM_RUNTIME_LIBRARY
Changed in version 3.14: if CMP0083 is set to NEW, then to get correct behavior at link time, the check_pie_supported() command from the CheckPIESupported module must be called before using the try_compile command. Like, mandatory mandatory. ๐ญ
Some policies get set automatically in the generated test project as needed, so the calling project's state is honored:
CMP0065(in CMake versions prior to 4.0)CMP0083CMP0091CMP0104CMP0123CMP0126CMP0128CMP0136CMP0141CMP0155CMP0157CMP0181CMP0184CMP0210
Set the variable CMAKE_TRY_COMPILE_CONFIGURATION to choose a build configuration:
- For multi-config generators, this selects which configuration to build. ๐ฅ
- For single-config generators, this sets
CMAKE_BUILD_TYPEin the test project.
Added in version 3.6: set the CMAKE_TRY_COMPILE_TARGET_TYPE variable to specify the type of target used for the source file signature.
Added in version 3.6: set the CMAKE_TRY_COMPILE_PLATFORM_VARIABLES variable to specify variables that must be propagated into the test project. Heads up bestie โ this variable is meant for use only in toolchain files, and it's only honored by the try_compile() command for the source files form, not when given a whole project. โ ๏ธ
Changed in version 3.8: if CMP0067 is set to NEW, or any of the <LANG>_STANDARD, <LANG>_STANDARD_REQUIRED, or <LANG>_EXTENSIONS options are used, then these language standard variables are honored:
CMAKE_C_STANDARDCMAKE_C_STANDARD_REQUIREDCMAKE_C_EXTENSIONSCMAKE_CXX_STANDARDCMAKE_CXX_STANDARD_REQUIREDCMAKE_CXX_EXTENSIONSCMAKE_OBJC_STANDARDCMAKE_OBJC_STANDARD_REQUIREDCMAKE_OBJC_EXTENSIONSCMAKE_OBJCXX_STANDARDCMAKE_OBJCXX_STANDARD_REQUIREDCMAKE_OBJCXX_EXTENSIONSCMAKE_CUDA_STANDARDCMAKE_CUDA_STANDARD_REQUIREDCMAKE_CUDA_EXTENSIONS
Their values are used to set the corresponding target properties in the generated project โ unless an explicit option overrides them, obviously. ๐
Changed in version 3.14: for the Green Hills MULTI generator, the GHS toolset and target system customization cache variables are also propagated into the test project.
Added in version 3.24: the CMAKE_TRY_COMPILE_NO_PLATFORM_VARIABLES variable may be set to disable passing platform variables into the test project. Off switch: acquired. ๐
โโ๏ธ
Added in version 3.25: if CMP0141 is set to NEW, you can use CMAKE_MSVC_DEBUG_INFORMATION_FORMAT to specify the MSVC debug information format.
Added in version 3.30: if the PROPAGATE_TOP_LEVEL_INCLUDES_TO_TRY_COMPILE global property is set to true, CMAKE_PROJECT_TOP_LEVEL_INCLUDES is propagated into the test project's build configuration when using the whole-project signature. ๐
Added in version 4.0: if CMP0184 is set to NEW, you can use CMAKE_MSVC_RUNTIME_CHECKS to specify the enabled MSVC runtime checks. ๐ซถ
Added in version 4.3: if CMP0210 is set to NEW, then CMAKE_<LANG>_LINK_FLAGS and CMAKE_<LANG>_LINK_FLAGS_<CONFIG> get propagated right into the test project's build configuration. slay, flags traveling ๐
See Also
try_run()๐
๐โจ try_run
Try compiling and then running some code. iconic behavior honestly ๐
Compiling and Running Source Files
try_run(<runResultVar> <compileResultVar>
[SOURCES_TYPE <type>]
{SOURCES <srcfile>... |
SOURCE_FROM_CONTENT <name> <content> |
SOURCE_FROM_VAR <name> <var> |
SOURCE_FROM_FILE <name> <path> }...
[LOG_DESCRIPTION <text>]
[NO_CACHE]
[NO_LOG]
[CMAKE_FLAGS <flags>...]
[COMPILE_DEFINITIONS <defs>...]
[LINK_OPTIONS <options>...]
[LINK_LIBRARIES <libs>...]
[COMPILE_OUTPUT_VARIABLE <var>]
[COPY_FILE <fileName> [COPY_FILE_ERROR <var>]]
[<LANG>_STANDARD <std>]
[<LANG>_STANDARD_REQUIRED <bool>]
[<LANG>_EXTENSIONS <bool>]
[RUN_OUTPUT_VARIABLE <var>]
[RUN_OUTPUT_STDOUT_VARIABLE <var>]
[RUN_OUTPUT_STDERR_VARIABLE <var>]
[WORKING_DIRECTORY <var>]
[ARGS <args>...]
)
Added in version 3.25.
Okay so bestie, this one builds an executable out of one or more source files. Build success? You get boolean true in <compileResultVar> (cached unless you pass NO_CACHE). Build failure? Boolean false, no drama. ๐ And if the build does succeed, it runs the executable and stashes the exit code in <runResultVar> (again, cached unless NO_CACHE is in the mix). But if the thing got built and then refused to run โ rude โ then <runResultVar> gets set to FAILED_TO_RUN. ๐ญ
Peep try_compile() for the docs on all the options these two commands share, plus the whole "how is the test project even constructed to build the source file" lore. ๐ฆ
You gotta give it one or more source files. Also, one of SOURCES and/or SOURCE_FROM_* has to come before the other keywords. order matters, periodt โจ
Added in version 3.26: this command records a configure-log try_run event if you don't pass the NO_LOG option. ๐
There's also an alternate signature for CMake older than 3.25. The one up above is the recommended one, for clarity reasons ๐
try_run(<runResultVar> <compileResultVar>
<bindir> {<srcfile>|SOURCES <srcfile>...}
[CMAKE_FLAGS <flags>...]
[COMPILE_DEFINITIONS <defs>...]
[LINK_OPTIONS <options>...]
[LINK_LIBRARIES <libs>...]
[LINKER_LANGUAGE <lang>]
[COMPILE_OUTPUT_VARIABLE <var>]
[COPY_FILE <fileName> [COPY_FILE_ERROR <var>]]
[<LANG>_STANDARD <std>]
[<LANG>_STANDARD_REQUIRED <bool>]
[<LANG>_EXTENSIONS <bool>]
[RUN_OUTPUT_VARIABLE <var>]
[OUTPUT_VARIABLE <var>]
[WORKING_DIRECTORY <var>]
[ARGS <args>...]
)
๐ธ Options ๐ธ
These are the options that are specifically try_run's whole thing:
COMPILE_OUTPUT_VARIABLE <var>โ drops the build output from the compile step into the variable you name. ๐ซถOUTPUT_VARIABLE <var>โ drops the compile build output and the output from running the executable into your variable. ngl this one exists for legacy reasons and the old try_run signature is the only one that supports it. PreferCOMPILE_OUTPUT_VARIABLEandRUN_OUTPUT_VARIABLEinstead, bestie. ๐RUN_OUTPUT_VARIABLE <var>โ drops the output from running the executable into your variable. โจRUN_OUTPUT_STDOUT_VARIABLE <var>โ added in version 3.25. drops the stdout from running the executable into your variable. ๐RUN_OUTPUT_STDERR_VARIABLE <var>โ added in version 3.25. drops the stderr from running the executable into your variable. ๐WORKING_DIRECTORY <var>โ added in version 3.20. runs the executable in the directory you give it. NoWORKING_DIRECTORY? Then the executable runs in<bindir>or the current build directory. ๐ARGS <args>...โ extra arguments to hand the executable when you run it. ๐
๐๏ธ Other Behavior Settings ๐๏ธ
Set the variable CMAKE_TRY_COMPILE_CONFIGURATION to pick a build configuration:
- For multi-config generators, this selects which configuration to build. ๐ฅ
- For single-config generators, this sets
CMAKE_BUILD_TYPEinside the test project. ๐
๐ Behavior when Cross Compiling ๐
Added in version 3.3: it uses CMAKE_CROSSCOMPILING_EMULATOR when running cross-compiled binaries. ๐ง
So here's the situation: when you're cross compiling, the executable built in the first step usually cannot run on the build host. Obviously. ๐ญ So try_run peeks at the CMAKE_CROSSCOMPILING variable to figure out whether CMake is in cross-compiling mode. If it is, it'll still try to compile the executable โ but it will not try to run it unless the CMAKE_CROSSCOMPILING_EMULATOR variable is set. Instead, it creates cache variables that the user has to fill in (or preset in some CMake script file) with the values the executable would have produced if it had actually run on its real target platform. manifesting the output, basically โจ
These are the cache entries:
<runResultVar>โ the exit code, if the executable were to be run on the target platform. ๐<runResultVar>__TRYRUN_OUTPUTโ the output from stdout and stderr, if the executable were to be run on the target platform. Only created if theRUN_OUTPUT_VARIABLEorOUTPUT_VARIABLEoption was used. ๐<runResultVar>__TRYRUN_OUTPUT_STDOUTโ added in version 3.25. the output from stdout, if the executable were to be run on the target platform. Only created if theRUN_OUTPUT_STDOUT_VARIABLEorRUN_OUTPUT_STDERR_VARIABLEoption was used. ๐ฆ<runResultVar>__TRYRUN_OUTPUT_STDERRโ added in version 3.25. the output from stderr, if the executable were to be run on the target platform. Only created if theRUN_OUTPUT_STDOUT_VARIABLEorRUN_OUTPUT_STDERR_VARIABLEoption was used. ๐ฆ
Bestie, real talk: to make cross compiling your project easier, only reach fortry_runif you genuinely need it. And if you do usetry_run, only use theRUN_OUTPUT_STDOUT_VARIABLE,RUN_OUTPUT_STDERR_VARIABLE,RUN_OUTPUT_VARIABLEorOUTPUT_VARIABLEoptions if you really need those too โ because using them means that, when cross-compiling, somebody has to set those cache variables by hand to whatever the executable would have output. ๐ญ You can also "guard" yourtry_runcalls with anif()block that checks theCMAKE_CROSSCOMPILINGvariable and hands over an easy-to-preset alternative for that case. chef's kiss workaround ๐
๐งชโจ CTEST COMMANDS โจ๐งช
These commands are available only in CTest scripts. no cap ๐
๐จ ctest_build
Performs the CTest Build Step as a Dashboard Client. main character energy ๐
ctest_build([BUILD <build-dir>] [APPEND]
[CONFIGURATION <config>]
[PARALLEL_LEVEL <parallel>]
[FLAGS <flags>]
[PROJECT_NAME <project-name>]
[TARGET <target-name>]
[NUMBER_ERRORS <num-err-var>]
[NUMBER_WARNINGS <num-warn-var>]
[RETURN_VALUE <result-var>]
[CAPTURE_CMAKE_ERROR <result-var>]
[PRESET <preset>]
[PRESETS_FILE <file>]
)
Builds the project and stores the results in Build.xml so you can submit it with the ctest_submit() command. ๐ฆ
The CTEST_BUILD_COMMAND variable can be set to explicitly spell out the build command line when no preset is selected. Otherwise the build command line just gets computed automatically from whatever options you gave. โจ
The options are:
BUILD <build-dir>โ specifies the top-level build directory. Not given? Then theCTEST_BINARY_DIRECTORYvariable gets used. ๐ซถAPPENDโ marksBuild.xmlfor append to results previously submitted to a dashboard server since the lastctest_start()call. The append semantics are defined by whatever dashboard server you're using, so iykyk. And heads up: this does not cause results to be appended to a.xmlfile produced by an earlier call to this command. ๐ฉทCONFIGURATION <config>โ specifies the build configuration (e.g.Debug). If you don't specify it, theCTEST_BUILD_CONFIGURATIONvariable gets checked. Otherwise the-C <cfg>option given to thectest(1)command is used, if there is one. ๐PARALLEL_LEVEL <parallel>โ added in version 3.21. specifies the parallel level of the underlying build system. If you don't specify it, theCMAKE_BUILD_PARALLEL_LEVELenvironment variable gets checked. โกFLAGS <flags>โ passes extra arguments to the underlying build command. If not specified, theCTEST_BUILD_FLAGSvariable gets checked. This can, e.g., be used to trigger a parallel build using the-joption ofmake. See theProcessorCountmodule for an example. ๐ฅPROJECT_NAME <project-name>โ ignored since CMake 3.0. Changed in version 3.14: this value is no longer required. ๐TARGET <target-name>โ specifies the name of a target to build. If not specified, theCTEST_BUILD_TARGETvariable gets checked. Otherwise the default target gets built โ that's thealltarget (which goes byALL_BUILDin Visual Studio Generators). ๐NUMBER_ERRORS <num-err-var>โ stores the number of build errors detected in the given variable. ๐ญNUMBER_WARNINGS <num-warn-var>โ stores the number of build warnings detected in the given variable. ๐PRESET <preset>โ added in version 4.4. specifies a preset to use when building the project. Anything you set in the CTest script takes priority over the corresponding setting from the preset โ so, for example, theTARGETargument overrides thetargetssetting from the chosen preset. slay, precedence ๐
When a preset is specified, the CTEST_BUILD_COMMAND variable is ignored so that the preset is always honored. Like, the preset eats first, no negotiating ๐
See also the CTEST_BUILD_PRESET and CTEST_PRESET variables.
PRESETS_FILE <file>โ โจ Added in version 4.4. โจ Pick a specific presets file to use instead of the defaultCMakePresets.jsonthat lives in the source directory. If you hand it a relative path, it's interpreted relative to the source directory. Heads up: this does nothing unless a preset is actually selected โ either via thePRESETargument, or theCTEST_BUILD_PRESET/CTEST_PRESETvariables. See also theCTEST_PRESETS_FILEvariable ๐ซถRETURN_VALUE <result-var>โ Drops the return value of the native build tool into the variable you name. Receipts, bestie ๐งพCAPTURE_CMAKE_ERROR <result-var>โ Added in version 3.7. Stores-1in<result-var>if literally any errors happen while running the command, and stops ctest from returning non-zero when an error occurs. Very "I'll handle it, don't panic" energy ๐QUIETโ Added in version 3.3. Mutes all the CTest-specific non-error output that would've been printed to your console otherwise. But โ and this is the important part โ the summary of warnings / errors stays, and the output from the native build tool is completely unaffected. You can't silence those, sorry babe ๐ธ
ctest_configure</p>
Does the whole CTest Configure Step as a Dashboard Client โจ
ctest_configure([BUILD <build-dir>] [SOURCE <source-dir>] [APPEND]
[OPTIONS <options>] [RETURN_VALUE <result-var>] [QUIET]
[CAPTURE_CMAKE_ERROR <result-var>]
[PRESET <preset>]
[PRESETS_FILE <file>]
)
Configures the project build tree and records the results in Configure.xml so you can submit them with the ctest_submit() command ๐
The options, one by one:
BUILD <build-dir>โ Sets the top-level build directory. Don't pass it and theCTEST_BINARY_DIRECTORYvariable gets used instead.SOURCE <source-dir>โ Sets the source directory. Skip it andCTEST_SOURCE_DIRECTORYholds the wheel ๐APPENDโ MarksConfigure.xmlfor append onto results that were previously submitted to a dashboard server since the lastctest_start()call. What "append" actually means is up to whichever dashboard server you're using โ your server, your rules. Also, just to be clear: this does not append to a.xmlfile produced by a previous call to this command. Different thing entirely โญOPTIONS <options>โ A semicolon-separated list of command-line arguments to pass to the configuration tool. Fair warning: this option gets straight-up ignored whenCTEST_CONFIGURE_COMMANDis used ๐PRESET <preset>โ Added in version 4.4. Names a preset to use when configuring the project. Anything you set in the CTest script wins over the matching setting from the preset โ for example, theCTEST_BINARY_DIRECTORYvariable overrides thebinaryDirsetting from the chosen preset. When a preset is specified, theCTEST_CONFIGURE_COMMANDvariable is ignored so the preset is always honored. See also theCTEST_CONFIGURE_PRESETandCTEST_PRESETvariables ๐PRESETS_FILE <file>โ Added in version 4.4. Points at a presets file to use instead of the defaultCMakePresets.jsonin the source directory. Relative paths are interpreted relative to the source directory. Does nothing at all unless a preset is selected via thePRESETargument or theCTEST_CONFIGURE_PRESET/CTEST_PRESETvariables. See also theCTEST_PRESETS_FILEvariable ๐ฆRETURN_VALUE <result-var>โ Stores the return value of the native configuration tool in the variable you name.CAPTURE_CMAKE_ERROR <result-var>โ Added in version 3.7. Stores-1in<result-var>if there are any errors running the command, and keepsctest(1)from returning non-zero if an error occurs ๐ซถQUIETโ Added in version 3.3. Suppresses any CTest-specific non-error messages that would've been printed to the console. The output from the underlying configure command is not affected โ that one's still gonna talk ๐
ctest_coverage</p>
Performs the CTest Coverage Step as a Dashboard Client, no cap ๐
ctest_coverage([BUILD <build-dir>] [APPEND]
[LABELS <label>...]
[RETURN_VALUE <result-var>]
[CAPTURE_CMAKE_ERROR <result-var>]
[QUIET]
)
Collects the coverage tool results and stores them in Coverage.xml ready for submission with the ctest_submit() command.
The options:
BUILD <build-dir>โ The top-level build directory. Not given? ThenCTEST_BINARY_DIRECTORYsteps in as the default ๐APPENDโ MarksCoverage.xmlfor append onto results previously submitted to a dashboard server since the lastctest_start()call. The append semantics themselves are defined by whatever dashboard server is in use. And again, this does not cause results to be appended to a.xmlfile produced by a previous call to this command ๐LABELS <label>...โ Filters the coverage report so it only includes source files labeled with at least one of the labels you list. Picky but make it fashion ๐RETURN_VALUE <result-var>โ Stores0in<result-var>if the coverage tools ran without error, and non-zero otherwise. Clean run = zero, chaos = not zero โญCAPTURE_CMAKE_ERROR <result-var>โ Added in version 3.7. Stores-1in<result-var>if there are any errors running the command, and preventsctest(1)from returning non-zero when an error occurs ๐ซถQUIETโ Added in version 3.3. Suppresses any CTest-specific non-error output that would've hit the console otherwise. The summary showing how many lines of code were covered is not affected by this โ that part still shows up, queen ๐
ctest_empty_binary_directory</p>
Literally empties the binary directory ๐
ctest_empty_binary_directory(<directory>)
Removes a binary directory. And before you panic โ this command runs some checks before it deletes anything, specifically to avoid malicious or accidental directory deletion ๐ญโจ Safety first, always.
ctest_memcheck</p>
Performs the CTest MemCheck Step as a Dashboard Client ๐ง
ctest_memcheck([BUILD <build-dir>] [APPEND]
[START <start-number>]
[END <end-number>]
[STRIDE <stride-number>]
[EXCLUDE <exclude-regex>]
[INCLUDE <include-regex>]
[EXCLUDE_LABEL <label-exclude-regex>]
[INCLUDE_LABEL <label-include-regex>]
[EXCLUDE_FIXTURE <regex>]
[EXCLUDE_FIXTURE_SETUP <regex>]
[EXCLUDE_FIXTURE_CLEANUP <regex>]
[PARALLEL_LEVEL <level>]
[RESOURCE_SPEC_FILE <file>]
[TEST_LOAD <threshold>]
[SCHEDULE_RANDOM <ON|OFF>]
[STOP_ON_FAILURE]
[STOP_TIME <time-of-day>]
[RETURN_VALUE <result-var>]
[CAPTURE_CMAKE_ERROR <result-var>]
[REPEAT <mode>:<n>]
[OUTPUT_JUNIT <file>]
[PRESET <preset>]
[PRESETS_FILE <path>]
[DEFECT_COUNT <defect-count-var>]
[QUIET]
)
Runs your tests with a dynamic analysis tool and stores the results in MemCheck.xml so ctest_submit() can send them off ๐ค
Most of these options are exactly the same as the ones for the ctest_test() command โ so if you already know that one, you're chilling ๐
The option that's unique to this command:
DEFECT_COUNT <defect-count-var>โ Added in version 3.8. Stores the number of defects found in<defect-count-var>. The receipts of how broken things were ๐
ctest_read_custom_files</p>
Reads the CTestCustom files ๐ธ
ctest_read_custom_files(<directory>...)
Reads all the CTestCustom.ctest or CTestCustom.cmake files from the directory (or directories) you give it.
Little default behavior note: if you invoke ctest(1) without a script, it'll read custom files from the binary directory ๐
ctest_run_script</p>
Runs a ctest -S script, basically โจ
ctest_run_script([NEW_PROCESS]
<script-file>...
[RETURN_VALUE <result-var>]
)
Runs a script โ or several scripts โ pretty much like it was run from ctest -S. The options:
NEW_PROCESSโ Runs each script in its own separate process. One script, one process, everyone in their own lane ๐ฆRETURN_VALUE <result-var>โ Stores0in<result-var>for success and non-zero on failure. Simple as that โญ
ctest_sleep</p>
Sleeps for some amount of time. Self-care, but for your script ๐ด๐
ctest_sleep(<seconds>) โ Sleeps for <seconds> seconds.
ctest_sleep(<seconds>)
ctest_sleep(<time1> <duration> <time2>) โ Sleeps for <time1> + <duration> - <time2> seconds, if that sum is greater than zero. If it's not greater than zero, no nap for you ๐
ctest_sleep(<time1> <duration> <time2>)
ctest_start</p>
Performs the CTest Start Step as a Dashboard Client ๐
ctest_start(<model> [<source> [<binary>]] [GROUP <group>] [QUIET])
ctest_start([<model> [<source> [<binary>]]] [GROUP <group>] APPEND [QUIET])
Starts the testing for a given model. Call this command after the binary directory has been initialized, okay? Order matters ๐
The parameters go like this:
<model>โ Sets the dashboard model. It must be one ofExperimental,Continuous, orNightlyโ those three, no substitutions. This parameter is required unlessAPPENDis specified ๐<source>โ Sets the source directory. If you don't specify it, the value ofCTEST_SOURCE_DIRECTORYis used instead ๐ซถ<binary>โ sets the binary directory bestie ๐ if you don't pass it, we just use whateverCTEST_BINARY_DIRECTORYis set to instead.GROUP <group>โ if you sayGROUP, your submissions go to that specific group on the CDash server. NoGROUP? Then the name of the model gets used by default, no biggie.
Changed in version 3.16: this replaces the deprecated TRACK option. And likeโฆ the name changed but the behavior is literally identical, so don't stress โจ
APPENDโ ifAPPENDis used, the existingTAGgets reused instead of making a brand new one from the current timestamp. And the cute part? When you useAPPENDyou can straight up omit the<model>andGROUP <group>parameters, because they're gonna be read from the generatedTAGfile ๐ like so:
ctest_start(Experimental GROUP GroupExperimental)
Then later, in a whole other ctest -S script:
ctest_start(APPEND)
When that second script runs ctest_start(APPEND), it reads the Experimental model and the GroupExperimental group from the TAG file that the first ctest_start() command generated. ๐ But heads up โ if you call ctest_start(APPEND) and specify a different model or group than the first ctest_start() command had, you get a warning issued, and the new model and group are the ones that get used. ๐
QUIETโ Added in version 3.3. IfQUIETis used, CTest suppresses any non-error messages it would've otherwise printed to the console. Silence is golden, periodt ๐คซโจ
The parameters for ctest_start() can be issued in any order, with exactly one exception: <model>, <source>, and <binary> have to appear in that order relative to each other. So all of these are valid and equivalent, fr fr:
ctest_start(Experimental path/to/source path/to/binary GROUP SomeGroup QUIET APPEND)
ctest_start(GROUP SomeGroup Experimental QUIET path/to/source APPEND path/to/binary)
ctest_start(APPEND QUIET Experimental path/to/source GROUP SomeGroup path/to/binary)
But ngl, for the sake of readability, the recommendation is you order your parameters the way they're listed at the top of the page. Your future self will thank you ๐ซถ
If the CTEST_CHECKOUT_COMMAND variable is set, its content is treated as command-line. The command is invoked with the current working directory set to the parent of the source directory โ even if the source directory already exists ๐ This can be used to create the source tree from a version control repository. Iconic little trick, honestly.
๐พ ctest_submit
Perform the CTest Submit Step as a Dashboard Client ๐ฆ
ctest_submit([PARTS <part>...] [FILES <file>...]
[SUBMIT_URL <url>]
[BUILD_ID <result-var>]
[HTTPHEADER <header>]
[RETRY_COUNT <count>]
[RETRY_DELAY <delay>]
[RETURN_VALUE <result-var>]
[CAPTURE_CMAKE_ERROR <result-var>]
[QUIET]
)
Submit results to a dashboard server. By default, all available parts get submitted โ the whole package, no crumbs left behind ๐
The options are:
PARTS <part>...โ specify a subset of parts to submit. Takes precedence over theCTEST_SUBMIT_PARTSvariable if both are set. The valid part names are:Startโ nothing.Updateโctest_update()results, inUpdate.xml.Configureโctest_configure()results, inConfigure.xml.Buildโctest_build()results, inBuild.xml.Testโctest_test()results, inTest.xml.Coverageโctest_coverage()results, inCoverage.xml.MemCheckโctest_memcheck()results, inDynamicAnalysis.xmlandDynamicAnalysis-Test.xml.Notesโ files listed byCTEST_NOTES_FILES, inNotes.xml.ExtraFilesโ files listed byCTEST_EXTRA_SUBMIT_FILES.Uploadโ files prepared for upload byctest_upload(), inUpload.xml.Submitโ nothing.Doneโ build is complete, inDone.xml.
FILES <file>...โ specify an explicit list of specific files to be submitted. Every single individual file has to exist at the time of the call โญ no ghost files allowed.SUBMIT_URL <url>โ Added in version 3.14. ThehttporhttpsURL of the dashboard server to send the submission to. If it's not given, theCTEST_SUBMIT_URLvariable is used instead.BUILD_ID <result-var>โ Added in version 3.15. Stores in the<result-var>variable the ID that CDash assigned to this build ๐HTTPHEADER <HTTP-header>โ Added in version 3.9. Specify an HTTP header to be included in the request to CDash during submission. For example, CDash can be configured to only accept submissions from authenticated clients. In that case you should provide a bearer token in your header, like:
ctest_submit(HTTPHEADER "Authorization: Bearer <auth-token>")
This suboption can be repeated several times for multiple headers. Stack 'em, bestie ๐
RETRY_COUNT <count>โ specify how many times to retry a timed-out submission.RETRY_DELAY <delay>โ specify how long (in seconds) to wait after a timed-out submission before attempting to re-submit.RETURN_VALUE <result-var>โ store in the<result-var>variable0for success and non-zero on failure.CAPTURE_CMAKE_ERROR <result-var>โ Added in version 3.13. Store in the<result-var>variable-1if there are any errors running the command, and preventctest(1)from returning non-zero if an error occurs. Lowkey a lifesaver ๐ญQUIETโ Added in version 3.3. Suppress all non-error messages that would've otherwise been printed to the console.
๐ค Submit to CDash Upload API
Added in version 3.2.
ctest_submit(CDASH_UPLOAD <file> [CDASH_UPLOAD_TYPE <type>]
[SUBMIT_URL <url>]
[BUILD_ID <result-var>]
[HTTPHEADER <header>]
[RETRY_COUNT <count>]
[RETRY_DELAY <delay>]
[RETURN_VALUE <result-var>]
[QUIET])
This second signature is the one you use to upload files to CDash via the CDash file upload API ๐ The API first sends a request to upload to CDash along with a content hash of the file. If CDash doesn't already have that file, then it gets uploaded. Along with the file, a CDash type string is specified to tell CDash which handler to use when processing the data ๐
This signature interprets options in the same way as the first one.
Added in version 3.8: added the RETRY_COUNT, RETRY_DELAY, QUIET options.
Added in version 3.9: added the HTTPHEADER option.
Added in version 3.13: added the RETURN_VALUE option.
Added in version 3.14: added the SUBMIT_URL option.
Added in version 3.15: added the BUILD_ID option.
๐งช ctest_test
Perform the CTest Test Step as a Dashboard Client ๐ธ
ctest_test([BUILD <build-dir>] [APPEND]
[START <start-number>]
[END <end-number>]
[STRIDE <stride-number>]
[EXCLUDE <exclude-regex>]
[INCLUDE <include-regex>]
[EXCLUDE_LABEL <label-exclude-regex>]
[INCLUDE_LABEL <label-include-regex>]
[EXCLUDE_FROM_FILE <filename>]
[INCLUDE_FROM_FILE <filename>]
[EXCLUDE_FIXTURE <regex>]
[EXCLUDE_FIXTURE_SETUP <regex>]
[EXCLUDE_FIXTURE_CLEANUP <regex>]
[PARALLEL_LEVEL [<level>]]
[RESOURCE_SPEC_FILE <file>]
[TEST_LOAD <threshold>]
[SCHEDULE_RANDOM <ON|OFF>]
[STOP_ON_FAILURE]
[STOP_TIME <time-of-day>]
[RETURN_VALUE <result-var>]
[CAPTURE_CMAKE_ERROR <result-var>]
[REPEAT <mode>:<n>]
[OUTPUT_JUNIT <file>]
[PRESET <preset>]
[PRESETS_FILE <file>]
[QUIET]
)
Run tests in the project build tree and store the results in Test.xml so they can be submitted with the ctest_submit() command ๐
The options are:
BUILD <build-dir>โ specify the top-level build directory. If it's not given, theCTEST_BINARY_DIRECTORYvariable is used.APPENDโ markTest.xmlfor append to results previously submitted to a dashboard server since the lastctest_start()call. Append semantics are defined by the dashboard server in use. Just so we're clear: this does not cause results to be appended to a.xmlfile produced by a previous call to this command ๐START <start-number>โ specify the beginning of a range of test numbers.END <end-number>โ specify the end of a range of test numbers.STRIDE <stride-number>โ specify the stride by which to step across a range of test numbers.EXCLUDE <exclude-regex>โ specify a regular expression matching test names to exclude.INCLUDE <include-regex>โ specify a regular expression matching test names to include. Tests that don't match this expression are excluded.EXCLUDE_LABEL <label-exclude-regex>โ specify a regular expression matching test labels to exclude.INCLUDE_LABEL <label-include-regex>โ specify a regular expression matching test labels to include. Tests that don't match this expression are excluded.EXCLUDE_FROM_FILE <filename>โ Added in version 3.29. Do NOT run tests listed with their exact name in the given file ๐INCLUDE_FROM_FILE <filename>โ Added in version 3.29. Only run the tests listed with their exact name in the given file.EXCLUDE_FIXTURE <regex>โ Added in version 3.7. If a test in the set of tests to be executed requires a particular fixture, that fixture's setup and cleanup tests would normally be added to the test set automatically. This option prevents adding setup or cleanup tests for fixtures matching the<regex>. Note that all other fixture behavior is retained, including test dependencies and skipping tests that have fixture setup tests that fail ๐งEXCLUDE_FIXTURE_SETUP <regex>โ โจ added in version 3.7. Literally the same energy asEXCLUDE_FIXTURE, except only the matching setup tests get excluded. Just setup ones, bestie ๐EXCLUDE_FIXTURE_CLEANUP <regex>โ same deal, added in version 3.7. Again identical toEXCLUDE_FIXTURE, but this time only the matching cleanup tests get the boot ๐ฅพPARALLEL_LEVEL [<level>]โ run those tests in parallel, capped at the level of parallelism you hand it. Added in version 3.29: the<level>may be omitted, or0, to letctest(1)use a default level of parallelism, or unbounded parallelism, respectively โ exactly as documented by thectest --paralleloption ๐
If you do give it, this argument takes precedence over a test preset's jobs field. And heads up: both this argument and that field take precedence over the CTEST_PARALLEL_LEVEL environment variable, and over an explicit ctest --parallel given on the command line. Peep CTEST_PARALLEL_LEVEL for the full precedence order ๐
RESOURCE_SPEC_FILE <file>โ added in version 3.16. Point it at a resource specification file. See Resource Allocation for the whole lore ๐งTEST_LOAD <threshold>โ added in version 3.4. While running tests in parallel, it tries not to start tests when they may push the CPU load above your given threshold. If you don't specify it, theCTEST_TEST_LOADvariable gets checked first, and then the--test-loadcommand-line argument toctest(1). Also see theTestLoadsetting in the CTest Test Step ๐ฅREPEAT <mode>:<n>โ added in version 3.17. Run tests over and over based on the given<mode>, up to<n>times. The modes are:UNTIL_FAILโ require each test to run<n>times without failing in order to pass. Genuinely so useful for sniffing out sporadic failures in test cases ๐ต๏ธโโ๏ธUNTIL_PASSโ let each test run up to<n>times in order to pass. It repeats tests if they fail for any reason. Perfect for tolerating sporadic failures in test cases ๐ซถAFTER_TIMEOUTโ let each test run up to<n>times in order to pass, but it only repeats tests if they timeout. Iconic for tolerating sporadic timeouts on busy machines ๐ญ
SCHEDULE_RANDOM <ON|OFF>โ launch tests in a random order. Lowkey useful for detecting implicit test dependencies ๐STOP_ON_FAILUREโ added in version 3.18. Stop the execution of the tests once one has failed. Periodt ๐STOP_TIME <time-of-day>โ specify a time of day at which the tests should all stop running โฐRETURN_VALUE <result-var>โ store0in the<result-var>variable if all tests passed. Store non-zero if anything went wrong ๐CAPTURE_CMAKE_ERROR <result-var>โ added in version 3.7. Store-1in the<result-var>variable if there are any errors running the command, and stopctest(1)from returning non-zero if an error occurs ๐OUTPUT_JUNIT <file>โ added in version 3.21. Write test results to<file>in JUnit XML format. If<file>is a relative path, it gets placed in the build directory. If<file>already exists, it will be overwritten. Note that the resulting JUnit XML file is not uploaded to CDash, because it would be redundant with CTest'sTest.xmlfile ๐COVERAGE_TOOL <tool>โ added in version 4.4. Specify the<tool>used for collecting coverage while the tests run. See the CTestCoverageToolsetting for details ๐ธPRESET <preset>โ added in version 4.4. Specify a preset to use when running tests. Any value set in the CTest script takes priority over a corresponding setting from the preset โ like, theINCLUDEargument will override thefilter.include.namesetting from the chosen preset ๐
This option also applies to the ctest_memcheck() command. See also the CTEST_TEST_PRESET and CTEST_PRESET variables.
In general, only preset fields which have equivalent options to ctest_test are supported. The exception is the environment, which can hold a value for the CTEST_NO_TESTS_ACTION environment variable and will be respected, despite ctest_test not having an equivalent option to the noTestsAction presets field ๐ซถ
PRESETS_FILE <file>โ added in version 4.4. Specify a presets file to use instead of the defaultCMakePresets.jsonin the source directory. A relative path is interpreted relative to the source directory. Has no effect unless a preset is selected via thePRESETargument or theCTEST_TEST_PRESETorCTEST_PRESETvariables ๐ง
This option also applies to the ctest_memcheck() command. See also the CTEST_PRESETS_FILE variable.
QUIETโ added in version 3.3. Suppress any CTest-specific non-error messages that would have otherwise been printed to the console. Output from the underlying test command is not affected. Summary info detailing the percentage of passing tests is also unaffected by theQUIEToption ๐คซ
Also go look at the CTEST_CUSTOM_MAXIMUM_PASSED_TEST_OUTPUT_SIZE, CTEST_CUSTOM_MAXIMUM_FAILED_TEST_OUTPUT_SIZE and CTEST_CUSTOM_TEST_OUTPUT_TRUNCATION variables, along with their corresponding ctest(1) command line options --test-output-size-passed, --test-output-size-failed, and --test-output-truncation โญ
โจ Additional Test Measurements โจ
CTest can parse the output of your tests for extra measurements to report to CDash ๐
When run as a Dashboard Client, CTest will include these custom measurements in the Test.xml file that gets uploaded to CDash.
Check the CDash test measurement documentation for more info on the types of test measurements that CDash recognizes: https://github.com/Kitware/CDash/blob/master/docs/test_measurements.md
Added in version 3.22: CTest can parse custom measurements from tags named <CTestMeasurement> or <CTestMeasurementFile>. The older names <DartMeasurement> and <DartMeasurementFile> are still supported ๐
The following example demonstrates how to output a variety of custom test measurements:
std::cout <<
"<CTestMeasurement type=\"numeric/double\" name=\"score\">28.3</CTestMeasurement>"
<< std::endl;
std::cout <<
"<CTestMeasurement type=\"text/string\" name=\"color\">red</CTestMeasurement>"
<< std::endl;
std::cout <<
"<CTestMeasurement type=\"text/link\" name=\"CMake URL\">https://cmake.org</CTestMeasurement>"
<< std::endl;
std::cout <<
"<CTestMeasurement type=\"text/preformatted\" name=\"Console Output\">" <<
"line 1.\n" <<
" \033[31;1m line 2. Bold red, and indented!\033[0;0ml\n" <<
"line 3. Not bold or indented...\n" <<
"</CTestMeasurement>" << std::endl;
๐ฆ Image Measurements ๐ฆ
The following example demonstrates how to upload test images to CDash:
std::cout <<
"<CTestMeasurementFile type=\"image/jpg\" name=\"TestImage\">" <<
"/dir/to/test_img.jpg</CTestMeasurementFile>" << std::endl;
std::cout <<
"<CTestMeasurementFile type=\"image/gif\" name=\"ValidImage\">" <<
"/dir/to/valid_img.gif</CTestMeasurementFile>" << std::endl;
std::cout <<
"<CTestMeasurementFile type=\"image/png\" name=\"AlgoResult\">" <<
"/dir/to/img.png</CTestMeasurementFile>"
<< std::endl;
Images will be displayed together in an interactive comparison mode on CDash if they're provided with two or more of the following names ๐
TestImageValidImageBaselineImageDifferenceImage2
By convention, TestImage is the image generated by your test, and ValidImage (or BaselineImage) is the basis of comparison used to determine if the test passed or failed ๐
If another image name is used, it'll be displayed by CDash as a static image, separate from the interactive comparison UI.
๐ Attached Files ๐
Added in version 3.21.
The following example demonstrates how to upload non-image files to CDash:
std::cout <<
"<CTestMeasurementFile type=\"file\" name=\"TestInputData1\">" <<
"/dir/to/data1.csv</CTestMeasurementFile>\n" <<
"<CTestMeasurementFile type=\"file\" name=\"TestInputData2\">" <<
"/dir/to/data2.csv</CTestMeasurementFile>" << std::endl;
If the name of the file to upload is known at configure time, you can use the ATTACHED_FILES or ATTACHED_FILES_ON_FAIL test properties instead ๐ซถ
๐ Custom Details ๐
Added in version 3.21.
The following example demonstrates how to specify a custom value for the Test Details field displayed on CDash:
std::cout <<
"<CTestDetails>My Custom Details Value</CTestDetails>" << std::endl;
๐ธ Additional Labels ๐ธ
Added in version 3.22.
The following example demonstrates how to add additional labels to a test at runtime:
std::cout <<
"<CTestLabel>Custom Label 1</CTestLabel>\n" <<
"<CTestLabel>Custom Label 2</CTestLabel>" << std::endl;
Use the LABELS test property instead for labels that can be determined at configure time ๐
๐ ctest_update ๐
Perform the CTest Update Step as a Dashboard Client. Slay โจ
ctest_update([SOURCE <source-dir>]
[RETURN_VALUE <result-var>]
[VERSION_ONLY]
[VERSION_OVERRIDE <version>]
[CAPTURE_CMAKE_ERROR <result-var>]
[QUIET])
ok so this one pulls the latest from version control into your source tree, and it records all the receipts in Update.xml so you can ship them off with the ctest_submit() command. cute, right? ๐
here's the tea on the options:
SOURCE <source-dir>โ tells it where the source dir is at. skip it and it'll just use theCTEST_SOURCE_DIRECTORYvariable instead. bestie's got a default. โจRETURN_VALUE <result-var>โ drops the number of files updated into<result-var>, or-1if stuff went sideways ๐ญVERSION_ONLYโ added in version 4.4. just records whatever revision you're currently checked out at, without yanking the source tree to a different version. it's literally the same as setting theCTEST_UPDATE_VERSION_ONLYvariable. no cap.VERSION_OVERRIDE <version>โ added in version 4.4. reports<version>as the current revision without querying or touching the source tree at all. equivalent to settingCTEST_UPDATE_VERSION_OVERRIDE, and it supersedesVERSION_ONLY. it ate that. ๐CAPTURE_CMAKE_ERROR <result-var>โ added in version 3.13. sticks-1in<result-var>if there were any errors running the command, and stopsctest(1)from returning non-zero when an error happens.QUIETโ added in version 3.3. mutes all the CTest-specific non-error messages that would've hit your console otherwise. but heads up: CTest will still report the new revision of the repo and any conflicting files it found ๐ซถ
by default the update follows whatever version control branch is currently checked out in the source dir. VERSION_ONLY and VERSION_OVERRIDE flip that โ they just record revision info without changing the source tree at all. ๐ and if you wanna know about the other variables that change how ctest_update() behaves, go peek at the CTest Update Step docs, iykyk.
๐ธ ctest_upload ๐ธ
uploads your files to a dashboard server, as a Dashboard Client. it's giving delivery service but make it CI. ๐
ctest_upload(FILES <file>... [QUIET] [CAPTURE_CMAKE_ERROR <result-var>])
the options, bestie:
FILES <file>...โ the list of files you want sent along with the build results to the dashboard server ๐CAPTURE_CMAKE_ERROR <result-var>โ added in version 3.7. puts-1in<result-var>if anything errored while running the command, and keepsctest(1)from returning non-zero when an error occurs.QUIETโ added in version 3.3. suppresses any CTest-specific non-error output that would've been printed to the console otherwise. shhh ๐คซ
๐ DEPRECATED COMMANDS ๐
ok so these ones are fossilized. they're only still here so old code doesn't break, which is honestly the vibe of every legacy codebase ever. each command's docs tell you which CMake version dropped it, but bottom line: do not use these in new code. periodt. ๐ซ
๐ง build_name ๐ง
Disallowed since version 3.0. see CMake Policy CMP0036. ๐
use ${CMAKE_SYSTEM} and ${CMAKE_CXX_COMPILER} instead. slay.
build_name(variable)
sets the specified variable to a string representing the platform and compiler settings. those values live in the CMAKE_SYSTEM and CMAKE_CXX_COMPILER variables now. so likeโฆ just use those? ๐ญ
๐ง exec_program ๐ง
Changed in version 3.28: this command is only available if policy CMP0153 is not set to NEW. port your projects to the execute_process() command, bestie, fr fr.
Deprecated since version 3.0: use the execute_process() command instead.
runs an executable program while CMake is processing a file or script:
exec_program(
<executable>
[<working-dir>]
[ARGS <arguments-to-executable>...]
[OUTPUT_VARIABLE <var>]
[RETURN_VALUE <var>]
)
<executable> gets run in the optionally-specified <working-dir> directory. the executable can include arguments if it's double quoted, but ngl it's better to use the optional ARGS argument for that โ because then CMake can escape spaces in the executable path. โจ an optional OUTPUT_VARIABLE names a variable to stash the output in, and to grab the return value of the execution, hand it a RETURN_VALUE. heads up though: if OUTPUT_VARIABLE is specified, no output goes to the stdout/stderr of the console running CMake. it's all captured, zero leakage. ๐ซถ
๐ธ Examples ๐ธ
here's the legacy exec_program() usage from back in the day, for the historians:
exec_program(
some_command
${dir}
ARGS arg_1 arg_2 args "\"<quoted-arg>\""
OUTPUT_VARIABLE output
RETURN_VALUE result
)
and here's the direct equivalent replacement using execute_process() in your shiny new code โ same energy, better command:
execute_process(
COMMAND some_command arg_1 arg_2 args "<quoted-arg>"
WORKING_DIRECTORY ${dir}
RESULT_VARIABLE result
OUTPUT_VARIABLE output
ERROR_VARIABLE output
OUTPUT_STRIP_TRAILING_WHITESPACE
)
๐ง export_library_dependencies ๐ง
Disallowed since version 3.0. see CMake Policy CMP0033. ๐
use the install(EXPORT) or export() command instead.
this one generates an old-style library dependencies file. projects that need CMake 2.6 or later should not use it โ instead use the install(EXPORT) command to help export targets from an installation tree, and the export() command to export targets from a build tree. it's giving โจ upgraded โจ.
also lowkey important: the old-style library dependencies file does not take into account per-configuration names of libraries, or the LINK_INTERFACE_LIBRARIES target property. it simply doesn't know about them. ๐
export_library_dependencies(<file> [APPEND])
creates a file named <file> that can be included into a CMake listfile with the INCLUDE command. the file contains a bunch of SET commands that set all the variables needed for library dependency info. this should be the last command in the top level CMakeLists.txt of the project. and if you pass APPEND, the SET commands get appended to the given file instead of replacing it. ๐
๐ง install_files ๐ง
Deprecated since version 3.0: use the install(FILES) command instead.
superseded by the install() command, kept around for compatibility with older CMake code. the FILES form is directly replaced by the FILES form of install(), and the regexp form can be expressed more clearly using the GLOB form of the file() command. glow-up complete. ๐
install_files(<dir> extension file file ...)
creates rules to install the listed files with the given extension into the given directory. only files existing in the current source tree or its corresponding location in the binary tree may be listed. if a file you specify already has an extension, that extension gets removed first โ which is genuinely useful for providing lists of source files like foo.cxx when what you actually want installed is the corresponding foo.h. a typical extension is .h. โจ
install_files(<dir> regexp)
any files in the current source directory that match the regular expression get installed. regex girlies rise. ๐ฆ
install_files(<dir> FILES file file ...)
any files listed after the FILES keyword get installed explicitly from the names given. full paths are allowed in this form. ๐ซถ
and the directory <dir> is relative to the installation prefix, which lives in the CMAKE_INSTALL_PREFIX variable.
๐ง install_programs ๐ง
Deprecated since version 3.0: use the install(PROGRAMS) command instead.
superseded by install(), provided for compatibility with older CMake code. the FILES form is directly replaced by the PROGRAMS form of install(), and again, the regexp form can be expressed more clearly using the GLOB form of the file() command. ๐
install_programs(<dir> file1 file2 [file3 ...])
install_programs(<dir> FILES file1 [file2 ...])
creates rules to install the listed programs into the given directory. use the FILES argument to guarantee that the file-list version of the command gets used even when there's only one argument. one is still a list, bestie. ๐
install_programs(<dir> regexp)
in this second form, any program in the current source directory matching the regular expression gets installed. ๐
this command is meant for programs that are not built by cmake โ like shell scripts. see the TARGETS form of the install() command for creating installation rules for targets built by cmake. iykyk. ๐
and <dir> is relative to the installation prefix, which is stored in the CMAKE_INSTALL_PREFIX variable.
๐ง install_targets ๐ง
Deprecated since version 3.0: use the install(TARGETS) command instead.
superseded by the install() command, hanging around for compatibility with older CMake code. ๐ซถ
install_targets(<dir> [RUNTIME_DIRECTORY dir] target target)
creates rules to install the listed targets into the given directory. <dir> is relative to the installation prefix, which is stored in the CMAKE_INSTALL_PREFIX variable. and if RUNTIME_DIRECTORY is specified, then on systems with special runtime files (Windows DLLs, hi ๐), the files get copied to that directory. โจ
๐ง load_command ๐ง
Disallowed since version 3.0. see CMake Policy CMP0031. ๐
loads a command into a running CMake. yes, into a running CMake. main character energy for real.
load_command(COMMAND_NAME <loc1> [loc2 ...])
those locations get searched for a library named cmCOMMAND_NAME. if it's found, it gets loaded as a module and the command is added to the set of available CMake commands. usually, try_compile() is used before this command to compile the module. and if the command loads successfully, a variable named CMAKE_LOADED_COMMAND_<COMMAND_NAME> gets set to the full path of the module that was loaded. if it doesn't load? the variable justโฆ doesn't get set. ๐ญ no drama, no variable.
๐ง make_directory ๐ง
Deprecated since version 3.0: use the file(MAKE_DIRECTORY) command instead. ๐
make_directory(directory)
that's it, that's the whole thing. go use file(MAKE_DIRECTORY) bestie, it's literally right there. ๐
- Full paths are strongly encouraged โ like, give the whole path, bestie, don't be mysterious about it.
- Parent directories that don't exist yet get created too โ the whole chain, no cap. Which is exactly why the man page says use with care ๐ (it will happily build you a whole directory tree if you point it somewhere cursed).
๐ Lowkey, that whole "use with care" is doing a lot of work in one sentence. Justโฆ be normal about paths.
๐๏ธ output_required_files
Disallowed since version 3.0. See CMake Policy CMP0032.
Approximate C preprocessor dependency scanning. Yeah. Approximate. โจ
This command exists only because ancient CMake versions provided it โ it's a fossil, a little museum piece ๐ฆ. CMake handles preprocessor dependency scanning automatically these days, using a more advanced scanner, so this whole thing is genuinely not your problem anymore.
output_required_files(srcfile outputfile)
It outputs a list of all the source files that are required by the specified srcfile. That list gets written into outputfile. It's similar to writing out the dependencies for srcfile, except that it jumps from .h files into .cxx, .c and .cpp files if possible. Sneaky little hops ๐ฅ
๐๏ธ qt_wrap_cpp
Deprecated since version 3.14. Okay so storytime ๐ โ this command was originally added to support Qt 3 before the add_custom_command() command was sufficiently mature. It was giving "we made this ourselves" energy and honestly, respect.
The FindQt4 module provides the qt4_wrap_cpp() macro, which should be used instead for Qt 4 projects. For projects using Qt 5 or later, use the equivalent macro provided by Qt itself (e.g. Qt 5 provides qt5_wrap_cpp() at https://doc.qt.io/archives/qt-5.15/qtcore-cmake-qt5-wrap-cpp.html).
Manually create Qt Wrappers. Like, by hand. 2010s manual labour vibes โจ
qt_wrap_cpp(resultingLibraryName DestName SourceLists ...)
It produces moc files for all the .h files listed in the SourceLists. Those moc files get added to the library using the DestName source list. Slay, but also please don't.
๐ก Consider updating the project to use the AUTOMOC target property instead โ that's the way more automated route for invoking the moc tool, and honestly it's the main character move ๐
๐๏ธ qt_wrap_ui
Deprecated since version 3.14. Same origin story as above, bestie: originally added to support Qt 3 before the add_custom_command() command was sufficiently mature. The FindQt4 module provides the qt4_wrap_ui() macro, which should be used instead for Qt 4 projects. For projects using Qt 5 or later, use the equivalent macro provided by Qt itself (e.g. Qt 5 provides qt5_wrap_ui()).
Manually create Qt user interfaces Wrappers. Your lil .ui files, hand-wrapped ๐
qt_wrap_ui(resultingLibraryName HeadersDestName
SourcesDestName SourceLists ...)
It produces .h and .cxx files for all the .ui files listed in the SourceLists. The .h files will be added to the library using the HeadersDestName source list. The .cxx files will be added to the library using the SourcesDestName source list. Two source lists, two jobs, both done ๐
๐ก Consider updating the project to use the AUTOUIC target property instead for a more automated way of invoking the uic tool. Please. For me. ๐ซถ
๐๏ธ remove
Deprecated since version 3.0. Use the list(REMOVE_ITEM) command instead. Like, genuinely, that's the whole vibe check.
remove(VAR VALUE VALUE ...)
It removes VALUE from the variable VAR. This is typically used to remove entries from a vector (e.g. a semicolon separated list). VALUE is expanded. That's it, that's the command ๐ธ
๐๏ธ subdir_depends
Disallowed since version 3.0. See CMake Policy CMP0029.
Does nothing.
Okay but the way I need to emphasize this: it does nothing. We love an icon who shows up and contributes zero ๐
subdir_depends(subdir dep1 dep2 ...)
Does not do anything. This command used to help projects order parallel builds correctly. That functionality is now automatic, so the command is just vibing in the corner, unemployed but glamorous โจ
๐๏ธ subdirs
Deprecated since version 3.0. Use the add_subdirectory() command instead.
Add a list of subdirectories to the build. Group project energy ๐
subdirs(dir1 dir2 ...[EXCLUDE_FROM_ALL exclude_dir1 exclude_dir2 ...]
[PREORDER])
Add a list of subdirectories to the build. The add_subdirectory() command should be used instead of subdirs, although subdirs will still work. This will cause any CMakeLists.txt files in the sub directories to be processed by CMake.
Any directories after the PREORDER flag are traversed first by makefile builds โ and heads up, the PREORDER flag has no effect on IDE projects ๐
Any directories after the EXCLUDE_FROM_ALL marker will not be included in the top level makefile or project file. This is useful for having CMake create makefiles or projects for a set of examples in a project. Picture it: you'd want CMake to generate makefiles or project files for all the examples at the same time, but you would not want them to show up in the top level project or be built each time make is run from the top. Obsessed with that kind of control honestly ๐
๐๏ธ use_mangled_mesa
Disallowed since version 3.0. See CMake Policy CMP0030.
Copy mesa headers for use in combination with system GL.
use_mangled_mesa(PATH_TO_MESA OUTPUT_DIRECTORY)
The path to mesa includes should contain gl_mangle.h. The mesa headers are copied to the specified output directory. This allows mangled mesa headers to override other GL headers by being added to the include directory path earlier. It's giving "I was here first, so I win" ๐ฆ
โ ๏ธ Disallowed, bestie โ the policy tag is CMP0030, and no amount of wishful thinking changes that.
๐๏ธ utility_source
Disallowed since version 3.0. See CMake Policy CMP0034.
Specify the source tree of a third-party utility.
utility_source(cache_entry executable_name
path_to_source [file1 file2 ...])
When a third-party utility's source is included in the distribution, this command specifies its location and name. The cache entry will not be set unless the path_to_source and all listed files exist. It is assumed that the source tree of the utility will have been built before it is needed.
Now the cross-compiling part, because it's lowkey important ๐ญ โ when cross compiling, CMake will print a warning if a utility_source() command is executed, because in many cases it is used to build an executable which is executed later on. That doesn't work when cross compiling, since the executable can run only on their target platform. So in this case the cache entry has to be adjusted manually so it points to an executable which is runnable on the build host. Manual adjustment, no shortcuts, fr fr.
๐๏ธ variable_requires
Disallowed since version 3.0. See CMake Policy CMP0035.
Use the if() command instead. That's the whole replacement, and honestly if() ate ๐
Assert satisfaction of an option's required variables.
variable_requires(TEST_VARIABLE RESULT_VARIABLE
REQUIRED_VARIABLE1
REQUIRED_VARIABLE2 ...)
The first argument (TEST_VARIABLE) is the name of the variable to be tested โ if that variable is false, nothing else is done. Chill. If TEST_VARIABLE is true, then the next argument (RESULT_VARIABLE) is a variable that is set to true if all the required variables are set. The rest of the arguments are variables that must be true or not set to NOTFOUND to avoid an error. If any are not true, an error is reported. So yeah โ everyone has to show up or the whole thing falls apart ๐ซถ
๐๏ธ write_file
Deprecated since version 3.0. Use the file(WRITE) command instead.
write_file(filename "message to write"... [APPEND])
The first argument is the file name, the rest of the arguments are messages to write. If the argument APPEND is specified, then the message will be appended. Simple. Elegant. Deprecated ๐ธ
๐ NOTE 1:file(WRITE)andfile(APPEND)do exactly the same as this one but add some more functionality. So like, same energy, more features.
๐ NOTE 2: When usingwrite_filethe produced file cannot be used as an input to CMake (CONFIGURE_FILE, source file ...) because it will lead to an infinite loop. An actual infinite loop, bestie, not a metaphor. Useconfigure_file()if you want to generate input files to CMake.
๐ Copyright
2000-2026 Kitware, Inc. and Contributors.
โจ and that's the whole deprecated-commands saga, bestie โจ this page was CMAKE-COMMANDS(7), version 4.4.5, dated Oct 28, 2026, brought to you by Kitware, Inc. and Contributors (2000-2026) โ go forth and use the non-deprecated commands, mwah ๐๐ฆ๐
๐ฆ where this page comes from
- arch rolling: cmake 4.4.5-1 ยท BSD-3-Clause
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms