跨平台编译工具--CMake上手教程

news2025/2/23 5:13:36

文章目录

  • 一、引入
  • 二、基本关键字
    • 1.PROJECT
    • 2.SET
    • 3.MESSAGE
    • 4.ADD_EXECUTABLE
    • 5.ADD_SUBDIRECTORY
      • (1)使用
      • (2)CMakeLists执行顺序
      • (3)输出文件的位置
    • 6.INSTALL
      • (1)安装文件
      • (2)安装非目标文件可执行文件
      • (3)安装目录
      • (4)安装指令
    • 7.ADD_LIBRARY
    • 8.SET_TARGET_PROPERTIES
  • 三、语法的基本规则
  • 四、使用CMake编写一个Hello CMake
  • 五、内部构建与外部构建
  • 六、让Hello world看起来更像一个工程
    • 1.整体结构
    • 2.编写两个CMakeLists.txt
    • 3.安装HelloWorld
  • 七、建立动态库和静态库
    • 1.结构
    • 2.CMakeLists编写
    • 3.静态库与动态库的构建
      • (1)动态库与静态库重名构建失败
      • (2)解决办法
      • (3)动静态库的安装
  • 八、使用动态库与静态库
    • 1.链接头文件
    • 2.链接动态库

一、引入

当多个人要使用不同的语言或者编译器来开发一个项目的时候,最终要输出一个可执行文件或者共享库(dll,so等等),CMake使得所有的操作都是通过编译CMakeLists.txt来实现的。
学习CMake的目的是为了将来处理大型的C/C++项目,可以先看下面的例子参照上面的关键字来进行学习。

二、基本关键字

1.PROJECT

PROJECT:用来指定工程的名字以及支持的语言,支持的语言不填的话,默认是支持所有语言。

PROJECT(HELLO)       #默认支持所有语言
PROJECT(HELLO C CXX) #指定支持C和C++

执行该条指令的时候隐式定义了两个CMAKE变量,分别是<projectname>_BINARY_DIR和<orojectname>_BINARY,其中<orojectname>就是项目名,也就是HELLO。这两个变量下面介绍的MESSAGE关键字都是可以直接使用的,在外部编译的部分介绍两者的区别。

2.SET

SET:用于显示的指定变量。

SET(SRC_LIST test.cc)           #SRC_LIST变量中就包含了test.cc
SET(SRC_LIST "test.cc")         #也可以加双引号         
SET(SRC_LIST test1.cc test2.cc) #一个变量中可以包含多个源文件

在SET指令中,如果源文件名中含有空格(比如ma in.cc),则必须加双引号,如果没有加不加都可以。

3.MESSAGE

MESSAGE:向终端输出用户自定义的信息。
主要包含三种信息:

  • SEND_ERROR,产生错误,生成过程被跳过。
  • STATUS,输出前缀为–的信息。
  • FATAL_ERROR,立即终止所有CMake的过程。
MESSAGE(STATUS "This is BINARY dir" ${HELLO_BINARY_DIR}) #此时的输出带有前缀--

4.ADD_EXECUTABLE

ADD_EXECUTABLE:生成可执行文件。

ADD_EXECUTABLE(test ${SRC_LIST}) #将变量SRC_LIST中文件编译成可执行文件test
ADD_EXECUTABLE(test test.cc)     #这样写也可以,不使用变量

其中test.cc的后缀可以不写,会自动去找.c或者.cc,但是不推荐这样写。

5.ADD_SUBDIRECTORY

(1)使用

ADD_SUBDIRCTORY:

  • 这个指令用来向当前工程添加存放源文件的子目录,并可以指定中间二进制和目标二进制的存放位置。
  • EXCLUDE_FROM_ALL函数是将写的目录从编译中排除,如程序中的example。
ADD_SUBDIRECTORY(src bin) #将src的子目录加入工程,并指定编译结果输出路径为bin目录。

该指令会自动创建一个bin目录,如果不指定则结果会放在build/src即SOURCE_DIR目录。

(2)CMakeLists执行顺序

CMakeLists是逐层进行执行的:

  • 首先执行cmake指定路径下的CMakeLists。
  • 当在CMakeLists中遇到ADD_SUBDIRECTORY的时候跳转到该关键字指定的路径下执行该路径下的CMakeLists。
  • 执行之后返回跳转位置的下一条指令,然后继续按顺序执行。

