C++生成静态库和动态库

什么是静态库和动态库

在项目开发中,或多或少地需要使用到第三方(非编译器提供)的程序库,使用第三方的程序库能够减少重复造轮子的工作,提高开发效率。本文将介绍如何把自己的写的程序制作为程序库提供给他人使用,学会制作程序库后,自然也就会掌握了如何使用他人提供的程序库了。

程序库从使用方式上分为两种,静态库和动态库。当我们在使用第三方提供的静态库时,当编译程序时,需要将我们自己写的程序和第三方库链接在一起形成一个单独的程序。而当使用第三方提供的动态库时,虽然我们使用了动态库提供的功能,但是我们只需要单独编译我们自己写的程序,当程序运行时并使用到了动态库中提供的功能时,才会把动态库中对应的程序的二进制代码加载进内存中。

静态库和动态库主要在使用上有些差别,其本质经过源程序编译、汇编后成为的二进制代码。下面的内容将在 linux 下进行实验,介绍如何制作静态库和动态库。

制作静态库

先准备实验需要的代码,如下所示,不用去关心代码细节。

.
├── include
│   └── head.h
├── main.cc
└── src├── add.cc├── div.cc├── mult.cc└── sub.cc2 directories, 6 files
// main.cc 为用于测试的代码
#include <iostream>
#include "./include/head.h"int main()
{std::cout << add(1, 2) << std::endl;std::cout << sub(5, 2) << std::endl;std::cout << mult(2, 3) << std::endl;std::cout << divi(5, 2) << std::endl;
}

