Linux-动静态库

背景

在实践中,我们一定会使用别人的库(不限于C、C++的库),在实践中,我们会使用成熟、被广泛使用的第三方库,而不会花费很多时间自己造轮子,为了能更好地使用库,就要在学习阶段了解其本质。那么对于库而言,可以从两方面认识它:

  • 如果想自己写一个库呢?(编写者)
  • 别人应该如何使用我们写的库?(使用者)
    作为C、C++的使用者,应该知道它是一门编译型语言,一堆源文件(.cpp)和一堆头文件(.h)要合在一起才能生成一个可执行程序(.exe):

预处理: 头文件展开、去注释、宏替换、条件编译等,生成.i文件

编译: 词法分析、语法分析、语义分析、符号汇总等,检查无误后将代码翻译成汇编指令,生成.s文件

汇编: 将汇编指令转换成二进制指令,生成.o文件

链接: 将生成的各个.o文件进行链接,生成可执行程序(Windows:.exe,Linux:.out)

例如: 用test1.c,test2.c以及main1.c形成可执行文件,需要先得到各个文件的目标文test1.o,test2.o以及main1.o,然后将这些目标文件链接起来,最终形成一个可执行程序。
在这里插入图片描述

实际上,对于可能频繁用到的源文件,比如这里的test1.c test2.c 可以将他们的目标文件test1.o,test2.o进行打包,之后需要用到这两个目标文件就可以直接链接这个包当中的目标文件即可,上面的打包就可以称为一个库。库的本质就是一堆.O文件集合,库的文件当中并不包含主函数而只是包含了大量写好的方法以供调用,因此,我们说动静态库是可执行程序的"半成品" -》所以库中没有main函数


认识静态库

站在编写者角度:生成静态库
以下面四个文件和一个main.c文件为例,演示其打包为库的过程

在这里插入图片描述
Add.c

  1 int Add(int x, int y)
  2 {
  3   return x + y;
  4 }                                                                                                         

Add.h

extern int Add(int x, int y);

Sub.c

  1 int Sub(int x, int y)
  2 {
  3   return x - y;
  4 }                                                                                                         

Sub.h

extern int Sub(int x, int y);

在这里插入图片描述

gcc -o Test Add.c Sub.c main.c
//我们使用 gcc -o 选项将所有的源文件进行编译,形成可执行

在这里插入图片描述

我们不建议上述方法,建议是将所有的源文件编译成.o文件,再将所有的.o文件链接形成我们的可执行
在这里插入图片描述

在 Makefile 中,$< 是一个自动化变量,表示规则中的第一个依赖文件(prerequisite)。
通过使用 $<,你可以方便地引用规则中的第一个依赖文件,使规则更加灵活和通用。

在这里插入图片描述
总结上面的操作也就是

gcc Add.o Sub.o main.o -o Test
//将别人的.o文件与自己写的main.c文件形成的.o文件链接起来,形成可执行,这个就是静态库的打包

通过上面的例子我们知道,需要将生成的所有目标文件和main.o文件链接才能生成可执行程序,但是除了main.o之外的.o文件都太分散了,用起来很麻烦(当然可以通过Makefile简化步骤),给别人使用也不太方便,还容易缺失,所以将它们打包。而将目标文件打包的结果就是一个静态库

使用ar指令将所有目标文件打包为静态库

ar 命令是 GNU Binutils 的一员,可以用来创建、修改静态库,也可以从静态库中提取单个模块。它可以将一个或多个指定的文件并入单个写成 ar 压缩文档格式的压缩文档文件。
在这里插入图片描述

例如,将Add.o和 Sub.o打包:

ar -rc libtest.a Add.o Sub.o

在这里插入图片描述
那么上面这个文件夹中就只有打包的库文件和头文件(因为头文件是公开的,我们通常可以看到stdio.h里面的内容)

在这里插入图片描述
但是,我们使用gcc编译的时候为什么报链接错误呢?

