Linux静态库与动态库加载

news2024/11/20 4:24:29

了解库:

        关于库相比大家之前肯定使用过,比如C/C++里面的标准库,STL里面的各种库,我们在调用STL里的容器时都需要使用库,那么库到底是什么呢?

库的本质就是可执行程序的"半成品"

我们先来回顾一下代码的执行流程:

1.预处理: 头文件展开,去注释,宏替换,条件编译,最终形成xxx.i的文件。

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

3.汇编: 将汇编指令转换成二进制指令,最终形成xxx.o文件。

4.链接: 将生成的各个xxx.o文件进行链接,最终形成可执行程序。

现在我们有这样的场景,有test1.c,test2.c,test3.c 最终经过上述的一系列处理转化成了test1.o,test2.o,test3.o,然后将这3个文件链接形成一个可执行程序a.out:

现在我想把我写的这个功能分享给别人,让别人能够使用test*.c中的方法,但是我不想让别人看到.c中的源代码,所以我们就可以,将test*.o打包成库,然后将库和头文件(方法的使用手册),发给别人,别人拿到库和头文件,查看头文件里每个方法的使用进行使用.o里的方法。

实际上,库的本质是一堆目标文件的集合(xxx.o)的集合,里面没用main函数但存在很多课调用的方法。

认识动静态库:

        我们在liunx下见一见库吧,现在我创建test1.c,编写如下程序:

这是一个非常简单的c语言程序,编译运行一下:

注意我们调用了printf函数,但我们并没有写printf函数的实现,为什么能输出结果呢?主要原因是编译器将c语言的c标准库链接进来了,c标准库里已经写好了printf的函数实现。

查看文件链接的标准库:ldd

这就是链接的c标准库,我们查一下这个文件libc.so.6:

没错,libc.so.6是一个软链接文件,我们再来查看一下这个目标文件的文件类型,使用file命令:

 可以发现它是一个共享的库,简单来说就是动态库。

  • 在Linux当中,以.so为后缀的是动态库,以.a为后缀的是静态库。
  • 在Windows当中,以.dll为后缀的是动态库,以.lib为后缀的是静态库。

认识了动态库,那静态库,又是什么呢?

动态库是和目标文件链接,具体怎么链接下面会讲,而静态库确不同,静态库是在编译的时候,将库中的代码直接拷贝到目标文件中,这就导致了我们最终形成的目标文件会很大,但优势在于形成了可执行程序后,该可执行程序可独立运行,不再需要库,但动态库不行,在日常我们都会使用动态库,很少使用静态库。

写一个自己的库:

在认识完库后,我们其实现在已经完全可以自己写一个库,我们简单实现一下加法:

test2.c:

test3.c:

test2.h:

test3.h:

我们先编程test* .c 形成test*.o:

 使用ar命令将目标文件打包成静态库,下面我们使用ar命令的-r选项和-c选项进行打包。

  • -r(replace):若静态库文件当中的目标文件有更新,则用新的目标文件替换旧的目标文件。
  • -c(create):建立静态库文件。

再打包一个静态库,改后缀即可:

 还可以使用ar命令中的选项查看库中的文件的信息:

  • -t:列出库中的文件。
  • -v(verbose):显示详细的信息。

当我们把库给别人使用时,只需两个文件,一个存放头文件,一个存放库,所以我将所以头文件放入include目录下,两个库放在lib下,再将这两个目录放在mylib下:

 使用:

现在我们就相当于这个库的使用者,我们编写main函数来使用Add和Sub函数:

这里我们不能直接用gcc像以前一样编译main.c,因为现在gcc编译器默认只认系统提供的库,而我们需要链接的是第三方库,这里我们链接第三方库有这几种方法如下:

第一种方法我们给编译器加上一些选项(推荐):

  • -I:指定头文件搜索路径。
  • -L:指定库文件搜索路径。
  • -l:指明需要链接库文件路径下的哪一个库。

注意-l后面接库名时需要去掉库的前缀lib和库的后缀.so或者.a

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

 运行一下:

第二种方法:将头文件和库拷贝到系统默认的库路径

前提我们需要知道系统默认的头文件和库文件路径:

系统头文件: /usr/include

系统库文件: /usr/lib64

将我们的库和头文件拷贝到对应目录就行,这里不做演示,因为这种方法不是很推荐,因为我们应尽量避免对系统默认文件修改。 

注意上面我打包了两个库,虽然看后缀一个静态库,一个动态库,但是其实上述的库都是静态库,linux不是单单通过后缀来判断一个库的类型,下面就来看看如何真正打包一个动态库吧。

动态库打包:

还在之前的几个目标文件:

用gcc编译时带上-fPIC选项:

  • -fPIC(position independent code):产生位置无关码。
gcc -fPIC -c test2.c test3.c

 -fPIC作用于编译阶段,告诉编译器产生与位置无关的代码,此时产生的代码中没有绝对地址,全部都使用相对地址,从而代码可以被加载器加载到内存的任意位置都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。

 打包:使用-shared选项将所有目标文件打包为动态库

与生成静态库不同的是,生成动态库时我们不必使用ar命令,我们只需使用gcc的-shared选项即可。

gcc -shared -o libmyc.so test2.o test3.o

 像之前一样将头文件和动态库组合进一个文件夹:

该动态库和刚才的静态库使用方法一样:

gcc main.c -o a.out -I ./libmyc/include/ -L ./libmyc/lib/ -lmyc

需要注意的是,我们使用-I-L-l这三个选项都是在编译期间告诉编译器我们使用的头文件和库文件在哪里以及是谁,但是当生成的可执行程序生成后就与编译器没有关系了,此后该可执行程序运行起来后,操作系统找不到该可执行程序所依赖的动态库,我们可以使用ldd命令进行查看。 

我们只是告诉了编译器头文件和动态库的位置,编程成可执行程序运行后变成进程,就和编译器无关了,就变成了一个进程,进程被操作系统管理,此时操作系统还不知道头文件和动态库的位置。

解决方法如下:

方法一: 拷贝.so文件到系统共享库路径下

cp ./libmyc/lib/libmyc.so /usr/lib64/

注意系统共享库路径,系统不同可能路径名有差异,需自行百度 

 这时我们再运行a.out:

方法二:更改LD_LIBRARY_PATH

 LD_LIBRARY_PATH是程序运行动态查找库时所要搜索的路径,我们只需将动态库所在的目录路径添加到LD_LIBRARY_PATH环境变量当中即可。

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/testdir/libmyc/lib

此方法在ubuntu 20.4版本已失效,故不作演示,centos的小伙伴可以自己去试一下。

方法三: 配置/etc/ld.so.conf.d/

contos: 

/etc/ld.so.conf.d/路径下存放的全部都是以.conf为后缀的配置文件,而这些配置文件当中存放的都是路径,系统会自动在/etc/ld.so.conf.d/路径下找所有配置文件里面的路径,之后就会在每个路径下查找你所需要的库。所以我们只需将动态库路径放在该配置文件中,当程序执行后,系统就会通过该配置文件找到所需的库。

先来看看/etc/ld.so.conf.d/

首先将库文件所在目录的路径存入一个以.conf为后缀的文件当中。

再将这个.conf文件放入/etc/ld.so.conf.d中:

此时a.out还是无法链接动态库的,因为配置文件只在系统刚启动的时候会更新生效给我们的系统配置好,中途修改无法马上修改,所以我们用ldconfig命令更新一下配置文件:

ldconfig

 最终可运行a.out,经过我的实测,unbuntu貌似无法使用该方法,不过unbuntu还有别的方法

unbuntu:

在/etc/ld.so.conf后面直接追加新第三方动态库路径:

nano /etc/ld.so.conf

 同样改完后ldconfig使配置文件生效。最后运行a.out

 

 

 

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

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

相关文章

原生APP开发和Flutter开发的比较

原生APP开发和Flutter开发各有优缺点,适用于不同的场景和需求。下面是两者的详细比较,从开发语言、性能、开发效率、维护和更新、社区和支持等多个方面进行分析。北京木奇移动技术有限公司,专业的软件外包开发公司,欢迎交流合作。…

工业安全智勇较量,赛宁网安工业靶场决胜工业网络攻防对抗新战场

2024年1月30日,工信部发布《工业控制系统网络安全防护指南》(工信部网安〔2024〕14号),围绕安全管理、技术防护、安全运营、责任落实四方面提出安全防护要求,强调聚焦安全薄弱关键环节,强化技术应对策略&am…

C语言序列化和反序列化--TPL中的API(三)

tpl_map 创建tpl的唯一方法是调用tpl_map()。第一个参数是格式字符串。后面是格式字符串中特定字符所需的参数列表。例如, tpl_node *tn; int i; tn tpl_map( "A(i)", &i );该函数在格式字符串中的项和给定地址的C程序变量之间创建映射。稍后,C变量…

C. Turtle and an Incomplete Sequence

思路:首先如果都是-1的话,我们可以输出1 2循环,否则。 首先处理首尾的连续-1串,这个也很好处理,最后我们处理两个非-1之间的-1串。 对于左边的数a[l]和右边的数a[r]: 如果a[l] > a[r],那么…

python移动文件

测试1(直接把B文件夹移动到了A里,成为了A的子文件夹) import os import shutil# 移动文件夹,B文件夹在当前目录没有了,跑到了A的子文件里 ## shutil.move(./example1/B/, ./example1/A/)测试2(B文件不动,将B文件里的所有的子文件夹移动到A内…

【算法】模拟算法——提莫攻击(easy)

题解&#xff1a;提莫攻击(模拟算法) 目录 1.题目2.题解3.参考代码4.总结 1.题目 题目链接&#xff1a;LINK 2.题解 举例&#xff1a; 3.参考代码 class Solution { public:int findPoisonedDuration(vector<int>& timeSeries, int duration) {int n timeSeri…

Java设计模式 _行为型模式_访问者模式

一、访问者模式 1、访问者模式 访问者模式&#xff08;Visitor Pattern&#xff09;是一种行为型模式。它允许在不修改已有类结构的情况下&#xff0c;向类中添加新的操作。访问者模式通过将操作封装在一个访问者对象中&#xff0c;使得可以在不改变各个元素类的前提下&#x…

thinkphp6 queue队列的maxTries自定义

前景需求&#xff1a;在我们用队列的时候发现maxtries的个数时255次&#xff0c;这个太影响其他队列任务 我目前使用的thinkphp版本是6.1 第一部定义一个新的类 CustomDataBase&#xff08;我用的mysql数据库存放的队列&#xff09; 重写__make 和createPlainPayload方法 …

《面试笔记》——MySQL终结篇30

三大范式&#xff1f; 第一范式&#xff1a;字段具有原子性&#xff0c;不可再分&#xff08;字段单一职责&#xff09; 第二范式&#xff1a;满足第一范式&#xff0c;每行应该被唯一区分&#xff0c;加一列存放每行的唯一标识符&#xff0c;称为主键&#xff08;都要依赖主…

VB.net进行CAD二次开发(四)

netload不能弹出对话框&#xff0c;参考文献2 参考文献1说明了自定义菜单的问题&#xff0c;用的是cad的系统命令 只要加载了dll&#xff0c;自定义的命令与cad的命令同等地位。 这时&#xff0c;可以将自定义菜单的系统命令替换为自定义命令。 <CommandMethod("Add…

Linux主机安全可视化运维(免费方案)

