CMake入门

news2024/11/20 15:18:07

1. CMake的介绍:

当多人开发同一个项目时,最终要输出一个可执行文件或者共享库(dll、so等),就可以使用cmake了
所有操作都是通过 CMakeLists.txt(严格区分大小写) 来完成的 ----> 简单

2. CMake的helloworld编译:

步骤一,写一个helloworld:

#include <iostream>

int main() {
	std::cout << "hello world" << std::endl;
	return 0;
}

步骤二,写CMakeLists.txt

PROJECT (HELLO)
  
SET(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})

步骤三,使用cmake,生成makefile文件

cmake .

输出:

cmake .
-- The C compiler identification is AppleClang 12.0.0.12000032
-- The CXX compiler identification is AppleClang 12.0.0.12000032
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /Library/Developer/CommandLineTools/usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /Library/Developer/CommandLineTools/usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- This is BINARY dir /Users/xuesong/SONGSONG
-- This is SOURCE dir /Users/xuesong/SONGSONG
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/xuesong/SONGSONG

步骤四,使用make命令编译:

make

输出:
[ 50%] Building CXX object CMakeFiles/hello.dir/main.cpp.o
[100%] Linking CXX executable hello
[100%] Built target hello

步骤五,最终生成了hello的可执行程序

3. CMakeLists语法介绍:

PROJECT 关键字:

可以用来指定工程的名字和支持的语言,默认支持所有语言;
PROJECT (HELLO) 指定了工程的名字,并且支持所有语言(建议)
PROJECT (HELLO CXX) 指定了工程的名字,并且支持语言是C++
PROCECT (HELLO C CXX) 指定了工程的名字,并且支持语言是C和C++

该指令隐式定义了两个CMAKE的变量:
<projectname>_BINARY_DIR 本例中是 HELLO_BINARY_DIR
<projectname>_SOURCE_DIR 本例中是 HELLO_SOURCE_DIR

MESSAGE关键字就可以直接使用这两个变量,当前都指向当前的工作目录,后面会涉及到外部编译。

此时有一个问题,如果改了工程名,这两个变量名也会改变,所以又定义了两个预定义变量:PROJECT_BINARY_DIRPROJECT_SOURCE_DIR,这两个变量和 HELLO_BINARY_DIR、HELLO_SOURCE_DIR是一致的。

SET关键字:

用来显式的指定变量,例如

SET(SRC_LIST main.cpp)

即使用来指定源文件列表

MESSAGE关键字:

MESSAGE关键字类似于C语言中的printf函数,用于将变量的值显示到终端,这样就可以查看cmake构建工程时CMakeLists.txt中某些变量的值是否正确。但是,MESSAGE要比printf函数的功能强大,它可以 终止 编译系统的构建,而且这通常是我们想要的效果。

语法格式:

MESSAGE([<mode>] "message text" ...)

mode的值包括 FATAL_ERRORWARNINGAUTHOR_WARNINGSTATUSVERBOSE

FATAL_ERROR:产生CMake Error,会停止编译系统的构建过程;
STATUS:最常用的命令,常用于查看变量值,类似于编程语言中的DEBUG级别信息。

“message text”为显示在终端的内容。

ADD_EXECUTABLE关键字:

生成可执行文件,例如:

ADD_EXECUTABLE(hello ${SRC_LIST})

生成的可执行文件名是“hello”,源文件读取变量SRC_LIST中的内容。

语法的基本规则:

  1. 使用 ${} 获取某个变量的值,例如 ${SRC_LIST}获取SRC_LIST变量的值;
  2. 指令中的参数使用()小括号括起来,参数之间使用空格或分号分隔开;
  3. 指令是大小写无关的,参数和变量 是大小写相关的,CMake中推荐指令全部大写。

4. CMake内部构建和外部构建:

内部构建就是在项目内部,有CMakeLists.txt的地方,直接 cmake .,比如上面的方式就是内部构建,它的缺点是会在项目目录下生成许多临时文件。

外部构建就是不直接在项目下面运行cmake,而是自己建立一个接收cmake之后产生的临时文件的文件夹(如 build/),然后在该文件下面调用 cmake <CMakeList_path> 来构建。

例如:

mkdir build

cd build

cmake ..

5. 让HelloWorld更像一个工程:

  • 为工程添加一个子目录src,用来放置工程源代码
  • 添加一个子目录doc,用来放置这个工程的文档hello.txt
  • 在工程目录添加文本文件COPYRIGHT,README
  • 在工程目录添加一个 runhello.sh 脚本,用来调用hello二进制
  • 将构建后的目标文件放入构建目录的bin子目录
  • 将doc目录的内容以及COPYRIGHT/README安装到/usr/share/doc/cmake