第一:将需要制作为库的源代码 *.cc 编译、汇编为二进制目标文件 ``*.o` 。

$ g++ src/*.cc -c$ tree
.
├── add.o
├── div.o
├── include
│   └── head.h
├── main.cc
├── mult.o
├── src
│   ├── add.cc
│   ├── div.cc
│   ├── mult.cc
│   └── sub.cc
└── sub.o

第二:将生成的二进制文件打包成静态库

$ ar rcs libcalc.a *.o
# 生成名为 libcalc.a 的静态库

在linux下,静态库的命名方式为 libxxx.a,中间的 xxx 为程序库的名字。windows下,静态库的命名方式为 libxxx.lib。

这里简单介绍一下“打包”工具 ar

The GNU ar program creates, modifies, and extracts from archives. An archive is a single file holding a collection of other files in a structure that makes it possible to retrieve the original individual files (called members of the archive).

ar 程序可以把多个文件合为一个文件,然后访问合并后的文件和访问合并前的文件是一样的。
简单解释一下使用 ar 打包程序库的三个参数 r, c, s

  • r, replace existing or insert new file(s) into the archive
  • c, do not warn if the library had to be created
  • s, create an archive index (cf. ranlib)

第三步:提供静态库和头文件。将生成的静态库和对应的头文件发布出去,就可以使用该静态库了。例如在上面的例子中,将 include/head.hlibcalc.a 提供出去。

使用静态库

仍然以上面的示例为例,将测试文件、静态库及其对应的头文件放在一个目录下,便于实验测试。

$ tree
.
├── head.h
├── libcalc.a
└── main.cc
$ g++ main.cc -L ./ -lcalc -o main
$ ./main
3
3
6
2.5

-L, 指定程序库的搜索路径;-l 指定程序库的名称,需要掐头(lib)去尾(.a)。

制作动态库

仍然以上面的代码为示例。在 linux 中,动态库以 lib 为前缀,.so 为后缀,例如 libcalc.so。在 windows 中,动态库以 lib 为前缀,以 dll 为后缀,例如 libcalc.dll

第一步:将需要制作为动态库的源文件编译、汇编为二进制文件。

$ g++ src/*.cc -c -fpic# 生成 *.o 二进制文件

-fpic 选项的作用是,生成位置无关代码(Position Independent Code,PIC)或者说是生成共享库时的代码。

(以下来自 ChatGPT,仅供参考)
PIC是一种特殊的代码,可以在内存中的任何位置执行而不受影响。它是动态链接库(shared library)的一种关键概念。当你编译一个动态链接库时,通常希望库的代码可以在内存中的不同位置加载,而不是绑定到特定的地址。这种灵活性使得同一份共享库可以被多个进程共享,因为它们可以在内存的不同位置加载,而不会相互冲突。

第二步:使用 gcc/g++ 命令生成动态库

$ g++ -shared *.o -o libcalc.so

-shared 选项用于告诉编译器生成一个动态库。

第一步和第二部也可以合并为一步,如下命令所示

$ g++ src/*.cc -shared -o libcalc.so -fpic

第三步:将制作的动态库和对应的头文件发布出去。

使用动态库

尝试使用和静态库一样的方式进行编译。

$ g++ main.cc -L ./ -lcalc -o main
$ ./main
./main: error while loading shared libraries: libcalc.so: cannot open shared object file: No such file or directory

可以看到,能成编译通过,但是运行报错,报错的内容为:找不到动态库。这是因为动态库不会和程序一起编译,上述编译编译的命令只是告诉了编译器在编译时能够找到动态库,但是当实际程序运行时,却搜索不到需要使用的动态库,因此程序报错。程序运行时,动态库的查找和内存加载操作是由 动态链接器 来完成的。

(以下来自ChatGPT)

动态链接器(Dynamic Linker)是操作系统的一部分,负责在程序运行时将程序中使用的动态库(共享库)加载到内存中,并解析程序与库之间的符号链接。

动态链接器搜索动态的路径为 /lib/usr/lib,因此解决办法之一就是将动态库拷贝到 /libusr/lib 目录下,然后就可以在运行时成功加载了。

$ cp /xxx/xxx/libcalc.so /usr/lib/
$ g++ main.cc -lcalc -o main
$ ./main
3
3
6
2.5

小结

本文介绍了静态库和动态库的区别,以及如何制作、使用静态库和动态库。但本文只是以简单的示例进行演示,对于复杂的项目,生成程序库需要需要借助 shell 脚本或 CMake 来完成一些复杂的逻辑操作。

参考资料

Linux 静态库和动态库

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

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

相关文章

Android 13 - Media框架(18)- CodecBase

从这一节开始我们会回到上层来看ACodec的实现&#xff0c;在这之前我们会先了解ACodec的基类CodecBase。CodecBase.h 中除了声明有自身接口外&#xff0c;还定义有内部类 CodecCallback、BufferCallback&#xff0c;以及另一个基类 BufferChannelBase&#xff0c;接下来我们会一…

mysql基本命令

MySQL 是一个流行的关系型数据库管理系统&#xff0c;以下是一些常用的 MySQL 基本命令&#xff1a; 连接到 MySQL 服务器&#xff1a; mysql -u [username] -p [password]其中 [username] 是你的 MySQL 用户名&#xff0c;[password] 是对应的密码。执行该命令后&#xff0c…

使用gcloud SDK 管理和部署 Cloud run service

查看cloud run 上的service 列表&#xff1a; gcloud run services list > gcloud run services listSERVICE REGION URL LAST DEPLOYED BY LAST DEPL…

小米秒享3--非小米电脑

小米妙享中心是小米最新推出的一款功能&#xff0c;能够为用户们提供更加舒适便利的操作体验。简单的说可以让你的笔记本和你的小米手机联动&#xff0c;比如你在手机的文档&#xff0c;连接小米共享后&#xff0c;可以通过电脑进行操作。 对于非小米电脑想要体验终版秒享AIOT…

使用java批量生成Xshell session(*.xsh)文件

背景 工作中需要管理多套环境, 有时需要同时登陆多个节点, 且每个环境用户名密码都一样, 因此需要一个方案来解决动态的批量登录问题. XShell Xshell有session管理功能: 提供了包括记住登录主机、用户名、密码及登录时执行命令或脚本(js,py,vbs)的功能 session被存储在xsh文…

计算机组成学习-数据的表示和运算总结

1、进制与编码 1.1 进位计数法 常用的进位计数法有十进制、二进制、八进制、十六进制等。十六进制每个 数位可取0〜9、A、B、C、D、E、F中的任意一个&#xff0c;其中A、B、C、D、E、F分别表示 10〜15。 八进制数字通常以前缀 "0"&#xff08;零&#xff09;加上数…

C++串口通信(转载)

Windows串口读取 要使用 C 读取串口数据&#xff0c;你需要使用串口编程库。在 Windows 平台上&#xff0c;可以使用 WinAPI 提供的串口编程接口。以下是一个简单的示例程序&#xff0c;用于打开 COM1 串口端口&#xff0c;读取数据并输出到控制台&#xff1a; #include <…

GoLong的学习之路,进阶,RabbitMQ (消息队列)

快有一周没有写博客了。前面几天正在做项目。正好&#xff0c;项目中需要MQ&#xff08;消息队列&#xff09;&#xff0c;这里我就补充一下我对mq的理解。其实在学习java中的时候&#xff0c;自己也仿照RabbitMQ自己实现了一个单机的mq&#xff0c;但是mq其中一个特点也就是&a…

基于ResNet18网络完成图像分类任务

目录 1 数据处理 1.1 数据集介绍 1.2 数据读取 1.3 构造Dataset类 2 模型构建 3 模型训练 4 模型评价 5 模型预测 6 什么是预训练模型和迁移学习 7 比较“使用预训练模型”和“不使用预训练模型”的效果。 总结 在本实践中&#xff0c;我们实践一个更通用的图像分类任务…

rust-flexi_logger

flexi_logger 是字节开源的rust日志库。目前有log4rs、env_log 等库&#xff0c;综合比较下来&#xff0c;还是flexi_logger简单容易上手&#xff0c;而且自定义很方便&#xff0c;以及在效率方面感觉也会高&#xff0c;下篇文章我们来测试下。 下面来看下怎么使用 关注 vx gol…

探索未来能源:可控核聚变的挑战与希望

探索未来能源:可控核聚变的挑战与希望 引言 随着人类社会的不断发展,对能源的需求也在持续增长。传统的化石燃料能源在燃烧过程中会产生大量的二氧化碳和其他温室气体,导致全球气候变暖,对环境产生了重大威胁。因此,寻找一种清洁、可持续、高效的能源成为了当务之急。在…

目标检测YOLO系列从入门到精通技术详解100篇-【目标检测】单目视觉估计

目录 前言 算法原理 单目3D目标检测新网络 GUP module以及HTL 单目深度估计 数据集介绍 2.1 KITTI

Redis hash表源码解析

整体数据结构&#xff1a;链式hash解决hash冲突、采用渐进式hash来完成扩容过程。 /** 哈希表节点*/ typedef struct dictEntry {// 键void *key;// 值union {void *val;uint64_t u64;int64_t s64;} v;// 指向下个哈希表节点&#xff0c;形成链表struct dictEntry *next;} dict…

ubuntu22.04离线手动安装openstack yoga和ceph quincy

目录 写在前面材料准备一. OpenStack部1. 创建虚拟网络和虚拟机2. 配置离线环境3. 环境准备3.1 配置网络3.2 配置主机名并配置解析3.3 时间调整3.4 安装openstack客户端3.5 安装部署MariaDB3.6 安装部署RabbitMQ控制节点操作3.7 安装部署Memcache控制节点操作 4. 部署配置keyst…

TwinCAT3一个PLC设备里多个程序工程之间通讯

目录 1、创建TwinCAT3工程&#xff0c;再分别创建两个PLC程序工程 2、PLC1工程中添加如下代码&#xff0c;然后编译重新生成PLC1工程 3、PLC2工程中添加如下代码&#xff0c;然后编译重新生成PLC2工程 4、变量关联 5、一个PLC运行多个PLC工程设置 7、工程下载链接 1、创建…

配置中心--Spring Cloud Config

目录 概述 环境说明 步骤 创建远端git仓库 准备配置文件 配置中心--服务端 配置中心--客户端 配置中心的高可用 配置中心--服务端 配置中心--客户端 消息总线刷新配置 配置中心--服务端 配置中心--客户端 概述 因为微服务架构有很多个服务&#xff0c;手动一个一…

wireshark自定义协议插件开发

目录 脚本代码 报文显示 脚本代码 local NAME "test" test_proto Proto("test", "test Protocol") task_id ProtoField.uint16("test.task_id", "test id", base.DEC) cn ProtoField.uint8("test.cn", &qu…

同步加载、异步加载、延迟加载、预加载的区别

<link rel"preload" href"script1.js" as"script"> <link rel"preload" href"script2.js" as"script"> 同步加载&#xff1a;浏览器在遇到<script>标签时&#xff0c;会立即停止解析HTML&#…

【记录】Python|Python3程序测试速度的整个流程、方法对比和选取方式

参考&#xff1a;Python3.7中time模块的time()、perf_counter()和process_time()的区别 其他的博客太&#xff01;长&#xff01;了&#xff01;我实在看不下去了&#xff0c;每次都不记得什么场景用什么函数。 让我来用表格总结一下各个函数的使用场景、特性。 并附上分别的测…

【Java 基础】15 注解

文章目录 1.什么是注解2.元注解1&#xff09;定义2&#xff09;分类 3.内置注解4.自定义注解5.注解的基本语法6.验证注解是否生效7.注解的使用场景8.注解的注意事项结语 1.什么是注解 注解&#xff08;Annotation&#xff09;可以理解成一种特殊的 “注释” 注解定义时以 符号…