因为自己写的库是第三方库,gcc不认识,所以需要指定-l链接我们自己写的第三方库

gcc main.c -ltest

在这里插入图片描述
但是链接的时候又出现错误,不能找到这个库,所以需要提供一个选项-L,说明这个库是在哪个路径底下

gcc main.c -ltest -L.

在这里插入图片描述

站在使用者角度:打包静态库
我们将头文件和.o文件分别放在一个文件夹下的两个文件夹中
在这里插入图片描述
然后将这个文件夹的压缩包给别人,用的时候就是将include里面的内容拷贝到/user/include目录底下,将lib里面的内容拷贝到/lib64/目录下。或者指定库的路径

指定库的路径

指定库的路径


动态库

依然使用之前的四个文件和一个main.c文件示例。

  1. 生成所有源文件对应的目标文件
    gcc 需要增加-fPIC选项(position independent code):位置无关码
gcc -fPIC -c Add.c
gcc -fPIC -c Print.c

位置无关代码对于 gcc 来说:

  • -fPIC作用于编译阶段,告诉编译器产生与位置无关的代码,此时产生的代码中没有绝对地址,全部都使用相对地址,从而代码可以被加载器加载到内存的任意位置都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。
  • 如果不加-fPIC选项,则加载. so 文件的代码段时,代码段引用的数据对象需要重定位,重定位会修改代码段的内容,这就造成每个使用这个. so 文件代码段的进程在内核里都会生成这个. so 文件代码段的拷贝,并且每个拷贝都不一样,这样就和动态库一样占用内存了,具体取决于这个. so 文件代码段和数据段内存映射的位置。
  • 不加-fPIC编译生成的. so 文件是要在加载时根据加载到的位置再次重定位的,因为它里面的代码 BBS 位置无关代码。如果该. so 文件被多个应用程序共同使用,那么它们必须每个程序维护一份. so 的代码副本 (因为. so 被每个程序加载的位置都不同,显然这些重定位后的代码也不同,当然不能共享)。
    我们总是用-fPIC来生成. so,但从来不用-fPIC来生成. a。但是. so 一样可以不用-fPIC选项进行编译,只是这样的. so 必须要在加载到用户程序的地址空间时重定向所有表目。
  1. 使用 gcc 的 -shared 选项将所有目标文件打包为一个动态库
gcc -shared -o libtest.so Add.o Print.o

在这里插入图片描述


动态库的使用

对于动态库,即使显式地提示 gcc main.c 中调用了第三方库中的函数,也会因为找不到库而编译错误。

例如,仍然使用 gcc 的三个选项说明编译 main.c 需要的库文件和头文件,以及应该链接哪个库。注意,此时的工作目录依然是:
在这里插入图片描述

gcc main.c -I./mylib/include -L./mylib/lib -ltest

在这里插入图片描述
不同于静态库,这里动态库生成的可执行程序并不能运行。

在这里插入图片描述
在这里插入图片描述

  • 拷贝到系统目录
    sudo cp mylib/lib/libtest.so /lib64
  • 建立动态库的软链接
ln -s mylib/lib/libtest.so libtest.so

在这里插入图片描述

  • 更改 LD_LIBRARY_PATH环境变量
    LD_LIBRARY_PATH是程序运行动态查找库时所要搜索的路径,我们只需将动态库所在的目录路径添加到LD_LIBRARY_PATH环境变量中,告诉系统程序依赖的动态库所在的路径:
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/root/2024_1_28/dy_test/my_lib/lib

注意要用:隔开,否则会覆盖原来的环境变量。但是这个方法是临时的,因为这个环境变量是内存级别的环境变量,机器会在下次登录时清理。

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

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

相关文章

jenkins+gitlab实现Android自动打包填坑之旅

一.背景 1.首先你需要知道你想要实现的Android自动打包的Android项目的一些环境配置及需要使用的一些开发版本。 声明&#xff1a;本文 Android项目基于&#xff1a;1.jdk11 2.SDK无要求 3.gradle无要求&#xff08;同Manven一样为项目自动化构建开源工具&#xff09; 注&am…

【控制算法笔记】卡尔曼滤波(二)——基于状态空间表达的KF基本计算流程以及Python实现

本文是个人学习笔记&#xff0c;包含个人理解&#xff0c;如有错误欢迎指正。 KF算法更多的情况下会用来处理复杂的非线性数据&#xff0c;尤其是当对象特征或检测的状态量不止一个时就得使用状态方程的方法&#xff0c;利用线性代数的计算方式来解决噪声的估计问题。这其中涉及…

C++实现满天星效果静态图片

用编程C实现随机生成不同效果的星星&#xff0c;实现看星星的效果图片&#xff0c;借助EasyX图形化工具!!! 在vs2019中新建文件夹&#xff0c;并且注意在项目目录下保存两张小人的抬头观看背景的图片 将下面代码粘贴进去实现效果&#xff1a; #define _CRT_SECURE_NO_WARNIN…

前端canvas项目实战——简历制作网站(三)——右侧属性栏(线条宽度样式)

目录 前言一、效果展示二、实现步骤1. 实现线条宽度&#xff08;strokeWidth&#xff09;的属性模块2. 实线线条样式&#xff08;strokeDashArray&#xff09;的属性模块3. 意料之外的“联动” 三、Show u the code后记 前言 上一篇博文中&#xff0c;我们初步实现了右侧属性栏…

IDEA 创建maven项目没有src

环境&#xff1a; IntelliJ IDEA 2022.3.3 (Ultimate Edition) JDK 17 Windows 11 10.0 Maven 3.9.5 创建maven项目的时候没有src目录 试过网上说的重新配置maven库&#xff0c;增加vm-options&#xff0c;并没有什么用。直到我看见了 正常创建就好了。

QoS服务质量

内存QoS——服务质量&#xff08;Quality of Service&#xff09; 作用&#xff1a;如果不开启QoS&#xff0c;会通过内存复用技术&#xff0c;动态调整虚拟机的资源&#xff0c;如果说有一台跑核心业务&#xff0c;然后通过QoS技术&#xff0c;通过限额&#xff0c;预留&…

思考,是世界上最有趣的事

经常有读者问我&#xff1a; 你总说我们要多思考&#xff0c;可是每天的生活就那样&#xff0c;究竟要怎么思考&#xff0c;思考什么呢&#xff1f; 跟大家分享我上周日的一天&#xff1a; 读完一篇推理小说&#xff0c;写了一篇书评发给作者&#xff0c;并跟作者聊了聊写作的…

vivado 配置I/O端口

配置I/O端口 AMD设备支持可配置的SelectIO™ 接口驱动程序和接收器&#xff0c;支持各种标准接口。这些标准接口包括输出的可编程控制强度和转换速率&#xff0c;使用DCI的片上终端&#xff0c;以及内部VREF的生成。你可以配置一个或多个I/O端口以定义I/O标准、驱动器强度、转…

LaTeX基础使用【系列四】

&#x1f308;个人主页&#xff1a;godspeed_lucip &#x1f525; 系列专栏&#xff1a;LaTeX基础使用 &#x1f984;1 LaTeX的多行数学公式&#x1f420;1.1 导入包&#x1f420;1.2 gather环境&#xff1a;多行公式&#x1f420;1.3 gather\* &#xff1a;无编号公式&#x1…

【Javaweb程序】【C00156】基于SSM餐饮管理系统(论文+PPT)

基于SSM餐饮管理系统&#xff08;论文PPT&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这是一个基于ssm的餐饮管理系统 本系统分为前台用户模块和后台管理员模块 其中前台用户模块的权限&#xff1a;当游客打开系统的网址后&#xff0c;首先看到的就是首页…

Day01_Java概述(JDK的下载安装,初学者常见错误)

