Tools - cmake使用指南
参考
- cmake官网 (opens new window)
- cmake基础及交叉编译 (opens new window)
- cmake的file命令 (opens new window)
- cmake的file命令官网 (opens new window)
- CMakeFile命令之file (opens new window)
- cmake的install指令 (opens new window)
概述
CMake是开源、跨平台的构建工具,可以让我们通过编写简单的配置文件去生成本地的Makefile,这个配置文件是独立于运行平台和编译器的,这样就不用亲自去编写Makefile了,而且配置文件可以直接拿到其它平台上使用,无需修改,非常方便。
cmake 即编程
cmake主要特点:
- 开放源代码,使用类 BSD 许可发布
- 跨平台,并可生成 native 编译配置文件,在 Linux/Unix 平台,生成 makefile,在苹果平台,可以生成 xcode,在 Windows 平台,可以生成 MSVC 的工程文件
- 能够管理大型项目
- 简化编译构建过程和编译过程;Cmake 的工具链非常简单:cmake+make
- 高效虑,按照 KDE 官方说法,CMake 构建 KDE4 的 kdelibs 要比使用 autotools 来构建 KDE3.5.6 的 kdelibs 快 40%,主要是因为 Cmake 在工具链中没有 libtool
- 可扩展,可以为 cmake 编写特定功能的模块,扩充 cmake 功能
- 支持out-of-source build:一个最大的好处是,对于原有的工程没有任何影响,所有动作全部发生在编译目录。
cmake基本结构
- 依赖CMakeLists.txt(文件名区分大小写)文件,项目主目录只有一个,主目录中可指定包含的子目录
- 在项目CMakeLists.txt中使用project指定项目名称,add_subdirectory或subdirs添加子目录
- 子目录CMakeLists.txt将从父目录CMakeLists.txt继承设置(但set变量不可继承)
常用指令
- cmake_minimum_required 设置 cmake 的最低版本号要求
- project 设置工程名字
- set 设置变量
- SET(CMAKE_CXX_COMPILER "g++") # 设定编译器
- include 从文件或模块加载并运行CMake代码(CMakeLists.txt 文件,cmake 模块)
- include(${PROJECT_SOURCE_DIR}/cmake/options.cmake)
- option 选项
- option(BUILD_EXAMPLES "Enable build all examples" ON)
- add_subdirectory 增加编译子目录,也可以使用
SUBDIRS
不推荐 - list 列表相关的操作
- message 用于打印、输出信息
- add_definitions 向 C/C++编译器添加-D 定义
- add_definitions(-DTESTCMAKE), 代码里可以判断对应标志位
- add_dependencies
- ADD_DEPENDENCIES(target-name depend-target1 depend-target2 …)
- 定义 target 依赖的其他 target,确保在编译本 target 之前,其他的 target 已经被构建
获取源文件
- aux_source_directory 发现一个目录下所有的源代码文件并将列表存储在一个变量中,这个指 令临时被用来自动构建源文件列表
- file CMake的文件操作命令
- FILE (GLOB DATA_MYSQL_TEST_FILES ${DATA_MYSQL_TEST_SRC_DIR}/*.cpp)
工程相关
- include_directories 向工程添加多个特定的头文件搜索路径 ,相当于指定g++编译器的-I参数
- add_library 生成库文件
- add_executable 生成可执行文件
- link_directories 向工程添加多个特定的库文件搜索路径 —>相当于指定g++编译器的-L参数
- target_link_libraries 为 target 添加需要链接的共享库 —>相同于指定g++编译器-l参数
- install 目标文件的安装
Cmake变量
CMake共用七种变量,如下所示:
- 提供信息的变量。
- 控制变量。
- 描述系统的变量。
- 控制构建过程的变量。
- 语言变量。
- CTest变量。
- CPack变量。
CMake内置变量与系统变量对应关系
变量名称 | CMake变量 | 系统变量 |
---|---|---|
C编译器 | CMAKE_C_COMPILER | CC |
C++编译器 | CMAKE_CXX_COMPILER | CXX |
生成器 | -G "*******" | CMAKE_GENERATOR(CMAKE 3.15+才支持) |
C编译选项 | CMAKE_C_FLAGS | CFLAGS |
C++编译选项 | CMAKE_CXX_FLAGS CXXFLAGS |
CMake变量引用的方式
使⽤ ${} 进⾏变量的引⽤。在 IF 等语句中,是直接使⽤变量名⽽不通过 ${} 取值。
cmake 定义变量的⽅式
主要有隐式定义和显式定义两种,举⼀个隐式定义的例⼦,就是 PROJECT 指令,他会隐式的定义_BINARY_DIR 和_SOURCE_DIR 两个变量。
⽽显式定义的例⼦,可以使⽤ SET 指令,就可以构建⼀个⾃定义变量了。
常用变量
预定义变量
变量名称 | 解释 |
---|---|
PROJECT_SOURCE_DIR | 工程的根目录 |
PROJECT_BINARY_DIR | 运行 cmake 命令的目录,通常是 ${PROJECT_SOURCE_DIR}/build |
PROJECT_NAME | 返回通过 project 命令定义的项目名称 |
CMAKE_CURRENT_SOURCE_DIR | 当前处理的 CMakeLists.txt 所在的路径 |
CMAKE_CURRENT_BINARY_DIR | target 编译目录 |
CMAKE_CURRENT_LIST_DIR | CMakeLists.txt 的完整路径 |
CMAKE_CURRENT_LIST_LINE | 当前所在的行 |
CMAKE_MODULE_PATH | 定义自己的 cmake 模块所在的路径,SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake),然后可以用INCLUDE命令来调用自己的模块 |
EXECUTABLE_OUTPUT_PATH | 重新定义目标二进制可执行文件的存放位置 |
LIBRARY_OUTPUT_PATH | 重新定义目标链接库文件的存放位置 |
环境变量
- 使用环境变量:$ENV{Name};
- 写入环境变量:set(ENV{Name} value),这里没有“$”符号;
系统信息
变量名称 | 解释 |
---|---|
CMAKE_MAJOR_VERSION | cmake 主版本号,比如 3.4.1 中的 3 |
CMAKE_MINOR_VERSION | cmake 次版本号,比如 3.4.1 中的 4 |
CMAKE_PATCH_VERSION | cmake 补丁等级,比如 3.4.1 中的 1 |
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 |
APPLE | 在所有苹果平台下该值为TRUE |
主要开关选项
BUILD_SHARED_LIBS:这个开关用来控制默认的库编译方式,如果不进行设置,使用 add_library 又没有指定库类型的情况下,默认编译生成的库都是静态库。如果 set(BUILD_SHARED_LIBS ON) 后,默认生成的为动态库
CMAKE_C_FLAGS:设置 C 编译选项,也可以通过指令 add_definitions() 添加
CMAKE_CXX_FLAGS:设置 C++ 编译选项,也可以通过指令 add_definitions() 添加,add_definitions(-DENABLE_DEBUG -DABC) # 参数之间用空格分隔
1
2
3
2
3
其他常用变量
变量名称 | 解释 |
---|---|
CMAKE_C_COMPILER | 指定C编译器 |
CMAKE_CXX_COMPILER | 指定C++编译器 |
EXECUTABLE_OUTPUT_PATH | 可执行文件输出的存放路径 |
LIBRARY_OUTPUT_PATH | 库文件输出的存放路径 |
CMAKE_CURRENT_SOURCE_DIR | 当前处理的CMakeLists.txt位于目录 |
CMAKE_CURRENT_LIST_DIR | 这是当前正在处理的listfile中的目录 |
编译选项:CMAKE_CXX_FLAGS【CMAKE_C_FLAGS gcc编译选项】【CMAKE_CXX_FLAGS g++编译选项】
# 在CMAKE_CXX_FLAGS编译选项后追加-std=c++11
set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
1
2
2
编译类型:CMAKE_BUILD_TYPE (Debug, Release)
# 设定编译类型为debug,调试时需要选择debug
set(CMAKE_BUILD_TYPE Debug)
# 设定编译类型为release,发布时需要选择release
set(CMAKE_BUILD_TYPE Release)
1
2
3
4
2
3
4
cmake file详解
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> [...])
Filesystem
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> [...])
Path Conversion
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> [...])
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
使用实例:
# 设置测试文件名称为 test1.txt
SET(TEST_FILE test1.txt)
# 打印当前路径
message(STATUS "current dir: ${CMAKE_CURRENT_SOURCE_DIR}")
# 写内容到 测试文件
file(WRITE ${TEST_FILE} "Some messages to Write\n" )
# 将信息内容追加到 测试文件 末尾
file(APPEND ${TEST_FILE} "Another message to write\n")
# 读取指定内容
# file(READ filename variable [LIMIT numBytes] [OFFSEToffset] [HEX])
# READ 会读取文件的内容并将其存入到变量中。它会在给定的偏移量处开始读取最多numBytes个字节。
# 如果指定了HEX参数,二进制数据将会被转换成十进制表示形式并存储到变量中。
file(READ ${TEST_FILE} CONTENTS LIMIT 4 OFFSET 12)
message(STATUS "contents of ${TEST_FILE} is: [${CONTENTS}]")
# 求取文件的MD5码,与该命令 md5sum test1.txt 一致
file(MD5 ${CMAKE_CURRENT_SOURCE_DIR}/${TEST_FILE} HASH_CONTENTS)
message(STATUS "hash contents of ${TEST_FILE} is: [${HASH_CONTENTS}]")
# STRINGS 从文件中解析出ASCII字符串列表并存储在变量中。
file(STRINGS ${TEST_FILE} PARSED_STRINGS)
message(STATUS "strings of ${TEST_FILE} is: [${PARSED_STRINGS}]")
# 当前路径下的所有文件
file(GLOB files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "*.*")
message(STATUS "files: ${files}")
# 文件操作
file(MAKE_DIRECTORY dir1 dir2)
file(RENAME dir2 dir3)
file(REMOVE dir3)
file(REMOVE_RECURSE dir3)
file(RELATIVE_PATH relative_path ${PROJECT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/${TEST_FILE})
message(STATUS "relative path : ${relative_path}")
# TO_CMAKE_PATH会将路径转换成cmake风格的路径表达形式。
file(TO_CMAKE_PATH "$ENV{PATH}" cmake_path)
message(STATUS "cmake path: ${cmake_path}")
# 将cmake风格的路径转换为操作系统特定风格的路径表式形式。
file(TO_NATIVE_PATH "/usr/local/sbin;/usr/local/bin" native_path)
message(STATUS "native path: ${native_path}")
# DOWNLOAD下载指定URL的资源到指定的文件上
file(DOWNLOAD "http://www.baidu.com" ${CMAKE_CURRENT_SOURCE_DIR}/index.html SHOW_PROGRESS)
# 拷贝和安装操作
#file(COPY ${TEST_FILE} DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/dir1)
file(INSTALL ${TEST_FILE} DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/dir1)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52