2007年5月16日星期三

linux下的静态、动态库zz

Linux下的静态库以.a结尾(Winodws下为.lib)
Linux下的动态库以.so 或 .so.y结尾,其中y代表版本号(Windows下为.dll)
而且,Linux下的库必须以lib开头,用于系统识别(如:libjpeg.a libsdl.so)

静态库必要的目标代码的是在对程序编译的时候被加入到程序中,而运行时不再需要.a的库了
而动态库,则是在运行时转载
所以,动态链接的可执行代码比静态链接的可执行代码小的多

把一个源代码编译成.so:
gcc -shared -o libtry.so try.c

而要生成静态库:
gcc -c try1.c
gcc -c try2.c
ar cqs libtry.a try1.o try2.o(或 ar r libtry.a try1.o try2.o)

静态库的使用
# gcc -c main.c -o main.o
# gcc main.o -o name -L. -ltry (-l后面的名字就是我们上面生成的try库)


动态库的使用
动态库分为显式调用和隐式调用
1.显示调用
需要了解以下几个函数:
const char *dlerror(void);
当动态链接库操作函数执行失败时,dlerror可以返回出错信息,为NULL时表示操作函数执行成功。
void *dlopen(const char *filename, int flag);
成功则返回为void*的句柄。flag可以为RTLD_LAZY(表明在动态链接库的函数代码执行时解决);RTLD_NOW(表明在dlopen返回前就解决所有未定义的符号,一旦未解决,dlopen将返回错误)。filename为动态库路径。
void *dlsym(void *handle, char *symbol);
dlsym 根据动态链接库操作句柄(handle)与符号(实际上就是欲调用的函数名),返回符号对应的函数的执行代码地址。由此地址,可以带参数执行相应的函数。 int dlclose (void *handle); 参数为动态链接库的句柄。 显式调用动态链接库必须包含动态链接库功能接口dlfcn.h(包含dl系列函数的声明)和被调函数的声明。
看起来还比较简单,但是当你对动态链接库函数使用比较频繁的时候,就知道他的麻烦了,所以,不推崇。
2.隐式调用
所谓隐式调用,就是调用的时候直接使用动态库中的函数,并不区别对待。
但是在隐式调用的时候必须要让程序能找到你所调用的函数的所属动态库。
我们先来建立一个感性认识:
# more /etc/ld.so.conf 你会看到以下内容:
/usr/kerberos/lib
/usr/X11R6/lib
/usr/lib/sane
/usr/lib/qt-3.1/lib
/usr/lib/mysql
/usr/lib/qt2/lib
/usr/local/lib
/usr/local/BerkeleyDB.4.3/lib
ld.so.conf是系统对动态链接库进行查找的路径配置文件,也就是说该文件是系统链接工具/usr/bin/ld查找动态链接库的地图,所以,要达到我们的目的有以下几种方法:
a.将自己的动态链接库文件拷到以上路径的目录下
# cp libwx.so.1 /usr/local/lib
b.将自己动态链接库文件的路径加入到该文件中
# vi /etc/ld.so.conf, 然后加入自己的路径(或pwd >>/etc/ld.so.conf)
(千万不要将>>写成>,前者是添加,后者是覆盖)
c.把当前路径加入环境变量LD_LIBRARY_PATH,其实就是/usr/bin/ld的环境变量
# export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH

编译的时候:
# gcc -o try main.c libtry.so.1
如果没有让/usr/bin/ld知道你的动态链接库在哪,编译的时候就要告诉它:
# gcc -o try main.c /root/libtry.so.1 ( 或:# gcc -L/root/wx -o qqq main.c libmy.so.1)
-L指定动态链接库所在的目录,有时候用gcc还会碰到-I,-l,他们分别指定头文件的目录和所链接的动态链接库


# ldd try 用来查看可执行文件qqq的动态链接库的依赖关系

libjpeg.so.62 => /usr/lib/libjpeg.so.62 (0x00867000)
libSDL-1.2.so.0 => /usr/lib/libSDL-1.2.so.0 (0x0638a000)
libc.so.6 => /lib/tls/libc.so.6 (0x0046d000)
libm.so.6 => /lib/tls/libm.so.6 (0x00598000)
libdl.so.2 => /lib/libdl.so.2 (0x005bd000)
libasound.so.2 => /lib/libasound.so.2 (0x062e1000)
libX11.so.6 => /usr/X11R6/lib/libX11.so.6 (0x005d5000)
libXext.so.6 => /usr/X11R6/lib/libXext.so.6 (0x0069e000)
libpthread.so.0 => /lib/tls/libpthread.so.0 (0x006ae000)
/lib/ld-linux.so.2 (0x00450000)

.dll
dll---com组件dll
| |
| |__常规dll--win32 dll
| |___mfc dll
| |___extended dll (所有dll不参与编译)
lib
|_____与obj文件类似的未编译过符号文件,与obj文件区别是声明了转入转出函数

DLL与LIB的区别:
1.DLL是一个完整程序,其已经经过链接,即不存在同名引用,且有导出表,与导入表
lib是一个代码集(也叫函数集)他没有链接,所以lib有冗余,当两个lib相链接时地址会重新建立,当然还有其它相关的不同,用lib.exe就知道了
2.在生成dll时,经常会生成一个.lib(导入与导出),这个lib实际上不是真正的函数集,其每一个导出导入函数都是跳转指令,直接跳转到DLL中的位置,这个目的是外面的程序调用dll时自动跳转
3.实际上最常用的lib是由lib.exe把*.obj生成的lib,这才是真正的库,他是代码集,可完全代替目标代码

没有评论: