文章目录
一.CMake基本语法
1. 注释
在CMake中注释使用#字符开始到此行结束。
# 这个是注释
2. 命令
- 命令不区分大小写(参数会区分大小写),命令由命令、参数列表组成,参数之间使用空格进行分隔。
- 使用一对双引号包括的字符串认为是一个参数。
- 命令可以是一个内置命令(例如:project,add_executable等),也可以是一个用户定义的宏(macro)或者函数(function)。
3. 数据类型
CMake的基本数据类型是字符串,一组字符串在一起称为列表(list)
# 通过 set 命令构建一个 listVAR
set(VAR a b c)
使用语法 ${VariableName}
来访问名字为 VariableName
的变量的值(变量名区分大小写)。需要注意的是,即使在字符串中也可以使用${VariableName}
来访问变量的值:
set(VAR a b c)
# 输出 VAR = a;b;c
message("VAR = ${VAR}")
二.CMake常用命令详解
1. list
cmake的list命令即对列表的一系列操作,cmake中的列表变量是用分号;分隔的一组字符串,创建列表可以使用set命令(参考set命令),例如:set (var a b c d)创建了一个列表 “a;b;c;d”,而set (var “a b c d”)则是只创建了一个变量"a c c d"。list命令的具体格式根据子命令不同会有所区别。
list命令的基本格式如下:
list (subcommand [args…])
-
subcommand:为具体的列表操作子命令,例如读取、查找、修改、排序等。其中:
- ENGTH:返回list的长度
- GET:返回list中index的element到value中
- APPEND:添加新element到list中
- FIND:返回list中element的index,没有找到返回-1
- INSERT:将新element插入到list中index的位置
- REMOVE_ITEM:从list中删除某个element
- REMOVE_AT:从list中删除指定index的element
- REMOVE_DUPLICATES:从list中删除重复的element
- REVERSE:将list的内容反转
- SORT:将list按字母顺序排序
-
[args…]:为对列表变量操作需要使用的参数表,不同的子命令对应的参数也不一致。
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>)
2. include
从文件或模块加载并运行CMake代码,格式为:
include(<file|module> [OPTIONAL][RESULT VARIABLE VAR])
注意,对于不同的文件类型,加载搜索的方式是不一样的:
-
普通文件(file)
1)如果是’相对’路径,是相对于include指令所在的CMakeLists.txt
的路径
2)'绝对’路径–>‘建议’
3)一般我们会将cmake文件放到cmake目录下,所以’前缀’一般是:CMAKE_CURRENT_SOURCE_DIR/cmake/
4)备注: 这里的file文件,必须以.cmake
结尾 -
模块文件(module)
1)首先搜索Cmake builtin module directory
-->cmake 内置的module目录
–>centos7 /usr/share/cmake/MOdules/
2)找不到’再搜索’–>CMAKE_MODULE_PATH
3)再找不到,则’报错’–>NOTFOUND
3. option
CMake中的option用于控制编译流程,相当于C语言中的宏条件编译。options基本格式如下:
option(<variable> "<help_text>" [value])
- variable:定义选项名称
- help_text:说明选项的含义
- value:定义选项默认状态,一般是OFF或者ON,除去ON之外,其他所有值都为认为是OFF。
4. message
在CMake中,message()函数用于向终端输出信息。
message( [STATUS|WARNING|AUTHOR_WARNING|FATAL_ERROR|SEND_ERROR] "message to display" ...)
- (无) = 重要消息;
- STATUS = 非重要消息;
- WARNING = CMake 警告, 会继续执行;
- AUTHOR_WARNING = CMake 警告 (dev), 会继续执行;
- SEND_ERROR = CMake 错误, 继续执行,但是会跳过生成的步骤;
- FATAL_ERROR = CMake 错误, 终止所有处理过程;
5. file
CMake中的file命令用于文件操作,其文件格式如下:
# 读文件
file(READ <filename> <out-var> [...])
file(STRINGS <filename> <out-var> [...])
file(<HASH> <filename> <out-var>)
file(TIMESTAMP <filename> <out-var> [...])
file(GET_RUNTIME_DEPENDENCIES [...])
# 写文件
file({WRITE | APPEND} <filename> <content>...)
file({TOUCH | TOUCH_NOCREATE} [<file>...])
file(GENERATE OUTPUT <output-file> [...])
file(CONFIGURE OUTPUT <output-file> CONTENT <content> [...])
# 文件系统
file({GLOB | GLOB_RECURSE} <out-var> [...] [<globbing-expr>...])
file(MAKE_DIRECTORY [<dir>...])
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>... [...])
# 路径转换
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>)
# 锁定
file(LOCK <path> [...])
# 命令结构
file(ARCHIVE_CREATE OUTPUT <archive> PATHS <paths>... [...])
file(ARCHIVE_EXTRACT INPUT <archive> [...])
# 传输
file(DOWNLOAD <url> [<file>] [<options>...])
file(UPLOAD <file> <url> [<options>...])
参数说明:
url
: 是要下载的文件的 URL,file
: 是要保存的文件路径(如果未指定,则由 CMake 自动生成一个临时文件路径),options
: 是可选的参数,用于指定下载过程中的一些行为,例如是否在下载之前删除已存在的文件、是否显示下载进度等。选项如下:名称 描述 INACTIVITY_TIMEOUT<seconds> 在一段时间的不活动后终止操作 LOG <variable> 将操作的信息记录到一个变量中,以便进行人可读的日志记录 SHOW_PROGRESS 打印操作进度信息作为状态消息,直到操作完成 STATUS<variable> 将操作的结果状态存储在一个变量中。状态是一个长度为2的分号分隔的列表。第一个元素是操作返回的数值,第二个元素是错误的字符串值。0的数字错误表示操作中没有错误。 TIMEOUT <seconds> 在给定的总时间过去后终止操作 USERPWD<username> :<password> 自版本3.7起。为操作设置用户名和密码 HTTPHEADER<HTTP-header> 自版本3.7起。为 DOWNLOAD 和 UPLOAD 操作设置 HTTP 头。HTTPHEADER 可以重复多次以提供多个选项 NETRC <level> 自版本3.11起。指定是否使用 .netrc 文件进行操作。如果未指定此选项,则使用 CMAKE_NETRC 变量的值 EXPECTED_HASH<algorithm>=<value> 用于验证下载的内容哈希是否与预期值匹配,其中是支持的算法之一。如果文件已存在并且与哈希匹配,则跳过下载。如果文件已存在但不匹配哈希,则再次下载文件。如果下载后文件不匹配哈希,则操作将失败并出现错误。如果在DOWNLOAD未给出的情况下指定此选项是错误的。 EXPECTED_MD5<value> 是历史悠久的EXPECTED_HASH MD5=<value>的简写方法。如果在DOWNLOAD未给出的情况下指定此选项是错误的。 RANGE_START<value> 是自版本3.24起添加的新选项。它指定了文件中范围的起始偏移量(以字节为单位)。可以省略以从指定的RANGE_END下载所有内容。 RANGE_END<value> 是自版本3.24起添加的新选项。它指定了文件中范围的结束偏移量(以字节为单位)。可以省略以从指定的RANGE_START下载所有内容。
6. execute_process
执行一个或多个子进程(cmake:使用execute_process调用shell命令或脚本)
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>])
选项说明:
选项 | 说明 |
COMMAND | 一个子进程命令行。 CMake直接使用操作系统api执行子进程。所有参数都被逐字传递给子进程。没有使用中间shell,所以像>这样的shell操作符被视为普通参数。(使用INPUT_*、OUTPUT_*和ERROR_*选项重定向stdin、stdout和stderr。) 如果需要连续执行多个命令,请使用多个execute_process()调用,并使用单个COMMAND参数。 |
WORKING_DIRECTORY | 命名目录将被设置为子进程的当前工作目录 |
TIMEOUT | 在指定的秒数(允许分数)之后,所有未完成的子进程将被终止,RESULT_VARIABLE将被设置为一个提到“超时”的字符串 |
RESULT_VARIABLE | 该变量将被设置为包含最后一个子进程的结果。这将是来自最后一个子节点的整数返回代码或描述错误条件的字符串 |
RESULTS_VARIABLE < variable> | 3.10新版功能。 该变量将按照给定的COMMAND参数的顺序,以分号分隔的列表的形式包含所有进程的结果。每个条目将是来自相应子条目的一个整数返回代码或描述错误条件的字符串。 |
OUTPUT_VARIABLE, ERROR_VARIABLE | 变量名将分别用标准输出管道和标准错误管道的内容设置。如果为两个管道命名相同的变量,它们的输出将按生成的顺序合并。 3.3新版功能:如果同一个文件同时被输出和错误命名,那么它将同时被使用。 |
INPUT_FILE、OUTPUT_FILE ERROR_FILE | 命名的文件将分别附加到第一个进程的标准输入、最后一个进程的标准输出或所有进程的标准错误 |
COMMAND_ECHO < where> | 正在运行的命令将回显到< where>,而< where>设置为STDERR、STDOUT或NONE之一。 请参阅CMAKE_EXECUTE_PROCESS_COMMAND_ECHO变量,了解当此选项不存在时控制默认行为的方法。 |
ENCODING < name> | 3.8新版功能。 在Windows上,用于解码进程输出的编码。在其他平台上被忽视。有效的编码名称是: NONE:执行没有解码。这假设过程输出的编码方式与CMake的内部编码(UTF-8)相同。这是默认值。 AUTO:使用当前活动控制台的代码页,如果不可用,则使用ANSI。 ANSI:使用ANSI代码页。 OEM:使用原始设备制造商(OEM)代码页。 UTF8 or UTF-8:使用UTF-8代码页。 |
ECHO_OUTPUT_VARIABLE, ECHO_ERROR_VARIABLE | 3.18新版功能。 标准输出或标准错误不会被专门重定向到已配置的变量。 输出将被重复,它将被发送到配置的变量中,也在标准输出或标准错误上。 这类似于tee Unix命令。 |
COMMAND_ERROR_IS_FATAL < ANY | LAST > |
三.CMake中常用预定义变量
1.CMake的预定义变量
- PROJECT_SOURCE_DIR:⼯程根⽬录;
- PROJECT_BINARY_DIR:运⾏cmake命令的⽬录。笔者建议定义为${PROJECT_SOURCE_DIR}/build下。具体原因见后⽂外部编译部分;
- CMAKE_INCLUDE_PATH:环境变量,⾮cmake变量;
- CMAKE_LIBRARY_PATH:环境变量;
- CMAKE_CURRENT_SOURCE_DIR:当前处理的CMakeLists.txt⽂件所在路径;
- CMAKE_CURRENT_BINARY_DIR:target编译⽬录;
- 使⽤ADD_SURDIRECTORY指令可以更改该变量的值;
- SET(EXECUTABLE_OUTPUT_PATH < dir >) 指令不会对该变量有影响,但改变了最终⽬标⽂件的存储路径;
- CMAKE_CURRENT_LIST_FILE:输出调⽤该变量的CMakeLists.txt的完整路径;
- CMAKE_CURRENT_LIST_LINE:输出该变量所在的⾏;
- CMAKE_MODULE_PATH:定义⾃⼰的cmake模块所在路径;
- EXECUTABLE_OUTPUT_PATH:重新定义⽬标⼆进制可执⾏⽂件的存放位置;
- LIBRARY_OUTPUT_PATH:重新定义⽬标链接库⽂件的存放位置;
- PROJECT_NAME:返回由PROJECT指令定义的项⽬名称;
- CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS:⽤来控制IF…ELSE…语句的书写⽅式;
2.系统信息预定义的变量
- CMAKE_MAJOR_VERSION cmake主版本号,如2.8.6中的2
- CMAKE_MINOR_VERSION cmake次版本号,如2.8.6中的8
- CMAKE_PATCH_VERSION cmake补丁等级,如2.8.6中的6
- CMAKE_SYSTEM 系统名称,例如Linux-2.6.22
- CMAKE_SYSTEM_NAME 不包含版本的系统名,如Linux
- CMAKE_SYSTEM_VERSION 系统版本,如2.6.22
- CMAKE_SYSTEM_PROCESSOR 处理器名称,如i686
- UNIX 在所有的类UNIX平台为TRUE,包括OS X和cygwin
- WIN32 在所有的win32平台为TRUE,包括cygwin
3.开关选项变量
- BUILD_SHARED_LIBS 控制默认的库编译⽅式。
- 注:如果未进⾏设置,使⽤ADD_LIBRARY时⼜没有指定库类型,默认编译⽣成的库都是静态库。
- CMAKE_C_FLAGS 设置C编译选项
- CMAKE_CXX_FLAGS 设置C++编译选项
四.CMake常用语法
-
CMAKE_MINIMUM_REQUIRED
# cmake的最低版本⾄少为2.6。 cmake_minimum_required (VERSION 2.6)
该语句⼀般都可以放置在CMakeLists.txt的开头,⽤于说明CMake最低版本要求。
这⾏命令是可选的,我们可以不写这句话,但在有些情况下,如果CMakeLists.txt⽂件中使⽤了⼀些⾼版本cmake特有的⼀些命令的时候,就需要加上这样⼀⾏,提醒⽤户升级到该版本之后再执⾏cmake。 -
PROJECT
该指令⼀般置于CMakeLists.txt的开头,定义了⼯程的名称。执⾏了该条指令之后,将会⾃动创建两个变量:
-
< projectname >_BINARY_DIR:⼆进制⽂件保存路径;
-
< projectname >_SOURCE_DIR:源代码路径;
project(CRNode) # 执⾏了上⼀条指令,即定义了⼀个项⽬名称CRNode, # 相应的会⽣成两个变量:CRNode_BINARY_DIR, CRNode_SOURCE_DIR
cmake中预定义了两个变量:PROJECT_BINARY_DIR与PROJECT_SOURCE_DIR。
在这个例⼦中:- PROJECT_BINARY_DIR = CRNode_BINARY_DIR
- PROJECT_SOURCE_DIR = CRNode_SOURCE_DIR
笔者强烈推荐直接使⽤PROJECT_BINARY_DIR与PROJECT_SOURCE_DIR,这样及时项⽬名称发⽣了变化,也不会影响CMakeLists.txt⽂件。
关于上⾯两个变量是否相同的问题,涉及到编译⽅法是内部编译还是外部编译。如果是内部编译,则上⾯两个变量相同;如果是外部编译,则两个变量不同。此处对内部编译与外部编译做出介绍:
(1) 外部构建与内部构建
假设此时已经完成了CMakeLists.txt的编写,在CMakeLists.txt所在⽬录下,有两种执⾏cmake的⽅法:
cmake ./ make
以及:
mkdir build cd ./build cmake ../ make
第⼀种⽅法是内部构建,第⼆种⽅法是外部构建。上述两种⽅法中,最⼤不同在于cmake与make的⼯作路径不同。
内部构建⽅法中,cmake⽣成的中间⽂件和可执⾏⽂件都会存放在项⽬⽬录中;外部构建⽅法中,中间⽂件与可执⾏⽂件都存放在build⽬录中。
笔者强烈建议使⽤外部构建⽅法。优点显⽽易见:最⼤限度的保持了代码⽬录的整洁,⽣成、编译与安装是不同于项⽬⽬录的其他⽬录中,在外部构建⽅法下,PROJECT_SOURCE_DIR指向⽬录与内部构建相同,为CMakeLists.txt所在根⽬录;⽽PROJECT_BINARY_DIR不同,它指向CMakeLists.txt所在根⽬录下的build⽬录。 -
-
SET(<变量名> <变量值>)
SET(VAR [VALUE] [CACHE TYPEDOCSTRING [FORCE]])
该例程中,我们显式的将CMAKE_INSTALL_PREFIX的值定义为/usr/local,如此在外部构建情况下执⾏make install命令时,make会将⽣成的可执⾏⽂件拷贝到/usr/local/bin⽬录下。
-
ADD_SUBDIRECTORY
这个指令⽤于向当前⼯程添加存放源⽂件的⼦⽬录,并可以指定中间⼆进制和⽬标⼆进制存放的位置。EXCLUDE_FROM_ALL 参数的含义是将这个⽬录从编译过程中排除。⽐如,⼯程有时候存在example,可能就需要⼯程构建完成后,再进⼊example⽬录单独进⾏构建。
ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
- source_dir:源⽂件路径;
- [binary_dir]:中间⼆进制与⽬标⼆进制存放路径;
- [EXECLUDE_FROM_ALL]:将这个⽬录从编译过程中排除;
-
file()
用于文件的操作
# 读取文件 file(READ <filename> <out-var> [...]) file(STRINGS <filename> <out-var> [...]) file(<HASH> <filename> <out-var>) file(TIMESTAMP <filename> <out-var> [...]) # 写文件 file({WRITE | APPEND} <filename> <content>...) file({TOUCH | TOUCH_NOCREATE} [<file>...]) file(GENERATE OUTPUT <output-file> [...]) # 文件系统 file({GLOB | GLOB_RECURSE} <out-var> [...] [<globbing-expr>...]) file(RENAME <oldname> <newname>) file({REMOVE | REMOVE_RECURSE } [<files>...]) file(MAKE_DIRECTORY [<dir>...]) file({COPY | INSTALL} <file>... DESTINATION <dir> [...]) file(SIZE <filename> <out-var>) file(READ_SYMLINK <linkname> <out-var>) file(CREATE_LINK <original> <linkname> [...]) # 路径转换 file(RELATIVE_PATH <out-var> <directory> <file>) file({TO_CMAKE_PATH | TO_NATIVE_PATH} <path> <out-var>) # 上传下载 file(DOWNLOAD <url> <file> [...]) file(UPLOAD <file> <url> [...]) # 查找 file(LOCK <path> [...])
-
list()
用于对列表的操作
# 返回list的长度 list(LENGTH <list><output variable>) # 返回list中index的element到value中 list(GET <list> <elementindex> [<element index> ...]<output variable>) # 添加新element到list中 list(APPEND <list><element> [<element> ...]) # 返回list中element的index,没有找到返回-1 list(FIND <list> <value><output variable>) # 将新element插入到list中index的位置 list(INSERT <list><element_index> <element> [<element> ...]) # 从list中删除某个element list(REMOVE_ITEM <list> <value>[<value> ...]) # 从list中删除指定index的element list(REMOVE_AT <list><index> [<index> ...]) # 从list中删除重复的element list(REMOVE_DUPLICATES <list>) # 将list的内容反转 list(REVERSE <list>) # 将list按字母顺序排序 list(SORT <list>)
-
option()
option用于控制编译流程,相当于C语言中的宏条件编译
option(<variable> "<help_text>" [value]) variable:定义选项名称 help_text:说明选项的含义 value:定义选项默认状态,一般是OFF或者ON,除去ON之外,其他所有值都为认为是OFF
-
configure_package_config_file()
该命令用于生成xxxCionfig.cmake文件的,其使用方式如下:
configure_package_config_file( <input> <output> INSTALL_DESTINATION <path> [PATH_VARS <var1> <var2> ... <varN>] [NO_SET_AND_CHECK_MACRO] [NO_CHECK_REQUIRED_COMPONENTS_MACRO] [INSTALL_PREFIX <path>] )
- input:文件名,一般为xxxConfig.cmake.in文件,需要自己提供
- output:文件名,一般为xxConfig.cmake文件。其会通过input中的文件进行生成
- INSTALL_DESTINATION:改参数后跟绝对或相对路径,表示output中的文件在install的时候会被装载到那个位置。如果使用相对路径,则其相对于INSTALL_PREFIX所表示的路径
- PATH_VARS:其后跟这变量的名字,这些变量需要在xxxConfig.cmake.in文件中出现。例如变量名 A,则在xxxConfig.cmake.in中要以 @PACKAGE_A@的形式出现。这些变量的作用一般是在xxxConfig.cmake.in生成xxxConfig.cmake的时候进行对应的变量替换
- INSTALL_PREFIX:install时候的prefix path
-
install()
install用于指定在安装时运行的规则。它可以用来安装很多内容,可以包括目标二进制、动态库、静态库以及文件、目录、脚本等
五.常用函数
- find_path 从默认⽬录和指定⽬录查找头⽂件,并返回结果
- find_library 从默认⽬录和指定⽬录查找库⽂件,并返回结果
六.
-
输出所有定义的变量
get_cmake_property(_variableNames VARIABLES) foreach (_variableName ${_variableNames}) message(STATUS "${_variableName}=${${_variableName}}") endforeach()