cmake 是一个跨平台编译工具,它面向各种平台提供适配的编译系统配置文件,进而调用这些编译系统完成编译工作。cmake 进入3.x 版本,指令大量更新,一些老的指令开始被新的指令集替代,并加入了一些更加高效的指令/参数。本文归纳了cmake 3.x 版本的常用指令,方便使用时备查。

  关于cmake工具的简单介绍和VS Code cmake Tools 环境配置,可以参考我的另一篇博客。本文参考资料:【公开课】现代CMake高级教程 - Bilibili 小彭老师,CMake Reference Documentation

ps: 本文是大全类文档,适合备查,完整学习cmake强烈建议跟随官方tutorial,会有非常好的效果

cmake 项目构建流程

典型的cmake 项目构建流程如下:

  1. 配置阶段 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作为生成器,效率较高
  2. 编译阶段 Build:根据生成的构建规则,调用构建系统进行构建,这一步真正输出项目目标(可执行文件、共享库等)

    cmake --build build
    
  3. 构建完成后,可以在build目录下找到输出结果(MSVC并不是直接放在build下,而是在构建模式对应目录下(Debug, Release),这与其他不同)

项目配置变量

项目配置变量是控制项目构建,以及包含项目信息的关键变量。这些变量可以在命令行配置(缓存变量),也可以在CMakeLists内部修改。

项目构建模式

一般有四种项目构建模式:

  • Debug 调试模式:不优化,生成调试信息 -O0 -g
  • Release 发布模式:最优化,性能最佳 -O3 -DNDEBUG
  • MinSizeRel 最小体积发布 :生成项目文件小,性能优化不完全 -Os -DNDEBUG
  • RelWithDebInfo 带调试信息发布 -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)
      
  • 另外,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)的项目自动引用该项目的头文件

现代 cmake (cmake 3.x) 操作大全相关推荐

  1. GridView的操作大全

    GridView的操作大全 一.GridView和DataGrid的异同 GridView 是 DataGrid的后继控件,在.net framework 2 中,虽然还存在DataGrid,但是Gr ...

  2. SQL语句操作大全(本文系转载)

    SQL语句操作大全(本文系转载) SQL语句操作大全(本文系转载) --通过知识共享树立个人品牌. 本文分为以下六个部分: 基础部分 提升部分 技巧部分 数据开发-经典部分 SQL Server基本函 ...

  3. oracle的操作大全,Oracle数据库操作大全(六)Oracle中操作数据

    Java连接数据库方法2,(方法1见:Oracle数据库操作大全(五)) 使用jdbc连接Oracle( 可远程连接 ) ***1.加载驱动 Class.forName("oracle.jd ...

  4. Java剪切板操作大全

    转载自   Java剪切板操作大全 1. 概述 提起剪切板,一般都是在桌面系统或工具中使用.目前,操作Java剪切板有两种形式,这也对应着两种不同的技术Swing和JavaFX. 而剪切板有可以分为系 ...

  5. python string 方法,python字符串的方法与操作大全

    一:字符串的方法与操作 *注意:首字母为l的为从左边操作,为r的方法为从右边操作 1.__contains__()判断是否包含 判断指定字符或字符串是否包含在一个字符串内,返回值为true或者fals ...

  6. slqite3库查询数据处理方式_SQLite3命令操作大全

    SQLite3命令操作大全 SQLite库包含一个名字叫做sqlite3的命令行,它可以让用户手工输入并执行面向SQLite数据库的SQL命令.本文档提供一个样使用sqlite3的简要说明. 一.ql ...

  7. python中numpy矩阵运算操作大全(非常全)!

    python中numpy矩阵运算操作大全(非常全) //2019.07.10晚 python矩阵运算大全 1.矩阵的输出形式: 对于任何一个矩阵,python输出的模板是: import numpy ...

  8. java中文件,java中文件操作大全

    java中文件操作大全 一.获得控制台用户输入的信息 view plaincopy to clipboardprint? / //获得控制台用户输入的信息 return throws ioexcept ...

  9. python字符串函数的find方法_python字符串的方法与操作大全

    一:字符串的方法与操作 *注意:首字母为l的为从左边操作,为r的方法为从右边操作 1.__contains__()判断是否包含 判断指定字符或字符串是否包含在一个字符串内,返回值为true或者fals ...

最新文章

  1. C和C++混合编程的Makefile的编写!
  2. 拥抱 Node.js 8.0,N-API 入门极简例子
  3. windows环境下配置Jupyter+vim
  4. vim 配置_一步一步配置vim(4)--与latex进行实时显示
  5. 基于WCF的RESTFul WebAPI如何对传输内容实现压缩
  6. Mac下GitHub安装及使用教程
  7. ARM GIC(六) GIC V3 电源/功耗管理 分析笔记。
  8. 如何在win7下安装XP系统?
  9. 配置全局使用的scss样式公用样式函数(后台框架整体颜色改变)
  10. 关于STM32F103x系列ISP烧写出现“程序文件不是0x8000000和0x20000000区域的”解决办法。
  11. 华硕笔记本提示android,华硕主板电脑和华硕笔记本开启VT进BIOS设置方法教程
  12. 日语基础学习 Day 08
  13. 解读CUDA Compiler Driver NVCC - Ch.4
  14. 按分类搜索淘宝直播接口API,淘宝直播API接口
  15. HTML期末大作业`关于在线电影主题网站设计——腾龙电影(3页) HTML+CSS+JavaScript 学生DW网页设计作业成品
  16. 透视Linux内核 神奇的BPF二
  17. CMake Error at CMakeLists.txt:97 (ADD_TARGET_DEFINITIONS): Unknown CMake command ADD_TARGET_DEFIN
  18. 无法启动 因为计算机丢失msvcp71,msvcp71.dll丢失怎样修复_msvcp71.dll丢失的解决方法 - 系统家园...
  19. 社会化分享功能的实现
  20. 如何恢复笔记本的工作报表呢

热门文章

  1. Java泛型:类型檫除、模板和泛型传递
  2. 实时弹载计算机软件闭环动态测试平台
  3. 快速排序Java实现
  4. 2020-11-22 如何在C#中往数据库插入数据
  5. mysql脚本自动拉起_shell脚本自动拉起启动程序
  6. 虚拟机克隆+虚拟机网络问题排查
  7. 【数字IC】从零开始的Verilog UART设计
  8. 把一个数随机分成n份,随机数字和等于这个数字
  9. 文本的下划线的几种方式
  10. 让别人夸赞你的 JS 写得漂亮