一、CMake介绍

CMake 是一个跨平台的自动化构建工具,用于管理软件项目的编译过程。它通过简单的配置文件(CMakeLists.txt)生成特定平台的构建文件(如 Makefile、Visual Studio 项目),让开发者可以专注于代码本身而非平台差异。

CMake官方网站:www.cmake.org

1.1 CMake 安装

这里介绍Ubuntu下安装Cmake,直接使用下述命令安装即可:

sudo apt install cmake

安装完成之后,直接在bash中查看CMake版本,我的版本是3.22.1

cmake -version

在这里插入图片描述

二、使用Cmake写一个Hello World

创建一个main.cpp,写上最简单的的程序——Hello World

#include<iostream>int main(){std::cout << "Hello World !" << std::endl;return 0;
}

在同级目录下创建一个CMakeLists.txt,用于配置CMake

touch CMakeLists.txt

CMakeLists中写入对应内容

cmake_minimum_required(VERSION 3.10)  # 添加最低版本要求PROJECT(hello)  # 创建项目,变量为hello_SOURCE_DIRSET(SRC_LIST main.cpp)  # 设置源文件列表# 打印构建目录信息
MESSAGE(STATUS "This is BINARY dir: ${hello_BINARY_DIR}")# 打印源文件目录信息
MESSAGE(STATUS "This is SOURCE dir: ${hello_SOURCE_DIR}")# 添加可执行文件
ADD_EXECUTABLE(hello ${SRC_LIST})

这个 CMakeLists.txt 的主要功能是:

  1. 设置项目名称为 “hello”
  2. 指定源文件为当前目录下的 main.cpp
  3. 打印构建目录和源文件目录的路径信息
  4. 创建名为 “hello” 的可执行文件

对于上述内容,在后续会讲解对应的语法,这里先看看CMake的整体流程


我们当前的项目结构是这样的,非常简单

在这里插入图片描述

我们在当前路径下,使用下述命令让cmake构建起来

cmake .

运行后,打印出来了我们的构建目录和源文件目录,并且在当前目录生成了Makefile

在这里插入图片描述

tree

在这里插入图片描述

使用make命令让Makefile跑起来

make

在这里插入图片描述

此时在当前路径下就生成了可执行文件hello

在这里插入图片描述

运行可执行文件,得到了Hello World!的打印

在这里插入图片描述

三、CMake语法介绍

在上述的工程中,我们用到了一些最基本的CMake语法,下面依次介绍

PROJECT 关键字

可以⽤来指定⼯程的名字和⽀持的语⾔,默认⽀持所有语⾔

  • PROJECT (HELLO) 指定了⼯程的名字,并且⽀持所有语⾔—建议
  • PROJECT (HELLO CXX) 指定了⼯程的名字,并且⽀持语⾔是C++
  • PROJECT (HELLO C CXX) 指定了⼯程的名字,并且⽀持语⾔是C和C++

该指定隐式定义了两个CMAKE的变量

  1. _BINARY_DIR,本例中是hello_BINARY_DIR
  2. _SOURCE_DIR,本例中是 hello_SOURCE_DIR

MESSAGE关键字就可以直接使⽤者两个变量,当前都指向当前的⼯作⽬录,后⾯会讲外部编译

如果改了⼯程名,这两个变量名也会改变,比如下面的例子,变量就是hello2了

cmake_minimum_required(VERSION 3.10)  # 添加最低版本要求PROJECT(hello2)  # 创建项目,变量为hello_SOURCE_DIRSET(SRC_LIST main.cpp)  # 设置源文件列表# 打印构建目录信息
MESSAGE(STATUS "This is BINARY dir: ${hello2_BINARY_DIR}")# 打印源文件目录信息
MESSAGE(STATUS "This is SOURCE dir: ${hello2_SOURCE_DIR}")# 添加可执行文件
ADD_EXECUTABLE(hello2 ${SRC_LIST})

编译生成的可执行文件的名称也改为了hello2

在这里插入图片描述

SET 关键字

  • SET关键字是用于设置变量名的,比如上述的SET(SRC_LIST main.cpp),其中SRC_LIST就代表了main.cpp

  • SET关键字后面也可以加入多个文件,可以使用空格隔开,比如

