现代 cmake (cmake 3.x) 操作大全

news2024/12/23 14:07:03

  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 PROPERTIES
						property_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(Usage
    PROPERTIES 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命令来构建,操作列表

Reading
  list(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>)

Search
  list(FIND <list> <value> <out-var>)

Modification
  list(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> [...])

Ordering
  list(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中,会显示如下,并可以被配置

image-20230116210855149

一般项目情形下,需要使用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)的项目自动引用该项目的头文件

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/340638.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MongoDB--》MongoDB数据库以及可视化工具的安装与使用—保姆级教程

目录 数据库简介 MongoDB数据库的安装 MongoDB数据库的启动 MongoDB数据库环境变量的配置 MongoDB图形化管理工具 数据库简介 在使用MongoDB数据库之前&#xff0c;我们应该要知道我们使用它的原因&#xff1a; 在数据库当中&#xff0c;有常见的三高需求&#xff1a; Hi…

如何手写一个springboot starter?

本文主要分享了如何手写一个spring starter&#xff0c;把你的代码作为jar包进行开源。命名规则&#xff08;不要使用spring-boot开头&#xff0c;以避免将来spring-boot官方使用你的starter而重名&#xff09;官方命名格式为&#xff1a;spring-boot-starter-xxx非官方命名格式…

ucos-ii 的任务调度原理和实现

ucosii 任务调度和原理1、ucos-ii 任务创建与任务调度 1.1、任务的创建 当你调用 OSTaskCreate( ) 进行任务的创建的时候&#xff0c;会初始化任务的堆栈、保存cpu的寄存器、创建任务的控制块&#xff08;OS_TCB&#xff09;等的操作&#xff1b; if (OSTCBPrioTbl[prio] (OS_…

Python中如何书写文件路径

当程序运行时&#xff0c;变量是保存数据的好方法&#xff0c;但变量、序列以及对象中存储的数据是暂时的&#xff0c;程序结束后就会丢失&#xff0c;如果希望程序结束后数据仍然保持&#xff0c;就需要将数据保存到文件中。Python 提供了内置的文件对象&#xff0c;以及对文件…

数据库 delete 表数据后,磁盘空间为什么还是被一直占用?

插&#xff1a; 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站。 坚持不懈&#xff0c;越努力越幸运&#xff0c;大家一起学习鸭~~~ 最近有个上位机获取下位机上报数据的项目&#xff0c…

计算机网络6:Http协议

目录HTTP1.基本概念1.1.1 URI2. 请求和响应报文2.1.请求报文2.2.响应报文3.HTTP报文实现细节3.1响应头主要字段3.2HTTP状态码3.3 HTTP方法3.3.1 GET方法3.3.2 HEAD3.3.3 POST3.3.4 PUT3.3.5 PATCH3.3.6 DELETE3.3.7 OPTIONS3.3.8 CONNECT3.4 HTTP首部&#xff08;头部&#xff…

【MT7628】开发环境搭建-Fedora12安装之后无法上网问题解决

1.按照如下图所示,打开Network Connections 2.点击Network Connections,弹出如下界面

面向对象程序(C++)设计基础

一、类&对象C 在 C 语言的基础上增加了面向对象编程&#xff0c;C 支持面向对象程序设计。类是 C 的核心特性&#xff0c;通常被称为用户定义的类型。类提供了对象的蓝图&#xff0c;所以基本上&#xff0c;对象是根据类来创建的。声明类的对象&#xff0c;就像声明基本类型…

面试题(二十二)消息队列与搜索引擎

2. 消息队列 2.1 MQ有什么用&#xff1f; 参考答案 消息队列有很多使用场景&#xff0c;比较常见的有3个&#xff1a;解耦、异步、削峰。 解耦&#xff1a;传统的软件开发模式&#xff0c;各个模块之间相互调用&#xff0c;数据共享&#xff0c;每个模块都要时刻关注其他模…

Grafana 系列文章(十五):Exemplars

Exemplars 简介 Exemplar 是用一个特定的 trace&#xff0c;代表在给定时间间隔内的度量。Metrics 擅长给你一个系统的综合视图&#xff0c;而 traces 给你一个单一请求的细粒度视图&#xff1b;Exemplar 是连接这两者的一种方式。 假设你的公司网站正经历着流量的激增。虽然…

ansible的模块详解

ansible 的概述 什么是ansible Ansible是一款为类Unix系统开发的自由开源的配置和自动化工具。 它用Python写成&#xff0c;类似于saltstack和Puppet&#xff0c;但是有一个不同和优点是我们不需要在节点中安装任何客户端。 它使用SSH来和节点进行通信。Ansible基于 Python…

Redux 源码分析

Redux 目录结构 redux ├─ .babelrc.js ├─ .editorconfig ├─ .gitignore …

列线图工具_Nomogram

定义 列线图是一种相对传统的分析方法&#xff0c;用于展示自变量和因变量的线性关系&#xff0c;及其特征的重要程度。 现在用SHAP&#xff0c;和机器学习库中的 Feature importance 工具可以实现类似甚至更好效果。不过很多传统的研究领域比较认这种方法。 列线图工具建立在…

什么是相机标定

1. 相机标定的定义及作用 相机标定是指借助标定板来计算单个或多个相机的内参、外参和镜头畸变参数。 作用&#xff1a; 将畸变的图像恢复为正常的图像&#xff0c;为后续进行拼接、SLAM等奠定基础。 多相机标定可以将所有相机输出变换到同一个坐标系。 相机标定是三维视觉…

适用于 Windows 11/10/8/7 的 10 大数据恢复软件分享

适用于 Windows 11/10/8/7 的 最佳数据恢复软件综述。选择首选的专业数据/文件恢复软件&#xff0c;轻松恢复丢失的数据或删除的照片、视频等文件、SSD、外接硬盘、USB、SD卡等存储设备中的文件等。流行的sh流行的数据恢复软件也包括在内。 10 大数据恢复软件分享 为了帮助您恢…

美赛Day2

3 熵权法 相对客观的权重计算方法&#xff08;层次分析法都是自己瞎填&#xff09; 3.1 原理 指标的变异程度越小&#xff0c;反应的信息越少&#xff0c;对应的权值越低。 一个事件的信息量&#xff1a;I(x) -ln(p(x)) 信息熵&#xff1a;对X可能发生的所有情况的信息量的…

仿真与测试:通过Signal Builder模块生成输入信号

本文研究通过Signal Builder模块生成输入信号的方法。 文章目录1 生成输入信号2 仿真过程2.1 搭建被测模型2.2 搭建Signal Builder输入模块2.3 配置仿真log及仿真3 总结1 生成输入信号 在汽车的电控软件开发中&#xff0c;经常会在Simulink模型内部进行单元测试。单元测试的本…

FlexRay™ 协议控制器 (E-Ray)-04

网络管理 累积的网络管理 (NM) 向量位于网络管理寄存器 1 到网络管理寄存器 3 (NMVx (x = 1-3)) 中。【The accrued Network Management (NM) vector is located in the Network Management Register 1 to Network Management Register 3 (NMVx (x = 1-3)).】 网络管理向量 x…

『前端必备』本地数据接口—json-server

文章目录前言一、json-server简介二、起步三、使用步骤前言 Ajax 是前端必学的一个知识点&#xff0c;但刚接触 Ajax 的同学可能会因为没接口测试而烦恼。本文 入门篇 会花你10分钟解决 没接口测试 这个烦恼&#xff0c;而且不需要你具备后端知识。 一、json-server简介 json…

一个测试人员,在现阶段的环境下如何在测试行业发展和自我价值。

前言周末和几个测试圈子里的大佬饭局上聊了一些职场和测试职业发展相关的话题&#xff0c;我将聊天的内容做了整理和阐述。。朋友圈有测试同学对这篇文章提了比较深刻的建议&#xff0c;下面是他的评价和建议&#xff1a;评价&#xff1a;据说是大佬饭桌总结&#xff0c;有两点…