一、工程属性相关

1.1 project

指定工程的名字和支持的语言,默认支持所有语言

PROJECT(HELLO) 			# 指定了工程的名字, 并支持所有语言--建议
PROJECT(HELLO CXX) # 指定了工程的名字, 并且支持语言为C++
PROJECT(HELLO C CXX) # 指定了工程的名字, 并且支持语言为C和C++

该指定隐式定义了两个CMake的变量

<projectname>_BINARY_DIR
<projectname>_SOURCE_DIR

MESSAGE关键字就可以直接使用这两个变量,当前都指向当前的工作目录

  1. 问题:如果改了工程名,这两个变量名也会改变
  2. 解决:CMake有两个预定义变量:PROJECT_BINARY_DIRPROJECT_SOURCE_DIR,这两个变量和HELLO_BINARY_DIRHELLO_SOURCE_DIR是一致的。所以改了工程名也没有关系

1.2 cmake_minimum_required

指定最低cmake版本

cmake_minimum_required(VERSION 3.0)

二、变量相关

2.1 预定义变量

  1. PROJECT_SOURCE_DIR:工程的根目录
  2. PROJECT_BINARY_DIR:运行 cmake 命令的目录,通常是${PROJECT_SOURCE_DIR}/build
  3. PROJECT_NAME:返回通过 project 命令定义的项目名称
  4. CMAKE_CURRENT_SOURCE_DIR:当前处理的 CMakeLists.txt 所在的路径
  5. CMAKE_CURRENT_BINARY_DIR:target 编译目录
  6. CMAKE_CURRENT_LIST_DIR:CMakeLists.txt 的完整路径
  7. CMAKE_CURRENT_LIST_LINE:当前所在的行
  8. CMAKE_MODULE_PATH:定义自己的 cmake 模块所在的路径,SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake),然后可以用INCLUDE命令来调用自己的模块
  9. EXECUTABLE_OUTPUT_PATH:重新定义目标二进制可执行文件的存放位置
  10. LIBRARY_OUTPUT_PATH:重新定义目标链接库文件的存放位置

2.2 set

显式指定变量

set(SRC_LIST main.cpp)    				# 令SRC_LIST变量包含main.cpp
set(SRC_LIST main.cpp t1.cpp t2.cpp) # 令SRC_LIST变量包含main.cpp、t1.cpp、t2.cpp

CMake缓存变量:

  1. Normal Variable 普通变量:在一个CMakeList中使用
  2. Cache Variable 缓存变量:在同一个CMake工程的任何地方都可以使用

定义缓存变量:

set(<variable> <value>... CACHE <type> <docstring> [FORCE])
set(BUILD_LIBRARY_TYPE "STATIC" CACHE STRING "Linking type for library")
  1. variable:变量名称
  2. value:变量值列表
  3. CACHE:cache变量的标志
  4. type:变量类型,取决于变量的值。类型分为:BOOLFILEPATHPATHSTRINGINTERNAL
  5. docstring:必须是字符串,作为变量概要说明
  6. FORCE:强制选项,强制修改变量值

2.3 set_property

在给定范围内设置一个对象的属性

set_property(<scope> [APPEND] [APPEND_STRING] PROPERTY <name> [value...])
set_property(CACHE BUILD_LIBRARY_TYPE PROPERTY STRINGS STATIC SHARED)
  1. scope:属性的范围

    Scope Description
    GLOBAL 属性在全局范围内有效,属性名称需唯一
    DIRECTORY 在指定目录内有效,可以是相对路径也可以是绝对路径
    TARGET 设置指定 TARGET 的属性
    SOURCE 属性对应零个或多个源文件。默认情况下,源文件属性仅对添加在同一目录 (CMakeLists.txt) 中的目标可见
    INSTALL 属性对应零个或多个已安装的文件路径。这些可供 CPack 使用以影响部署
    TEST 属性对应零个或多个现有测试
    CACHE 属性对应零个或多个缓存现有条目
  2. APPEND | APPEND_STRING:表示属性是可扩展的列表

    1. 如果设置了,那么后面的 <value1>... 将以列表的形式附加到指定属性的后面
    2. APPEND_STRING表示后面的<value1> 将以字符串的形式添加到属性的后面
  3. PROPERTY:标识

  4. name:属性名称

  5. value:属性的值

