在线教育网站有哪些厦门外贸网站建
cmake 是一个跨平台编译工具,它面向各种平台提供适配的编译系统配置文件,进而调用这些编译系统完成编译工作。cmake 进入3.x 版本,指令大量更新,一些老的指令开始被新的指令集替代,并加入了一些更加高效的指令/参数。本文归纳了cmake 3.x 版本的常用指令,方便使用时备查。
关于cmake工具的简单介绍和VS Code cmake Tools 环境配置,可以参考我的另一篇博客。本文参考资料:【公开课】现代CMake高级教程 - Bilibili 小彭老师,CMake Reference Documentation
ps: 本文是大全类文档,适合备查,完整学习
cmake强烈建议跟随官方tutorial,会有非常好的效果
cmake 项目构建流程
典型的cmake 项目构建流程如下:
-  
配置阶段 Configure:根据编写的
CmakeLists.txt文件,以及选择的编译系统,生成该系统的构建规则文件。(例如,对make生成Makefile,对MSVC生成sln(可以在VS中打开))cmake -B build- 以上指令可以在当前目录下创建
build目录,而不需要事先创建并进入 - 通过
-D设置缓存变量,格式-D<OPTION>=<VALUE>,如:- 编译器路径:
CMAKE_C_COMPILTER,CMAKE_CXX_COMPILER等 - 安装路径(在Configure阶段配置):
CMAKE_INSTALL_PREFIX - 构建模式:
CMAKE_BUILD_TYPE - 自定义缓存变量:
-Dvar:type=value,可以将option设定为OFF,即表示不启用(会覆盖CMakeLists中的默认选项) 
 - 编译器路径:
 -G指定生成器(Generator,即构建系统),可以通过--help查看支持的列表-A指定架构(For MSVC build system)-T指定工具链,例如使用ClangCL:-T ClangCL,host=x64(For MSVC build system)- 推荐使用
Ninja作为生成器,效率较高 
 - 以上指令可以在当前目录下创建
 -  
编译阶段 Build:根据生成的构建规则,调用构建系统进行构建,这一步真正输出项目目标(可执行文件、共享库等)
cmake --build build -  
构建完成后,可以在
build目录下找到输出结果(MSVC并不是直接放在build下,而是在构建模式对应目录下(Debug,Release),这与其他不同) 
项目配置变量
项目配置变量是控制项目构建,以及包含项目信息的关键变量。这些变量可以在命令行配置(缓存变量),也可以在CMakeLists内部修改。
项目构建模式
一般有四种项目构建模式:
- Debug 调试模式:不优化,生成调试信息 
-O0 -g - Release 发布模式:最优化,性能最佳 
-O3 -DNDEBUG MinSizeRel最小体积发布 :生成项目文件小,性能优化不完全-Os -DNDEBUGRelWithDebInfo带调试信息发布-O2 -g -DNDEBUG- 默认为Debug模式
 
可以通过在CMakeLists中增加默认选项脚本的方法修改默认选项为Release
if (NOT CMAKE_BUILD_TYPE)set(CMAKE_BUILD_TYPE Release)
endif()
 
项目信息
使用命令project初始化项目信息
project(<PROJECT-NAME> [<language-name>...])
project(<PROJECT-NAME>[VERSION <major>[.<minor>[.<patch>[.<tweak>]]]][DESCRIPTION <project-description-string>][HOMEPAGE_URL <url-string>][LANGUAGES <language-name>...])
 
- language: 指定项目使用语言,默认
C CXX- 支持
C CXX ASM FORTRAN CUDA OBJC OBJCXX ISPC 
 - 支持
 VERSION字段:设置项目版本号,会自动配置相关变量
该命令将初始化名为project_name的项目,并给相关变量赋值:
PROJECT_NAME: 项目名称CMAKE_PROJECT_NAME:根项目名称PROJECT_SOURCE_DIR:项目源码路径,即初始化project的CMakeLists.txt所在路径PROJECT_BINARY_DIR:项目输出路径,通常是./build路径CMAKE_CURRENT_SOURCE_DIR:当前源码路径CMAKE_CURRENT_BINARY_DIR:当前输出路径,即当前CMakeLists.txt所在路径,子模块中指子模块路径- 更多属性,请参考project — CMake 3.25.1 Documentation
 
项目语言标准
一般通过如下指令设置标准(推荐放在project指令前,会在project语言启用时检测)
set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON)
set(CMAKE_C_EXTENSIONS OFF)
 
- 设置C标准为C11, C++设置CXX对应属性
 CMAKE_C_STANDARD_REQUIRED在启用语言时检查编译器是否支持该标准CMAKE_C_EXTENSIONS是否启用GNU拓展语言特性(对跨平台有影响)
