Linux下动态库使用

时间:2021-12-27 14:19:43

1. 静态库和动态库的基本概念

静态库,是在可执行程序连接时就已经加入到执行码中,在物理上成为执行程序的一部分;使用静态库编译的程序运行时无需该库文件支持,哪里都可以用, 但是生成的可执行文件较大。动态库,是在可执行程序启动时加载到执行程序中,可以被多个可执行程序共享使用。使用动态库编译生成的程序相对较小,但运行时 需要库文件支持,如果机器里没有这些库文件就不能运行。

2.  如何使用动态库

如何程序在连接时使用了共享库,就必须在运行的时候能够找到共享库的位置。linux的可执行程序在执行的时候默认是先搜索/lib和/usr /lib这两个目录,然后按照/etc/ld.so.conf里面的配置搜索绝对路径。同时,Linux也提供了环境变量LD_LIBRARY_PATH 供用户选择使用,用户可以通过设定它来查找除默认路径之外的其他路径,如查找/work/lib路径,你可以在/etc/rc.d/rc.local或其 他系统启动后即可执行到的脚本添加如下语句:LD_LIBRARY_PATH =/work/lib:$(LD_LIBRARY_PATH)。并且LD_LIBRARY_PATH路径优先于系统默认路径之前查找(详细参考《使用 LD_LIBRARY_PATH》)。

不过LD_LIBRARY_PATH的设定作用是全局的,过多的使用可能会影响到其他应用程序的运行,所以多用在调 试。(LD_LIBRARY_PATH的缺陷和使用准则,可以参考《Why LD_LIBRARY_PATH is bad》 )。通常情况下推荐还是使用gcc的-R或-rpath选项来在编译时就指定库的查找路径,并且该库的路径信息保存在可执行文件中,运行时它会直接到该路 径查找库,避免了使用LD_LIBRARY_PATH环境变量查找。

3.库的链接时路径和运行时路径

现代连接器在处理动态库时将链接时路径(Link-time path)和运行时路径(Run-time path)分开,用户可以通过-L指定连接时库的路径,通过-R(或-rpath)指定程序运行时库的路径,大大提高了库应用的灵活性。比如我们做嵌入式 移植时#arm-linux-gcc $(CFLAGS) –o target  –L/work/lib/zlib/ -llibz-1.2.3  (work/lib/zlib下是交叉编译好的zlib库),将target编译好后我们只要把zlib库拷贝到开发板的系统默认路径下即可。或者通过 -rpath(或-R )、LD_LIBRARY_PATH指定查找路径。

小问题:

1.编译时的-L选项是否影响LD_LIBRARY_PATH的值?

举一个实例:

当前文件夹结构如下:

test.c tools/

tool下有tool.c tool.h my_err.h 以及由此生成的libtool.so

tool下编译生成库文件

gcc -Wall -g -shared -o tool.so tool.c

在当前文件夹引用:

gcc -Wall -g -o test test.c -Ltools -ltool

编译不报错,但是运行加载的时候就出现cannot open shared object file。

如果将该库文件拷贝到/usr/lib下就没有错误,正常运行。

说明编译时的-L选项并不影响环境变量LD_LIBRARY_PATH,-L只是指定了程序编译连接时库的路径,并不影响程序执行时库的路径,系统还是会到默认路径下查找该程序所需要的库。

共享库(Shared Libary)/动态链接库

http://feizf.blogbus.com/logs/6586196.html

有两种方法使用lib库
    static library 连接时连接器将产生一个独立的object文件(这些object文件保存着程序所要引用的函数和数据)的copy。
    shared library 用这样连接出来的程序仅在可执行程序中存储着共享库的名字和一些程序引用到的标号。在运行时,动态连接器(在ELF中也叫做程序解释器)将把共享库映象到 进程的虚拟地址空间里去,通过名字解析在共享库中的标号。该处理过程也称为动态连接(dynamic linking)

一个简单的汇编使用libc链接库的例子如下:
.section .data
helloworld:
.ascii "hello world\n\0"
.section .text
.globl _start
_start:
pushl $helloworld
call printf
pushl $0
call exit

编译连接
# as helloworld-lib.s -o helloworld-lib.o
# ld -dynamic-linker /lib/ld-linux.so.2 \
-o helloworld-lib helloworld-lib.o -lc
# ./helloworld-lib
hello world

其中, -dynamic-linker /lib/ld-linux.so.2 表示设置动态链接器为ld-linux.so.2
-lc 告诉linker在libc.so这个共享库文件中寻找函数.

使用ldd命令可以查看可执行文件用到的共享库
# ldd helloworld-lib
        linux-gate.so.1 =>  (0x00f20000)
        libc.so.6 => /lib/libc.so.6 (0x00112000)
        /lib/ld-linux.so.2 (0x0052b000)

dynamically-linked 在Windows平台叫dll动态链接库,在Linux平台下称为共享库,一般存放在/lib、
/usr/lib目录下,是以.so(shared object)作为后缀的文件. 使用objdump命令可以查看某个共享库的内容,如:
# objdump -R /lib/libc-2.4.so
如果想查看某个共享库的详细信息,可以从网上查找文档。
从网址 http://www.gnu.org/software/libc/manual/ 可以看到完整的libc manual.

创建和使用共享库

--------------------------------------------------------------
Programming from Ground Up 的第7章有个例子, 其中add-year-robust.s为主程序,
当链接生成目标可执行程序时需要链接下面的一些.o文件
#as add-year-robust.s -o add-year-robust.o
#ld add-year-robust.o read-record.o write-record.o error-exit.o \
count-chars.o write-newline.o  -o add-year-robust
--------------------------------------------------------------

现在要把所有这些.o用到的文件做成一个共享库librecord.so (这也符合共享库的含义,可以被其他程序使用), 如下:
# ld -shared write-record.o read-record.o count-chars.o \
error-exit.o write-newline.o -o librecord.so

接着来使用这个共享库
# as add-year-robust.s -o add-year-robust.o
# ld -L . -dynamic-linker /lib/ld-linux.so.2 \
-o add-year-robust -lrecord add-year-robust.o

其中:
-L . 告诉linker在当前目录寻找共享库
-dynamic-linker /lib/ld-linux.so.2 设置动态链接器为ld-linux.so.2
-lrecord 告诉linker在librecord.so这个共享库文件中寻找函数. (-lfile表示libfile.so)

上面生成的程序运行时,可能会出现错误提示如下
./add-year-robust: error while loading shared libraries:
librecord.so: cannot open shared object file: No such
file or directory

这是因为默认情况下linker只在/lib、/usr/lib和/etc/ld.so.conf中列出的目录中寻找共享库. 所以要想正常运行程序,要么把共享库移到相关目录下,要么修改LD_LIBRARY_PATH把当前目录.加入 
# LD_LIBRARY_PATH=.
# export LD_LIBRARY_PATH
或者
# setenv LD_LIBRARY_PATH

man ld.so 可以看到很多关于Linux动态链接的信息.