跳转至

CMakeLists

  • https://cmake.org/cmake/help/latest/
  • https://runebook.dev/zh-CN/docs/cmake/
  • https://zhuanlan.zhihu.com/p/534439206
CMakeLists中命令不区分大小写的,但通常建议命令使用大写

1 入门示例

  • cmake_minimum_required:指定cmake最低版本
  • project:指定项目名称
  • add_executable:添加可执行文件
cmake_minimum_required(VERSION 3.10)

## set the project name
project(Tutorial)

## add the executable
add_executable(Tutorial tutorial.cxx)

2 项目命令

2.1 项目设置

2.1.1 cmake_minimum_required

  • 功能:设置需要的cmake最小版本号
  • 语法:cmake_minimum_required(VERSION <min>[...<policy_max>] [FATAL_ERROR])
    • <min>:(必选)最小版本号,格式是major.minor[.patch[.tweak]],比如1.2.0
    • ...<policy_max>:(可选)最大版本号
    • FATAL_ERROR:(可选)该参数在cmake的_2.6_及以后的版本被忽略,在cmake的_2.4_及以前的版本,需要指明该参数,以便cmake能提示失败而不仅仅是一个警告。
  • 示例
cmake_minimum_required(VERSION 3.12.0)
cmake_minimum_required(VERSION 3.12.0...3.24.0)

2.1.2 project

project会影响以下几个变量:
- `PROJECT_NAME`:这是在当前目录范围或上层范围内最近一次调用的 project() 命令的名称。
- `CMAKE_PROJECT_NAME`:这是在顶级 CMakeLists.txt 文件中最近一次调用project() 命令的名称。
- `PROJECT_SOURCE_DIR`, `<PROJECT-NAME>_SOURCE_DIR`:项目源文件的绝对路径
- `PROJECT_BINARY_DIR`, `<PROJECT-NAME>_BINARY_DIR`:项目二进制文件的绝对路径
- `PROJECT_IS_TOP_LEVEL`, `<PROJECT-NAME>_IS_TOP_LEVEL`:New in version 3.21.
  • 功能:设置项目的名称,并将其存储在变量 PROJECT_NAME 中。当从顶层调用时,CMakeLists.txt 还将项目名称存储在变量 CMAKE_PROJECT_NAME 中。
  • 语法:project(<PROJECT-NAME> [<language-name>...])
  • 示例
cmake_minimum_required(VERSION 3.0)
project(First)
project(Second)
add_subdirectory(sub)
project(Third)

2.2 库生成

1. `add_dependencies`相当于gcc中`-l`链接库
2. `target_include_directories、include_directories`相当于gcc中`-I`头文件搜索路径
3. 

2.2.1 add_executable

  • 功能:使用指定的源文件生成可执行文件。
  • 语法:add_executable(<name> [source1] [source2 ...])
    • <name>:可执行文件名
    • [source1] [source2 ...]:源文件名
  • 示例
add_executable(main main.cc)

2.2.2 add_library

  • 功能:使用指定的源文件生成库文件。
  • 语法:add_library(<name> [STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL] [<source>...])
    • <name>
    • [STATIC | SHARED | MODULE]:STATIC表示静态库、SHARED表示动态库
    • [EXCLUDE_FROM_ALL]
    • [<source>...]
title: 当不指定库类型时,生成静态库还是动态库,遵循什么规则?
1. 当`BUILD_SHARED_LIBS`变量值为ON时,生成动态库,否则生成静态库
  • 示例:设置BUILD_SHARED_LIBS变量值ON,生成动态库
message(STATUS "BUILD_SHARED_LIBS=${BUILD_SHARED_LIBS}" )
set(BUILD_SHARED_LIBS on )
message(STATUS "BUILD_SHARED_LIBS=${BUILD_SHARED_LIBS}" )
add_library(MathFunctions mysqrt.cxx)

## cmake输出结果(部分)
-- BUILD_SHARED_LIBS=
-- BUILD_SHARED_LIBS=on
## make 输出结果(部分)
[ 25%] Building CXX object MathFunctions/CMakeFiles/MathFunctions.dir/mysqrt.cxx.o
[ 50%] Linking CXX shared library libMathFunctions.so
  • 示例:生成动态库