在这里插入图片描述

然后在 build/ 目录下执行 cmake ..

ADD_SUBDIRECTORY命令:

命令格式:

ADD_SUBDIRECTORY([source_dir] [binary_dir] [EXCLUDE_FROM_ALL])

[source_dir]: 源文件路径;
[binary_dir]: 中间二进制与目标二进制存放路径;
[EXCLUDE_FROM_ALL]:将这个目录从编译过程中排除。

在项目中CMake配置文件一般为 树形结构,项目总的CMake配置文件调用各模块的CMake配置文件;

6. 使用CMake来进行安装:

make:编译程序、库、文档等
make install:安装已经编译好的程序、复制文件树中的文件到指定的位置
make unistall:卸载已经安装的程序
make clean:删除由make命令产生的文件
make distclean:删除由./configure产生的文件
make check:测试刚刚编译的软件(某些程序可能不支持)
make installcheck:检查安装的库和程序(某些程序可能不支持)

cmake INSTALL 命令:INSTALL用于指定在安装时运行的规则,
通俗的说,就是在运行cmake生成makefile之后,make intall 时都需要安装哪些内容。
它可以用来安装很多内容,可以包括 目标二进制、动态库、静态库、文件、目录、脚本等。

INSTALL(TARGETS <target> ... [...])					// TARGETS: 库(.a, .so)
INSTALL({FILES | PROGRAMS} <file> ... [...]) 		// FILES: 文件 PROGRAMS: 二进制(可执行)文件
INSTALL(DIRECTORY <dir> ... [...]) 					// DIRECTORY: 目录
INSTALL(SCRIPT <file> [...]) 						// SCRIPT: 脚本
INSTALL(CODE <code> [...]) 							//
INSTALL(EXPORT <export-name> [...]) 				//

举例:

在 项目的顶层目录下先手动创建COPYRIGHT、README、runhello.sh文件
在这里插入图片描述
顶层的CMakeLists.txt中加入INSTALL命令:
在这里插入图片描述
然后在 build/ 目录下 cmake .., make, make install
在这里插入图片描述
在share目录下就拷贝了上述几个文件:
在这里插入图片描述

7. CMake构建动态库和静态库:

顶层目录:
在这里插入图片描述
顶层CMakeLists.txt的内容:
在这里插入图片描述
lib/ 目录下的内容:
在这里插入图片描述
lib目录下的CMakeLists.txt的内容:
在这里插入图片描述
STATIC 表示生成静态库,SHARED 表示生成动态库,生成的库文件格式是 libXXX.alibXXX.so

在 build/ 目录下执行 cmake ..make,就可以在 build/lib/ 目录下查看到生成的库文件:
在这里插入图片描述

ADD_LIBRARY 命令:

命令格式:

ADD_LIBRARY(<name> [ STATIC | SHARED | MODULE ]
							[EXCLUDE_FROM_ALL]
							[source1] [source2][...])

添加名为 name 的库,库的文件件可指定,也可用 target_sources() 后续指定。
库的类型是 STATIC(静态库)/SHARED(动态库)/MODULE(模块库) 之一。

如何同时构建动态库和静态库:

其他的不需要改动,lib/ 目录下的CMakeLists.txt 文件:
在这里插入图片描述
将动态库和静态库文件编译的名字都设置为“hello”即可。
编译后 在 build/lib/ 目录下就同时生成了 libhello.a 和 libhello.so:
在这里插入图片描述

SET_TARGET_PROPERTIES 命令:

命令格式:

SET_TARGET_PROPERTIES(target1 target2 ...
												  PROPERTIES prop1 value1
												  prop2 value2 ...)

这个命令是设置目标的属性,设置之后可以使用 GET_PROPERTY()或者GET_TARGET_PROPERTY()命令获取目标的属性值。

SET_TARGET_PROPERTIES 命令除了可以实现同时生成动态库和静态库,还可以用来 设置动态库的版本号:

SET_TARGET_PROPERTIES(hello PROPERTIES VERSION 1.2 SOVERSION 1)

VERSION指代动态库版本,SOVERSION指代API版本。

8. 共享库与头文件的安装和使用:

使用CMake安装库文件:

在 lib/ 目录下的CMakeLists.txt中 加入INSTALL命令:
在这里插入图片描述

执行 cmake .., make, make install,安装头文件和共享库:

在这里插入图片描述

INSTALL命令在安装库文件时:

