Linux 动态和静态库小结(1)
在Linux中,库,也称为“shared component”或者“archive libraries”,指的是将一个或多个编译好的object code文件打包成一个文件,以供使用。至于使用库的原因和优缺点在这里不想多讲,本小结仅关注如何在Linux中构建和使用库,以及关于库配置的一些小结。
Linux 库的类型:
linux中有两种类型的库可以被创建:
1 静态库(static libraries,以后缀.a结尾): 静态库最终被linker链接到目标可执行程序当中,作为可执行程序整体一个部分存在。
2 动态库(dynamic shared libraries,以后缀.so结尾(share object)):动态库仅以(.so)一种形式存在,但是有两种使用方法。
2.1 Dynamically linked at run time but statically aware: 在这种形式下,动态库在编译和链接阶段就必须是可以使用的。也就是说在编译和链接目标可执行的程序的时候,需要明确指定动态库的位置,并且其为可用。但是,动态库并没用像静态库那样被加入到目标可执行程序当中去,而是在运行时动态链接到该可执行程序对应的进程的地址空间当中去。
2.2 Dynamically loaded/unloaded and linked during execution (如浏览及的plugin就是采用这种方式)。通过使用动态链接装载系统调用,这种方式可用在运行时动态的装载/卸载和链接动态库到可执行程序对应的进程的地址空间当中。
关于Linux 库的一些约定
1 库的名字一般是以“lib”作为前缀,后缀为“.so”或“.a”。当链接库的时候,-l command line option仅需要指定库的名称,而不用指定其前缀和后缀。
如需要使用libthread.so 库,对应的cc参数为gcc source_file.c –lm -lpthread 。
2 对于动态库(shared object),有几个名字需要注意下。
每一个动态库有一个特殊的名字称之为”soname”。“soname”由前缀“lib”,库的名称,后缀“.so”以及“.version number”构成。其中,version number 会随着库的接口的变化而增加。
3 每个动态库还有一个名字“real name”。“real name”是包含实际代码的库文件的名字。“real name”是在“soname”末尾添加“.<minor number>.<release number>”构成。其中”.<release number>“是可选的。minor number和release number可以帮助你识别当前是哪个版本的动态库正在被使用。
此外,另外一个名字,在compiler请求动态库的时候使用,称为“linker name”。“linker name”的构成是由soname去掉末尾的version number构成。
“soname”,“real name”和“linker name”三者之间的关系如下图所示:
静态库(.a)
在这一节总结创建和使用静态库的一般步骤:
1 compile源文件。 cc –Wall –c ctest1.c ctest2.c
注意-c 选项告示cc仅编译源代码。
2 创建静态库.a archive 文件。 ar –cvq libctest.a ctest1.o ctest2.o
关于ar的详细时候,请参看man ar。 –c 是创建一个archive,-v是verbose方式, -q是quick append。
3 查看archive .a文件中包含的object文件。 ar –t libctest.a
4 通过链接使用静态库。
cc –o executable-name prog.c libctest.a
cc –o executable-name prog.c –L/path/to/library-path –lctest
注意,在4中,有两种方式可以使用静态库,一种是之间链接静态库文件libctest.a。 另外一种是使用 –l 命令,它会指示ld在系统的规定目录下(如/usr/lib, /lib etc)寻找静态库并且链接。在这类,-l的参数是ctest,需要去掉前缀”lib” 和后缀”.a”。
动态库(.so)
这里总结创建和使用动态库的一般步骤:
1 gcc –Wall –fPIC –c *.c
2 gcc –shared –Wl,-soname,libctest.so.1 –o libctest.so.1.0 *.o
3 mv libctest.so.1.0 /opt/lib
ln –sf /opt/lib/libctest.so.1.0 /opt/lib/libctest.so.1
ln –sf /opt/lib/libctest.so.1.0 /opt/lib/libctest.so
4 使用动态库编译主程序
gcc –Wall –I<path to include-files> –L<path to libraries> prog.c –lctest –o prog
关于选项:
-Wall 编译时包含warning信息。
-fPIC : 编译器指令,指示编译输出地址无关代码(Position Independent Code),编译动态库所要求使用。另见-fpic的用法,关于-fPIC和-fpic,参加man gcc 帮助。
-shared: 动态共享库,可以被链接到其他object文件,最终构成可执行文件。
-Wl: 将其逗号后面的选项传递给链接程序ld
-o:输出的so文件的文件名称,这里是libctest.so.1.0
列举库依赖关系ldd
列举某个可执行程序的动态共享库依赖关系,使用ldd命令。
ldd prog
linux-gate.so.1 => (0xb76fc000)
libctest.so.1 => /root/apue2/c_expert/ar/libctest.so.1 (0xb76ea000)
libc.so.6 => /lib/i686/cmov/libc.so.6 (0xb758f000)
/lib/ld-linux.so.2 (0xb76fd000)
运行:
设置动态库的路径: export LD_LIBRARY_PATH=/opt/lib:$LD_LIBRARY_PATH
运行:./prog
Library PATH设置
为了使得可执行程序正确运行,需要正确配置使得可执行程序在运行时可以找到所有需要的动态共享库。有以下几种方式可以完成该任务。
1 /etc/ld.so.conf:
编辑该文件,加入你希望系统从哪些目录下查找并且装载动态库文件。如将/opt/lib 加入到该文件。
Sample: /etc/ld.so.conf
/usr/X11R6/lib /usr/lib ... .. /usr/lib/sane /usr/lib/mysql /opt/lib
然后,执行ldconfig,使得linker重新更新运行时的绑定情况。
你可以是使用ldconfig –f <conf file>来使用另外的ld.so.conf文件,而不使用默认的/etc/ld.so.conf文件。
2 通过环境变量LD_LIBRARY_PATH来指定动态库的查询目录。
(Linux/Solaris: LD_LIBRARY_PATH; HP_UX: SHLIB_PATH; AIX:LIBPATH;
Mac OS X: DYLD_LIBRARY_PATH).
export LD_LIBRARY_PATH=/opt/lib;$LD_LIBRARY_PATH 或者将其添加到~/.bashrc 文件当中去。