Cmake(4)——库的创建和链接

库的创建和链接

插播!插播!插播!亲爱的朋友们,我们的Cmake/Makefile/Shell这三个课程上线啦!感兴趣的小伙伴可以去下面的链接学习哦~

构建工具大师-CSDN程序员研修院

在众多成熟的项目中,有时会遇到这样的情况:某个模块是整个项目核心技术的核心,我们希望将其保密,不对外泄露。为了解决这个问题,我们可以将这个模块创建为静态库或动态库。这样,库文件就能将模块的实现细节隐藏起来,只暴露必要的接口。这样一来,其他程序只需调用库中的接口,无需了解具体的实现细节,从而提高了代码的安全性和可维护性。

此外,如果一个模块被多个程序所使用,我们可以将其编译成库文件,实现代码的复用。多个程序可以共享同一个库文件,避免了重复编写和维护相同的代码。这大大降低了开发成本,提高了开发效率。

库(Library)是一组可重用的代码,提供一些函数和数据结构,以便其他程序在其基础上开发功能。库分为静态库和动态库两种类型。下面我们将详细介绍这两种库的区别。

在编译程序时,需要将库文件链接到程序中,以便程序可以使用库中的函数和变量。静态库(Static  Library)是在编译时与应用程序代码一起链接生成的。当程序需要使用静态库中的函数或变量时,链接器会将静态库的代码复制到最终的可执行文件中,因此在运行时不需要额外的库文件。

与静态库相比,动态库(Dynamic  Library)在运行时才被加载。它和应用程序代码是分开编译和链接的。当需要使用动态库中的函数或变量时,操作系统会将动态库文件加载到内存中,并在需要的时候将其中的代码映射到应用程序的地址空间中,从而扩充应用程序的功能。

1、库的创建

在CMake中,我们能够利用add_library指令来创建静态库或动态库。创建静态库的命令格式如下:

add_library(name  STATIC  库源文件列表)

在上述命令中,第一个参数是库的名称,第二个参数STATIC表示创建静态库,SHARED表示创建动态库。第三个参数是库的源文件列表。一旦库文件被创建,我们就可以在程序中使用库中的函数和变量了。

比如说,如果我们想把显示模块编译成静态库,可以遵循以下步骤:首先将main函数移除src目录,因为我们在制作静态库时并不需要这个文件。为了在add_library命令中简洁地指定库的源文件列表,我们可以定义一个变量SRC_PATH,其值为源文件路径。

set(SRC_PATH  ${PROJECT_SOURCE_DIR}/src)

接下来,我们对这个目录下的lcd.cpp文件进行相应的操作。为了给静态库命名,在Linux中,静态库文件的后缀为“.a”,并且静态库名字分为三部分:lib+库名字+.a。我们只需指定出库的名字即可,其余两部分在生成该文件时会自动填充。这里我们取名为lcd。

add_library(lcd STATIC ${SRC_PATH}/lcd.cpp)

完成静态库的制作命令后,我们需要注释掉生成执行文件的命令,因为我们这里并不需要生成可执行文件。如果不注释掉这个命令,可能会引发编译错误。这一点我们将在后面详细解释。

然后我们还是重新编译测试看看,是否这样做真的可以做到生成我们所需要的静态库

我们已经成功地构建了静态库。如果我们需要的是动态库,在Linux系统中,其文件后缀为“.so”。创建动态库同样需要使用add_library命令,但第二个参数应改为SHARED,以表示创建的是动态库(也称为共享库)。

如果我们想把键盘模块构建为动态库,我们可以将其命名为key作为第一个参数,将第二个参数改为SHARED,并指定键盘模块的源文件路径作为第三个参数。以下是如何做到这一点的命令:

add_library(key SHARED ${SRC_PATH}/key.cpp)

修改CMakeLists.txt文件添加制作动态库语句后,我们再重新编译整个项目。

那么现在这两个库也已经全部生成了。

2、库存放路径的修改

在构建一个项目时,库文件的组织和管理是非常重要的。为了提高可维护性和清晰度,通常建议将库文件放在一个独立的目录中。这个目录可以命名为“lib”或者使用其他名称,关键是保持一致性。通过将库文件放在单独的目录中,可以更好地组织项目结构,并使得其他开发者更容易找到和使用这些库文件。