(3)输出文件的位置

ADD_SUBDIRECTORY可以识别出指定路径中CMakeLists中的ADD_EXECUTABLE生成的可执行文件是一个输出文件,并会将该文件添加到指定的输出文件路径。这个输出文件也可以是一个动态库或者静态库。

6.INSTALL

INSTALL:为安装关键字,他可以用来安装一个文件,也可以用来安装脚本等。

(1)安装文件

安装文件:

INSTALL(FIELS README DESTINATION share/doc/cmake/)
  • 其中FILES表示安装文件,README是文件名,DESTINATION后面跟的是安装路径。
  • 这个路径可以是一个绝对路径,也可以是一个相对路径。
  • 如果是相对路径会使用CMake的一个变量CMAKE_INSTALL_PREFIX,他表示的是/usr/local/。因此我们安装的绝对路径是/usr/local/share/doc/cmake。

(2)安装非目标文件可执行文件

安装脚本:

INSTALL(PROGRAMES runhello.sh DESTINATION bin)
  • 其中PROGRAMES表示的是非目标文件的可执行文件,bin还是一个相对路径。
  • 此时文件绝对路径为/usr/local/bin

(3)安装目录

安装目录:

INSTALL(DIRECTORY doc/ DESTINATION share/doc/cmake)
  • 其中DIRECTORY表示目录。
  • 注意doc/和doc是有区别的,doc/表示将整个目录安装到对应路径下,二doc表示将目录中的内容安装到对应路径下。

(4)安装指令

注意仅仅cmake是不能够进行安装的,而是在生成makefile之后还需要进行make install操作。才算安装成功。

7.ADD_LIBRARY

ADD_LIBRARY:用来将源文件创建成动态库,即将test.cc编程libtest.so

ADD_LIBRARY(hello SHARED test.cc)
  • 其中hello为库名,生成的名字后会加上前缀和后缀,及libhello.so。
  • SHARED表示动态库,STATIC表示静态库。
  • test.cc:源文件。

8.SET_TARGET_PROPERTIES

SET_TARGET_PROPERTIES:用来设置输出的名称,对于动态库,还可以指定动态库版本和API版本。
这个在动静态库中结合场景具体介绍。

三、语法的基本规则

  • 变量使用${}来进行取值,比如上述的ADD_EXECUTABLE中的${SRC_LIST},就是获取该变量中的值,该变量中可以是多个值也可以是一个值。
  • 关键字指令的参数是使用空格或者分号来进行隔开的。
  • 指令无关大小写,参数和变量有关。

四、使用CMake编写一个Hello CMake

这里主要编写CMakeLists.txt

PROJECT(TEST)
SET(SRC_LIST test.cc)
MESSAGE(STATUS "This is a BINARY dir" ${TEST_BINARY_DIR})
MESSAGE(STATUS "This is a SOURCE dir" ${TEST_SOURCE_DIR})
ADD_EXECUTABLE(test ${SRC_LIST})

假设CMakeLists.txt和test.cc在同一个路径下:
执行:cmake .
可以看到生成了Makefile文件,此时make,就可以完成对test.cc的编译。
在这里插入图片描述

五、内部构建与外部构建

上面的例子就是内部构建,而外部构建与之的区别是新建一个build目录,在build目录中进行CMake的操作。我们可以将上面CMake生成的文件进行删除,然后在build中对上一级目录进行CMake。
在这里插入图片描述
在这里插入图片描述
此时在build目录下执行make,就可以在build下生成可执行文件了。

同时我们可以发现BINARY的路径变为了build路径,而SOURCE没有发生变化。

强烈推荐使用外部构建。

六、让Hello world看起来更像一个工程

1.整体结构

在这里插入图片描述

2.编写两个CMakeLists.txt

#外部的CMakeLists.txt
PROJECT(TEST) #工程名
ADD_SUBDIRECTORY(src bin) #将src目录下的文件加入工程,并指定编译生成的文件在bin中

#内部的CMakeLists.txt
ADD_EXECUTABLE(hello test.cc) #对test.cc进行编译(因为已经将其加入工程,所以可以找到),生成的hello会放在bin中

还是进入build进行CMake操作,然后进行make操作,会发现的build目录下生成了一个bin文件夹,进入该文件夹有可执行文件test。
在这里插入图片描述