INSTALL(TARGETS MyLib
				EXPORT MyLibTargets
				LIBRARY DESTINATION lib 	# 动态库安装路径
				ARCHIVE DESTINATION lib		# 静态库安装路径
				RUNTINE DESTINATION bin		# 可执行文件安装路径
				PUBLIC_HEADER DESTINATION include	# 头文件安装路径
				)

PS:为什么Linux安装程序都要放到 “/usr/local” 目录下:

Linux的软件安装目录也是有讲究的,理解这一点,在对系统管理是有益的。

/usr: 系统级的目录,可以理解为C:/Windows/,/usr/lib 可以理解为 C:/Windows/System32;

/usr/local: 用户级的程序目录,可以理解为 C:/Program Files/,用户自己编译的软件默认会安装到这个目录下

/opt:用户级的程序目录,可以理解为 D:/Software,opt有可选的意思,这里可以用于放置第三方大型软件(或游戏等),当你不需要时,直接 rm -rf 删除即可。在硬盘容量不够时,也可将 /opt 单独挂载到其他磁盘上使用。

源码放哪里:
/usr/src:系统级的源码目录
/usr/local/src: 用户级的源码目录

在这里插入图片描述

使用CMake链接库文件:

在另外的目录下编写一个main.cpp,其中包含上面的hello.h头文件:

// main.cpp
#include <hello.h>
int main() {
	func();
	return 0;
}

此时运行make编译时会报错,找不到hello.h头文件,这是因为上面安装hello.h时指定的安装目录是 “include/hello”:
在这里插入图片描述

直接的解决方法有两种:

  1. hello.h 在cmake install安装时直接安装到 /usr/local/include 目录下,取消 hello/这一级目录;
  2. main.cpp 源文件中使用 #include <hello/hello.h> 的方式指名包含的路径。

然而,在项目中,更普遍的做法是使用 cmake中的 INCLUDE_DIRECTORIES 命令解决这个问题:

在这里插入图片描述

INCLUDE_DIRECTORIES 命令:

命令格式:

INCLUDE_DIRECTORIES([AFTER | BEFORE] [SYSTEM] dir1 [dir2 ...])

将指定目录添加到编译器的头文件搜索路径之下,指定的目录被解释成当前源码路径的相对路径。

PS:#include <> 与 #include “” 的区别:

  1. 使用场景不同:
    #include <> 一般用于包含系统头文件,例如 stdlib.h,stdio.h 等;
    #include "" 一般用于包含自定义的头文件,例如 test.h,declare.h 等;

  2. 查找的目录不同:
    #include <> 编译器直接从系统类库目录里查找头文件,例如 在Linux gcc编译环境下,一般为 /usr/include/usr/local/include 目录;如果类库目录下查找失败,编译器会终止查找,直接报错:No such file or directory
    #include "" 默认从项目当前目录查找头文件,即项目工程文件所在的目录。如果在项目当前目录下查找失败,再从项目配置的头文件引用目录查找头文件。

在加入 INCLUDE_DIRECTORIES 命令之后,就可以解决 hello.h头文件找不到的问题了:

在这里插入图片描述
这是因为没有链接 hello.so 库,所以找不到func()函数的定义。
解决方法有两种:

  1. LINK_DIRECTORIES 命令,添加非标准共享库的搜索路径(某个路径);
  2. TARGET_LINK_LIBRARIES 命令,添加需要链接的共享库(没某个具体的库)(注意此关键字在CMakeListst.txt中必须位于 ADD_EXECUTABLE 之后)。

在这里插入图片描述
命令格式:

TARGET_LINK_LIBRARIES(<target>
											<PRIVATE | PUBLIC | INTERFACE> <item> ...
											[<PRIAVTE | PUBLIC | INTERFACE> <item> ...] ...)

对于静态库也是相同的方式:

TARGET_LINK_LIBRARIES(main libhello.a)

此时解决了make时找不到func()函数定义的问题,并可以成功生成main可执行文件。
但是在执行 ./main 时,又报错找不到 libhello.so 动态库:

在这里插入图片描述
使用 ldd 查看main的依赖中抓不到libhello.so的路径:
在这里插入图片描述

这是因为,默认情况下,编译器只会使用 /lib/usr/lib 这两个目录下的库文件,如果不指定 --prefix,会将库安装在 /usr/local/lib 目录下;当运行程序需要链接动态库时,提示找不到相关的.so库,就会报错。

解决方法有两个:

  1. 手动将 /usr/local/lib 目录下的 libhello.so 拷贝到 /usr/lib 目录下;
  2. 在CMakeListsts.txt 中加入prefix,指定so库的安装路径。

