Linux库概念,动态库和静态库的制作,如何移植第三方库

原创 一口Linux 2024-06-17 17:20

点击左上方蓝色“一口Linux”,选择“设为星标

第一时间看干货文章 

【干货】嵌入式驱动工程师学习路线
【干货】Linux嵌入式知识点-思维导图-免费获取
【就业】一个可以写到简历的基于Linux物联网综合项目
【就业】找工作简历模版



 

一、什么是库?

在windows平台和linux平台下都大量存在着库。一般是软件作者为了发布方便、替换方便或二次开发目的,而发布的一组可以单独与应用程序进行compile time或runtime链接的二进制可重定位目标码文件。

本质上来说库是一种可执行代码的二进制形式,这个文件可以在编译时由编译器直接链接到可执行程序中,也可以在运行时由操作系统的runtime enviroment根据需要动态加载到内存中。

一组库,就形成了一个发布包,当然,具体发布多少个库,完全由库提供商自己决定。

由于windows和linux的本质不同,因此二者库的二进制是不兼容的。

现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常。

共享库的好处是,不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例。

本文仅讨论linux下的库。

二、库的分类

库有两种:静态库和共享库(动态库)。

win32平台下,静态库通常后缀为.lib,动态库为.dll ;
linux平台下,静态库通常后缀为.a,动态库为.so 。

从本质上来说,由同一段程序编译出来的静态库和动态库,在功能上是没有区别的。不同之处仅仅在于其名字上,也就是“静态”和“动态”。

二者均以文件的形式存在,其本质上是一种可执行代码的二进制格式,可以被载入内存中执行。无论是动态链接库还是静态链接库,它们无非是向其调用者提供变量、函数和类。

1. 静态库

所谓静态库,就是在静态编译时由编译器到指定目录寻找并且进行链接,一旦链接完成,最终的可执行程序中就包含了该库文件中的所有有用信息,包括代码段、数据段等。

2. 动态库

所谓动态库,就是在应用程序运行时,由操作系统根据应用程序的请求,动态到指定目录下寻找并装载入内存中,同时需要进行地址重定向。

3. 区别

我们以编译链接、载入时刻两点来讨论静态库和动态库的区别。

编译链接

静态链接库在程序编译时会被链接到目标代码中,目标程序运行时将不再需要改动态库,移植方便,体积较大,浪费控件和资源,因为所有相关的对象文件与牵涉到库都被链接合成一个可执行文件,这样导致可执行文件的体积较大。

动态库在程序编译时并不会被链接到目标代码中,而是在程序运行时才被载入,因为可执行文件体积较小。有了动态库,程序的升级会相对比较简单,比如某个动态库升级了,只需要更换这个动态库的文件,而不需要去更换可执行文件。但要注意的是,可执行程序在运行时需要能找到动态库文件。可执行文件时动态库的调用者。

程序代码和库

载入时刻

二者的不同点在于代码被载入的时刻不同。静态库的代码在编译过程中已经被载入可执行程序,因此体积较大。共享库的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此代码体积较小。

4. 优缺点

相对于动态库,静态库的优点在于直接被链接进可执行程序中,之后,该可执行程序就不再依赖于运行环境的设置了(当然仍然会依赖于 CPU指令集和操作系统支持的可执行文件格式等硬性限制)。

而动态库的优点在于,用户甚至可以在程序运行时随时替换该动态库,这就构成了动态插件系统的基础。具体使用静态库和动态库,由程序员根据需要自己决定。

三、库文件的制作

1. 库文件命名

静态库的名字一般为libxxxx.a,其中xxxx是该lib的名称;动态库的名字一般为libxxxx.so.x.y.z,含义如下图所示:

2. 制作库文件常用参数

首先需要了解gcc编译库要用到一些参数,很重要。

参数含义
-shared指定生成动态链接库。
-static指定生成静态链接库。
-fPIC表示编译为位置独立的代码,用于编译共享库。目标文件需要创建成位置无关码,概念上就是在可执行程序装载它们的时候,它们可以放在可执行程序的内存里的任何地方。
-L表示要连接的库在当前目录中。
-l指定链接时需要的动态库。编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.so来确定库的名称。
-Wall生成所有警告信息。
-ggdb此选项将尽可能的生成gdb的可以使用的调试信息。
-g编译器在编译的时候产生调试信息。
-c只激活预处理、编译和汇编,也就是把程序做成目标文件(.o文件)。
-Wl,options把参数(options)传递给链接器ld。如果options中间有逗号,就将options分成多个选项,然后传递给链接程序。

3. 库源文件

假定我们要将以下两个文件制作成库文件 add.c

int add(int x,int y)
{
     return x+y;
}
int sub(int x,int y)
{
     return x-y;
}

add.h

int add(int x,int y);
int sub(int x,int y);

4. 制作静态库并使用

  1. 需要把 add.c 编译成.o文件
gcc -c add.c
  1. 使用 ar 命令生成静态库libadd.a
ar -rc libadd.a add.o      遵循静态库命名的规则 lib + 名字 + .a
  1. 使用静态库 要是用静态库libadd.a,只需要包含add.h,就可以使用函数add()、sub()。
#include 
#include "add.h"
void main()
{
    printf("add(5,4) is %d\n",add(5,4));
    printf("sub(5,4) is %d\n",sub(5,4));
}

静态库的文件可以放在任意的位置,编译时只需要找到该库文件即可。

gcc test.c -o run libadd.a
  1. 库和头文件如果在其他目录下

使用以下命令编译:

gcc -c -I /home/xxxx/include test.c //假设test.c要使用对应的静态库
gcc -o test -L /home/xxxxx/lib test.o libadd.a

或者

gcc -c -I /home/xxxx/include -L /home/xxxxx/lib  libadd.a test.c

1). 通过-I(是大i)指定对应的头文件 2). 通过-L制定库文件的路径,libadd.a就是要用的静态库。3). 在test.c中要包含静态库的头文件。

5. 制作动态库并使用

  1. 把add.c编译成动态链接库libadd.so
gcc -fPIC -o libadd.o -c add.c
gcc -shared -o libadd.so libadd.o

也可以直接使用一条命令

gcc -fPIC -shared -o libadd.so add.c
  1. 动态库的安装 通常动态库拷贝到/lib下即可:
sudo cp libadd.so /lib
  1. 使用动态库
#include 
#include "add.h"
void main()
{
    printf("add(5,4) is %d\n",add(5,4));
    printf("sub(5,4) is %d\n",sub(5,4));
}

编译动态库:

gcc static -o run  -ladd

注意观察编译时动态库的名字与库文件对应关系

libadd.so<--------->-ladd

去掉 .so, lib简化成l,其他字母保留。

6. 动态加载的函数库Dynamically Loaded (DL) Libraries

动态加载的函数库Dynamically loaded (DL) libraries是一类函数库,它可以在程序运行过程中的任何时间加载。它们特别适合在函数中加载一些模块和plugin扩展模块的场合,因为它可以在当程序需要某个plugin模块时才动态的加载。

Linux系统下,DL函数库与其他函数库在格式上没有特殊的区别,它们创建的时候是标准的object格式。主要的区别就是这些函数库不是在程序链接的时候或者启动的时候加载,而是通过一个API来打开一个函数库,寻找符号表,处理错误和关闭函数库。通常C语言环境下,需要包含这个头文件。

dlopen()

dlopen函数打开一个函数库然后为后面的使用做准备。C语言原型是:

 void * dlopen(const char *filename, int flag);
 参数

filename
如果文件名filename是以“/”开头,也就是使用绝对路径,那么dlopne就直接使用它,而不去查找某些环境变量或者系统设置的函数库所在的目录了。否则dlopen()就会按照下面的次序查找函数库文件:
1. 环境变量LD_LIBRARY指明的路径。
2. /etc/ld.so.cache中的函数库列表。
3. /lib目录,然后/usr/lib。

一些很老的a.out的loader则是采用相反的次序,也就是先查 /usr/lib,然后是/lib。

flag
的值必须是RTLD_LAZY或者RTLD_NOW,RTLD_LAZY的意思是resolve undefined symbols as code from the dynamic library is executed,而RTLD_NOW的含义是resolve all undefined symbols before dlopen() returns and fail if this cannot be done'。
返回值
dlopen()函数的返回值是一个句柄,然后后面的函数就通过使用这个句柄来做进一步的操作。如果打开失败dlopen()就返回一个NULL。如果一个函数库被多次打开,它会返回同样的句柄。 

如果有好几个函数库,它们之间有一些依赖关系的话,例如X依赖Y,那么你就要先加载那些被依赖的函数。例如先加载Y,然后加载X。

dlerror()

通过调用dlerror()函数,我们可以获得最后一次调用dlopen(),dlsym(),或者dlclose()的错误信息。

dlsym()

如果你加载了一个DL函数库而不去使用当然是不可能的了,使用一个DL函数库的最主要的一个函数就是dlsym(),这个函数在一个已经打开的函数库里面查找给定的符号。这个函数如下定义:

 void * dlsym(void *handle, char *symbol);
参数
handle
就是由dlopen打开后返回的句柄,
symbol
是一个以NIL结尾的字符串。
功能:
如果dlsym()函数没有找到需要查找的symbol,则返回NULL。如果你知道某个symbol的值不可能是NULL或者0,那么就很好,你就可以根据这个返回结果判断查找的symbol是否存在了;不过,如果某个symbol的值就是NULL,那么这个判断就有问题了。标准的判断方法是先调用dlerror(),清除以前可能存在的错误,然后调用dlsym()来访问一个symbol,然后再调用dlerror()来判断是否出现了错误。

dlclose()

dlopen()函数的反过程就是dlclose()函数,dlclose()函数用力关闭一个DL函数库。Dl函数库维持一个资源利用的计数器,当调用dlclose的时候,就把这个计数器的计数减一,如果计数器为0,则真正的释放掉。真正释放的时候,如果函数库里面有_fini()这个函数,则自动调用_fini()这个函数,做一些必要的处理。Dlclose()返回0表示成功,其他非0值表示错误。

举例

#include 
#include 
void main()
{
    int (*add)(int x,int y);
    int (*sub)(int x,int y);
    void *libptr;
    libptr=dlopen("./libadd.so",RTLD_LAZY); //加载动态库
    add=dlsym(libptr,"add"); //获取函数地址
    sub=dlsym(libptr,"sub");
    printf("add(5,4) is %d\n",add(5,4));
    printf("sub(5,4) is %d\n",sub(5,4));
    dlclose(libptr);
}

四、库的两个查看命令

  1. 查看依赖库命令ldd

使用ldd命令可以查看一个可执行程序依赖哪些库。

这个命令非常有用,实际工作中经常会一直各种库,而有些程序的执行需要依赖好几种库,各种库的版本有很多历史版本,经常会出现库不兼容的情况,我们需要根据实际情况,适当的降低版本或者升级版本。

例如:

可以看到线程库libpthread-2.23.so依赖于libc库和ld-linux库。

  1. nm

nm工具可以打印出库中的涉及到的所有符号,下面是我们查看我们创建的动态库libadd.a:

nm

五、库的安装

在新安装一个库之后如何让系统能够找到他,有以下几种方法:

1. 拷贝到/lib或者/usr/lib下

如果安装在/lib或者/usr/lib下,那么ld默认能够找到,无需其他操作。如果安装在其他目录,需要将其添加到/etc/ld.so.cache文件中,步骤如下

2.通过配置文件/etc/profile

永久生效的环境变量设置,编辑/etc/profile即可。

 vi /etc/profile

在文件里末尾加上对应的环境变量信息。

动态库环境变量设置:

export LD_LIBRARY_PATH=/home/peng/mylib/

/home/peng/mylib/指的是动态库文件夹所在位置。即,.so等文件在/home/peng/mylib/下。

编辑完成,保存编辑并退出; 使配置即时生效:

source /etc/profile

3./etc/ld.so.conf

编辑/etc/ld.so.conf文件,加入库文件所在目录的路径

vim /etc/ld.so.conf

在里面添加动态库所在路径即可,例如

/usr/local/lib/

运行ldconfig,该命令会重建/etc/ld.so.cache文件

七、常见库的移植

1.jpeg库,用于jpeg图像处理

下载地址:

http://www.ijg.org/files/

解压

tar xvzf jpegsrc.v6b.tar.gz
cd jpeg-6b

生成Makefile

./configure --host=arm-linux-gnueabihf --prefix=$PWD/temp_install

编译,   安装

 make
 make install

注意这个库的安装程序有BUG,不会自动创建发布的lib,include,man等,因此要手工创建,要不先把其它库做好,再安装这个库

 mkdir -p /home/peng/jpeg-6b/temp_install/include
 mkdir -p /home/peng/jpeg-6b/temp_install/lib
 mkdir -p /home/peng/jpeg-6b/temp_install/man/man1  

end



一口Linux 


关注,回复【1024】海量Linux资料赠送


精彩文章合集

文章推荐

【专辑】ARM
【专辑】粉丝问答
【专辑】所有原创
专辑linux入门
专辑计算机网络
专辑Linux驱动
【干货】嵌入式驱动工程师学习路线
【干货】Linux嵌入式所有知识点-思维导图


一口Linux 写点代码,写点人生!
评论
  • 习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习笔记&记录学习习笔记&记学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记
    youyeye 2024-12-11 17:58 108浏览
  • 本文介绍瑞芯微RK3588主板/开发板Android12系统下,APK签名文件生成方法。触觉智能EVB3588开发板演示,搭载了瑞芯微RK3588芯片,该开发板是核心板加底板设计,音视频接口、通信接口等各类接口一应俱全,可帮助企业提高产品开发效率,缩短上市时间,降低成本和设计风险。工具准备下载Keytool-ImportKeyPair工具在源码:build/target/product/security/系统初始签名文件目录中,将以下三个文件拷贝出来:platform.pem;platform.
    Industio_触觉智能 2024-12-12 10:27 115浏览
  • 应用环境与极具挑战性的测试需求在服务器制造领域里,系统整合测试(System Integration Test;SIT)是确保产品质量和性能的关键步骤。随着服务器系统的复杂性不断提升,包括:多种硬件组件、操作系统、虚拟化平台以及各种应用程序和服务的整合,服务器制造商面临着更有挑战性的测试需求。这些挑战主要体现在以下五个方面:1. 硬件和软件的高度整合:现代服务器通常包括多个处理器、内存模块、储存设备和网络接口。这些硬件组件必须与操作系统及应用软件无缝整合。SIT测试可以帮助制造商确保这些不同组件
    百佳泰测试实验室 2024-12-12 17:45 113浏览
  • 首先在gitee上打个广告:ad5d2f3b647444a88b6f7f9555fd681f.mp4 · 丙丁先生/香河英茂工作室中国 - Gitee.com丙丁先生 (mr-bingding) - Gitee.com2024年对我来说是充满挑战和机遇的一年。在这一年里,我不仅进行了多个开发板的测评,还尝试了多种不同的项目和技术。今天,我想分享一下这一年的故事,希望能给大家带来一些启发和乐趣。 年初的时候,我开始对各种开发板进行测评。从STM32WBA55CG到瑞萨、平头哥和平海的开发板,我都
    丙丁先生 2024-12-11 20:14 94浏览
  • 在智能化技术快速发展当下,图像数据的采集与处理逐渐成为自动驾驶、工业等领域的一项关键技术。高质量的图像数据采集与算法集成测试都是确保系统性能和可靠性的关键。随着技术的不断进步,对于图像数据的采集、处理和分析的需求日益增长,这不仅要求我们拥有高性能的相机硬件,还要求我们能够高效地集成和测试各种算法。我们探索了一种多源相机数据采集与算法集成测试方案,能够满足不同应用场景下对图像采集和算法测试的多样化需求,确保数据的准确性和算法的有效性。一、相机组成相机一般由镜头(Lens),图像传感器(Image
    康谋 2024-12-12 09:45 117浏览
  • 时源芯微——RE超标整机定位与解决详细流程一、 初步测量与问题确认使用专业的电磁辐射测量设备,对整机的辐射发射进行精确测量。确认是否存在RE超标问题,并记录超标频段和幅度。二、电缆检查与处理若存在信号电缆:步骤一:拔掉所有信号电缆,仅保留电源线,再次测量整机的辐射发射。若测量合格:判定问题出在信号电缆上,可能是电缆的共模电流导致。逐一连接信号电缆,每次连接后测量,定位具体哪根电缆或接口导致超标。对问题电缆进行处理,如加共模扼流圈、滤波器,或优化电缆布局和屏蔽。重新连接所有电缆,再次测量
    时源芯微 2024-12-11 17:11 141浏览
  • 全球智能电视时代来临这年头若是消费者想随意地从各个通路中选购电视时,不难发现目前市场上的产品都已是具有智能联网功能的智能电视了,可以宣告智能电视的普及时代已到临!Google从2021年开始大力推广Google TV(即原Android TV的升级版),其他各大品牌商也都跟进推出搭载Google TV操作系统的机种,除了Google TV外,LG、Samsung、Panasonic等大厂牌也开发出自家的智能电视平台,可以看出各家业者都一致地看好这块大饼。智能电视的Wi-Fi连线怎么消失了?智能电
    百佳泰测试实验室 2024-12-12 17:33 119浏览
  • 铁氧体芯片是一种基于铁氧体磁性材料制成的芯片,在通信、传感器、储能等领域有着广泛的应用。铁氧体磁性材料能够通过外加磁场调控其导电性质和反射性质,因此在信号处理和传感器技术方面有着独特的优势。以下是对半导体划片机在铁氧体划切领域应用的详细阐述: 一、半导体划片机的工作原理与特点半导体划片机是一种使用刀片或通过激光等方式高精度切割被加工物的装置,是半导体后道封测中晶圆切割和WLP切割环节的关键设备。它结合了水气电、空气静压高速主轴、精密机械传动、传感器及自动化控制等先进技术,具有高精度、高
    博捷芯划片机 2024-12-12 09:16 111浏览
  • 习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习笔记&记录学习习笔记&记学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记录学习学习笔记&记
    youyeye 2024-12-12 10:13 79浏览
  • 天问Block和Mixly是两个不同的编程工具,分别在单片机开发和教育编程领域有各自的应用。以下是对它们的详细比较: 基本定义 天问Block:天问Block是一个基于区块链技术的数字身份验证和数据交换平台。它的目标是为用户提供一个安全、去中心化、可信任的数字身份验证和数据交换解决方案。 Mixly:Mixly是一款由北京师范大学教育学部创客教育实验室开发的图形化编程软件,旨在为初学者提供一个易于学习和使用的Arduino编程环境。 主要功能 天问Block:支持STC全系列8位单片机,32位
    丙丁先生 2024-12-11 13:15 86浏览
  • 一、SAE J1939协议概述SAE J1939协议是由美国汽车工程师协会(SAE,Society of Automotive Engineers)定义的一种用于重型车辆和工业设备中的通信协议,主要应用于车辆和设备之间的实时数据交换。J1939基于CAN(Controller Area Network)总线技术,使用29bit的扩展标识符和扩展数据帧,CAN通信速率为250Kbps,用于车载电子控制单元(ECU)之间的通信和控制。小北同学在之前也对J1939协议做过扫盲科普【科普系列】SAE J
    北汇信息 2024-12-11 15:45 140浏览
  • RK3506 是瑞芯微推出的MPU产品,芯片制程为22nm,定位于轻量级、低成本解决方案。该MPU具有低功耗、外设接口丰富、实时性高的特点,适合用多种工商业场景。本文将基于RK3506的设计特点,为大家分析其应用场景。RK3506核心板主要分为三个型号,各型号间的区别如下图:​图 1  RK3506核心板处理器型号场景1:显示HMIRK3506核心板显示接口支持RGB、MIPI、QSPI输出,且支持2D图形加速,轻松运行QT、LVGL等GUI,最快3S内开
    万象奥科 2024-12-11 15:42 123浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