本文介绍如何使用免费的主机安全软件,在自有机房或企业网络实现对Linux系统进行可视化“主机安全”管理。 一、适用对象 本文适用于个人或企业内的Linux服务器运维场景,实现免费、高效、可视化的主机安全管理。提前发现主机存在的安全风险,全方位实时监控主机运行时入侵事…

如何设置eclipse中web.xml 文件的地址

新学了一个项目 &#xff0c;项目结构与平常自己构建的web项目不同 &#xff0c;用eclipse打开之后&#xff0c;eclipse竟然自己创建了一个web.xml 而项目里面原本的web.xml 文件eclipse没有识别出来&#xff0c;导致后来浏览器访问任何路径都报错404 一、修改项目中web.xml的…

Centos7.9环境下安装Keepalived(亲测版)

目录 一、在线安装 二、离线安装 (1)、 下载 (2)、安装依赖包 (3)、解压文件 (4)、编译 (4.1)、进入 keepalived-2.2.8 目录中 (4.2)、安装Keepalived (5)、配置文件修改 (6)、启动 (7)、检查启动状态 (8)、 设置开机自启 (9)、配置从节点 (10)、启动从节点keepalived…

ArcGIS教程(05):计算服务区和创建 OD 成本矩阵

准备视图 启动【ArcMap】->双击打开【Exercise05.mxd】->启用【Network Analyst 扩展模块】。前面的文章已经讲过&#xff0c;这里不再赘述。 创建服务区分析图层 1、在 Network Analyst 工具栏上&#xff0c;单击 【Network Analyst】&#xff0c;然后单击【新建服务…

el-table的一些操作

1.el-table实现全部选择和全部取消 其实非常简单&#xff0c;el-table自带的都有方法toggleAllSelection()和clearSelection() 表格数据&#xff1a; <el-button clickcheckAll>全选</el-button> <el-button clickcancelAll>反选</el-button>// 全…

每日一练编程题:今天是【接口,多态】

设计程序 : 电脑类的属性USB接口数组 : 有3个usb插口电脑类的功能 : 通过接口插入外设 (u盘,麦克风,键盘等) addUSB(USB usb) { }开机 要求: 电脑开机前,先启动外设关机 要求: 电脑关机前,先关闭外设 外设类(u盘,麦克风,键盘等) 功能 : 启动 关闭 USB接口 定义usb设备的统一…

高速服务区智慧公厕管理系统引导屏UI界面展示

在现代社会&#xff0c;高速服务区作为人们出行途中的重要休憩场所&#xff0c;其各项设施的智能化水平也在不断提升。其中&#xff0c;智慧公厕管理系统的出现&#xff0c;为人们带来了更加便捷、舒适的如厕体验&#xff0c;而引导屏 UI 界面更是这一系统的重要展示窗口。 智慧…

电脑设置密码怎么设置?让你的电脑更安全!

在如今信息化的社会中&#xff0c;保护个人电脑的安全至关重要。设置密码是最基本的电脑安全措施之一&#xff0c;它可以有效防止未经授权的访问和保护个人隐私&#xff0c;可是电脑设置密码怎么设置&#xff1f;本文将介绍三种设置电脑密码的方法&#xff0c;帮助您加强电脑的…

vue3学习使用笔记

1.学习参考资料 vue3菜鸟教程&#xff1a;https://www.runoob.com/vue3/vue3-tutorial.html 官方网站&#xff1a;https://cn.vuejs.org/ 中文文档: https://cn.vuejs.org/guide/introduction.html Webpack 入门教程&#xff1a;https://www.runoob.com/w3cnote/webpack-tutor…

wampserver安装与汉化

wampserver安装与汉化 文章目录 wampserver安装与汉化一、安装二、汉化1.升级软件并安装补丁 介绍&#xff1a; WampServer是一款由法国人开发的Apache Web服务器、PHP解释器以及MySQL数据库的整合软件包。免去了开发人员将时间花费在繁琐的配置环境过程&#xff0c;从而腾出更…