add_library(MathFunctions SHARED mysqrt.cxx)

### make 输出结果(部分)
[ 25%] Building CXX object MathFunctions/CMakeFiles/MathFunctions.dir/mysqrt.cxx.o
[ 50%] Linking CXX shared library libMathFunctions.so
  • 示例:生成静态库
add_library(MathFunctions STATIC mysqrt.cxx)

### make 输出结果(部分)
[ 25%] Building CXX object MathFunctions/CMakeFiles/MathFunctions.dir/mysqrt.cxx.o
[ 50%] Linking CXX static library libMathFunctions.a

2.2.3 add_dependencies

  • 功能:在目标添加一个依赖关系,确保依赖库在目标链接前已经存在,比如生成main可执行文件需要链接liba.so,libb.so,则可以使用add_dependencies(main a b)
  • 语法:add_dependencies(<target> [<target-dependency>]...)
    • <target>:只能是add_library、add_executable指定的目标文件

2.2.4 add_definitions

  • 功能:添加宏定义
  • 语法add_definitions(-DFOO -DBAR ...)

2.2.5 add_compile_definitions

  • 功能:将预处理器定义添加到源文件的编译中
  • 语法:add_compile_definitions(<definition> ...),使用语法 VAR 或 VAR=value 指定定义。

2.2.6 target_include_directories、include_directories

title: target_include_directories、include_directories区别?
其中target_include_directories只添加到指定的目标上,而include_directories将给定目录添加到编译器用于搜索包含文件的目录
  • 功能:添加 include 文件搜索路径
target_include_directories(<target> [SYSTEM] [AFTER|BEFORE]
  <INTERFACE|PUBLIC|PRIVATE> [items1...]
  [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
  • 功能:指定目标文件的依赖库
  • 语法:target_link_libraries(<target> ... <item>... ...)
    • <target>:只能是add_library、add_executable指定的目标文件

2.2.8 add_subdirectory

  • 功能:将子目录添加到 cmake 构建树中。
  • 语法:
add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL] [SYSTEM])

其中 source_dir 指定了源 CMakeLists.txt 和代码文件所在的目录,可选的 binary_dir 表示的是构建生成二进制文件的位置,如果不指定 binary_dir,则使用 source_dir 作为输出目录

2.3 依赖检查

2.3.1 find_library

  • 功能:找到一个库。
  • 语法:
find_library (<VAR> name1 [path1 path2 ...])

其中 <VAR> 是一个变量,用来存储查询结果,如果查询成功则是库的全路径,否则是 <VAR>-NOTFOUNDname1 是查询的库名称,可以是 libnsl.so 或者去除前缀后缀的 nslpath 则表示要搜索库的位置。

2.3.2 find_package

  • 功能:找到一个包 (通常由项目外部提供)。

2.4 脚本命令

2.4.1 message

在3.17后增加了check功能

-功能:输出提示信息 - 语法:

message([<mode>] "message text" ...)
message(<checkState> "message text" ...)
  • 主要的mode有
    • FATAL_ERROR:错误,会停止执行cmake命令
    • WARNING:警告,继续执行
    • STATUS:状态信息
  • 新增的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()
  • 输出
-- Finding my things
--   Finding partA
--   Finding partA - found
--   Finding partB
--   Finding partB - not found
-- Finding my things - missing components: B

2.4.2 set

  • 功能:给变量设置值
  • 语法:
    • 设置普通变量:set(<variable> <value>... [PARENT_SCOPE])
    • 设置Cache Entry:set(<variable> <value>... CACHE <type> <docstring> [FORCE])
    • 设置ENV变量:set(ENV{<variable>} [<value>])
  • 示例
message(STATUS "BUILD_SHARED_LIBS=${BUILD_SHARED_LIBS}" )
set(BUILD_SHARED_LIBS on )
message(STATUS "BUILD_SHARED_LIBS=${BUILD_SHARED_LIBS}" )
message(STATUS "CC=$ENV{CC}")
set(ENV{CC} g++)
message(STATUS "CC=$ENV{CC}")
  • 输出
-- BUILD_SHARED_LIBS=
-- BUILD_SHARED_LIBS=on
-- CC=
-- CC=g++
-- Configuring done
-- Generating done