文章目录 JavaSE_Day01 Java概述学习目标1.1 JavaSE课程体系介绍1.2 计算机语言概述1、计算机语言是什么2、计算机语言发展3、计算机语言分类4、计算机语言排行榜 1.3 Java语言概述1、Java语言发展历史2、Java是最好的语言吗&#xff1f;3、Java语言的特点4、Java生态圈5、Java…

【MySQL】学习如何通过DML更新数据库的数据

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” #mermaid-svg-QIqURn9fNFMjLD9l {font-family:"trebuchet ms",verdana,arial,sans-serif;font-siz…

【贪吃蛇:C语言实现】

文章目录 前言1.了解Win32API相关知识1.1什么是Win32API1.2设置控制台的大小、名称1.3控制台上的光标1.4 GetStdHandle&#xff08;获得控制台信息&#xff09;1.5 SetConsoleCursorPosition&#xff08;设置光标位置&#xff09;1.6 GetConsoleCursorInfo&#xff08;获得光标…

mysql 存储过程学习

存储过程介绍 1.1 SQL指令执行过程 从SQL执行的流程中我们分析存在的问题: 1.如果我们需要重复多次执行相同的SQL&#xff0c;SQL执行都需要通过连接传递到MySQL&#xff0c;并且需要经过编译和执行的步骤; 2.如果我们需要执行多个SQL指令&#xff0c;并且第二个SQL指令需要…

Linux文本三剑客---awk

awk&#xff08;是一种处理文本文件的应用程序&#xff0c;它依次处理文件的每一行&#xff0c;并读取里面的每一个字段。&#xff09; awk 包含几个特殊的内建变量&#xff08;可直接用&#xff09;如下所示&#xff1a; 1、获取根分区剩余大小 #可以使用df -h命令来查看所有…

AlexNet,ZFNet详解

1 AlexNet 网络结构 对于AlexNet网络来说&#xff0c;因为当时资源环境受限&#xff0c;他从第一步卷积开始就把一个图像分到两个GPU上训练&#xff0c;然后中间进行组合最后进行融合成全连接成1000个置信度 1 得到一张3x224x224的图像&#xff0c;然后进行11x11的卷积&…

1|Java代码是怎么跑起来的?

相信每个Java程序员都想过一个问题&#xff1a; “我写的Java代码时怎样在机器上跑起来的&#xff1f;“&#x1f914; 这篇文章就尝试把这个问题说一下✍ Java代码执行流程 二话不说先把图丢出来&#xff1a; 大概经历了这么几个步骤&#xff1a; 一位高级程序猿&#xff0…

竞赛练一练 第31期:GESP和电子学会相关题目练习

Day20&#xff1a;CIE一级2020.09_小鸡与鸭妈拥抱 1. 准备工作 &#xff08;1&#xff09;背景&#xff1a;Farm; &#xff08;2&#xff09;角色&#xff1a;Chick、Duck。 2. 功能实现 &#xff08;1&#xff09;角色的初始位置、方向和造型如图所示。 &#xff08;2&am…

DualSPHysics v5.0源码编译教程,新手入门

目录 一、前期准备1. 安装C编译器2. 安装CUDA 二、下载源码三、编译四、报错解决五、验证 一、前期准备 DualSPHysics是可以编译运行在CPU和GPU上的&#xff0c;所以需要安装C编译器&#xff1a;例如gcc&#xff0c;和CUDA编译器&#xff1a;nvcc。 如果电脑上不支持CUDA&…

【笔试常见编程题01】删除公共字符串、组队竞赛、倒置字符串、排序子序列

1. 删除公共字符串 输入两个字符串&#xff0c;从第一字符串中删除第二个字符串中所有的字符。 例如&#xff0c;输入”They are students.”和”aeiou”&#xff0c;则删除之后的第一个字符串变成”Thy r stdnts.” 输入描述 每个测试输入包含2个字符串 输出描述 输出删除后的…