CMAKE_INSTALL_PREFIX 命令:

CMAKE_INSTALL_PREFIX 是cmake内置变量,用于指定cmake执行install目标时,安装的路径前缀。

方法一: 在执行cmake时指定:

cmake -D CMAKE_INSTALL_PREFIX=<目标路径>

方法二: 在 CMakeLists.txt 中设置变量:

SET(CMAKE_INSTALL_PREFIX <install_path>)

在编译.so库文件时指定install安装路径:

在这里插入图片描述
make install 时可以看到成功安装到了 /usr/lib 路径下:
在这里插入图片描述

重新回到main工程下,执行./main,可以正常执行了:

在这里插入图片描述

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

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

相关文章

C51——超声波测距 函数封装和舵机代码结合

要注意舵机转动中 延时函数要放在哪里 #include "reg52.h" sbit D5 P3^7;// sbit D6 P3^6;// sbit Trig P1^5; sbit Echo P1^6; sbit sg90_con P1^1; int cnt; int jd; double time; void Delay10us() //11.0592MHz { unsigned ch…

操作系统管程-地址-重定位-内存管理与存储管理

管程的基本概念&#xff1a;为什么会出现管程&#xff1f;信号量机制的不足&#xff1a;程序编写困难、易出错解决&#xff1a;Brinch Hansen(1973)Boare(1974)方案&#xff1a;在程序设计语言中引入管程成分一种高级同步机制管程的定义&#xff1a;是一个特殊的模块有一个名字…

使用MAXScript脚本编写圣诞树建模插件教程

一、前言 2022年圣诞节到来啦&#xff0c;很高兴这次我们又能一起度过~ 今年的圣诞节为大家分享用MAXScript脚本编写圣诞树建模插件的技术创意&#xff0c;喜欢的同学别忘记在下面点个赞&#xff01; 二、创意名 一键圣诞树插件 三、效果展示 四、实现步骤 1.制作圣诞树的设计稿…

智能巡检系统:企业安全生产管理的智能助手

智能巡检是一种高效代替传统人工巡检的新方式&#xff0c;其依靠物联感知技术&#xff0c;通过物联网采集获取信息&#xff0c;自动记录巡检信息&#xff0c;及时发现问题&#xff0c;实现巡检科学化。 工业4.0带来的技术革新加速了企业的转型升级进程&#xff0c;传统企业的运…

F5张振伦:让应用安全、快速、可靠地交付到需要的地方丨2022首届全球数字生态大会

科技云报道原创。 日前&#xff0c;由杭州市人民政府和浙江省商务厅主办的“2022首届全球数字生态大会”在杭州国际博览中心成功举办。 本次大会以“新技术、新业态、新模式”为主题&#xff0c;邀请到国内外20余位演讲嘉宾和超300位专业观众线下参会。 与此同时&#xff0c;…

IB成绩换成GPA,美国大学是如何算的?

IB课程体系是全球公认的难度大、结构强的课程体系。 IB课程可以通过IB文凭课程&#xff08;也称为IBDP&#xff09;进行系统研究。IB课程体系是国际公认的基础文凭&#xff0c;世界上几乎所有大学都认可IB课程体系。这是否意味着IB在申请美国大学时会有优势&#xff1f; 事实上…

【vue系列-02】vue的核心属性,数据代理,事件

vue的核心属性一&#xff0c;vue的核心属性1&#xff0c;模板语法1.1&#xff0c;插值语法1.2&#xff0c;指令语法2&#xff0c;数据绑定2.1&#xff0c;单向绑定2.2&#xff0c;双向绑定3.mvvm模型4&#xff0c;数据代理4.1&#xff0c;数据代理的基本使用4.2&#xff0c;数据…

pytorch实现好莱坞明星识别

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f366; 参考文章地址&#xff1a; 365天深度学习训练营-第P6周&#xff1a;好莱坞明星识别&#x1f356; 作者&#xff1a;K同学啊一、前期准备 1.设置GPU import torch from torch import nn …

获取rdp保存的凭证

获取用户保存的rdp凭证 当获取到一台windows服务器&#xff0c;可以尝试获取本地远程连接的信息&#xff0c;如果用户在登入rdp时勾选了 允许为我保存凭证的选项&#xff0c;则在该用户本地会生成一个凭证文件&#xff0c;我们只需要破解该凭证文件即可获取其明文密码。 通过注…

[含文档+PPT+源码等]基于SSM框架图书借阅管理系统开发与设计