可以看到我们在build目录中编译,那库文件自然就默认生成在这个目录下,那我们该如何让这个库文件直接自动生成到我们创建的lib目录下呢?

在CMake中,可以使用LIBRARY_OUTPUT_PATH变量来指定编译生成的库文件应该保存的路径。通过设置这个变量,可以控制库文件的输出位置。在CMakeLists.txt文件中,可以按照以下方式进行设置:

set(LIBRARY_OUTPUT_PATH <path>)

其中,<path>是要设置的输出路径。需要注意的是,这个语句必须在add_library语句之前调用,以确保对所有库的输出路径进行正确设置。

在我们这里可以这样设置:

set(LIBRARY_OUTPUT_PATH  ${PROJECT_SOURCE_DIR}/lib)

修改完后,我们继续重新构建并编译整个项目,这时发现我们生成的库文件已经保存到我们指定的目录lib底下了。

3、库的链接

在库文件生成之后,我们需要将其与程序进行链接,这样才能使程序调用库中的函数和利用库中的变量。在cmake环境中,无论是链接静态库还是动态库,都可以采用target_link_libraries命令来实现。该命令的语法格式如下:

target_link_libraries(<target> [PRIVATE|PUBLIC|INTERFACE] <library> )

在这里,<target>代表需要链接的目标项目或库的名称,而<library>则是需要链接的库的名称。通过向该命令添加多个库文件,我们可以将它们合并到目标项目中。此外,我们还可以使用私有(PRIVATE)、公共(PUBLIC)或接口(INTERFACE)关键字来定义链接库的属性。

-私有(PRIVATE):这意味着链接库仅对目标项目本身可用。在这种情况下,其他目标项目无法使用该库。

-公共(PUBLIC):表示链接库对目标项目及其所使用的其他项目均可用。这意味着其他项目可以调用该库。

-接口(INTERFACE):这意味着链接库仅对需要使用该目标及其所使用的其他项目可用。这表明其他项目可以调用该库,但该库不会直接用于目标项目本身。

这种分类有助于管理库的依赖关系,确保项目在编译和运行时能够正确地访问所需的库函数和变量。在实际开发过程中,根据项目需求和库的特性选择合适的链接方式,可以提高代码的可维护性和可扩展性。

在本项目当中,我们如何运用  `target_link_libraries`命令来实现静态库与动态库的链接呢?在构建库文件的过程中,为了确保库文件的顺利生成,我曾注释掉了  `add_executable`这条命令,该命令用于创建可执行文件。这是因为我在  `main`函数中调用了库文件的函数,若没有链接库文件的语句,将导致编译无法通过。现在,我们将注释取消,添加可执行文件所依赖的源文件,暂不链接库文件,重新构建并编译以观察效果。

可见确实是我们预想的那样,那么接下来我们开始链接库文件,通过target_link_libraries命令链接lcd ,key两个库文件到可执行文件。

target_link_libraries(${CMAKE_PROJECT_NAME}  PRIVATE  lcd  key)

在此需要注意的是,通常情况下,我们会将链接库文件的命令置于创建可执行文件的命令之后。这是因为当链接动态库时,动态库在生成可执行程序的链接阶段并不会被集成到可执行程序中。只有当可执行程序启动并调用动态库中的函数时,动态库才会被加载到内存。因此,在CMake中指定要链接的动态库时,应将相关命令置于生成可执行文件之后。

若链接库的语句出现在可执行文件的创建语句之前,将会导致编译无法通过。因此,我们通常会将`add_executable`命令放在`target_link_libraries`命令之前,以确保可执行文件能够正确链接库文件并运行。

可以看一下,如果放在add_executable是个什么结果:

因此我们需要这样写CMakeLists.txt:

修改完后,再重新构建并编译整个项目,可见已经可以编译成可执行文件了。

但在构建链接库文件时,我们需关注一个重要细节:若所链接的静态库或动态库并非系统自带,而是自行制作或采用第三方提供的库,在可执行程序启动过程中,可能出现库找不到的情况,即无法确定库所在位置。因此,我们需要指定库的路径。在  CMake  中,可在生成可执行程序前,利用命令  `link_directories`指明要链接的静态库位置,同样可用于指定动态库位置。该命令语法如下:

link_directories(<lib path>)

接下来,我们需在  CMakeLists.txt文件中添加相应内容,以指定库的路径。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Spring源码分析】从源码角度去熟悉依赖注入(二)

从源码角度去熟悉依赖注入&#xff08;二&#xff09; 一、AutowiredFieldElement 注入分析二、AutowiredMethodElement注入分析三、doResolveDependency 源码分析1. Value 注解解析测试 ${} 和 #{} 2. resolveMultipleBeans 筛选特殊类型&#xff08;处理多Bean&#xff09;测…

关于网络协议的笔记

简介&#xff1a; 协议&#xff0c; 网络协议的简称&#xff0c;网络协议是通信计算机双方必须共同遵从的一组约定。如怎么样建立连 接、怎么样互相识别等。只有遵守这个约定&#xff0c;计算机之间才能相互通信交流。它的 三要素是&#xff1a;语 法、语义、时序。 为了使数…

水经微图系列产品新功能盘点!

水经微图&#xff0c;简称“微图”。 我们曾在直播中分享过微图APP苹果版的功能&#xff0c;本周四晚19:30我们将在另一个视频号分享盘点微图APP安卓版的详细功能&#xff0c;以及Web版近期上线的新功能功能。 微图APP安卓版 我们在《水经微图安卓版APP正式上线》一文中&…

configure: error: openSSL library not found.解决方案

大家好,我是爱编程的喵喵。双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中。从事机器学习以及相关的前后端开发工作。曾在阿里云、科大讯飞、CCF等比赛获得多次Top名次。现为CSDN博客专家、人工智能领域优质创作者。喜欢通过博客创作的方式对所学的…

初识node.js(使用)

文章目录 项目目录介绍和运行流程1.index.html&#x1f447;2.整个项目的核心入口文件其实是main.js3.App.vue 组件化开发 和 根组件普通组件的注册1.局部注册2.全局注册 综合案例 项目目录介绍和运行流程 1.index.html&#x1f447; <!DOCTYPE html> <html lang&quo…

Offer必备算法_滑动窗口_八道力扣OJ题详解(由浅到深)

目录 滑动窗口算法介绍 ①力扣209. 长度最小的子数组 解析及代码 ②力扣3. 无重复字符的最长子串 解析及代码 ③力扣1004. 最大连续1的个数 III 解析及代码 ④力扣1658. 将x减到0的最小操作数 解析及代码 ⑤力扣904. 水果成篮 解析及代码1&#xff08;使用容器&…

初识SQL注入

目录 注入攻击 SQL注入 手工注入 Information_schema数据库 自动注入 介绍一下这款工具&#xff1a;sqlmap 半自动注入 前面给大家通过学习练习的方式将XSS攻击的几种形式和一些简单的靶场和例题的演示&#xff0c;从本篇开始我将和小伙伴们通过边复习、边练习的方式来进…

2024年购买阿里云服务器多少钱?1000元左右预算可购买的8款云服务器参考

1000元左右预算可以买到哪些配置的阿里云服务器&#xff1f;目前阿里云活动中价格在1000元左右的云服务器有8款&#xff0c;其中经济型e实例云服务器三款&#xff0c;通用算力型u1实例云服务器五款&#xff0c;碰到阿里云有优惠券或者代金券活动时&#xff0c;购买过程中还能使…

Angular组件(一) 分割面板ShrinkSplitter

Angular组件(一) 分割面板ShrinkSplitter 前言 分割面板在日常开发中经常使用&#xff0c;可将一片区域&#xff0c;分割为可以拖拽整宽度或高度的两部分区域。模仿iview的分割面板组件&#xff0c;用angular实现该功能&#xff0c;支持拖拽和[(ngModel)]双向绑定的方式控制区…

Dock的安装部署和基础命令

1 Docker基础 1.1 Docker概述 Docker是一个开源的应用容器引擎&#xff0c;用来运行容器里的运用&#xff0c;可以用来管理容器和镜像的一种工具&#xff0c;基于go语言开发并遵循了apache2.0协议开源。 Docker是在Linux容器里运行应用的开源工具&#xff0c;是一种轻量级的…