SET(SRC_LIST main.cpp a.cpp b.cpp)

MESSAGE 关键字

  • MESSAGE 是 CMake 的一个输出信息命令,用于在 CMake 配置(生成构建文件)阶段向控制台打印信息

主要包含三种信息

  1. SEND_ERROR,产生错误,生成过程中被跳过
  2. STATUS,普通状态信息,用于提示配置过程
  3. FATAL_ERROR,致命错误,立即终止所有的cmake过程

ADD_EXECUTABLE 关键字

  • 生成可执行文件,比如上述的ADD_EXECUTABLE(hello ${SRC_LIST}),就是将main.cpp源文件编译为hello这个可执行文件

  • 上述程序使用的是自定义的变量名,也可以直接写成ADD_EXECUTABLE(hello main.cpp)

  • 工程名称的PROJECT(hello)和我们这里的ADD_EXECUTABLE(hello ${SRC_LIST})没有关系,名字完全可以不同,没有影响

语法的基本原则

  • 变量使用${变量名}的方法取值,但是在IF控制语句中是直接使用变量名,这里需要注意

  • 指令(参数1 参数2 参数3 …),参数之间使用括弧,参数之间使用空格或者分号进行分开,例如我们的ADD_EXECUTABLE命令可以这样写:

ADD_EXECUTABLE(hello main.cpp a.cpp b.cpp)

或者

ADD_EXECUTABLE(hello main.cpp;a.cpp;b.cpp)
  • 指令是大小写不区分的,但是参数和变量是大小区分的,不过通常推荐使用全大写来书写指令

语法注意事项

  • SET(SRC_LIST main.cpp)可以改写为SET(SRC_LIST "main.cpp"),如果文件名中含有空格,则必须使用双引号,比如SET(SRC_LIST "m ain.cpp")

  • ADD_EXECUTABLE(hello main)后缀可以不写,此时cmake会自动查找.c.cpp后缀的文件,比如main.cmain.cpp,但是通常情况下我们推荐写上,防止存在main.cmain.cpp两个文件

四、内部构建和外部构建

我们上述使用cmake进行构建就是内部构建,内部构建的意思就是在当前文件夹下进行构建:

cmake .

内部构建产生的临时文件特别多,不方便清理,我们下面介绍外部构建,外部构建就是将生成的临时文件全部放到build文件夹内部,这样项目结构更加清晰,并且利于清理


同样的main.cpp,我们进行外部构建,先在当前目录下创建一个build文件夹,进入到build目录下

mkdir build
cd build

build的上级目录存在CMakeLists.txt,因此使用..表示上级目录

cmake ..

对于外部编译,这里的内置变量hello2_BINARY_DIRhello2_SOURCE_DIR就不同了,可以发现配置路径变成了当前路径下的build文件夹内

在这里插入图片描述

这样,配置文件和源文件就分开了

在这里插入图片描述

如果cmake指定路径不对,则会报错,比如cmake .,提示找不到CMakeLists.txt

在这里插入图片描述

后续步骤和内部构建是一样的,在build目录下使用Makefile编译,然后运行可执行文件

在这里插入图片描述

五、添加更多工程配置

为了让我们的Hello World更像一个工程,我们还需要添加下面的几个文件/文件夹

  1. src文件夹,用于存放工程的源代码
  2. doc文件夹,用于存放工程的文档
  3. READEMECOPYRIGHT,主要是一些项目说明和版权说明
  4. runhello的脚本,用于调用可执行可执行文件hello
  5. 将构建好的目标文件放入构建目录下的bin子目录
  6. doc目录的内容以及READMECOPYRIGHT安装到usr/share/doc/cmake路径下

5.1 将目标文件放入构建目录的bin子目录

每个目录下都要有一个CMakeLists.txt说明,整体的项目结构如下

在这里插入图片描述

  • 外层的CMakeLists.text如下,主要是定义项目的名称以及项目的子目录srcbin
  • ADD_SUBDIRECTORY 命令用于将子目录中的 CMake 项目纳入当前构建系统,子目录必须含有CMakeLists.txt文件
PROJECT(HELLO)ADD_SUBDIRECTORY(src bin)

内层的CMakeLists.txt如下,添加了可执行文件hello

ADD_EXECUTABLE(hello main.cpp)