3.安装HelloWorld

首先构建目录树,为了方便演示,先将build中内容删除。
在这里插入图片描述
其中新增了COPYRIGHT为版权文件,README为说明文件,runhello.sh为一个运行脚本。
增加安装的命令:

PROJECT(TEST)
ADD_SUBDIRECTORY(src bin)
INSTALL(FILES README COPYRIGHT DESTINATION share/doc/cmake)
INSTALL(PROGRAMS runhello.sh DESTINATION bin)
INSTALL(DIRECTORY doc/ DESTINATION share/doc/cmake)

在执行make之后,还需要执行make install来进行安装。
在这里插入图片描述
此时可以看到文件安装成功了。

七、建立动态库和静态库

目标:建立一个HelloFunc函数来提供给其他函数使用,该函数可以输出Hello World。建立该函数的头文件以及共享库。

1.结构

在这里插入图片描述

2.CMakeLists编写

#外层
PROJECT(HELLO)
ADD_SUBDIRECTORY(lib bin)

#内层
SET(LIBHELLO_SRC hello.cc)
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})

其中外层的ADD_SUBDIRECTORY会识别内存的输出文件即动态库,并将其放在执行cmake的文件(build下),执行make之后就可以在bin中看到该动态库libhello.so了。
在这里插入图片描述

3.静态库与动态库的构建

在写这里的时候发生了一个让我震惊的事情,所有博客对于这里的描述都是一模一样的,而我没有理清他的逻辑。
所以我经过查阅文档,大概给出了一个可以自洽的逻辑。

(1)动态库与静态库重名构建失败

ADD_LIBRARY(hello SHARED $(LIBHELLO_SRC))
ADD_LIBRARY(hello STATIC $(LIBHELLO_SRC))

虽然后缀不同,但是cmake认为两者是相同的,会构建失败。

(2)解决办法

使用SET_TARGET_PROPERTIES