2.4 list

与SET命令类似,即使列表本身是在父域中定义的,LIST命令也只会在当前域创建新的变量

list(LENGTH	 			<list> <output variable>)
list(GET <list> <elementindex> [<element index> ...]<output variable>)
list(APPEND <list> <element> [<element> ...])
list(FIND <list> <value> <output variable>)
list(INSERT <list> <element_index> <element> [<element> ...])
list(REMOVE_ITEM <list> <value> [<value> ...])
list(REMOVE_AT <list> <index> [<index> ...])
list(REMOVE_DUPLICATES <list>)
list(REVERSE <list>)
list(SORT <list>)
  1. LENGTH:返回list的长度
  2. GET:返回list中index的element到value中
  3. APPEND:添加新element到list中
  4. FIND:返回list中element的index,没有找到返回-1
  5. INSERT :将新element插入到list中index的位置
  6. REMOVE_ITEM:从list中删除某个element
  7. REMOVE_AT:从list中删除指定index的element
  8. REMOVE_DUPLICATES:从list中删除重复的element
  9. REVERSE:将list的内容反转
  10. SORT:将list按字母顺序排序

三、配置相关

3.1 add_definitions

命令原型:

add_definitions(-DFOO -DBAR ...)

说明: 在源文件的编译中添加 -D 标志。

测试用例

  1. 假设代码中通过USE_MACRO 作为区分是否编译部分模块的代码。
#ifdef USE_MACRO
...
#endif

可以通过项目中中的CMakeLists.txt 中添加如下代码控制代码的开启和关闭。

option(USE_MACRO "Build the project using macro" OFF)

if(USE_MACRO)
add_definitions(-D USE_MACRO)
endif(USE_MACRO)

运行构建项目的时候可以添加参数控制宏的开启和关闭。

cmake -D USE_MACRO=on	# 开启
cmake -D USE_MACRO=off # 关闭

说明

  1. 当运行cmake -DUSE_MACRO=on时,会编译 #ifdef USE_MACRO 里的代码模块
  2. 当运行cmake -DUSE_MACRO=off时,不会编译 #ifdef USE_MACRO 里的代码模块。

3.2 option

控制编译流程,相当于C语言中的宏条件编译

option(<variable> "<help_text>" [value])
option(RENDERING_FORCE_OPENGL "Rendering force opengl." ON)
  1. variable:定义选项名称
  2. help_text:说明选项的含义
  3. value:定义选项默认状态,一般是OFF或者ON,除去ON之外,其他所有值都为认为是OFF

四、文件结构相关

4.1 add_subdirectory

向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制存放的位置

ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
  • EXCLUDE_FROM_ALL函数是将写的目录从编译中排除,如程序中的example
  • ADD_SUBDIRECTORY(src bin)
    • 将 src 子目录加入工程并指定编译输出(包含编译中间结果)路径为bin 目录
    • 如果不进行 bin 目录的指定,那么编译结果(包括中间结果)都将存放在build/src 目录

4.2 add_library

add_library(hello SHARED ${LIBHELLO_SRC})
  • hello:就是正常的库名,生成的名字前面会加上lib,最终产生的文件是libhello.so
  • SHARED,动态库 STATIC,静态库
  • ${LIBHELLO_SRC} :源文件

4.3 set_target_properties

这条指令可以用来设置输出的名称,对于动态库,还可以用来指定动态库版本和 API 版本

set(LIBHELLO_SRC hello.cpp)

# 生成静态库
add_library(hello_static STATIC ${LIBHELLO_SRC})
# 重名为hello
set_target_properties(hello_static PROPERTIES OUTPUT_NAME "hello")
# cmake在构建一个新的target时,会尝试清理掉其他使用这个名字的库
# 因为在构建libhello.so时, 就会清理掉 libhello.a
set_target_properties(hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)

# 生成共享库
add_library(hello SHARED ${LIBHELLO_SRC})
# 重命名为hello
set_target_properties(hello PROPERTIES OUTPUT_NAME "hello")
set_target_properties(hello PROPERTIES CLEAN_DIRECT_OUTPUT 1)