ADD_SUBDIRECTORY 关键字

ADD_SUBDIRECTORY(source_dir [binary_dir] [EXCLUDE_FROM_ALL])
  • 这个指令用于向当前工程添加存放源文件的子目录,并且可以指定中间二进制和目标二进制存放的位置

  • EXCLUDE_FROM_ALL函数是将写的目录从编译中排出,如程序的`example

  • 上述的ADD_SUBDIRECTORY(src bin)的意思是将src子目录加入工程并且指定编译输出(包含编译中间结果)路径为bin目录,如果不指定二进制文件存放位置,那么文件默认存放在build/src目录中


进入到build路径,执行cmake ..,查看到我们的二进制文件都存放在了自动生成的bin文件夹中

在这里插入图片描述

更改二进制的保存路径

  • SET 指令重新定义 EXECUTABLE_OUTPUT_PATHLIBRARY_OUTPUT_PATH 变量 来指定最终的⽬标⼆进制的位置

  • 比如,我们想让目标二进制的位置在build/bin路径下,我们可以这样写:

SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR/bin})
  • 比如,我们想让生成的库文件放在build/lib里面,我们可以这样写:
SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR/lib})

更改上述外层的CMakeLists.txt,可以不指定ADD_SUBDIRECTOR中二进制的生成路径了,如下

PROJECT(HELLO)SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)ADD_SUBDIRECTORY(src)

构建的项目结构如下,效果就是目标二进制文件在build/bin路径下,中间二进制文件在build/src下,因为这里没有选择生成库文件,因此就没有build/lib文件夹

在这里插入图片描述

5.2 安装

  • 一种是从代码编译后直接make install 安装
  • 另一种是打包时指定目录安装
    • 比如make install DESTDIR=/tmp/test
    • 比如./configure -prefix=/usr/local/test

如何安装上述hello项目

需要使用到一个新的关键字INSTALL

  • INSTALL关键字可以用于安装二进制文件、动态库、静态库、目录、文件、脚本等
  • 可以配合CMake的变量CMAKE_INSTALL_PREFIX来指定安装的路径,CMAKE_INSTALL_PREFIX 默认是在 /usr/local/
安装文件COPYRIGHTREADME

比如我们将上述的READMECOPYRIGHT安装到/usr/local/share/doc/cmake/下,新增READMECOPYRIGHT

touch README COPYRIGHT

在这里插入图片描述

修改外层CMakeLists.txt,安装文件使用的是FILES

PROJECT(HELLO)SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin)SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib)INSTALL(FILES COPYRIGHT README DESTINATION share/doc/cmake/)
ADD_SUBDIRECTORY(src)

进入到build路径下,启动cmake ..,编译make,然后执行,这里需要有权限

sudo make install

查看安装的路径下的文件,与预期配置相符

在这里插入图片描述

也可以在配置的时候重新指定CMAKE_INSTALL_PREFIX的路径,比如改为/usr,这样相对路径就是/usr开头的

cmake -D CMAKE_INSTALL_PREFIX=/usr

配置是输出信息,显示安装的文件在/usr/share/doc/cmake路径下,成功改变了相对路径

在这里插入图片描述

安装脚本runhello.sh

安装脚本使用的是PROGRAMS,安装到usr/bin路径下,这里我们使用绝对路径试试

INSTALL(PROGRAMS runhello.sh DESTINATION /usr/bin)

在这里插入图片描述

进入build路径,执行下述命令

cmake .. && make && sudo make install

可以查看到,安装到了/usr/bin路径下

ls /usr/bin | grep hello

在这里插入图片描述

安装doc目录下的所有文件
  • 使用DIRECTORY可以递归安装整个目录

在这里插入图片描述

  • 修改CMakeLists.txt,我们把目录安装到usr/local/share/doc/cmake中,与READMECOPYRIGHT放在一起
INSTALL(DIRECTORY doc/ DESTINATION share/doc/cmake/)

执行构建 & 编译 & 安装命令

cmake .. && make && sudo make install

查看文件都安装到了正确的位置
在这里插入图片描述

⽬录名以/结尾:将这个⽬录中的内容安装到⽬标路径

  1. ⽬录名不以/结尾:这个⽬录将被安装为⽬标路径下的
  2. ⽬录名以/结尾:将这个⽬录中的内容安装到⽬标路径

如果上述使用doc安装,我们测试一下:

INSTALL(DIRECTORY doc DESTINATION share/doc/cmake/)

实际上是doc这个文件夹安装到里面了

在这里插入图片描述

并且这个文件夹内部的所有文件都被一起安装过去了

在这里插入图片描述

更多资料:https://github.com/0voice

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

贪心算法题解——划分字母区间【LeetCode】

763. 划分字母区间 本题目&#xff0c;“同一字母最多出现在一个片段中”&#xff0c;因为这句话&#xff0c;所以本质上 这道题目属于合并区间 一、算法逻辑&#xff08;逐步思路&#xff09; ✅ 目标&#xff1a; 将字符串 s 划分成尽可能多的片段&#xff0c;要求&#xf…

Python----目标检测(使用YOLOV8网络训练人脸)

一、Ultralytics安装 网址&#xff1a;主页 -Ultralytics YOLO 文档 Ultralytics提供了各种安装方法&#xff0c;包括pip、conda和Docker。通过 ultralytics pip包安装最新稳定版本的YOLOv8&#xff0c;或克隆Ultralytics GitHub 存储库以获取最新版本。可以使用Docker在隔离的…

Filament引擎(三) ——引擎渲染流程

通过Filament引擎(二) ——引擎的调用及接口层核心对象的介绍我们知道&#xff0c;要在项目中使用filament&#xff0c;首先我们需要构建出filament的Engine的对象&#xff0c;然后通过filament::Engine对象实例&#xff0c;来构建其他对象&#xff0c;组装渲染场景&#xff0c…

Oracle存储过程导出数据到Excel:全面实现方案详解

技术背景与需求分析 数据导出是企业级应用的核心功能,Oracle存储过程因其高性能执行(减少网络传输)、代码复用性(封装业务逻辑)和事务安全性(ACID保障)成为理想载体。Excel作为使用率$ \geq 95% $的办公工具,其兼容性需求尤为突出。典型场景包括: 财务报表自动生成物…

解决el-table右下角被挡住部分

一部分展示不全&#xff0c;被遮挡&#xff0c;因为 最右边加了fixed"right"<el-table-column fixed"right" label"操作" width"120">解决&#xff1a;1、去除fixed"right"或2、设置样式单页面<style lang"sc…

Waiting for server response 和 Content Download

在浏览器网络调试&#xff08;如 Chrome DevTools 的 Network 面板&#xff09;中&#xff0c;Timing 选项卡下的 Waiting for server response 和 Content Download 是两个关键性能指标&#xff0c;它们分别代表了 HTTP 请求生命周期的不同阶段。以下是详细解释和优化方案&…

《Java Web程序设计》实验报告五 Java Script学习汇报

目 录 一、实验目的 二、实验环境 三、实验步骤和内容 1、小组成员分工&#xff08;共计4人&#xff09; 2、实验方案 3、实验结果与分析 Ⅰ、简述JavaScript的产生过程与Java的关系 Ⅱ、简述JavaScript的特点有哪些 Ⅲ、简述ECMAScript的历史 Ⅳ、简述ECMAScript与J…

C#与FX5U进行Socket通信

实现效果实现步骤&#xff1a;注意&#xff1a;详细的参数这里就不说明了&#xff0c;自己网上搜即可&#xff1b;打开GX Works3 创建FX5U项目系统参数设置PLC的具体型号&#xff08;我有实物PLC&#xff09;设置IP及组态参数添加通讯设备&#xff08;这里PLC做客户端&#xff…

ubuntu20.04基于tensorRT和c++跑yolo11

设备 系统&#xff1a;Ubuntu 20.04 显卡&#xff1a;NVIDIA GeForce RTX 3050 显卡驱动&#xff1a; Driver Version: 535.183.01 CUDA Version: 12.2 关键软件版本总结 Cmake: 3.28.6 Cuda&#xff1a; 12.2.2 Cudnn: 8.9.7 TensorRT: 10.8.0.43 Python&#xff1a;3.10.1…

玖玖NFT数字藏品源码(源码下载)

玖玖NFT数字藏品源码 这套还是很不错的&#xff0c;前端uniapp&#xff0c;后端FastAdmin&#xff0c;对接汇元支付&#xff0c;富友支付&#xff0c;对接avata链&#xff0c;感兴趣的自行下载研究 源码下载&#xff1a;https://download.csdn.net/download/m0_66047725/9133…

【Redis-05】高可用方案-主从哨兵

1 概述 高可用&#xff08;High Availability&#xff09;指系统在部分节点故障时仍能持续提供服务的能力。Redis 作为核心缓存组件&#xff0c;主流的高可用方案有主从复制、哨兵模式、集群模式三种。本文介绍主从复制、哨兵模式两种高可用方案。 2 主从复制 通过 “一主多从”…

焊接机器人智能节气装置

工业焊接作为现代制造业的重要组成部分&#xff0c;广泛应用于汽车、航空航天、建筑、船舶等多个领域。随着自动化技术的快速发展&#xff0c;焊接机器人已成为提升焊接效率和质量的关键装备。在传统焊接及部分自动化焊接过程中&#xff0c;气体流失问题仍然普遍存在&#xff0…

【6.1.0 漫画数据库技术选型】

漫画数据库技术选型 &#x1f3af; 学习目标&#xff1a;掌握架构师核心技能——数据库技术选型&#xff0c;针对不同业务场景选择最合适的数据库方案 &#x1f3db;️ 第一章&#xff1a;关系型数据库对比选型 &#x1f914; MySQL vs PostgreSQL vs TiDB 想象数据库就像不同…

CVE-2022-4262/CVE-2022-3038

CVE-2022-4262&#xff08;Linux内核UAF漏洞&#xff09;漏洞原理CVE-2022-4262是Linux内核中RDS&#xff08;Reliable Datagram Sockets&#xff09;协议实现的一个UAF&#xff08;Use-After-Free&#xff0c;释放后使用&#xff09;漏洞。具体来说&#xff1a;在rds_rdma_ext…

[Token]Token merging for Vision Generation

Token Compression for Vision Domain_Generation 文章目录Image GenerationToken Merging for Fast Stable Diffusion, CVPRW 2023.Token Fusion: Bridging the Gap between Token Pruning and Token Merging, WACV 2024ToDo: Token Downsampling for Efficient Generation of…

React封装过哪些组件-下拉选择器和弹窗表单

背景&#xff08;S - Situation&#xff09;&#xff1a;在某活动管理系统中&#xff0c;前端页面需要支持用户选择“要配置的当前活动”&#xff0c;并提供「新增」「编辑」功能&#xff0c;操作内容包括填写活动名称、ID、版本号等字段。原始实现逻辑分散、复用性差&#xff…

多租户架构下的多线程处理实践指南

在现代 SaaS 系统中&#xff0c;多租户架构&#xff08;Multi-Tenant Architecture&#xff09;已成为主流。然而&#xff0c;随着系统性能要求的提升和业务复杂度的增加&#xff0c;多线程成为不可避免的技术手段。但在多租户环境下使用多线程&#xff0c;容易引发数据错乱、租…

MyBatis插件机制揭秘:从拦截器开发到分页插件实战

一、拦截器体系架构解析 1.1 责任链模式在MyBatis中的实现 MyBatis通过动态代理技术构建拦截器链&#xff0c;每个插件相当于一个切面&#xff1a; // 拦截器链构建过程 public class InterceptorChain {private final List<Interceptor> interceptors new ArrayList<…

百度文心一言开源ERNIE-4.5深度测评报告:技术架构解读与性能对比

目录一、技术架构解读1.1、ERNIE 4.5 系列模型概览1.2、模型架构解读1.2.1、异构MoE&#xff08;Heterogeneous MoE&#xff09;1.2.2、视觉编码器&#xff08;Vision Encoder&#xff09;1.2.3、适配器&#xff08;Adapter&#xff09;1.2.4、多模态位置嵌入&#xff08;Multi…

Matplotlib 模块入门

Python 中有个非常实用的可视化库 ——Matplotlib。数据可视化是数据分析中不可或缺的环节&#xff0c;而 Matplotlib 作为 Python 的 2D 绘图库&#xff0c;能帮助我们生成高质量的图表&#xff0c;让数据更直观、更有说服力。接下来&#xff0c;我们将从 Matplotlib 的概述、…