lichao 发表于 2024-9-10 22:46:17

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]
查看完整版本: OLLVM学习之三 —— CMake学习