添加构建目标
构建目标主要有两种类型:
可执行文件 executable
使用add_executable命令添加可执行文件目标:
add_executable(<name> [WIN32] [MACOSX_BUNDLE][EXCLUDE_FROM_ALL][source1] [source2 ...])
 
- 添加一个
name的可执行文件目标,源文件来自source- 可以是列表或者空格分开的多个文件名
 - 也可以是变量
${var_name},目录的所有文件可以使用aux_source_directory添加 
 - 其中,
source可以省略(>3.11),并在后面以target_sources的形式给出 
库 library
add_library(<name> [STATIC | SHARED | MODULE][EXCLUDE_FROM_ALL][<source>...])
 
STATIC/SHARED指定生成静态库/动态库,默认静态
另外还有对象库object library
add_library(<name> OBJECT [<source>...])
 
-  
对象库不输出实际的库文件,而是可以直接被加入到其他构建目标中,如:
add_library(... $<TARGET_OBJECTS:objlib> ...) add_executable(... $<TARGET_OBJECTS:objlib> ...)或者使用
target_link_libraries()链接到对象库(CMAKE >3.12) -  
注意:动态库不能直接引用静态库,因为动态库开启PIC,而静态库没有
- 解决方案:使用对象库替代静态库,或者为静态库配置PIC
set_property(TARGET target_name PROPERTY POSITION_INDEPENDENT_CODE ON) 
 - 解决方案:使用对象库替代静态库,或者为静态库配置PIC
 -  
另外,Windows平台如果要使用动态库,则需要添加宏
-  
声明前添加
#ifdef _MSC_VER__declspce(dllimport) #endif -  
定义前加
#ifdef _MSC_VER__declspce(dllexport) #endif 
 -  
 
配置构建目标
设置对象属性
set_target_properties(target_name PROPERTIESproperty_name value...)
 
使用set_target_properties设置编译目标属性
这些属性包括(详细信息参考cmake-properties(7) — CMake 3.25.1 Documentation):
- 语言标准版本
 - 编译器设置
 - 目标输出位置
*_OUTPUT_DIRECTORY 
链接三方库
使用target_link_libraries()链接第三方库
target_link_libraries(<target> ... <item>... ...)
 
其中,item可以是:
- 库对象名(使用
add_library( IMPORTED)引入) - 指向库文件的完整路径
 - 库文件名,这会调用链接器自动搜索(在Linux下可以依据lib搜索)
 
优化方案(对使用cmake的三方库,限Linux):
find_package(LIBRARY_NAME REQUIRED)
target_link_libraries(<target> [PUBLIC] LIBRARY_NAME::library_target_name)
 
- 使用
find_package会在/usr/lib/cmake下增加.cmake配置文件,cmake会自动搜索并链接相应的库。 - 另外,在链接库的时候,还会按照配置文件进行引用传播,引用其的对象自动引用其头文件目录。
 
编译时定义
使用target_compile_definitions来配置编译时宏定义,这些定义可以在C/C++的宏中被使用
target_compile_definitions(target PUBLIC def)
 
- 将def设置到target的编译过程中
 
安装 install
install(TARGETS <target>... [destination])
 
以上命令用于安装对象到destination
子命令还可以是:
FILES安装文件,如头文件等DIRECTORY目录- 详见install — CMake 3.25.1 Documentation
 
部署 ctest
使用enable_testing以启用ctest,ctest会自动执行命令,并匹配输出,自动化完成测试
以下示例增加一个ctest,并设置匹配的输出结果
add_test(NAME Usage COMMAND Tutorial)
set_tests_properties(UsagePROPERTIES PASS_REGULAR_EXPRESSION "Usage:.*number")
 
如果程序输出:Usage:[any]number,就算正确通过
还可以将测试集写为函数,增强代码复用性
function (do_test target arg result)add_test(NAME Comp${arg} COMMAND ${target} ${arg})set_tests_properties(Comp${arg}PROPERTIES PASS_REGULAR_EXPRESSION "${arg} is ${result}")
endfunction()function (do_math_test target)do_test(${target} 4 2)do_test(${target} -25 "(-nan|nan|0)")
endfunction()
do_math_test(Tutorial)
 
Scripting Commands
- cmake命令不区分大小写,不过小写命令更推荐使用
 - cmake 变量,参数等区分大小写
 
基础设置变量
使用set命令来设置变量:
set(<variable> <value>... [PARENT_SCOPE])
 
- 如果value为空格分隔的字符串(不加引号),则被认为是列表
 - 列表也可以用
"a;b"(以分号分隔,加引号)等效 
CMakeLists 文件结构
通常情况下,CMakeLists文件结构如下所示:
cmake_minimum_required(VERSION 3.0)project(project_name)...
 