Java(TM) Platform SE binary (Process Id: 4412)

Java™ Platform SE binary (Process Id: 4412&#xff09;JAVA8安装过程中出现上述问题win10解决方法 打开任务管理器 在任务管理器中找到详细信息&#xff0c;然后根据上边的进程id找到对应的程序&#xff0c;右键结束任务即可。 在安装jdk17时候&#xff0c;同时出现了上…

05 双向链表

目录 1.双向链表 2.实现 3.OJ题 4.链表和顺序表对比 1. 双向链表 前面写了单向链表&#xff0c;复习一下 无头单向非循环链表&#xff1a;结构简单&#xff0c;一般不会单独用来存数据。实际中更多作为其他数据结构的子结构&#xff0c;如哈希桶、图的邻接等。另外这种结构在…

Pycharm中出现Comparison with None performed with equality operators

此图中警告翻译过来是 &#xff1a;与使用相等运算符执行的None进行比较 这里不应该使用 或者 &#xff01; 而应改为 is 或者 is not

聚观早报 | 华为P70 Art细节曝光;红魔9 Pro龙年限定版官宣

聚观早报每日整理最值得关注的行业重点事件&#xff0c;帮助大家及时了解最新行业动态&#xff0c;每日读报&#xff0c;就读聚观365资讯简报。 整理丨Cutie 1月24日消息 华为P70 Art细节曝光 红魔9 Pro龙年限定版官宣 努比亚Z60 Ultra龙年限定版 小米14 Ultra或没有双版…

创新医疗服务:宠物在线问诊系统的搭建与应用

随着科技的不断进步&#xff0c;创新的医疗服务方式也日渐成为宠物主人关心爱宠健康的首选。本文将深入介绍如何搭建一套创新的宠物在线问诊系统&#xff0c;并展示其应用的技术代码。 1. 系统架构与技术选择 在开始搭建之前&#xff0c;我们需要设计系统的架构并选择合适的…

【Linux工具篇】编辑器vim

目录 vim的基本操作 进入vim(正常模式&#xff09; 正常模式->插入模式 插入模式->正常模式 正常模式->底行模式 底行模式->正常模式 底行模式->退出vim vim正常模式命令集 vim插入模式命令集 vim末行模式命令集 vim操作总结 vim配置 Linux编译器…

网络安全的使命:守护数字世界的稳定和信任

在数字化时代&#xff0c;网络安全的角色不仅仅是技术系统的守护者&#xff0c;更是数字社会的信任保卫者。网络安全的使命是保护、维护和巩固数字世界的稳定性、可靠性以及人们对互联网的信任。本文将深入探讨网络安全是如何履行这一使命的。 第一部分&#xff1a;信息资产的…

使用Sobel算子把视频转换为只剩边缘部分

效果展示 原始视频 修改后的视频 整体代码 import cv2vc cv2.VideoCapture(test.mp4)if vc.isOpened():open, frame vc.read() else:open Falsei 0 while open:ret, frame vc.read()if frame is None:breakif ret True:i 1# 转换为灰度图gray cv2.cvtColor(frame, cv…

复合机器人颠覆传统上下料,实现高效精准生产

在追求高效、精准生产的现代制造业中&#xff0c;传统的上下料方式已经无法满足企业的需求。复合机器人的出现&#xff0c;为制造业带来了革命性的变革。它不仅提高了生产效率&#xff0c;降低了生产成本&#xff0c;还为企业创造了更大的竞争优势。复合机器人的广泛应用&#…

多维时序 | Matlab实现CNN-BiGRU-Mutilhead-Attention卷积双向门控循环单元融合多头注意力机制多变量时间序列预测

多维时序 | Matlab实现CNN-BiGRU-Mutilhead-Attention卷积双向门控循环单元融合多头注意力机制多变量时间序列预测 目录 多维时序 | Matlab实现CNN-BiGRU-Mutilhead-Attention卷积双向门控循环单元融合多头注意力机制多变量时间序列预测效果一览基本介绍程序设计参考资料 效果一…
最新文章