4.4 include_directores

这条指令可以用来向工程添加多个特定的头文件搜索路径,路径之间用空格分割

include_directores(/usr/include/hello)

添加非标准的共享库搜索路径

link_directories(/home/myproject/libs)

添加需要链接的共享库,共享库需要在标准路径下

# 链接动态库
target_link_libraries(main libhello.so)
# 链接静态库
target_link_libraries(main libhello.a)

五、文件操作命令

5.1 file

5.1.1 WRITE

将一则信息写入文件filename

file(WRITE filename "message towrite"... )
  1. 如果该文件存在,它会覆盖它
  2. 如果不存在,它会创建该文件

5.1.2 APPEND

如同WRITE,区别在于它将信息内容追加到文件末尾

file(APPEND filename "message to write"... )

5.1.3 READ

读取文件的内容并将其存入到变量中

file(READ filename variable [LIMIT numBytes] [OFFSEToffset] [HEX])
  1. 它会在给定的偏移量处开始读取最多numBytes个字节
  2. 如果指定了HEX参数,二进制数据将会被转换成十进制表示形式并存储到变量中

5.1.4 加密

计算出文件内容对应的加密散列

file(<MD5|SHA1|SHA224|SHA256|SHA384|SHA512> filenamevariable)

5.1.6 STRING

从文件中解析出ASCII字符串列表并存储在变量中

file(STRINGS filename variable 
[LIMIT_COUNT num]
[LIMIT_INPUT numBytes]
[LIMIT_OUTPUT numBytes]
[LENGTH_MINIMUM numBytes]
[LENGTH_MAXIMUMnumBytes]
[NEWLINE_CONSUME]
[REGEX regex]
[NO_HEX_CONVERSION])
# 将输入文件的每行内容存储在变量"myfile"中
file(STRINGS myfile.txt myfile)
  1. 文件中的二进制数据将被忽略。回车符(CR)也会被忽略
  2. 也能解析Intel HexMotorola S-record文件
    1. 这两种文件在读取时会自动转换为二进制格式,可以使用参数NO_HEX_CONVERSION禁用这种自动转换
  3. LIMIT_COUNT:设置可返回的最大数量的字符串
  4. LIMIT_INPUT:设置从输入文件中可读取的最大字节数
  5. LIMIT_OUTPUT:设置存储在输出变量中最大的字节数。
  6. LENGTH_MINIMUM:设置返回的字符串的最小长度。小于这个长度的字符串将被忽略。
  7. LENGTH_MAXIMUM:设置返回的字符串的最大长度。大于这个长度的字符串将被切分为长度不大于于最大长度值的子字符串
  8. NEWLINE_CONSUME:允许换行符包含进字符串中而不是截断它们
  9. REGEX:指定了返回的字符串必须匹配的正则表达式的模式典型用法

5.1.7 GLOB

会产生一个由所有匹配globbing表达式的文件组成的列表,并将其保存到变量中

file(GLOB variable [RELATIVE path] [globbingexpressions]...)
  1. Globbing 表达式与正则表达式类似,但更简单

  2. 如果指定了RELATIVE 标记,返回的结果将是与指定的路径相对的路径构成的列表

  3. 通常不推荐使用GLOB命令来从源码树中收集源文件列表

    1. 原因是:如果CMakeLists.txt文件没有改变,即便在该源码树中添加或删除文件,产生的构建系统也不会知道何时该要求CMake重新产生构建文件
  4. globbing 表达式包括:

    *.cxx      // match all files with extension cxx
    *.vt? // match all files with extension vta,...,vtz
    f[3-5].txt // match files f3.txt,f4.txt, f5.txt

5.1.8 GLOB_RECURSE

