cmake 常用指令入门指南
本博客记录:在使用cmake进行构建工程时,写CMakeLists.txt 文件时,常使用到的命令与变量, 不断补充更新中。
相关链接
官方地址: https://cmake.org/cmake/help/
git上很好实践教程: https://github.com/ttroy50/cmake-examples
CMKAE中脚本相关的命令
cmake_minimum_required 命令
语法与参数介绍
语法: cmake_minimum_required(VERSION min[...policy_max] [FATAL_ERROR])
-
min 指定了编译当前的cmake需要的最old的版本号,如果cmake版本号小于指定的版本号时,运行cmake 就报错。
举例:当前有cmake版本号为
3.10.2
, 运行如下的CMakeLists.txt 文件时, 就会报错:cmake_minimum_required(VERSION 3.12)
运行
cmake
命令,报错如下:提示运行版本小于要求的最小版本。CMake Error at CMakeLists.txt:1 (cmake_minimum_required): CMake 3.10.3 or higher is required. You are running version 3.10.2 -- Configuring incomplete, errors occurred!
-
... 表示min或max版本号之间的连接符。
-
policy_max 参数与cmake的policy setting相关,当指定了【policy_max】参数(要大于等于min版本号)时, 所有【小于等于 policy_max版本 或者 小于等于当前运行版本(谁小取谁)】中的已经的policy都设置为NEW.
policy 可以理解为版本之间的变更,例如语法新增加、约束变严等, policy使用
CMPXXXX
格式的编号,例如:CMP0000表示cmake文件中必须指定要求的最低版本号,CMP0002表示....等。
在新的版本中,如果要指定policy的新的规定, 语法为:cmake_policy(SET CMPXXXX NEW)
, 有时候为了新版本兼容之前写的CMakeLists.txt文件, 则可以使用原来的policy, 语法为:cmake_policy(SET CMPXXXX OLD)
.
可以使用cmake_policy(VERSION min[...max])
指定policy的要求min与max版本号:
- 当不指定max版本号时,cmake会把min版本以及之前的版本引入的所有policy设置为NEW, 大于min版本号引入的policy默认不设置。
- 当指定max版本号时, cmake会把 【max版本或者当前运行的版本号(谁小取谁)】以及之前的版本号引入的的所有polixy设置为NEW, 超过的版本引入的policy默认不设置。
当使用cmake_minimum_required(VERSION)
命令时,会隐式地调用cmake_policy(VERSION)
命令用于设置policy相关的版本要求。
举例: 下面的cmake命令:
cmake_mini_mum_required(VERSION 3.12...3.15)
# 上面命令会隐示地调用下面这条命令
cmake_policy(VERSION 3.12...3.15)
- FATAL_ERROR
该选项在2.6涉及2.6版本以下有用, 当指定该选项时,如果当前支行的版本号小于要求的版本号,就会报错;如果不指定该选项时,只会报warning. 2.6版本之后,都是报错了,所以用不着该选项了。
引入的变量
- CMAKE_MINIMUM_REQUIRED_VERSION : 设置该变量的值为
min
.
file 命令
file 命令专门用于访问文件系统对文件与路径进行操作的。
读相关
写相关
文件系统相关
file(GLOB variable 通配符表达式)
语法与参数
使用语法为: file(GLOB <variable> [LIST_DIRECTORIES true|false] [RELATIVE <path>] [CONFIGURE_DEPENDS] [<globbing-expressions>...])
含义: GLOB, 就是globbing的缩写, 该命令查找所有在当前目录(CMakeLists.txt所在目录,即CMAKE_CURRENT_SOURCE_DIR
变量)下所有满足匹配通配符表达式的文件,并保存到给定的变量中。
- GLOB: 是关键字。
- variable: 保存文件名的变量
- LIST_DIRECTORIES true| false : 表示是否要保存文件的路径,默认保存。 (试了一下,置为false为什么不管用呢?)
- RELATIVE path: 给定该参数时,保存的路径中是相对于给定path的路径名。
- globbing-expressions: 通配符表达式。
使用举例
file(GLOB source_list "src/*.cpp")
注意事项
不建议使用该命令搜索源文件名,原因是:如果CMakeLists.txt文件没有变化,但是你增加了源文件, 此时给的结果不一样正确。(我试了一下,ubuntu下可以给出正确结果)
路径转换相关
set命令
设置普通的命令
使用语法:set(<variable> <value>... [PARENT_SCOPE])
, 设置一个变量的值。 如果不给定值,就表示取消该变量的设置。
- PARENT_SCOPE: 表示在上层作用域内设置变量的值。
使用举例
set(SOURCE_LIST 1.c 2.c 3.c)
设置cache 变量
使用语法与参数含义
语法:set(<variable> <value>... CACHE <type> <docstring> [FORCE])
, 该命令会设置的cache变量会被保存到CMakeCache.txt 文档中, 可以打开看看的。
- CACHE 是关键字。
- type 表示变量的类型, 包含: BOOL、FILEPATH、PATH、STRING、INTERNAL。
- docstring: 类型注释,表明该参数的含义。
- FORCE: 默认情况下,如果该cache 变量已经设置过了,再次执行该变量就不会被写入,如果使用了FORCE关键字的话,只要命令被执行,就会对变量进行写入的。
使用举例
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Choose the type of build." FORCE)
set_property 命令
使用语法与参数含义
该命令用于设置一个对象的属性信息, 它的使用语法如下所示:
set_property(<GLOBAL |
DIRECTORY [<dir>] |
TARGET [<target1> ...] |
SOURCE [<src1> ...]
[DIRECTORY <dirs> ...] |
[TARGET_DIRECTORY <targets> ...]
INSTALL [<file1> ...] |
TEST [<test1> ...] |
CACHE [<entry1> ...] >
[APPEND] [APPEND_STRING]
PROPERTY <name> [<value1> ...])
- [对象类型] [对象名称]: 指定了对象的类型以及要设置的对象名称, 包含: GLOBAL, DIRECTORY, TARGET, SOURCE 等。例如
TARGET hello_main
. - PROPERTY 属性名: 指定了要设置的属性名以及属性值。
使用举例
cmake_minimum_required(VERSION 3.10.2)
project(hello_main)
add_executable(hello_main main.cpp)
set_property(TARGET hello_main PROPERTY CXX_STANDARD 11)
include 命令
** 语法与参数说明**
该命令用于导入文件或模块中的CMAKE代码, 类似于c语言中的include 功能。 使用语法为:
include(<file|module> [OPTIONAL] [RESULT_VARIABLE <var>]
[NO_POLICY_SCOPE])
- file | module: 指定的包含CMKE指定的文件 或者 模块名。模块名其实就是安装cmake时已经提供的***.cmake文件(例如
/usr/share/cmake-3.10/Modules/
目录下好多模块) - OPTIONAL: 如果指定了该选项,当cmake查找不到指定文件时,不会报错, 因为它是可选的嘛。
- RESULT_VARIABLE var: 用于保存查找到的文件路径(查找成功时) 或者保存失败结果NOTFOUND(失败时)
举例说明
cmake_minimum_required(VERSION 2.8)
project (hello_cpp11)
#这里导入CheckCXXCompilerFlag模块, 并运行该模块内的CHECK_CXX_COMPILER_FLAG命令。
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
message 命令
该命令是用于记录log消息的,使用语法为:message([<mode>] "message text" ...)
。 其中,mode 关键字用于表示要记录的log的类型,常用的有:
- FATAL_ERROR: cmake errer, 遇到该错误,cmake 直接停止处理。
- WARNING: 警告信息, 但是cmake会继续执行下去的。
- STATUS: 用于记录一些cmake 运行过程中的有用的信息。
例如:
message(STATUS "hello, world.")
set(NAME xiaoming)
messaeg(STATUS "hello, ${NAME}")
CMAKE中project相关命令
project 命令
语法与参数
使用语法为:project(项目名字, [VERSION 版本号] [DESCRIPTION 描述字符串] )
, 例如:
project(myproject, VERSION 1.0.0 DESCRIPTION "my first project" )
项目名字
, 即指定一个项目名字VERSION
, 指定项目的版本号, 可选字段, 一般不用不着它,不学习,不介绍DESCRIPTION
, 项目的描述, 可选字段,一般也不需要用它,不学习,不介绍- 还有其它的可选参数,例如
HOMEPAGE_URL
,LANGUAGES
, 用不着,不介绍
隐式引入的变量
PROJECT_NAME
: 它的值为 最近调用的project()
命令设置的项目名, 例如你的子目录中调用了project()
命令,那么该变量名在子目录中的值就是新设置的项目名。CMAKE_PROJECT_NAME
: 它的值为 最top 层的 project 设置的项目名PROJECT_SOURCE_DIR
: 最近 调用project()
命令定义的项目所在的源文件的绝对路径。
例如:在根目录中定义的CMakeLists.txt文件中调用了project()
命令, 在该作用域内, 该变量的值就是定义该CMakeLists.txt的绝对路径。
如果在子目录中定义的CMakeLists.txt文件中也调用了project()
命令, 在子目录中CMakeLists.txt的作用域内,该变量的值就是子目录的绝对路径。PROJECT_BINARY_DIR
: 最近调用project()
命令定义的项目的binary的绝对路径。 与调用cmake命令的位置有关, 通常会在build 目录下调用cmake, 所以该binary目录都在build 目录内。<PROJECT-NAME>_SOURCE_DIR
: 首先不推荐使用它,如果你修改的项目名字,该变量名也需要适配。 它的值与PROJECT_SOURCE_DIR
变量的值相同。<PROJECT-NAME>_BINARY_DIR
: 不推荐使用, 与PROJECT_BINARY_DIR
的值相同。
add _executable 命令
普通的可执行文件
语法与参数说明
使用语法为:add_executable(name [WIN32] [MACOSX_BUNDLE] [EXCLUDE_FROM_ALL] [source1] [source2] ...)
. 例如:
cmake_minimum_required(VERSION 3.12)
add_executable(myMain 1.c 2.c)
-
name
: 即可执行文件的名字。windows平台下实际产生的可执行文件名为name.exe
, linux平台下产生的可执行文件名就是name
. -
WIN32关键字
: 用不着,不学习,跳过。 -
MACOSX_BUNDLE
: 用不着,不学习,跳过。 -
source1
: 源文件列表, 多个源文件使用空格分开,说明如下:- 从3.1版本开始, 可以使用“generator expressions"语法表示($<...>)依赖的源文件列表。
- 在该命令中可以暂时不写依赖的源文件列表, 后续由
target_sources()
再添加源文件列表。
-
EXCLUDE_FROM_ALL
:当指定该参数时,要构建的target 就会被排除在all target 列表之外, 这样当执行make
或make all
时, 该target 不会被编译。
相关变量
CMAKE_RUNTIME_OUTPUT_DIRECTORY
: 该变量指定了生成的可执行文件的保存路径.
import可执行文件
用到的时候补。
alias可执行文件
使用语法:add_library(<name> ALIAS <target>)
, 为给定的target添加一个别名name. 例如:
add_library(other_name ALIAS mylib)
add_library 命令
Normal Libraries
语法与参数说明
使用语法:add_library(<name> [STATIC | SHARED | MODULE] [EXCLUDE_FROM_ALL] [<source>...])
, 该命令用于添加一个库文件的target, 包含静态库、动态库等。
- name: target的名字。
- [STATIC | SHARED | MODULE]: STATIC 表示静态库,SHARED 表示动态库,MODULE表示模块库,可以在运行时使用 dlopen 之类的命令动态加载的插件。
- EXCLUDE_FROM_ALL: 与
add_executable
命令中的参数相同,当指定该参数时,要构建的target 就会被排除在all target 列表之外。 - source: 源文件列表。
例如举例
add_library(hello_library STATIC src/Hello.cpp)
相关变量
- ARCHIVE_OUTPUT_DIRECTORY: 修改静态库的输出路径。
- LIBRARY_OUTPUT_DIRECTORY: 修改动态库的输出路径。
- ARCHIVE_OUTPUT_NAME: 修改静态库的输出路径。
- LIBRARY_OUTPUT_NAME: 修改动态库的输出路径。
target_include_directories 命令
语法与参数说明
语法:target_include_directories(<target> [SYSTEM] [AFTER|BEFORE] <INTERFACE|PUBLIC|PRIVATE> [items1...] [<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
当编译给定target时,该命令用于指令要包含的路径名。 当使用 gcc 编译器编译目标时,就会使用-I
选项指定该命令添加的路径, 使用-I directory/include
.
- target: 要编译的目标文件
- SYSTEM: 感觉用不到,跳过。
- AFTER 或 BEFORE: 控制把需要添加的路径append 还是 prepend 到已有的路径列表中。
- INTERFACE/PUBLIC/PRIVATE: 这几个关键字很有用。
- 从内部实现上讲: 当使用
PRIVATE
或PUBLIC
指定路径名时, 会把路径名添加到target的INCLUDE_DIRECTORIES
属性中; 当使用PUBLIC
或INTERFACE
指定路径名时, 会把路径名添加到target的INTERFACE_INCLUDE_DIRECTORIES
的属性中。 - 从外部表现上讲:使用
PRIVATE
关键字时,添加的路径只会在编译当前target时使用到。 当使用INTERFACE
关键字时,添加的路径只会在编译任何链接到当前target的目标文件时使用到。 使用PUBLIC
关键字时,会包含以两种使用。 因此,通常情况下,如果target是可执行文件,建议使用PRIVATE
, 如果target是动态或静态库, 建议使用PUBLIC
,比较方便。
- 从内部实现上讲: 当使用
命令举例
target_include_directories(mylib PUBLIC include/1.h PUBLIC ${PROJECT_SOURCE_DIR}/include)
target_include_directories(mytarget PRIVATE ${PROJECT_SOURCE_DIR}/include)
target_link_libraries命令
语法及参数含义
使用语法: target_link_libraries(<target> <PRIVATE|PUBLIC|INTERFACE> <item>...[<PRIVATE|PUBLIC|INTERFACE> <item>...]...)
该命令的用于指定一个target的链接阶段的依赖库。 它还可以 propagate any include directories with PUBLIC or INTERFACE scope from the linked library target.
PRIVATE|PUBLIC|INTERFACE的作用
暂时不太明白。
使用举例
target_link_libraries( hello_binary PRIVATE hello_library)
install 命令
Installing Target
语法与参数
该命令用于安装指定的target到指定目录内。 全量的使用语法为:
install(TARGETS targets ... [EXPORT <export-name>]
[RUNTIME_DEPENDENCIES args...|RUNTIME_DEPENDENCY_SET <set-name>]
[[ARCHIVE|LIBRARY|RUNTIME|OBJECTS|FRAMEWORK|BUNDLE|
PRIVATE_HEADER|PUBLIC_HEADER|RESOURCE]
[DESTINATION <dir>]
[PERMISSIONS permissions...]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <component>]
[NAMELINK_COMPONENT <component>]
[OPTIONAL] [EXCLUDE_FROM_ALL]
[NAMELINK_ONLY|NAMELINK_SKIP]
] [...]
[INCLUDES DESTINATION [<dir> ...]]
)
- TARGET targets: 指明了要安装的target.
- ARCHIVE|LIBRARY|RUNTIME等: 指明了target的类型。
- DESTINATION dir: 指明了要安装到的路径。当使用相对路径时,是相对于变量
CMAKE_INSTALL_PREFIX
的, 该变量默认为/usr/local/
, 也可以在CMakeLists.txt文件中指定,也可以在运行CMAKE命令时指定,例如:cmake .. -DCMAKE_INSTALL_PREFIX=/install/location
使用举例
install(TARGETS mylib LIBRARY DESTINATION lib)
install(TARGETS mybin RUNTIME DESTINATION bin)
Installing Directories
该命令用于安装指定的目录(包含目录内的文件)到指定目录。
使用语法与参数说明
install(DIRECTORY dirs...
TYPE <type> | DESTINATION <dir>
[FILE_PERMISSIONS permissions...]
[DIRECTORY_PERMISSIONS permissions...]
[USE_SOURCE_PERMISSIONS] [OPTIONAL] [MESSAGE_NEVER]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <component>] [EXCLUDE_FROM_ALL]
[FILES_MATCHING]
[[PATTERN <pattern> | REGEX <regex>]
[EXCLUDE] [PERMISSIONS permissions...]] [...])
- DIRECTORY dirs: 要安装的头文件的目录路径,默认为相对于当前的路径。 注意:如果路径以
/
结尾时, 会把路径里面的内容复制到给定路径,如果没有以/
结尾,则也会复制该层目录的。 - DESTINATION: 要安装到的目录路径。
使用举例
install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/ DESTINATION include)
Installing Files
使用语法与参数介绍
该命令用于安装指定的文件到指定目录:
install(<FILES|PROGRAMS> files...
TYPE <type> | DESTINATION <dir>
[PERMISSIONS permissions...]
[CONFIGURATIONS [Debug|Release|...]]
[COMPONENT <component>]
[RENAME <name>] [OPTIONAL] [EXCLUDE_FROM_ALL])
- FILES files: 指定要安装的文件。
- DESTINATION dir: 指定要安装的路径。
使用举例
install(FILES cmake.config DESTINATION etc)
target_compile_definitions
使用语法与参数定义
该命令用于指定指定编译给定的target时,要定义的宏名称:
target_compile_definitions(<target>
<INTERFACE|PUBLIC|PRIVATE> [items1...]
[<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
- target: 要指定编译的target。
- INTERFACE/PUBLIC/PRIVATE: 与之前介绍的类似, 从内部实现是讲: 当使用
INTERFACE
和PUBLIC
时,会把宏定义指定赋值给INTERFACE_COMPILE_DEFINITIONS
变量, 当使用PUBLIC
和PRIVATE
时,会把宏定义内容赋值给COMPILE_DEFINITIONS
变量。从外部表现上讲, 当使用INTERFACE
和PUBLIC
时,表示编译任何链接到该target(当target是一个库时)的目标文件时,都增加了该宏定义。当使用PUBLIC
或PRIVATE
时,表示编译当前target时,才使用该宏定义。 - items1: 表示要定义的宏名字。
其它方法:1. 修改变量CMAKE_CXX_FLAGS
(c++) 或者CMAKE_C_FLAGS
(C代码),也可以实现该效果,但是建议使用target_compile_definitions
命令。
2. 在执行cmake 命令时,也可以通过参数指定,例如:cmake .. -DCMAKE_CXX_FLAGS="-DCHINA"
, 它就会定义一个CHINA
的宏定义。
使用举例
main函数定义如下:
#include <iostream>
int main() {
#ifdef CHINA
std::cout << "I Love CHINA" << std::endl;
#endif
return 0;
}
cmake_minimum_required(VERSION 3.10.2)
add_executable(myTarget main.c)
target_compile_definations(myTarget PRIVATE CHINA)
add_subdirectory 命令
该命令用于增加一个构建的子目录。 注意执行的数据流: cmake 命令会执行完子目录中的CmakeLists.txt文件之后,再执行后面的命令。
使用语法与参数说明
使用语法为: add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
- source_dir: 要添加的子目录, 建议使用相对路径啊(相对于当前位置)。
- binary_dir: 用于保存输出文件位置。 一般都不写。
- EXCLUDE_FROM_ALL: 该参数很熟悉了,就是编译的时候(make 或 make all),默认不被编译。如果想要编译它,显示自己执行。
举例
cmake_minimum_required(VERSION 3.10.2)
project(example)
add_subdirectory(subdir1)
add_subdirectory(subdir2)
set_target_properties 命令
该命令用于设置给定target的一些属性值,类似于类对象的成员变量的值。 它们会影响到该target如何被构建的。
使用语法与参数说明
使用语法为:
set_target_properties(target1 target2 ...
PROPERTIES prop1 value1
prop2 value2 ...)
- target1... : 要设置的target的名字。
- PROPERTIES: 后面跟要设置的属性的名字以及它们的值。
使用举例
cmake_minimum_required(VERSION 3.10.2)
project(hello_main)
add_executable(hello_main main.cpp)
set_target_properties(hello_main PROPERTIES CXX_STANDARD 11)
target_compile_features 命令
该命令用于 Specifies compiler features required when compiling a given target.
使用语法与参数说明
使用语法为:target_compile_features(<target> <PRIVATE|PUBLIC|INTERFACE> <feature> [...])
.
- target: 要编译的目标文件的名称。
- PRIVATE | PUBLIC | INTERFACE : 这个关键字已经介绍过N次了,它指明了什么场景下生效该设置。
- feature: 就是支持的一些feature了,例如:
cxx_std_98
、cxx_std_11
、cxx_rvalue_references
等。
使用举例
cmake_minimum_required(VERSION 3.10.2)
project(hello_main)
add_executable(hello_main main.cpp)
target_compile_features(hello_main PRIVATE cxx_std_11)
cmake中的常用变量
CMAKE_SOURCE_DIR
表示:源码的根目录,也就是最top层 CMakeLists.txt文件存在的目录。
CMAKE_BINARY_DIR
表示:为编译的binary的根目录,也就是运行CMake时的目录,一般就是build
目录。
CMAKE_CURRENT_SOURCE_DIR
表示:当前正在运行的CMakeLists.txt文件的目录
CMAKE_CURRENT_BINARY_DIR
表示:当前正处于的编译目录,例如如果正在运行src目录下的CMakeLists.txt, 该变量通常为build/src
目录。
CMAKE_CXX_FLAGS 和 CMAKE_C_FLAGS
表示:当使用g++(或gcc)编译文件时,用于设置compiler flags, 也就是宏定义。
CMAKE_CXX_STANDARD
表示:该变量用于编译target时,使用的c++标准,支持98, 11, 14, 17, 20, 23
. 该变量的作用原理是:用于初始化target的CXX_STANDARD
属性。
C++编译器相关的宏命令
check_cxx_compiler_flag 命令
该宏定义在CheckCXXCompilerFlag.cmake
模块中, 可以打开该文件看它的实现的。 它的功能是用于检测c++编译器是否支持给定的编译选项,并把检测结果写的给定变量中。
使用语法为:check_cxx_compiler_flag(<flag> <var>)
,
- flag: 要检测的c++编译选项
- var: 保存检测结果的cache 变量。
使用举例