博主介绍&#xff1a;✌在职Java研发工程师、专注于程序设计、源码分享、技术交流、专注于Java技术领域和毕业设计✌ 项目名称 [含文档PPT源码等]基于SSM框架图书借阅管理系统开发与设计 系统介绍 《基于SSM框架图书管理系统开发与设计》 该项目含有源码、配套开发软件、软件安…

元数据相关的术语,你知道几个?

元数据被认为是数据治理的基石&#xff0c;但关于元数据相关的概念&#xff0c;很多人不是那么清楚&#xff0c;今天就和大家详解元数据相关的术语。当然&#xff0c;与元数据相关的概念非常多&#xff0c;以下仅罗列几个常见的。 01 元数据 1.名词解释 元数据最简单的定义…

【关于时间序列的ML】项目 7 :使用机器学习进行每日出生预测

&#x1f50e;大家好&#xff0c;我是Sonhhxg_柒&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流&#x1f50e; &#x1f4dd;个人主页&#xff0d;Sonhhxg_柒的博客_CSDN博客 &#x1f4c3; &#x1f381;欢迎各位→点赞…

u盘无法识别如何修复?恢复U盘,建议尝试下这些方法

我们基本都有使用过U盘&#xff0c;也都遇到过U盘损坏的问题。u盘无法识别如何修复&#xff1f;有没有什么实用的方法呢&#xff1f;来看看这篇文章&#xff0c;简单几步&#xff0c;就可以修复成功。如果在操作过程中&#xff0c;遇到数据丢失&#xff0c;也有方法帮你恢复&am…

ASP.NET开发的医疗健康咨询平台源码 养生知识咨询 寻根问药平台源码 C#源码

一、源码特点&#xff1a; 爱心医生健康知识门户网站是一个权威的医疗科普视频、语音、知识、医疗健康问答平台。 包含所有源代码和数据库&#xff0c;可以直接部署到IIS中使用。 二、菜单功能 网站页面&#xff1a; 1、首页&#xff1a;包含幻灯片。 2…

MySQL面试常问问题(SQL 优化 ) —— 赶快收藏

目录 1.慢SQL如何定位呢&#xff1f; 2.有哪些方式优化慢SQL&#xff1f; 避免不必要的列 分页优化 索引优化 JOIN优化 排序优化 UNION优化 3.怎么看执行计划&#xff08;explain&#xff09;&#xff0c;如何理解其中各个字段的含义&#xff1f; 1.慢SQL如何定位呢&a…

基于python开发的DIY宠物桌面系统(附源码)--可自定义修改

定制你的宠物桌面 最近想要做一个自己独一无二的桌面宠物&#xff0c;可以直接使用python来自己订制。属于一个小项目&#xff0c;这个教程主要包含几个步骤&#xff1a; 准备需要的动图素材 规划自己需要的功能 使用python的PyQt5订制功能 在这个教程中&#xff0c;我主要…

Apache Flink 任务 Tasks 和任务槽 Task Slots

目录 任务槽&#xff08;Task Slots&#xff09; 任务槽数量的设置 任务对任务槽的共享 任务槽和并行度的关系 任务槽&#xff08;Task Slots&#xff09; Flink 中每一个 worker(也就是 TaskManager)都是一个 JVM 进程&#xff0c;它可以启动多个独立的线程&#xff0c;来并…

【数据结构】详解队列和循环队列

目录一.队列1.队列的概念及结构2.队列的实现Queue.hQueue.c二.循环队列1.循环队列的实现2.设计循环队列解题思路代码一.队列 1.队列的概念及结构 队列&#xff1a;只允许在一端进行插入数据操作&#xff0c;在另一端进行删除数据操作的特殊线性表&#xff0c;队列具有先进先出…

四、网络层(六)移动IP

目录 6.1 移动IP的概念 6.2 移动IP的基本工作原理 6.2.1代理发现与注册 6.2.2固定主机向移动主机发送IP数据报 6.2.3移动主机向固定主机发送IP数据报 6.2.4同址转交地址&#xff08;简单了解&#xff09; 6.2.5三角形路由问题&#xff08;简单了解&#xff09; 6.1 移…

事关你“吃住行游购娱”的12项安全国标图解来了

标准是安全建设的“尺子”。近期&#xff0c;国家市场监督管理总局、国家标准化管理委员会发布中华人民共和国国家标准公告&#xff08;2022年第13号&#xff09;&#xff0c;全国信息安全标准化技术委员会归口的14项网络安全国家标准获批发布&#xff0c;其中12项涉及数据安全…