cmake_minimum_required指定了该项目生成需要的最小版本project()指定项目名称,该命令以下部分都是该项目的配置
批量添加文件
aux_source_directory(<variable> <source_dir>)
 
此命令将添加source_dir下的所有匹配文件到variable中。(匹配文件根据项目语言决定)
文件操作指令
-  
file是cmake中的文件操作指令,可以完成复制、创建等一系列工作,也可以用于查找文件:file(GLOB <variable> CONFIGURE_DEPENDS <globbing-expressions>)CONFIGURE_DEPENDS可以在文件更新时自动更新cmake- 后面是查找文件的表达式,可以是通配符,如
*.cpp *.h等 
 -  
configure_file可以完成文件配置,按照模板文件生成目标文件configure_file(Config.h.in ${PROJECT_SOURCE_DIR}/Config.h)该命令会将模板文件
Config.h.in中内容替换为实际配置内容,并将头文件写入source目录下的Config.h中,这样,可以完成对文件内容的修改,如启用选项,编辑#define常量,或其他宏补全效果。常用模板格式如下:
#define FOO_STR "@FOO_STR@" #cmakedefine FOO_ENABLE该命令会将
@号包含的部分转换为cmake 执行环境中变量,使用cmakedefine,如果cmake环境中存在变量,则会将其修改为#define FOO_ENABLE即,如果在CMakeLists中设置
set(FOO_STR "Hello world") option(FOO_ENABLE True)则模板文件中的定义将被输出为:
#define FOO_STR "Hello world" #define FOO_ENABLE 
输出字符串
使用message命令输出字符串
message([<mode>] "message text" ...)
 
其中模式可以为下列等:
STATUS状态信息,前面带--WARNING警告信息,黄色警告FATAL_ERROR致命错误INFO默认,前面不带任何,白色,输出到stderr
列表 list
使用list命令来构建,操作列表
Readinglist(LENGTH <list> <out-var>)list(GET <list> <element index> [<index> ...] <out-var>)list(JOIN <list> <glue> <out-var>)list(SUBLIST <list> <begin> <length> <out-var>)Searchlist(FIND <list> <value> <out-var>)Modificationlist(APPEND <list> [<element>...])list(FILTER <list> {INCLUDE | EXCLUDE} REGEX <regex>)list(INSERT <list> <index> [<element>...])list(POP_BACK <list> [<out-var>...])list(POP_FRONT <list> [<out-var>...])list(PREPEND <list> [<element>...])list(REMOVE_ITEM <list> <value>...)list(REMOVE_AT <list> <index>...)list(REMOVE_DUPLICATES <list>)list(TRANSFORM <list> <ACTION> [...])Orderinglist(REVERSE <list>)list(SORT <list> [...])
 
详见list — CMake 3.25.1 Documentation,[下一小节](#选项 option)会有应用选项的列表操作
选项 option
使用option来生成选项,这些选项**会在ccmake**或cmake-gui中被显示
option(VAR_NAME [Description] [default_value])
 
option中的默认选项会被命令行中的-D选项覆盖
例如,
option(USE_MYMATH "Enable MyMath Library" True)
 
在cmake-gui中,会显示如下,并可以被配置
 
一般项目情形下,需要使用option来控制某个子功能是否启动,可以使用以下命令(接上例USE_MYMATH):
if (USE_MYMATH)add_subdirectory(MathFunctions)list(APPEND EXTRA_LIBS MathFunctions)list(APPEND EXTRA_INCLUDES MathFunctions)
endif()
 
如果选项中启用USE_MYMATH,才会进行库引用
生成器表达式
使用生成器表达式可以简化指令
$<$<var_name:value>:statement>
 
只有在变量=值时,才会表现为statement,否则,生成器表达式的值为空
变量与作用域
默认变量传播规则:parent->child
如果要child->parent,则增加选项PARENT_SCOPE
Usage Requirements
在外部引用项目时,需要满足一些特定条件,这些条件称为usage requirements
只要项目开发者编写Usage Requirements,使用者就可以直接通过link完成寻找包和链接功能,而不需要另外的配置(添加include等),是现代cmake的主要构成。
同时,这些引用也是会传递的,不需要进行额外配置(但要保证配置正确)
在配置项目时,一般有三种配置选项PRIVATE|PUBLIC|INTERFACE,其中,PRIVATE仅限于项目自身编译时使用,INTERFACE是Usage Requirements,它要求所有使用该库的项目添加该动作。PUBLIC则是两者兼有。
例如,
add_library(MathFunctions mysqrt.cxx)
target_include_directories(MathFunctions INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
 
以上指令会使所有引用该库(MathFunctions)的项目自动引用该项目的头文件