#建立不同名的动态库和静态库
ADD_LIBRARY(hello_static STATIC ${LIBHELLO_SRC})
ADD_LIBRARY(hello SHARED ${LIBHELLO_SRC})
#将静态库改名
SET_TARGET_PROPERTIES(hello_static PROPERTIES OUTPUT_NAME "hello")
#这两行我也不知道干啥的,反正要写,好像是清理之前的名字???经过我的测试,不加这两行也可以
SET_TARGET_PROPERTIES(hello_static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
SET_TARGET_PROPERTIES(hello PROPERTIES CLEAN_DIRECT_OUTPUT 1)

最后两行代码的具体工作说实话我也没太搞懂,有无大佬解释一下。。。
在这里插入图片描述
此时可以看到生成了一个动态库和静态库。

(3)动静态库的安装

使用INSTALL指令来进行安装:

#安装头文件和动静态库
INSTALL(FILES hello.h DESTINATION include/hello)
INSTALL(TARGETS hello hello_static LIBRARY DESTINATION lib ARCHIVE DESTINATION lib)

注意这里指定的还是相对路径,他的前缀是usr/local,如果想修改这个前缀,那么可以使用如下指令:

cmake -D CMAKE_INSTALL_PREFIX=/usr
还有一个指令也想介绍一下,那就是生成debug版本的方式
cmake -D CMAKE_BUILD_TYPE=debug

此时就将其修改为了usr路径了。
在这里插入图片描述
使用make install来完成安装。

八、使用动态库与静态库

1.链接头文件

当使用include<>包含头文件的时候会发生报错,CMake有专门的函数来帮助找到这个头文件。

INCLUDE_DIRECTORIES(/usr/local/include/hello) #头文件搜索路径

2.链接动态库

TARGET_LINK_LIBRARY:如果你的库在标准的库搜索路径,直接在这里写上库名就好。如果不是可以使用绝对路径。

TARGET_LINK_LIBRARIES(hello /usr/local/lib/libhello.so)

注意,链接动态库需要写在ADD_EXECULABLE之下。他的第一个参数表示的就是要将库中内容加载进的可执行文件。
在这里插入图片描述
此时执行make可以生成可执行文件hello。

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

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

相关文章

知识引擎藏经阁天花板——高性能Java架构核心原理手册

开场 本书是按照程序设计与架构的顺序编写的&#xff0c;共13章。 第1章介绍学习高性能Java应了解的核心知识&#xff0c;为前置内容。 第2章和第3章讲解在编写代码之前&#xff0c;如何高效地为My SQL填充亿级数据&#xff0c;并对My SQL进行基准测试&#xff0c;以便在之后…

Linux-awk和printf

printf printf ‘输出类型输出格式’ 输内容 输出类型&#xff1a; %ns 输出字符串&#xff0c;n是数字指代输出几个字符 %ni 输出整数&#xff0c;n是数字&#xff0c;指代输出几个数字 %m.nf 输出浮点数&#xff0c;m和n是数字&#xff0c;指代输出总位数和小数位数&#xf…

YOLO V1学习总结

图片大小&#xff1a;448 * 448 —> 7 * 7 *&#xff08;5 * B C&#xff09; 5&#xff1a;每个框的x,y,w,h,confidence; B2&#xff1a;在7*7的feature上&#xff0c;每个cell会生成2个预测框&#xff1b; C&#xff1a;类别数。 损失函数 坐标中心误差和位置宽高的误差…

卷积神经网络基本概念

卷积神经网络基本概念1. 感受野2. 卷积核3. 特征图【feature map】4. 通道【channel】5. 填充【padding】6. 步长【stride】7. 池化【pooling】8. dropout数字1处&#xff1a;一个圈表示一个神经元数字2处&#xff1a;一个圈表示一个神经元&#xff0c;圈的大小表示感受野的大小…

基于matlab的最小支配集CDS仿真

目录 1.算法描述 2.仿真效果预览 3.MATLAB部分代码预览 4.完整MATLAB程序 1.算法描述 支配集的定义如下&#xff1a;给定无向图G &#xff08;V , E&#xff09;,其中V是点集&#xff0c; E是边集&#xff0c; 称V的一个子集S称为支配集当且仅当对于V-S中任何一个点v, 都有…

一、FFmpeg 的初尝试《FFmpeg 音视频开发基础入门到实战》

学习目标 了解 FFmpeg学习 FFmpeg 工具的下载及环境配置了解 FFmpeg 工具的使用方式了解 FFmpeg play 的使用方法了解 FFmpeg paly 的音量设置、窗口设置、音量设置等设置方法 一、了解 FFmpeg FFmpeg 是一个音视频处理的工具&#xff0c;通过 FFmpeg 可以对视频进行旋转、缩…

新零售SaaS架构:多租户系统架构设计

什么是多租户&#xff1f; 多租户是SaaS领域的特有产物&#xff0c;在SaaS服务中&#xff0c;租户是指使用SaaS系统的客户&#xff0c;租户不同于用户&#xff0c;例如&#xff0c;B端SaaS产品&#xff0c;用户可能是某个组织下的员工&#xff0c;但整个企业组织是SaaS系统的租…

得数据者得天下!作为后端开发必备技能之一的MySQL,这份十多年经验总结的应用实战与性能调优我想你肯定是需要的!

MySQL对于很多Linux从业者而言&#xff0c;是一个非常棘手的问题&#xff0c;多数情况都是因为对数据库出现问题的情况和处理思路不清晰。在进行MySQL的优化之前必须要了解的就是MySQL的查询过程&#xff0c;很多的查询优化工作实际上就是遵循一些原则让MySQL的优化器能够按照预…

跑步戴什么耳机比较好、精挑五款最佳跑步耳机推荐

运动蓝牙耳机近几年受到市场的欢迎&#xff0c;种类越来越多&#xff0c;各类功能也日益五花八门&#xff0c;消费者很难准确的进行分辨&#xff0c;一不小心可能买到华而不实的产品。现在了解一下值得入手的运动蓝牙耳机&#xff0c;从多个角度对蓝牙耳机进行评估后&#xff0…

大数据项目之电商数仓、实时数仓同步数据、离线数仓同步数据、用户行为数据同步、日志消费Flume配置实操、日志消费Flume测试、日志消费Flume启停脚本

文章目录8. 实时数仓同步数据9. 离线数仓同步数据9.1 用户行为数据同步9.1.1 数据通道9.1.1.1 用户行为数据通道9.1.2 日志消费Flume配置概述9.1.2.1 日志消费Flume关键配置9.1.3 日志消费Flume配置实操9.1.3.1 创建Flume配置文件9.1.3.2 配置文件内容如下9.1.3.2.1 配置优化9.…

Arcpy新增随机高程点、空间插值及批量制图

&#xff08;1&#xff09;在“地质调查点基础数据表.xls”中图幅范围内增加200个随机位置的高程点。构建一个shape文件&#xff0c;采用自定义工具的模式&#xff0c;参数有两个&#xff1a;一个是让用户选择excel文件&#xff0c;一个让用户指定新生成的文件名。 &#xff08…

五子棋小游戏——Java

文章目录一、内容简介&#xff1a;二、基本流程三、具体步骤1.菜单栏2.创建棋盘并初始化为空格(1)定义行数、列数为常量(2)定义棋盘(3)给棋盘添加坐标并初始化棋盘为空格3.打印棋盘4.玩家落子5.判断输赢四、代码实现五、效果展示一、内容简介&#xff1a; 五子棋小游戏是我们日…

网络工程SSM毕设项目 计算机毕业设计【源码+论文】

文章目录前言 题目1 : 基于SSM的游戏攻略资讯补丁售卖商城 <br /> 题目2 : 基于SSM的疫情期间医院门诊网站 <br /> 题目3 : 基于SSM的在线课堂学习设计与实现<br /> 题目4 : 基于SSM的大学生兼职信息系统 <br /> 题目5 : 基于SSM的大学生社团管理系统 …

2022 云原生编程挑战赛圆满收官,见证冠军战队的诞生

11 月 3 日&#xff0c;天池大赛第三届云原生编程挑战赛在杭州云栖大会圆满收官。三大赛道18大战队手历经 3 个月激烈的角逐&#xff0c;终于交上了满意的答卷&#xff0c;同时也捧回了属于他们的荣耀奖杯。 云原生编程挑战赛发起人王荣刚在开场分享中提到&#xff0c;“在阿里…

【无标题】后来,我认为王阳明比尼采,叔本华都高明

悲欣交集 ——灵遁者 虽然我是个写作者&#xff0c;但我还是希望无苦难可以诉说。可事与愿违&#xff0c;我的笔下总有忧伤&#xff0c;也许我天生忧郁。 我觉得现在比以往任何时候&#xff0c;都更能体验和接触苦难。打开新闻&#xff0c;打开抖音&#xff0c;苦难就扑面而…

SpringBoot 整合 Shiro 权限框架

目录Shiro概述Shiro介绍基本功能Shiro架构SpringBoot整合Shiro环境搭建登录、授权、角色认证实现自定义实现 RealmShiro配置类controller代码权限异常处理多个 realm 的认证策略设置会话管理获得session方式Shiro概述 Shiro介绍 Apache Shiro 是一个功能强大且易于使用的 Jav…

力扣(LeetCode)42. 接雨水(C++)

栈 明确目标——计算接雨水的总量。 可以想到一层一层的接雨水。和算法结合&#xff0c;介绍思想 &#xff1a; 遍历柱子&#xff0c;栈 stkstkstk 维护降序高度的柱子&#xff0c;如果出现升序&#xff0c;说明形成凹槽&#xff0c;计算凹槽能接的雨水&#xff0c;加入答案。…

Java强软弱虚引用和ThreadLocal工作原理(一)

一、概述 本篇文章先引入java的四种引用在android开发中的使用&#xff0c;然后结合弱引用来理解ThreadLocal的工作原理。 二、JVM名词介绍 在提出四种引用之前&#xff0c;我们先提前说一下 Java运行时数据区域 虚拟机栈 堆 垃圾回收机制 这四个概念。 2.1 java运行时数据…

freeswitch通过limit限制cps

概述 freeswitch在业务开发中有极大的便利性&#xff0c;因为fs内部实现了很多小功能&#xff0c;这些小功能组合在一起&#xff0c;通过拨号计划就可以实现很多常见的业务功能。 在voip云平台的开发中&#xff0c;我们经常会碰到资源的限制&#xff0c;有外部线路资源方面的…

Linux环境下安装并使用使用Git命令实现文件上传

⭐️前面的话⭐️ 本篇文章将介绍在Linux环境下安装Git并使用Git实现代码上传到gitee&#xff0c;上传操作的核心就是三把斧&#xff0c;一是add&#xff0c;二是commit&#xff0c;三是push&#xff0c;此外还会简单介绍一下.gitignore配置文件的作用。 &#x1f4d2;博客主页…