静态库和动态库的分析
来源:互联网 发布:秩为1的矩阵,求其n次方 编辑:程序博客网 时间:2024/05/22 13:37
在Linux操作系统中,普遍使用ELF格式作为可执行程序或者程序生成过程中的中间格式。ELF(Executable and Linking Format,可执行连接格式)。
ELF文件格式包括三种主要的类型:可执行文件、可重定向文件、共享库:
1、可执行文件(应用程序)
可执行文件包含了代码和数据,是可以直接运行的程序。
2、可重定向文件(*.o)
可重定向文件又称为目标文件,它包含了代码和数据(这些数据是和其他重定位文件和共享的object文件一起连接时使用的)。
*.o文件参与程序的连接(创建一个程序)和程序的执行(运行一个程序),它提供了一个方便有效的方法来用并行的视角看待文件的内容,这些*.o文件的活动可以反映出不同的需要。
Linux下,我们可以用gcc -c编译源文件时可将其编译成*.o格式。
3、共享文件(*.so)
也称为动态库文件,它包含了代码和数据(这些数据是在连接时候被连接器ld和运行时动态连接器使用的)。动态连接器可能称为ld.so.1,libc.so.1或者 ld-linux.so.1。
那么到底什么是库呢?
库从本质上来说是一种可执行代码的二进制格式,可以被载入内存中执行。库分静态库和动态库两种。二者的不同点在于代码被载入的时刻不同。
静态库:这类库的名字一般是libxxx.a,xxx为库的名字。静态库在程序编译时会被连接到目标代码中,利用静态函数库编译成的文件比较大,因为整个函数库的所有数据都会被整合进目标代码中,他的优点就显而易见了,即编译后的执行程序不需要外部的函数库支持,因为所有使用的函数都已经被编译进去了。当然这也会成为他的缺点,因为如果静态函数库改变了,那么你的程序必须重新编译。
动态库:这类库的名字一般是libxxx.M.N.so,同样的xxx为库的名字,M是库的主版本号,N是库的副版本号。当然也可以不要版本号,但名字必须有。相对于静态函数库,动态函数库在编译的时候并没有被编译进目标代码中,你的程序执行到相关函数时才调用该函数库里的相应函数,因此动态函数库所产生的可执行文件比较小。由于函数库没有被整合进你的程序,而是程序运行时动态的申请并调用,所以程序的运行环境中必须提供相应的库。动态函数库的改变并不影响你的程序,所以动态函数库的升级比较方便。linux系统有几个重要的目录存放相应的函数库,如/lib /usr/lib。
当要使用静态的程序库时,连接器会找出程序所需的函数,然后将它们拷贝到执行文件,由于这种拷贝是完整的,所以一旦连接成功,静态程序库也就不再需要了。然而,对动态库而言,就不是这样。动态库会在执行程序内留下一个标记指明当程序执行时,首先必须载入这个库。由于动态库节省空间,linux下进行连接的缺省操作是首先连接动态库,也就是说,如果同时存在静态和动态库,不特别指定的话,将与动态库相连接。
一、静态库
前面已经介绍了静态库的概念,下面我们通过一个实例来看静态库的使用
1、生成静态库
1)这里准备了两个库的源码st1 、st2用它们来制作库libmytest.a,如下
fs@ubuntu:~/qiang/stalib$ ls -ltotal 12-rw-rw-r-- 1 fs fs 98 Jan 5 19:56 main.c-rw-rw-r-- 1 fs fs 69 Jan 5 19:55 st1.c-rw-rw-r-- 1 fs fs 68 Jan 5 19:55 st2.cfs@ubuntu:~/qiang/stalib$ cat st1.c#include <stdio.h>void print1(){printf("Hello!I am st1!\n ");}fs@ubuntu:~/qiang/stalib$ cat st2.c#include <stdio.h>void print2(){printf("Hello!I am st2!\n");}fs@ubuntu:~/qiang/stalib$ cat main.c#include <stdio.h>int main(int argc, const char *argv[]){print1();print2();return 0;}fs@ubuntu:~/qiang/stalib$
2) 生成libmytest.a文件
创建静态库用ar命令,它将很多.o转换成.a
fs@ubuntu:~/qiang/stalib$ gcc -c st1.c st2.cfs@ubuntu:~/qiang/stalib$ ar crs libmytest.a st1.o st2.ofs@ubuntu:~/qiang/stalib$ ls -ltotal 24-rw-rw-r-- 1 fs fs 2262 Jan 5 20:04 libmytest.a-rw-rw-r-- 1 fs fs 98 Jan 5 19:56 main.c-rw-rw-r-- 1 fs fs 69 Jan 5 20:03 st1.c-rw-rw-r-- 1 fs fs 1024 Jan 5 20:04 st1.o-rw-rw-r-- 1 fs fs 69 Jan 5 20:03 st2.c-rw-rw-r-- 1 fs fs 1024 Jan 5 20:04 st2.ofs@ubuntu:~/qiang/stalib$ file libmytest.a libmytest.a: current ar archivefs@ubuntu:~/qiang/stalib$
静态库文件libmytest.a已经生成,用file命令查看其属性,发现它确实是归档压缩文件。用ar -t libmytest.a可以查看一个静态库包含了那些obj文件:
fs@ubuntu:~/qiang/stalib$ ar -t libmytest.a st1.ost2.ofs@ubuntu:~/qiang/stalib$
2、使用静态库
前面我们已经写好了main.c,现在测试一下
fs@ubuntu:~/qiang/stalib$ gcc -o test main.c -L. -lmytestfs@ubuntu:~/qiang/stalib$ ls -ltotal 32-rw-rw-r-- 1 fs fs 2262 Jan 5 20:04 libmytest.a-rw-rw-r-- 1 fs fs 98 Jan 5 19:56 main.c-rw-rw-r-- 1 fs fs 69 Jan 5 20:03 st1.c-rw-rw-r-- 1 fs fs 1024 Jan 5 20:04 st1.o-rw-rw-r-- 1 fs fs 69 Jan 5 20:03 st2.c-rw-rw-r-- 1 fs fs 1024 Jan 5 20:04 st2.o-rwxrwxr-x 1 fs fs 7248 Jan 5 20:07 testfs@ubuntu:~/qiang/stalib$ ./test Hello! I am st1!Hello! I am st2!fs@ubuntu:~/qiang/stalib$
这里gcc的参数-L是告诉编译器库文件的路径是当前目录,-l是告诉编译器要使用的库的名字叫mytest。
二、动态库
动态库的基本概念
1、动态链接库是程序运行时加载的库,当动态链接库正确安装后,所有的程序都可以使用动态库来运行程序。动态链接库是目标文件的集合,目标文件在动态链接库中的组织方式是按照特殊方式形成的。库中函数和变量的地址是相对地址,不是绝对地址,其真实地址在调用动态库的程序加载时形成。
2、动态链接库的名称有别名(soname), 真名(realname)和链接名(linker name)。别名由一个前缀lib,然后是库的名字,再加上一个后缀“.so”构成("libxxx.so")。真名是动态链接库真实名称,一般总是在别名的基础加上一个小版本号,发布版本等构成。除此之外,还有一个链接名,即程序链接时使用的库的名字。
3、在动态链接库安装的时候,总是复制文件到某个目录下,然后用一个软连接生成别名,在库文件进行更新的时候,仅仅更新软链接即可。
下面我们通过一个实例来学习如何生成动态库和使用动态库
1、生成动态库
1)当前文件夹下有下面四个文件
fs@ubuntu:~/qiang/lib/dylib$ ls -ltotal 16-rw-rw-r-- 1 fs fs 73 Jan 5 18:11 dy1.c-rw-rw-r-- 1 fs fs 74 Jan 5 18:11 dy2.c-rw-rw-r-- 1 fs fs 90 Jan 5 18:11 main.c-rw-rw-r-- 1 fs fs 95 Jan 5 18:10 mylib.hfs@ubuntu:~/qiang/lib/dylib$
文件内容分别为:
fs@ubuntu:~/qiang/lib/dylib$ cat mylib.h #ifndef _MYLIB_H_#define _MYLIB_H_#include <stdio.h>void print1();void print2();#endiffs@ubuntu:~/qiang/lib/dylib$ cat dy1.c#include "mylib.h"void print1(){printf("My first shared lib!\n");}fs@ubuntu:~/qiang/lib/dylib$ cat dy2.c#include "mylib.h"void print2(){printf("My second shared lib!\n");}fs@ubuntu:~/qiang/lib/dylib$ cat main.c#include "mylib.h"int main(int argc, char *argv[]){print1();print2();return 0;}fs@ubuntu:~/qiang/lib/dylib$
2)这里我们将dy1.c与dy2.c用来创建动态库
fs@ubuntu:~/qiang/lib/dylib$ gcc -fPIC -Wall -c dy1.c dy2.cfs@ubuntu:~/qiang/lib/dylib$ gcc -shared -o libtest.so dy1.o dy2.ofs@ubuntu:~/qiang/lib/dylib$
这里 -fPIC 创建与地址无关的编译程序,-shared指定生成动态链接库。
我们也可以一步到位
fs@ubuntu:~/qiang/lib/dylib$ gcc -o libtest.so -fPIC -shared dy1.c dy2.cfs@ubuntu:~/qiang/lib/dylib$
我们可以看到下面已经生成了一个libtest.so
fs@ubuntu:~/qiang/lib/dylib$ ls -ltotal 32-rw-rw-r-- 1 fs fs 73 Jan 5 18:11 dy1.c-rw-rw-r-- 1 fs fs 1332 Jan 5 18:29 dy1.o-rw-rw-r-- 1 fs fs 74 Jan 5 18:11 dy2.c-rw-rw-r-- 1 fs fs 1336 Jan 5 18:29 dy2.o-rwxrwxr-x 1 fs fs 6798 Jan 5 18:29 libtest.so-rw-rw-r-- 1 fs fs 90 Jan 5 18:11 main.c-rw-rw-r-- 1 fs fs 95 Jan 5 18:10 mylib.hfs@ubuntu:~/qiang/lib/dylib$
2、使用动态链接库
在编译程序时,使用动态链接库和静态库是一致的,使用”-l库名”的方式,在生成可执行文件的时候会链接库文件。使用如下命令:
fs@ubuntu:~/qiang/lib/dylib$ gcc -o test main.c -L. -ltestfs@ubuntu:~/qiang/lib/dylib$ lsdy1.c dy2.c libtest.so main.c mylib.h test
这里 -L 指定动态链接库的路劲,-ldtest链接库函数test 。-ltest是动态库的调用规则。Linux系统下的动态库命名方式是lib*.so,而在链接时表示位-l*,*是自己命名的库名。
我们可以看到这里已经生成了test可执行文件,我们可以执行一下:
fs@ubuntu:~/qiang/lib/dylib$ ./test./test: error while loading shared libraries: libtest.so: cannot open shared object file: No such file or directoryfs@ubuntu:~/qiang/lib/dylib$
可以发现发生了错误,这是因为程序运行时没有找到动态链接库造成的。程序编译时链接动态库和运行时使用动态链接库的概念是不同的,在运行时,程序链接的动态链接库需要在系统目录下才行。
这就到了动态库的路径问题,有三种方法:
1)把库拷贝到/usr/lib和/lib目录下:
fs@ubuntu:~/qiang/lib/dylib$ sudo cp libtest.so /lib[sudo] password for fs:
这里要超级用户权限sudo,我们看一下执行结果:
fs@ubuntu:~/qiang/lib/dylib$ ./test My first shared lib!My second shared lib!fs@ubuntu:~/qiang/lib/dylib$
这里执行结果正确。
2)在 LD_LIBRARY_PATH 环境变量中加上库所在路径
fs@ubuntu:~/qiang/lib/dylib$ export LD_LIBRARY_PATH=`pwd`:$LD_LIBRARY_PATHfs@ubuntu:~/qiang/lib/dylib$
我们可以看到:libtest.so 的路径已经存在
fs@ubuntu:~/qiang/lib/dylib$ ldd testlinux-gate.so.1 => (0xb774b000)libtest.so => /home/fs/qiang/lib/dylib/libtest.so (0xb7746000)libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb758d000)/lib/ld-linux.so.2 (0xb774c000)fs@ubuntu:~/qiang/lib/dylib$
我们可以看一下结果:
fs@ubuntu:~/qiang/lib/dylib$ ./test My first shared lib!My second shared lib!fs@ubuntu:~/qiang/lib/dylib$
也能得到正确结果。
3)添加/etc/ld.so.conf.d/*.conf文件。把库所在的路径加到文件末尾,并执行ldconfig刷新。
fs@ubuntu:~/qiang/lib/dylib$ cd /etc/ld.so.conf.d/fs@ubuntu:/etc/ld.so.conf.d$ lsi386-linux-gnu_GL.conf libc.confi686-linux-gnu.conf vmware-tools-libraries.conffs@ubuntu:/etc/ld.so.conf.d$ sudo vi my.conf[sudo] password for fs: fs@ubuntu:/etc/ld.so.conf.d$ cat my.conf /home/fs/qiang/lib/dylib/libtest.sofs@ubuntu:/etc/ld.so.conf.d$
在/etc/ld.so.conf.d/下建立 my.conf 里面只有一句/home/fs/qiang/lib/dylib/libtest.so 即libtest.so的路径,然后执行ldconfig刷新即可。
- 静态库和动态库的分析
- 静态库和动态库的分析
- 静态库和动态库的分析
- Linux静态库和动态库的分析
- Linux静态库和动态库的分析
- 关于Linux静态库和动态库的分析
- 关于linux静态库和动态库的分析
- 关于Linux静态库和动态库的分析
- 【zz】关于Linux静态库和动态库的分析
- 【转】关于Linux静态库和动态库的分析
- 关于Linux静态库和动态库的分析
- Linux静态库和动态库的分析
- 关于Linux静态库和动态库的分析
- 关于Linux静态库和动态库的分析
- 关于Linux静态库和动态库的分析
- 摘抄-linux的静态库和动态库分析
- 关于Linux静态库和动态库的分析
- 关于Linux静态库和动态库的分析
- Linux下MySQL数据库常用基本操作
- Android高效显示图片详解(一)
- Android studio jni编写步骤,流程
- Anakia 转换xml文档为其他格式
- Android中webview快速上手方式
- 静态库和动态库的分析
- 1065 最小正子段和
- Android高效显示图片详解(二)
- 黑马程序员_File对象的练习
- swustoj----142猴子报数
- 数据库中的模式跟基本表、视图、索引的区别
- Android高效显示图片详解(三)
- HBase的Nonce实现分析
- Android WebView总结