CMake官方文档
https://cmake.org/cmake/help/v3.15/index.html
基本命令方法
cmake_minimum_required
为工程设置CMake最低需求版本
cmake_minimum_required(VERSION 3.5) #检查cmake的版本,至少为3.5
project
设置工程的名称
project (hello_cmake) # 设置当前工程名为 hello_cmake
使用该指令之后系统会自动创建两个变量:
message(${PROJECT_NAME})
message(${${PROJECT_NAME}_BINARY_DIR})
message(${${PROJECT_NAME}_SOURCE_DIR})
# <projectname>_BINARY_DIR:二进制文件保存路径
# <projectname>_SOURCE_DIR:源代码路径
# 输出:
# TestDemo
# /home/leacock/CLionProjects/TestDemo/cmake-build-debug
# /home/leacock/CLionProjects/TestDemo
add_executable(exename srcname)
exename:生成的可执行文件的名字
srcname:依赖的源文件
指定生成可执行文件的名字以及指出需要依赖的源文件的文件名
add_executable(hello_cmake main.cpp) #生产可执行文件hello_cmake 依赖源文件main.cpp
set
Set a normal, cache, or environment variable to a given value.
设置局部变量、缓存变量(相当于全局变量)、环境变量
#设置局部变量:
set(MY_VARIABLE "value")
#变量的名称通常大写
#访问变量:${MY_VARIABLE}
#设置缓存变量:
set(MY_CACHE_VALUE "cache_value" CACHE INTERNAL "THIS IS MY CACHE VALUE")
#THIS IS MY CACHE VALUE,这个字符串相当于对变量的描述说明,不能省略,但可以自己随便定义
#设置环境变量:
set(ENV{variable_name} value)
#获取环境变量:$ENV{variable_name}
#缓存就是CMakeCache文件
target_include_directories
指定在编译给定目标时需要使用的文件目录
target_include_directories(<target> [SYSTEM] [BEFORE]
<INTERFACE|PUBLIC|PRIVATE> [items1...]
[<INTERFACE|PUBLIC|PRIVATE> [items2...] ...])
# <target> 必须被add_executable() 或 add_library() 创建
# <INTERFACE|PUBLIC|PRIVATE> 用于指定后面参数的范围
# eg:
target_include_directories(hello_library
PUBLIC
${PROJECT_SOURCE_DIR}/include
)
include_directories
将给定的目录添加到编译器用于搜索包含文件的目录中。指定的目录被解释成当前源码路径的相对路径。
include_directories([AFTER|BEFORE] [SYSTEM] dir1 [dir2 ...])
# eg:
include_directories(sub)
include_directories(sub2) #默认将sub2添加到列表最后
include_directories(BEFORE sub3) #可以临时改变行为,添加到列表最前面
默认情况下,
include_directories
命令会将目录添加到列表最后,可以通过命令设置
CMAKE_INCLUDE_DIRECTORIES_BEFORE
变量为
ON
来改变它默认行为,将目录添加到列表前面。也可以在每次调用
include_directories
命令时使用
AFTER
或
BEFORE
选项来指定是添加到列表的前面或者后面。
注:
官方文档更推荐使用
target_include_directories
。
target_include_directories
命令将包含目录添加到各个指定目标。相对来说
include_directories
影响范围更大。
add_library
生成lib库
add_library(<name> [STATIC | SHARED | MODULE]
[EXCLUDE_FROM_ALL]
[source1] [source2 ...])
# libname:生成的库文件的名字
# [SHARED|STATIC|MODULE]:生成库文件的类型(动态库|静态库|模块)
# [EXCLUDE_FROM_ALL]:有这个参数表示该库不会被默认构建
# [source1] [source2 ...]:生成库依赖的源文件,如果源文件比较多,可以使用aux_sourcr_directory命令获取路径下所有源文件
# eg:
#Generate the static library from the library sources
add_library(hello_library STATIC
src/Hello.cpp
)
add_library(hello::library ALIAS hello_library)
# ALIAS 创建动态库别名 hello::library
target_link_libraries
为给定的目标设置链接时使用的库(设置要链接的库文件的名称)
target_link_libraries(<target> [item1 [item2 [...]]] [[debug|optimized|general] <item>] ...)
# eg:
target_link_libraries(MyProject a b.a c.so) # 将若干库文件链接到MyProject中,target_link_libraries里的库文件的顺序符合gcc/g++链接顺序规则,即:被依赖的库放在依赖他的库的后面,如果顺序有错,链接将会报错
# 关键字:debug对应于调试配置
# 关键字:optimized对应于所有其他的配置类型
# 关键字:general对应于所有的配置(该属性是默认值)
find_package
如果编译的过程使用了外部的库,事先并不知道其头文件和链接库的位置,得在编译命令中加上包含外部库的查找路径,CMake中使用find_package方法
find_package()
原理解读
find_package()
find_package()
有Module模式(基本用法,basic signature)和Config模式(full signature,完全用法),其中Module模式是基础,Config模式则更复杂高级些。
只有这3种情况下才是Config模式:
-
find_package()
中指定
CONFIG
关键字 - `
-
find_package()
中指定
NO_MODULE`关键字 -
find_package()
中使用了不在”basic signature”(也就是Module模式下所有支持的配置)关键字
find_package()
区别是Module模式还是Config模式,如果是Module模式,在查找失败时会继续采用Config模式查找
Module模式下
find_package()
的用法
find_package()
find_package(<PackageName> [version] [EXACT] [QUIET] [MODULE]
[REQUIRED] [[COMPONENTS] [components...]]
[OPTIONAL_COMPONENTS components...]
[NO_POLICY_SCOPE])
version
和
EXACT
: 都是可选的,
version
指定的是版本,如果指定就必须检查找到的包的版本是否和
version
兼容。如果指定
EXACT
则表示必须完全匹配的版本而不是兼容版本就可以。
QUIET
可选字段,表示如果查找失败,不会在屏幕进行输出(但是如果指定了
REQUIRED
字段,则
QUIET
无效,仍然会输出查找失败提示语)。
MODULE
可选字段。前面提到说“如果Module模式查找失败则回退到Config模式进行查找”,但是假如设定了
MODULE
选项,那么就只在Module模式查找,如果Module模式下查找失败并不回落到Config模式查找。
REQUIRED
可选字段。表示一定要找到包,找不到的话就立即停掉整个cmake。而如果不指定
REQUIRED
则cmake会继续执行。
COMPONENTS
,
components
:可选字段,表示查找的包中必须要找到的组件(components),如果有任何一个找不到就算失败,类似于
REQUIRED
,导致cmake停止执行。
OPTIONAL_COMPONENTS
和
components
:可选的模块,找不到也不会让cmake停止执行。
Module模式查找顺序
Module模式下是要查找到名为
Find.cmake
的文件;先在
CMAKE_MODULE_PATH
变量对应的路径中查找。如果路径为空,或者路径中查找失败,则在cmake module directory(cmake安装时的Modules目录,比如
/usr/local/share/cmake/Modules
)查找。
Config模式下
find_package()
的用法
find_package()
参见
https://www.jianshu.com/p/39fc5e548310
aux_source_directory
查找目录中的所有源文件
aux_source_directory(<dir> <variable>)
搜集所有在指定路径下的源文件的文件名,将输出结果列表储存在指定的变量中。
add_subdirectory
将指定的文件夹加到build任务列表中
add_subdirectory(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
# eg:
add_subdirectory(src)
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 错误, 终止所有处理过程;
# 可以打印变量
message("PROJECT_SOURCE_DIR = ${PROJECT_SOURCE_DIR}")
list
列表操作,参见
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>)
#LENGTH 返回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按字母顺序排序
# eg:
list(APPEND libraries log4cplus zmq)
install
make install的时候,是需要我们定义一个install的目标,命令install用于指定在安装时运行的规则。
参见
install官方文档
参数中的
TARGET
可以是很多种目标文件,最常见的是
通过ADD_EXECUTABLE或者ADD_LIBRARY定义的目标文件,即可执行二进制、动态库、静态库
DESTINATION
参数:定要将文件安装到磁盘上的目录。 推荐配置在安装目录变量下的文件夹。
install(TARGETS <target>... [...])
install({FILES | PROGRAMS} <file>... [...])
install(DIRECTORY <dir>... [...])
install(SCRIPT <file> [...])
install(CODE <code> [...])
install(EXPORT <export-name> [...])
# 安装 Binaries
install (TARGETS cmake_examples_inst_bin
DESTINATION bin) # 将 cmake_examples_inst_bin 安装到 ${CMAKE_INSTALL_PREFIX}/bin 目录
# 安装 Library
# Note: may not work on windows
install (TARGETS cmake_examples_inst
LIBRARY DESTINATION lib) # 将 cmake_examples_inst 安装到 ${CMAKE_INSTALL_PREFIX}/lib 目录
# 安装 Header files
install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/
DESTINATION include) # 将 指定文件夹 安装到 ${CMAKE_INSTALL_PREFIX}/include 目录
# 安装 Config
install (FILES cmake-examples.conf
DESTINATION etc) # 将 指定文件 安装到 ${CMAKE_INSTALL_PREFIX}/etc 目录
CMAKE_INSTALL_PREFIX
,
用于指定cmake install时的相对地址前缀
。用法如:
cmake -DCMAKE_INSTALL_PREFIX=/usr ..
DESTINATION定义了安装的路径,如果路径以/开头,那么指的是绝对路径,这时候CMAKE_INSTALL_PREFIX其实就无效了。如果你希望使用CMAKE_INSTALL_PREFIX来定义安装路径,就要写成相对路径,即不要以/开头,那么安装后的路径就是${CMAKE_INSTALL_PREFIX}/<DESTINATION定义的路径>
基本控制语法
if
if (expression)
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
...
else (expression)
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
...
endif (expression)
# 注意:endif要和if对应
if(not exp) # 非
if(var1 AND var2) # 与
if(var1 OR var2) # 或
if(COMMAND cmd) # 如果cmd确实是命令并可调用 为真;
if(EXISTS dir) # 如果目录存在 为真
if(EXISTS file) # 如果文件存在 为真
if(file1 IS_NEWER_THAN file2) # 当file1比file2新 或file1/file2中有一个不存在时为真 文件名需使用全路径
if(IS_DIRECTORY dir) # 当dir是目录时 为真
if(DEFINED var) # 如果变量被定义 为真
if(string MATCHES regex) # 当给定变量或字符串能匹配正则表达式regex时 为真
if(var LESS number) # var小于number为真
if(var GREATER number) # var大于number为真
if(var EQUAL number) # var等于number为真
if(var1 STRLESS var2) # var1字母顺序小于var2为真
if(var1 STRGREATER var2) # var1字母顺序大于var2为真
if(var1 STREQUAL var2) # var1和var2字母顺序相等为真
while
while(<condition>)
<commands>
endwhile()
# <condition> 使用同 if
# 命令 break() 和 continue() 用于跳出和继续循环
foreach
foreach有四种使用形式的语法,且每个foreach都需要一个endforeach()与之匹配
1. 第一种形式 列表循环
foreach(loop_var arg1 arg2 ...)
COMMAND1(ARGS ...)
COMMAND2(ARGS ...)
...
endforeach(loop_var)
# eg:
foreach(i 0 1 2 3)
message(STATUS "current is ${i}")
endforeach(i)
注意
endforeach(loop_var)
的变量最好不要省略,因为foreach循环是依靠变量来跳出循环的。
在
foreach
和匹配
endforeach
之间的所有命令都会被系统记录而不被调用。 一旦找到了了
endforeach
,则会执行原来记录的命令。在循环的每次迭代之前,
${loop_var}
将被设置为具有列表中当前值的变量。
2. 第二种形式 范围循环
foreach(loop_var RANGE total)
# eg: 范围将会是0-3
foreach(i RANGE 3)
message(STATUS "current is ${i}")
endforeach(i)
3. 第三种形式 范围步进循环
foreach(loop_var RANGE start stop [step])
# eg:
foreach(i RANGE 0 3 1)
message(STATUS "current is ${i}")
endforeach(i)
从start开始直到stop结束之间的值,可以设置步进值step
4. 第四种形式 LISTS范围循环
foreach(loop_var IN [LISTS [list1 [...]]]
[ITEMS [item1 [...]]])
# eg:
set(A 0;1)
set(B 2 3)
set(C "4 5")
set(D 6;7 8)
set(E "")
foreach(X IN LISTS A B C D E)
message(STATUS "X=${X}")
endforeach()
基本参数
PROJECT_SOURCE_DIR
当前项目的顶层源目录
PROJECT_BINARY_DIR
项目的编译目录完整路径。
CMAKE_INSTALL_PREFIX
用于指定cmake install时的相对地址前缀
,参见
install
CMAKE_ARCHIVE_OUTPUT_DIRECTORY
指定在编译时将所有归档目标文件放在哪里,用于初始化所有目标上的
ARCHIVE_OUTPUT_TRISTORY
属性。
CMAKE_LIBRARY_OUTPUT_DIRECTORY
指定在编译时将所有库文件放在哪里,用于初始化所有目标上的
Library_Output_Directory
属性。
CMAKE_RUNTIME_OUTPUT_DIRECTORY
指定所有运行时目标文件放在哪里,于初始化所有目标上的
RUNTIME_OUTPUT_DIRECTORY
属性。
# 输出目录,${PROJECT_BINARY_DIR}为Cmake命令执行的位置
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin)