OLLVM学习之三 —— CMake学习
本帖最后由 lichao 于 2024-9-23 08:52 编辑## 写在前面
  因为有事在外地一周, 所以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>... )
unset(<variable> )
```
```cmake
set(MY_VARIABLE "value") # 声明变量
set(MY_LIST "one" "two") # 列表
set(MY_LIST "one;two") # 同上
```
* 缓存变量
```
set(<variable> <value>... CACHE <type> <docstring> )
unset(<variable> )
```
预定义变量<https://cmake.org/cmake/help/latest/manual/cmake-variables.7.html>
```cmake
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型变量
```
* 环境变量
```cmake
set(ENV{<variable>} [<value>])
unset(ENV{<variable>})
```
```cmake
set(ENV{MY_ENV} value) # 设置
$ENV{MY_ENV} # 读取
```
* 属性
```cmake
set_property(<GLOBAL |
DIRECTORY [<dir>] |
TARGET [<target1> ...] |
SOURCE [<src1> ...]
|
INSTALL [<file1> ...] |
TEST [<test1> ...]
|
CACHE [<entry1> ...] >
PROPERTY <name> [<value1> ...])
```
预定义属性<https://cmake.org/cmake/help/latest/manual/cmake-properties.7.html>
```cmake
set_property(TARGET TargetName PROPERTY CXX_STANDARD 11)# 可设置多目标
set_target_properties(TargetName PROPERTIES CXX_STANDARD 11) # 设置一个目标多属性
get_property(ResultVariable TARGET TargetName PROPERTY CXX_STANDARD)
```
### 宏和函数
宏:
```cmake
macro(<name> [<arg1> ...])
<commands>
endmacro()
```
参数:
`${ARGC}, ${ARGV0}, ${ARGV1}, ${ARGV2}, ...`
`${ARGN}`
例:
```cmake
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)
```
函数:
```cmake
function(<name> [<arg1> ...])
<commands>
endfunction()
```
调用及参数同宏
```cmake
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}")
```
输出:
```txt
-- 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
```cmake
set(message_command "message")
cmake_language(CALL ${message_command} STATUS "Hello World!")
# 等价于
message(STATUS "Hello World!")
```
* 表达式计算
`cmake_language(EVAL CODE <code>...)`
```cmake
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
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
```
```cmake
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
语法
```cmake
if(<condition>)
<commands>
elseif(<condition>) # optional block, can be repeated
<commands>
else() # optional block
<commands>
endif()
```
##### 基本表达式
```cmake
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
```
##### 逻辑操作
```cmake
if(NOT <condition>)
if(<cond1> AND <cond2>)
if(<cond1> OR <cond2>)
if((condition) AND (condition OR (condition)))
```
##### 存在性检测
```cmake
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>)
```
##### 文件操作
```cmake
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>)
```
##### 比较
```cmake
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>)
```
##### 版本比较
```cmake
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>)
```
##### 路径比较
```cmake
if(<variable|string> PATH_EQUAL <variable|string>)
```
```cmake
# 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
```cmake
while(<condition>)
<commands>
endwhile()
```
#### foreach
```cmake
foreach(<loop_var> <items>)
<commands>
endforeach()
foreach(<loop_var> RANGE <stop>)
foreach(<loop_var> RANGE <start> <stop> [<step>])
```
```cmake
foreach(<loop_var> IN ] ])
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()
```
```cmake
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
```cmake
# 在配置阶段的DEBUG模式下开启编译标志
target_compile_options(MyTarget PRIVATE "$<$<CONFIG:Debug>:--my-flag>")
# 编译阶段和安装阶段指定不同的目录
target_include_directories(
MyTarget
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
```
#### block
```cmake
block( ] )
<commands>
endblock()
```
```cmake
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
从文件/目录/函数返回
```cmake
return()
```
```cmake
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
例:
```cmake
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>...)`
```cmake
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
```cmake
find_package(<PackageName> [<version>] )
find_package(<PackageName>
[ ]
)
find_package(<PackageName>
[ ]
]
]
]
]
]
# Deprecated; does nothing.
[CMAKE_FIND_ROOT_PATH_BOTH |
ONLY_CMAKE_FIND_ROOT_PATH |
NO_CMAKE_FIND_ROOT_PATH])
```
### include
```cmake
include(<file|module> )
```
### file
```cmake
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> )
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
```cmake
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
```cmake
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>] )
string(UUID <out-var> ...)
JSON
string(JSON <out-var>
{GET | TYPE | LENGTH | REMOVE}
<json-string> <member|index> [<member|index> ...])
string(JSON <out-var>
MEMBER <json-string>
[<member|index> ...] <index>)
string(JSON <out-var>
SET <json-string>
<member|index> [<member|index> ...] <value>)
string(JSON <out-var>
EQUAL <json-string1> <json-string2>)
```
### find
```cmake
find_file (<VAR> name1 )
find_file (
<VAR>
name | NAMES name1
... ]
... ]
]
[CMAKE_FIND_ROOT_PATH_BOTH |
ONLY_CMAKE_FIND_ROOT_PATH |
NO_CMAKE_FIND_ROOT_PATH]
)
```
```cmake
find_library (<VAR> name1 )
find_library (
<VAR>
name | NAMES name1
... ]
... ]
]
[CMAKE_FIND_ROOT_PATH_BOTH |
ONLY_CMAKE_FIND_ROOT_PATH |
NO_CMAKE_FIND_ROOT_PATH]
)
```
```cmake
find_path (<VAR> name1 )
find_path (
<VAR>
name | NAMES name1
... ]
... ]
]
[CMAKE_FIND_ROOT_PATH_BOTH |
ONLY_CMAKE_FIND_ROOT_PATH |
NO_CMAKE_FIND_ROOT_PATH]
)
```
```cmake
find_program (<VAR> name1 )
find_program (
<VAR>
name | NAMES name1
... ]
... ]
]
[CMAKE_FIND_ROOT_PATH_BOTH |
ONLY_CMAKE_FIND_ROOT_PATH |
NO_CMAKE_FIND_ROOT_PATH]
)
```
### math
`math(EXPR <variable> "<expression>" )`
例:
```cmake
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>] )`
#### cmake_host_system_information
* 查询主机信息
`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>)`
```cmake
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)
```
生成:
```txt
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> ] <args>)`
```cmake
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
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 <out-var>)
cmake_path(GET <path-var> STEM <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> <out-var>)
cmake_path(COMPARE <input1> <OP> <input2> <out-var>)
cmake_path(SET <path-var> <input>)
cmake_path(APPEND <path-var> [<input>...] )
cmake_path(APPEND_STRING <path-var> [<input>...] )
cmake_path(REMOVE_FILENAME <path-var> )
cmake_path(REPLACE_FILENAME <path-var> <input> )
cmake_path(REMOVE_EXTENSION <path-var> )
cmake_path(REPLACE_EXTENSION <path-var> <input> )
cmake_path(NORMAL_PATH <path-var> )
cmake_path(RELATIVE_PATH <path-var> )
cmake_path(ABSOLUTE_PATH <path-var> )
cmake_path(NATIVE_PATH <path-var> <out-var>)
cmake_path(CONVERT <input> TO_CMAKE_PATH_LIST <out-var> )
cmake_path(CONVERT <input> TO_NATIVE_PATH_LIST <out-var> )
cmake_path(HASH <path-var> <out-var>)
```
#### configure_file
```cmake
configure_file(<input> <output>
[NO_SOURCE_PERMISSIONS | USE_SOURCE_PERMISSIONS |
FILE_PERMISSIONS <permissions>...]
[@ONLY]
])
```
```txt
# 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
```cmake
execute_process(COMMAND <cmd1> [<arguments>]
]...
)
```
#### 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> ...)`
```cmake
if (MSVC)
# warning level 4
add_compile_options(/W4)
else()
# additional warnings
add_compile_options(-Wall -Wextra -Wpedantic)
endif()
```
#### add_definitions
```cmake
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
```cmake
add_custom_target(Name ]
...]
]
])
```
#### add_custom_command
```cmake
add_custom_command(OUTPUT output1
COMMAND command1
...]
]
]
[IMPLICIT_DEPENDS <lang1> depend1
[<lang2> depend2] ...]
)
```
```cmake
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 )`
#### enable_language
`enable_language(<lang>... )`
#### export
```cmake
export(TARGETS <target>... [...])
export(EXPORT <export-name> [...])
export(PACKAGE <PackageName>)
export(SETUP <export-name> [...])
export(TARGETS <target>... [...])
export(TARGETS <target>...
FILE <filename>
)
```
#### build_command
```cmake
build_command(<variable>
# legacy, causes warning
)
```
#### cmake_file_api
```
cmake_file_api(
QUERY
API_VERSION <version>
)
```
#### define_property
```cmake
define_property(<GLOBAL | DIRECTORY | TARGET | SOURCE |
TEST | VARIABLE | CACHED_VARIABLE>
PROPERTY <name>
]
]
)
```
#### get_target_property
`get_target_property(<variable> <target> <property>)`
#### include_directories
`include_directories( dir1 )`
#### include_regular_expression
`include_regular_expression(regex_match )`
#### link_directories
`link_directories( directory1 )`
#### link_libraries
`link_libraries(]] [ <item>] ...)`
#### load_cache
```cmake
load_cache(pathToBuildDirectory READ_WITH_PREFIX prefix entry1...)
load_cache(pathToBuildDirectory )
```
#### set_target_properties
`set_target_properties(<targets> ... PROPERTIES <prop1> <value1> [<prop2> <value2>] ...)`
#### target_compile_definitions
```cmake
target_compile_definitions(<target>
<INTERFACE|PUBLIC|PRIVATE>
[<INTERFACE|PUBLIC|PRIVATE> ...])
```
#### target_compile_features
`target_compile_features(<target> <PRIVATE|PUBLIC|INTERFACE> <feature> [...])`
#### target_compile_options
```cmake
target_compile_options(<target> <INTERFACE|PUBLIC|PRIVATE> [<INTERFACE|PUBLIC|PRIVATE> ...])
```
#### target_include_directories
```cmake
target_include_directories(<target>
<INTERFACE|PUBLIC|PRIVATE>
[<INTERFACE|PUBLIC|PRIVATE> ...])
```
#### target_link_directories
```cmake
target_link_directories(<target>
<INTERFACE|PUBLIC|PRIVATE>
[<INTERFACE|PUBLIC|PRIVATE> ...])
```
#### target_link_libraries
```cmake
target_link_libraries(<target> ... <item>... ...)
# 目标和/或其依赖
target_link_libraries(<target>
<PRIVATE|PUBLIC|INTERFACE> <item>...
[<PRIVATE|PUBLIC|INTERFACE> <item>...]...)
# 目标及其依赖
target_link_libraries(<target> <item>...)
```
#### target_link_options
```cmake
target_link_options(<target>
<INTERFACE|PUBLIC|PRIVATE>
[<INTERFACE|PUBLIC|PRIVATE> ...])
```
#### target_precompile_headers
```cmake
target_precompile_headers(<target>
<INTERFACE|PUBLIC|PRIVATE>
[<INTERFACE|PUBLIC|PRIVATE> ...])
```
#### target_sources
```cmake
target_sources(<target> <INTERFACE|PUBLIC|PRIVATE> [<INTERFACE|PUBLIC|PRIVATE> ...])
```
#### add_library
普通库:
`add_library(<name> [<type>] <sources>...)`
type: STATIC/SHARED/MODULE/EXCLUDE_FROM_ALL
目标库:
`add_library(<name> OBJECT <sources>...)`
`add_library(... $<TARGET_OBJECTS:objlib> ...)`
`add_executable(... $<TARGET_OBJECTS:objlib> ...)`
接口库:
`add_library(<name> INTERFACE)`
`add_library(<name> INTERFACE <sources>...)`
导入库:
`add_library(<name> <type> IMPORTED )`
别名库:
`add_library(<name> ALIAS <target>)`
#### install
```cmake
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
```cmake
project(<PROJECT-NAME> [<language-name>...])
project(<PROJECT-NAME>
]]]
)
```
页:
[1]