写在前面
因为有事在外地一周, 所以OLLVM学习耽搁了几天, 现在接着之前的研究继续. 为什么要研究CMake呢, 因为LLVM底层使用CMake编译, 且笔者将要作为测试基板的LLVM-Pass基于CMake也是最方便的, 虽然笔者在第一篇中也用过Makefile.
CMake版本历史
- 2003-08 1.x
- 2005-04 2.x
- 2014-06 3.0 引入target_*/find_package
- 2014-12 3.1 支持C++11/14, 引入CMake_build_type
- 2015-03 3.2 支持UTF8, 引入CMake_language/CMake_policy
- 2015-11 3.4 支持Swift, 支持CCache
- 2016-03 3.5 支持ARM
- 2016-11 3.7 支持交叉编译到Android, 支持服务器模式
- 2017-04 3.8 支持C#, 支持CUDA, 支持C++17
- 2017-11 3.10 支持CppCheck
- 2018-07 3.12 支持cmake_minimum_required, 支持-j/--parallel并行构建, 支持C++20
- 2018-11 3.13 支持target_link_options/add_link_options/target_link_directories
- 2019-11 3.16 支持Objective-C/Objective-C++
- 2021-03 3.20 支持C++23
- 2021-07 3.21 支持MSYS
- 2022-11 3.25 支持C++26
CMake语法
变量
set(<variable> <value>... [PARENT_SCOPE])
unset(<variable> [PARENT_SCOPE])
set(MY_VARIABLE "value") # 声明变量
set(MY_LIST "one" "two") # 列表
set(MY_LIST "one;two") # 同上
set(<variable> <value>... CACHE <type> <docstring> [FORCE])
unset(<variable> [CACHE])
预定义变量https://cmake.org/cmake/help/latest/manual/cmake-variables.7.html
set(MY_CACHE_VARIABLE "VALUE" CACHE STRING "Description")
set(MY_CACHE_VARIABLE "VALUE" CACHE STRING "" FORCE) # 覆盖已有值
option(MY_OPTION "This is settable from the command line" OFF) # BOOL型变量
set(ENV{<variable>} [<value>])
unset(ENV{<variable>})
set(ENV{MY_ENV} value) # 设置
$ENV{MY_ENV} # 读取
set_property(<GLOBAL |
DIRECTORY [<dir>] |
TARGET [<target1> ...] |
SOURCE [<src1> ...]
[DIRECTORY <dirs> ...]
[TARGET_DIRECTORY <targets> ...] |
INSTALL [<file1> ...] |
TEST [<test1> ...]
[DIRECTORY <dir>] |
CACHE [<entry1> ...] >
[APPEND] [APPEND_STRING]
PROPERTY <name> [<value1> ...])
预定义属性https://cmake.org/cmake/help/latest/manual/cmake-properties.7.html
set_property(TARGET TargetName PROPERTY CXX_STANDARD 11) # 可设置多目标
set_target_properties(TargetName PROPERTIES CXX_STANDARD 11) # 设置一个目标多属性
get_property(ResultVariable TARGET TargetName PROPERTY CXX_STANDARD)
宏和函数
宏:
macro(<name> [<arg1> ...])
<commands>
endmacro()
参数:
${ARGC}, ${ARGV0}, ${ARGV1}, ${ARGV2}, ...
${ARGN}
例:
macro(foo)
<commands>
endmacro()
# 调用
foo()
Foo()
FOO()
cmake_language(CALL foo)
if(${ARGV1})
if(${ARGC} GREATER 2)
set(list_var "${ARGN}")
foreach(loop_var IN LISTS list_var)
函数:
function(<name> [<arg1> ...])
<commands>
endfunction()
调用及参数同宏
function(SIMPLE REQUIRED_ARG)
message(STATUS "Simple arguments: ${REQUIRED_ARG}, followed by ${ARGN}")
set(${REQUIRED_ARG} "From SIMPLE" PARENT_SCOPE)
endfunction()
simple(This Foo Bar)
message("Output: ${This}")
输出:
-- Simple arguments: This, followed by Foo;Bar
Output: From SIMPLE
cmake_language
- 动态调用
cmake_language(CALL <command> [<arg>...])
禁止的命令:
- if/elseif/else/endif
- block/endblock
- while/endwhile
- foreach/endforeach
- function/endfunction
- macro/endmacro
set(message_command "message")
cmake_language(CALL ${message_command} STATUS "Hello World!")
# 等价于
message(STATUS "Hello World!")
cmake_language(EVAL CODE <code>...)
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()"
)
# 等价于
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)
cmake_language(DEFER <options>... CALL <command> [<arg>...])
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")
# output
#Immediate Message
#Deferred Message
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")
# output
#Immediate Message
#Deferred Message 1
#Deferred Message 2
cmake_language(GET_MESSAGE_LOG_LEVEL <output_variable>)
cmake_language(EXIT <exit-code>)
控制流程
条件语法优先级
- 括号
- 一元操作符: EXISTS, COMMAND, DEFINED, NOT, TARGET
- 二元操作符: EQUAL, LESS, LESS_EQUAL, GREATER, GREATER_EQUAL, STREQUAL, STRLESS, STRLESS_EQUAL, STRGREATER, STRGREATER_EQUAL, VERSION_EQUAL, VERSION_LESS, VERSION_LESS_EQUAL, VERSION_GREATER, VERSION_GREATER_EQUAL, PATH_EQUAL, MATCHESVERSION_LESS_EQUAL
- 一元逻辑操作符: NOT
- 二元逻辑操作符: AND, OR
if
语法
if(<condition>)
<commands>
elseif(<condition>) # optional block, can be repeated
<commands>
else() # optional block
<commands>
endif()
基本表达式
if(<constant>) # True if the constant is 1, ON, YES, TRUE, Y, or a non-zero number, False if the constant is 0, OFF, NO, FALSE, N, IGNORE, NOTFOUND, the empty string, or ends in the suffix -NOTFOUND
if(<variable>) # True if given a variable that is defined to a value that is not a false constant. False otherwise, including if the variable is undefined
if(<string>) # A quoted string always evaluates to false unless the string's value is one of the true constants
逻辑操作
if(NOT <condition>)
if(<cond1> AND <cond2>)
if(<cond1> OR <cond2>)
if((condition) AND (condition OR (condition)))
存在性检测
if(COMMAND <command-name>) # 若目标为命令/宏/函数则为真
if(POLICY <policy-id>)
if(TARGET <target-name>) # 若目标为add_executable/add_library/add_custom_target创建则为真
if(TEST <test-name>) # 若目标是add_test创建则为真
if(DEFINED <name>|CACHE{<name>}|ENV{<name>}) # 若目标是变量/缓存变量/环境变量则为真
if(<variable|string> IN_LIST <variable>)
文件操作
if(EXISTS <path-to-file-or-directory>)
if(IS_READABLE <path-to-file-or-directory>)
if(IS_WRITABLE <path-to-file-or-directory>)
if(IS_EXECUTABLE <path-to-file-or-directory>)
if(<file1> IS_NEWER_THAN <file2>)
if(IS_DIRECTORY <path>)
if(IS_SYMLINK <path>)
if(IS_ABSOLUTE <path>)
比较
if(<variable|string> MATCHES <regex>)
if(<variable|string> LESS <variable|string>)
if(<variable|string> GREATER <variable|string>)
if(<variable|string> EQUAL <variable|string>)
if(<variable|string> LESS_EQUAL <variable|string>)
if(<variable|string> GREATER_EQUAL <variable|string>)
if(<variable|string> STRLESS <variable|string>)
if(<variable|string> STRGREATER <variable|string>)
if(<variable|string> STREQUAL <variable|string>)
if(<variable|string> STRLESS_EQUAL <variable|string>)
if(<variable|string> STRGREATER_EQUAL <variable|string>)
版本比较
if(<variable|string> VERSION_LESS <variable|string>)
if(<variable|string> VERSION_GREATER <variable|string>)
if(<variable|string> VERSION_EQUAL <variable|string>)
if(<variable|string> VERSION_LESS_EQUAL <variable|string>)
if(<variable|string> VERSION_GREATER_EQUAL <variable|string>)
路径比较
if(<variable|string> PATH_EQUAL <variable|string>)
# 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()
while
while(<condition>)
<commands>
endwhile()
foreach
foreach(<loop_var> <items>)
<commands>
endforeach()
foreach(<loop_var> RANGE <stop>)
foreach(<loop_var> RANGE <start> <stop> [<step>])
foreach(<loop_var> IN [LISTS [<lists>]] [ITEMS [<items>]])
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()
foreach(<loop_var>... IN ZIP_LISTS <lists>)
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()
break/continue
生成器表达式
可用于配置/构建/安装阶段
配置表达式: $<CONFIG:cfg_lst>
, CONFIG满足cfg_lst中一个则表达式为1, 否则为0
条件表达式: $<condition:true_string>
, condition满足则表达式为true_string
# 在配置阶段的DEBUG模式下开启编译标志
target_compile_options(MyTarget PRIVATE "$<$<CONFIGebug>:--my-flag>")
# 编译阶段和安装阶段指定不同的目录
target_include_directories(
MyTarget
PUBLIC
$<BUILD_INTERFACE{CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
block
block([SCOPE_FOR [POLICIES] [VARIABLES] ] [PROPAGATE <var-name>...])
<commands>
endblock()
set(var1 "INIT1")
set(var2 "INIT2")
block(PROPAGATE var1 var2)
set(var1 "VALUE1")
unset(var2)
endblock()
# Now var1 holds VALUE1, and var2 is unset
return
从文件/目录/函数返回
return([PROPAGATE <var-name>...])
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()
CMake命令
message
- 通用消息
message([<mode>] "message text" ...)
mode: FATAL_ERROR/SEND_ERROR/WARNING/AUTHOR_WARNING/DEPRECATION
NOTICE/STATUS/VERBOSE/DEBUG/TRACE
- 检测报告
message(<checkState> "message text" ...)
checkState: CHECK_START/CHECK_PASS/CHECK_FAIL
例:
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()
- 配置日志
message(CONFIGURE_LOG <text>...)
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()
find_package
find_package(<ackageName> [<version>] [REQUIRED] [COMPONENTS <components>...])
find_package(<ackageName> [version] [EXACT] [QUIET] [MODULE]
[REQUIRED] [[COMPONENTS] [components...]]
[OPTIONAL_COMPONENTS components...]
[REGISTRY_VIEW (64|32|64_32|32_64|HOST|TARGET|BOTH)]
[GLOBAL]
[NO_POLICY_SCOPE]
[BYPASS_PROVIDER])
find_package(<ackageName> [version] [EXACT] [QUIET]
[REQUIRED] [[COMPONENTS] [components...]]
[OPTIONAL_COMPONENTS components...]
[CONFIG|NO_MODULE]
[GLOBAL]
[NO_POLICY_SCOPE]
[BYPASS_PROVIDER]
[NAMES name1 [name2 ...]]
[CONFIGS config1 [config2 ...]]
[HINTS path1 [path2 ... ]]
[PATHS path1 [path2 ... ]]
[REGISTRY_VIEW (64|32|64_32|32_64|HOST|TARGET|BOTH)]
[PATH_SUFFIXES suffix1 [suffix2 ...]]
[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])
include
include(<file|module> [OPTIONAL] [RESULT_VARIABLE <var>] [NO_POLICY_SCOPE])
file
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 [...])
list
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} REGEX <regex>)
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> [...])
string
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>)
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 | TYPE | LENGTH | 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>)
find
find_file (<VAR> name1 [path1 path2 ...])
find_file (
<VAR>
name | NAMES name1 [name2 ...]
[HINTS [path | ENV var]... ]
[PATHS [path | ENV var]... ]
[REGISTRY_VIEW (64|32|64_32|32_64|HOST|TARGET|BOTH)]
[PATH_SUFFIXES suffix1 [suffix2 ...]]
[VALIDATOR function]
[DOC "cache documentation string"]
[NO_CACHE]
[REQUIRED]
[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]
)
find_library (<VAR> name1 [path1 path2 ...])
find_library (
<VAR>
name | NAMES name1 [name2 ...] [NAMES_PER_DIR]
[HINTS [path | ENV var]... ]
[PATHS [path | ENV var]... ]
[REGISTRY_VIEW (64|32|64_32|32_64|HOST|TARGET|BOTH)]
[PATH_SUFFIXES suffix1 [suffix2 ...]]
[VALIDATOR function]
[DOC "cache documentation string"]
[NO_CACHE]
[REQUIRED]
[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]
)
find_path (<VAR> name1 [path1 path2 ...])
find_path (
<VAR>
name | NAMES name1 [name2 ...]
[HINTS [path | ENV var]... ]
[PATHS [path | ENV var]... ]
[REGISTRY_VIEW (64|32|64_32|32_64|HOST|TARGET|BOTH)]
[PATH_SUFFIXES suffix1 [suffix2 ...]]
[VALIDATOR function]
[DOC "cache documentation string"]
[NO_CACHE]
[REQUIRED]
[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]
)
find_program (<VAR> name1 [path1 path2 ...])
find_program (
<VAR>
name | NAMES name1 [name2 ...] [NAMES_PER_DIR]
[HINTS [path | ENV var]... ]
[PATHS [path | ENV var]... ]
[REGISTRY_VIEW (64|32|64_32|32_64|HOST|TARGET|BOTH)]
[PATH_SUFFIXES suffix1 [suffix2 ...]]
[VALIDATOR function]
[DOC "cache documentation string"]
[NO_CACHE]
[REQUIRED]
[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]
)
math
math(EXPR <variable> "<expression>" [OUTPUT_FORMAT <format>])
例:
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"
其他脚本命令
cmake_minimum_required
指定CMake最小版本
cmake_minimum_required(VERSION <min>[...<policy_max>] [FATAL_ERROR])
- 查询主机信息
cmake_host_system_information(RESULT <variable> QUERY <key> ...)
key:
-
NUMBER_OF_LOGICAL_CORES
-
NUMBER_OF_PHYSICAL_CORES
-
HOSTNAME
-
FQDN (Fully qualified domain name)
-
TOTAL_VIRTUAL_MEMORY
-
AVAILABLE_VIRTUAL_MEMORY
-
TOTAL_PHYSICAL_MEMORY
-
AVAILABLE_PHYSICAL_MEMORY
-
IS_64BIT
-
HAS_FPU
-
HAS_MMX
-
HAS_MMX_PLUS
-
HAS_SSE
-
HAS_SSE2
-
HAS_SSE_FP
-
HAS_SSE_MMX
-
HAS_AMD_3DNOW
-
HAS_AMD_3DNOW_PLUS
-
HAS_IA64
-
HAS_SERIAL_NUMBER
-
PROCESSOR_SERIAL_NUMBER
-
PROCESSOR_NAME
-
PROCESSOR_DESCRIPTION
-
OS_NAME
-
OS_RELEASE
-
OS_VERSION
-
OS_PLATFORM
-
OS_PLATFORM
-
DISTRIB_INFO
-
DISTRIB_<name>
-
查询Windows注册表
cmake_host_system_information(RESULT <variable> QUERY WINDOWS_REGISTRY <key> ...)
cmake_parse_arguments
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>)
macro(my_install)
set(options OPTIONAL FAST)
set(oneValueArgs DESTINATION RENAME)
set(multiValueArgs TARGETS CONFIGURATIONS)
cmake_parse_arguments(MY_INSTALL "${options}" "${oneValueArgs}"
"${multiValueArgs}" ${ARGN} )
# ...
my_install(TARGETS foo bar DESTINATION bin OPTIONAL blub CONFIGURATIONS)
生成:
MY_INSTALL_OPTIONAL = TRUE
MY_INSTALL_FAST = FALSE # was not used in call to my_install
MY_INSTALL_DESTINATION = "bin"
MY_INSTALL_RENAME <UNDEFINED> # was not used
MY_INSTALL_TARGETS = "foo;bar"
MY_INSTALL_CONFIGURATIONS <UNDEFINED> # was not used
MY_INSTALL_UNPARSED_ARGUMENTS = "blub" # nothing expected after "OPTIONAL"
MY_INSTALL_KEYWORDS_MISSING_VALUES = "CONFIGURATIONS"
# No value for "CONFIGURATIONS" given
separate_arguments
separate_arguments(<variable> <mode> [PROGRAM [SEPARATE_ARGS]] <args>)
separate_arguments (out UNIX_COMMAND PROGRAM "cc -c main.c")
separate_arguments (out UNIX_COMMAND PROGRAM SEPARATE_ARGS "cc -c main.c")
cmake_path
路径处理
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>)
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>)
cmake_path(COMPARE <input1> <OP> <input2> <out-var>)
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>])
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>])
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])
cmake_path(HASH <path-var> <out-var>)
configure_file(<input> <output>
[NO_SOURCE_PERMISSIONS | USE_SOURCE_PERMISSIONS |
FILE_PERMISSIONS <permissions>...]
[COPYONLY] [ESCAPE_QUOTES] [@ONLY]
[NEWLINE_STYLE [UNIX|DOS|WIN32|LF|CRLF] ])
# foo.h.in
#cmakedefine FOO_ENABLE
#cmakedefine FOO_STRING "@FOO_STRING@"
# CMakeLists.txt
option(FOO_ENABLE "Enable Foo" ON)
if(FOO_ENABLE)
set(FOO_STRING "foo")
endif()
configure_file(foo.h.in foo.h @ONLY)
# output -> foo.h
#define FOO_ENABLE
#define FOO_STRING "foo"
execute_process
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>]
[ECHO_OUTPUT_VARIABLE]
[ECHO_ERROR_VARIABLE]
[COMMAND_ERROR_IS_FATAL <ANY|LAST>])
variable_watch
variable_watch(<variable> [<command>])
COMMAND(<variable> <access> <value> <current_list_file> <stack>)
项目命令
add_compile_definitions
添加预定义宏
add_compile_definitions(<definition> ...)
add_compile_options
add_compile_options(<option> ...)
if (MSVC)
# warning level 4
add_compile_options(/W4)
else()
# additional warnings
add_compile_options(-Wall -Wextra -Wpedantic)
endif()
add_definitions
add_definitions(-DFOO -DBAR ...)
remove_definitions(-DFOO -DBAR ...)
add_dependencies
add_dependencies(<target> [<target-dependency>]...)
add_executable
add_executable(<name> <options>... <sources>...)
add_link_options
add_link_options(<option> ...)
add_custom_target
add_custom_target(Name [ALL] [command1 [args1...]]
[COMMAND command2 [args2...] ...]
[DEPENDS depend depend depend ... ]
[BYPRODUCTS [files...]]
[WORKING_DIRECTORY dir]
[COMMENT comment]
[JOB_POOL job_pool]
[JOB_SERVER_AWARE <bool>]
[VERBATIM] [USES_TERMINAL]
[COMMAND_EXPAND_LISTS]
[SOURCES src1 [src2...]])
add_custom_command
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]
[COMMAND_EXPAND_LISTS]
[DEPENDS_EXPLICIT_ONLY])
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)
add_subdirectory
add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL] [SYSTEM])
enable_language
enable_language(<lang>... [OPTIONAL])
export
export(TARGETS <target>... [...])
export(EXPORT <export-name> [...])
export(PACKAGE <ackageName>)
export(SETUP <export-name> [...])
export(TARGETS <target>... [...])
export(TARGETS <target>... [NAMESPACE <namespace>]
[APPEND] FILE <filename> [EXPORT_LINK_INTERFACE_LIBRARIES]
[CXX_MODULES_DIRECTORY <directory>])
build_command
build_command(<variable>
[CONFIGURATION <config>]
[PARALLEL_LEVEL <parallel>]
[TARGET <target>]
[PROJECT_NAME <projname>] # legacy, causes warning
)
cmake_file_api
cmake_file_api(
QUERY
API_VERSION <version>
[CODEMODEL <versions>...]
[CACHE <versions>...]
[CMAKEFILES <versions>...]
[TOOLCHAINS <versions>...]
)
define_property
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>])
get_target_property
get_target_property(<variable> <target> <property>)
include_directories
include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...])
include_regular_expression
include_regular_expression(regex_match [regex_complain])
link_directories
link_directories([AFTER|BEFORE] directory1 [directory2 ...])
link_libraries
link_libraries([item1 [item2 [...]]] [[debug|optimized|general] <item>] ...)
load_cache
load_cache(pathToBuildDirectory READ_WITH_PREFIX prefix entry1...)
load_cache(pathToBuildDirectory [EXCLUDE entry1...] [INCLUDE_INTERNALS entry1...])
set_target_properties
set_target_properties(<targets> ... PROPERTIES <prop1> <value1> [<prop2> <value2>] ...)
target_compile_definitions
target_compile_definitions(<target>
<INTERFACE|PUBLIC|PRIVATE> [items1...]
[<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
target_compile_features
target_compile_features(<target> <RIVATE|PUBLIC|INTERFACE> <feature> [...])
target_compile_options
target_compile_options(<target> [BEFORE] <INTERFACE|PUBLIC|PRIVATE> [items1...] [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
target_include_directories
target_include_directories(<target> [SYSTEM] [AFTER|BEFORE]
<INTERFACE|PUBLIC|PRIVATE> [items1...]
[<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
target_link_directories
target_link_directories(<target> [BEFORE]
<INTERFACE|PUBLIC|PRIVATE> [items1...]
[<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
target_link_libraries
target_link_libraries(<target> ... <item>... ...)
# 目标和/或其依赖
target_link_libraries(<target>
<RIVATE|PUBLIC|INTERFACE> <item>...
[<RIVATE|PUBLIC|INTERFACE> <item>...]...)
# 目标及其依赖
target_link_libraries(<target> <item>...)
target_link_options
target_link_options(<target> [BEFORE]
<INTERFACE|PUBLIC|PRIVATE> [items1...]
[<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
target_precompile_headers(<target>
<INTERFACE|PUBLIC|PRIVATE> [header1...]
[<INTERFACE|PUBLIC|PRIVATE> [header2...] ...])
target_sources
target_sources(<target> <INTERFACE|PUBLIC|PRIVATE> [items1...] [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
add_library
普通库:
add_library(<name> [<type>] [EXCLUDE_FROM_ALL] <sources>...)
type: STATIC/SHARED/MODULE/EXCLUDE_FROM_ALL
目标库:
add_library(<name> OBJECT <sources>...)
add_library(... $<TARGET_OBJECTSbjlib> ...)
add_executable(... $<TARGET_OBJECTSbjlib> ...)
接口库:
add_library(<name> INTERFACE)
add_library(<name> INTERFACE [EXCLUDE_FROM_ALL] <sources>...)
导入库:
add_library(<name> <type> IMPORTED [GLOBAL])
别名库:
add_library(<name> ALIAS <target>)
install
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(RUNTIME_DEPENDENCY_SET <set-name> [...])
project
project(<ROJECT-NAME> [<language-name>...])
project(<ROJECT-NAME>
[VERSION <major>[.<minor>[.<patch>[.<tweak>]]]]
[DESCRIPTION <project-description-string>]
[HOMEPAGE_URL <url-string>]
[LANGUAGES <language-name>...])