与GLOB类似,区别在于它会遍历匹配目录的所有文件以及子目录下面的文件

  1. 对于属于符号链接的子目录,只有FOLLOW_SYMLINKS指定一或者cmake策略CMP0009没有设置为NEW时,才会遍历这些目录
  2. /dir/*.py:match all Python files in /dir and subdirectories
file(GLOB_RECURSE variable 
[RELATIVE path]
[FOLLOW_SYMLINKS]
[globbingexpressions]...
)

5.1.9 RENAME

将文件系统中的文件或目录移动到目标位置,并自动替换目标位置处的文件或目录

file(RENAME <oldname> <newname>)

5.1.10 REMOVE

删除指定的文件以及子目录下的文件

file(REMOVE [file1 ...])

5.1.11 REMOVE_RECURSE

删除指定的文件及子目录,包括非空目录

file(REMOVE_RECURSE [file1 ...])

5.1.12 MAKE_DIRECTORY

在指定目录处创建子目录,如果它们的父目录不存在,也会创建它们的父目录

file(MAKE_DIRECTORY [directory1 directory2 ...])

5.1.13 RELATIVE_PATH

推断出指定文件相对于特定目录的路径

file(RELATIVE_PATH variable directory file)

5.1.14 TO_CMAKE_PATH

将路径转换成cmake风格的路径表达形式

file(TO_CMAKE_PATH path result)

5.1.15 TO_NATIVE_PATH

与TO_CMAKE_PATH类似,但执行反向操作,将cmake风格的路径转换为操作系统特定风格的路径表式形式

file(TO_NATIVE_PATH path result)

5.1.16 DOWNLOAD

下载指定URL的资源到指定的文件上

file(DOWNLOAD url file 
[INACTIVITY_TIMEOUT timeout]
[TIMEOUT timeout]
[STATUS status]
[LOG log]
[SHOW_PROGRESS]
[EXPECTED_MD5 sum])
  1. 如果指定了LOG参数,将会把下载的日志保存到相应的变量中
  2. 如果指定了STATUS变量,操作的状态信息就会保存在相应的变量中。返回的状态是一个长度为2的列表。第一个元素是操作的返回值。0表示操作过程中无错误发生
  3. 如果指定了TIMEOUT,单位为秒,且必须为整数,那么在指定的时间后,操作将会超时,
  4. INACTIVITY_TIMEOUT指定了操作在处于活动状态超过指定的秒数后,应该停止。如果指定了EXPECTED_MD5,如果操作会检验下载后的文件的实际md5校验和是否与预期的匹配,如果不匹配,操作将会失败,并返回相应的错误码。如果指定了 SHOW_PROGRESS,那么进度的信息将会被打印成状态信息直到操作完成。

5.2 get_filename_component

获取完整文件名的特定部分

get_filename_component(<variable> <Filename> <mode> [CACHE])
  1. variable:保存获取部分的变量
  2. Filename:完整的文件名
  3. mode:要获取文件名的哪个部分
    1. DIRECTORY:文件所在目录
    2. NAME:没有目录的文件名
    3. EXT:最长的扩展名,即第一个.开始
    4. NAME_WE:没有目录和扩展名的文件名
    5. LAST_EXT:最后一个扩展名
    6. NAME_WLE:没有目录和最后一个扩展名的文件名
  4. CACHE:若指定,则获取到的结果变量会放到缓存中
get_filename_component(<variable> <Filename> <mode> [BASE_DIR <dir>] [CACHE])
  1. variable:保存获取部分的变量
  2. Filename:完整的文件名
  3. mode:要获取文件名的哪个部分
    1. ABSOLUTE:文件的绝对路径
    2. REALPATH:如果为符号连接文件,取得实际的文件的绝对路径。如果不是连接文件,则与ABSOLUTE一样
  4. BASE_DIR <dir>:如果指定基本目录,则获取的绝对路径为基本目录+文件名。如果不指定,则基于CMAKE_CURRENT_SOURCE_DIR 目录
  5. CACHE:若指定,则获取到的结果变量会放到缓存中
get_filename_component(<variable> <Filename> PROGRAM [PROGRAM_ARGS <arg_var>] [CACHE])
  1. variable:保存获取部分的变量
  2. Filename:完整的文件名
  3. PROGRAM_ARGS <arg_var>:FileName的字符串分离为程序名和参数,然后把参数保存在arg_var中
  4. CACHE:若指定,则获取到的结果变量会放到缓存中