关于Linux静态库和动态库的分析

关于Linux静态库和动态库的分析

关于Linux静态库和动态库的分析

1.什么是库
windows平台和linux平台下都大量存在着库。
本质上来说库是一种可运行代码的二进制形式。能够被操作系统加载内存运行。
因为windowslinux的本质不同,因此二者库的二进制是不兼容的。
本文仅限于介绍linux下的库。


2.库的种类
linux下的库有两种:静态库和共享库(动态库)。


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


3.库存在的意义
库是别人写好的现有的。成熟的,能够复用的代码,你能够使用但要记得遵守许可协议。
现实中每一个程序都要依赖非常多基础的底层库,不可能每一个人的代码都从零開始。因此库的存在意义非同平常。
共享库的优点是。不同的应用程序假设调用同样的库。那么在内存里仅仅须要有一份该共享库的实例。


4.库文件是怎样产生的在linux
静态库的后缀是.a。它的产生分两步
Step 1. 
由源文件编译生成一堆.o每一个.o里都包括这个编译单元的符号表
Step 2.   ar命令将非常多.o转换成.a,成文静态库
        
动态库的后缀是.so,它由gcc加特定參数编译产生。
比如:
$ gcc -fPIC -c *.c $ gcc -shared -Wl,-soname, libfoo.so.1 -o libfoo.so.1.0 *.


5.库文件是怎样命名的,有没有什么规范
linux下,库文件一般放在/usr/lib /lib下。
静态库的名字一般为libxxxx.a,当中xxxx是该lib的名称
动态库的名字一般为libxxxx.so.major.minorxxxx是该lib的名称。major是主版本, minor是副版本


6.怎样知道一个可运行程序依赖哪些库
ldd
命令能够查看一个可运行程序依赖的共享库,
比如# ldd /bin/lnlibc.so.6
=> /lib/libc.so.6 (0×40021000)/lib/ld-linux.so.2
=> /lib/ld- linux.so.2 (0×40000000)
能够看到ln命令依赖于libc库和ld-linux


7.可运行程序在运行的时候怎样定位共享库文件
当系统载入可运行代码时候。可以知道其所依赖的库的名字,可是还须要知道绝对路径
此时就须要系统动态加载器(dynamic linker/loader)
对于elf格式的可运行程序,是由ld-linux.so*来完毕的,它先后搜索elf文件的 DT_RPATH环境变量LD_LIBRARY_PATH—/etc/ld.so.cache文件列表—/lib/,/usr/lib文件夹找到库文件后将其加载内存


8.在新安装一个库之后怎样让系统可以找到他
假设安装在/lib或者/usr/lib下,那么ld默认可以找到。无需其它操作。
假设安装在其它文件夹。须要将其加入到/etc/ld.so.cache文件里,过程例如以下
1.
编辑/etc/ld.so.conf文件,增加库文件所在文件夹的路径
2.
执行ldconfig。该命令会重建/etc/ld.so.cache文件


们通常把一些公用函数制作成函数库,供其他程序使用。

函数库分为静态库和动态库两种。

静态库在程序编译时会被连接到目标代码中,程序执行时将不再须要该静态库。动态库在程序编译时并不会被连接到目标代码中。而是在程序执行是才被加载,因此在程序执行时还须要动态库存在。

本文主要通过举例来说明在Linux 中怎样创建静态库和动态库,以及使用它们。在创建函数库前,我们先来准备举例用的源程序,并将函数库的源程序编译成.o文件。

1步:编辑得到举例的程序--hello.hhello.cmain.c

hello.h(见程序1)为该函数库的头文件。

hello.c(见程序2)是函数库的源程序。当中包括公用函数hello。该函数将在屏幕上输出"Hello XXX!"

main.c(见程序3)为測试库文件的主程序,在主程序中调用了公用函数hello


 

程序1: hello.h

#ifndef HELLO_H

#define HELLO_H

void hello(const char *name);

#endif //HELLO_H


 

程序2: hello.c

#include <stdio.h>

 

void hello(const char *name)

{

       printf("Hello %s! ", name);

}


#include "hello.h"

 

int main()

{

hello("everyone");

return 0;

}


 

2步:将hello.c编译成.o文件;

不管静态库,还是动态库,都是由.o文件创建的。因此,我们必须将源程序hello.c通过gcc先编译成.o文件。

在系统提示符下键入下面命令得到hello.o文件。

# gcc -c hello.c

我们执行ls命令看看是否生存了hello.o文件。

# ls

hello.c hello.h hello.o main.c

ls命令结果中,我们看到了hello.o文件。本步操作完毕。

以下我们先来看看怎样创建静态库,以及使用它。


 

3步:由.o文件创建静态库。

静态库文件名称的命名规范是以lib为前缀。紧接着跟静态库名。扩展名为.a。比如:我们将创建的静态库名为myhello,则静态库文件名称就是libmyhello.a

在创建和使用静态库时,须要注意这点。创建静态库用ar命令。

在系统提示符下键入下面命令将创建静态库文件libmyhello.a

# ar cr libmyhello.a hello.o

我们相同执行ls命令查看结果:# ls    ls命令结果中有libmyhello.a

hello.c hello.h hello.o libmyhello.a main.c


4步:在程序中使用静态库。

静态库制作完了,怎样使用它内部的函数呢?仅仅须要在使用到这些公用函数的源程序中包括这些公用函数的原型声明。然后在用gcc命令生成目标文件时指明静态库名。gcc将会从静态库中将公用函数连接到目标文件里。

注意。gcc会在静态库名前加上前缀lib。然后追加扩展名.a得到的静态库文件名称来查找静态库文件。

在程序3:main.c中。我们包括了静态库的头文件hello.h,然后在主程序main中直接调用公用函数hello。以下先生成目标程序hello。然后执行hello程序看看结果怎样。

# gcc -o hello main.c -L. -lmyhello

# ./hello

Hello everyone!

我们删除静态库文件试试公用函数hello是否真的连接到目标文件 hello中了。

# rm libmyhello.a

rm: remove regular file `libmyhello.a'?

y

# ./hello

Hello everyone!

程序照常执行,静态库中的公用函数已经连接到目标文件里了。

我们继续看看怎样在Linux中创建动态库。

我们还是从.o文件開始。


 

5步:由.o文件创建动态库文件。

动态库文件名称命名规范和静态库文件名称命名规范类似。也是在动态库名添加前缀lib,但其文件扩展名为.so

比如:我们将创建的动态库名为myhello,则动态库文件名称就是libmyhello.so

gcc来创建动态库。

在系统提示符下键入下面命令得到动态库文件libmyhello.so

# gcc -shared -fPIC -o libmyhello.so hello.o

我们照样使用ls命令看看动态库文件是否生成。# ls

hello.c hello.h hello.o libmyhello.so main.c


 

6步:在程序中使用动态库;

在程序中使用动态库和使用静态库全然一样,也是在使用到这些公用函数的源程序中包括这些公用函数的原型声明,然后在用gcc命令生成目标文件时指明动态库名进行编译。我们先执行gcc命令生成目标文件,再执行它看看结果。

# gcc -o hello main.c -L. –lmyhello

$gcc–o app main.c /home/test/program/ibmyLib.so

$gcc -o app2 main.c $PWD/libmyhelloso.so

# ./hello

./hello: error while loading shared libraries: libmyhello.so: cannot open shared object file: No such file or directory

#

哦!出错了。快看看错误提示。原来是找不到动态库文件libmyhello.so

程序在执行时,会在/usr/lib/lib等文件夹中查找须要的动态库文件。若找到,则加载动态库。否则将提示类似上述错误而终止程序执行。我们将文件libmyhello.so拷贝到文件夹/usr/lib中,再试试。

# mv libmyhello.so /usr/lib

# ./hello

./hello: error while loading shared libraries: /usr/lib/libhello.so: cannot restore segment prot after reloc: Permission denied
因为SELinux引起。

# chcon -t texrel_shlib_t /usr/lib/libhello.so

# ./hello

Hello everyone!

#

成功了。这也进一步说明了动态库在程序执行时是须要的。



原文地址:https://www.cnblogs.com/gavanwanggw/p/6888871.html