2.4.3 string

- 内容较多,参考[官方文档](https://cmake.org/cmake/help/latest/command/string.html#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>)

2.4.4 list

- 内容较多,参考[官方文档](https://cmake.org/cmake/help/latest/command/list.html#list)
  • 功能:列表操作
  • 语法:其中最常用的是APPEND,向列表追加内容
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> [...])

2.4.5 option

  • 功能:提供用户可以选择的布尔选项。通常和if条件语句配合使用,可选择的执行命令
  • 语法:option(<variable> "<help_text>" [value])
    • <variable> :选项的变量名
    • "<help_text>":针对选项的帮助信息
    • [value]:默认是OFF,表示选项关闭,ON表示选项打开
  • 示例
option(OPENMESSAGE "是否执行信息输出" OFF)
if(OPENMESSAGE)
message(STATUS "condition 1")
else()
message(STATUS "condition 2")
endif()
  • 输出:cmake .
$ cmake .
-- condition 2
  • 输出: cmake -DOPENMESSAGE=ON .
$ cmake -DOPENMESSAGE=ON .
-- condition 1

2.4.6 条件if

- 详细教程参考[官方文档](https://cmake.org/cmake/help/latest/command/if.html)
  • 功能:有条件地执行一组命令。
  • 语法:
if(<condition>)
  <commands>
elseif(<condition>) ## optional block, can be repeated
  <commands>
else()              ## optional block
  <commands>
endif()
  • 示例
option(OPENMESSAGE "是否执行信息输出" OFF)
if(OPENMESSAGE)
message(STATUS "condition 1")
else()
message(STATUS "condition 2")
endif()

2.4.7 function

  • 功能:定义一个函数,可以被调用。
  • 语法:
function(<name> [<arg1> ...])
  <commands>
endfunction()

其中 <name> 表示函数名称,<arg1> 表示函数参数,<commands> 是函数体,最后的 endfunction() 是函数结束标志。

定义为:

function(foo)
  <commands>
endfunction()

函数调用不区分大小写。可以以下任一种方式调用:

foo()
Foo()
FOO()
cmake_language(CALL foo)

2.4.8 endfunction

  • 功能:配合 function 使用,表示函数结束。
  • 语法:
endfunction([<name>])

其中 <name> 是可选的,如果要写,必须和 function 中的 <name> 一致。

2.5 变量

title: cmake中变量有3种类型
1. Normal Variable(普通变量):
2. Environment Variable(环境变量):如`CC、CFLAGS、CMAKE_PREFIX_PATH`等
3. Cache Entry(缓存条目):

2.5.1 变量值获取

  • 普通变量:${variable}
  • 环境变量:$ENV{variable}

2.5.2 变量值设置

设置变量的方式有3种,可以通过以下命令设置
1. set
2. string
3. list
---
示例如下:
Strings using `set()`:
- `set(MyString "Some Text")`
- `set(MyStringWithVar "Some other Text: ${MyString}")`
- `set(MyStringWithQuot "Some quote: \"${MyStringWithVar}\"")`

Or with `string()`:
- `string(APPEND MyStringWithContent " ${MyString}")`

Lists using `set()`:
- `set(MyList "a" "b" "c")`
- `set(MyList ${MyList} "d")`

Or better with `list()`:
- `list(APPEND MyList "a" "b" "c")`
- `list(APPEND MyList "d")`
  • 普通变量:set(<variable> [<value>])
  • 环境变量:set(ENV{<variable>} [<value>])
  • 示例
message(STATUS "BUILD_SHARED_LIBS=${BUILD_SHARED_LIBS}" )
set(BUILD_SHARED_LIBS on )
message(STATUS "BUILD_SHARED_LIBS=${BUILD_SHARED_LIBS}" )
message(STATUS "CC=$ENV{CC}")
set(ENV{CC} g++)
message(STATUS "CC=$ENV{CC}")
add_library(MathFunctions mysqrt.cxx)

### cmake输出结果(部分)
-- BUILD_SHARED_LIBS=
-- BUILD_SHARED_LIBS=on
-- CC=/usr/bin/cc
-- CC=g++