linux动/静态库的生成和使用

在小乌的眼里,库文件就是资源文件,也没有什么难以理解的;可是如果真要问得深入一点:“动态链接库和静态链接库有什么区别?”,“怎么做一个动态链接库?”,“怎么生成静态/动态链接库?”,“什么叫显示/隐示调用?”。。。小乌就郁闷了,所以今天决定要拍死这些问题。
Window下面的动/静态链接库文件名分别为:.dll和.lib;
Linux下则为:.so或.so.x和.a;.so文件的标准形式应该为:libxxx.so或libxxx.so.y,前缀的lib是为了系统能识别它,后缀的.y则是版本号,可有可无;静态链接库对于linux来说叫共享库或许来的比较标准,静态库文件.a则可以看做是目标文件.o的一个集合,形式也必须为libxxx.a。
.lib对.a,.dll对.so。或许从名字及应用的OS来看,没什么太大的联系,但实际上都是换汤不换药,一个故事,所以在这里拿到一起来说。依小乌之见,所有的库文件实际上都是资源文件,也就是说,作为“备选的资源”而存在,只将必要的部分导入到自己的程序中;但是区别是:静态库必要的目标代码的是在对程序编译的时候被加入到程序中,而动态库的目标代码是在被调用的时候加入到程序中,所以相比之下动态库更加灵活,也没有象静态库那样存在对系统资源浪费的问题。但是静态库是不是就没有他存在的意义呢?不见得,有人举了这么一个例子:如果你用libpcap库编了一个程序,要给被人运行,而他的系统上没有装pcap库,该怎么解决呢?最简单的办法就是编译该程序时把所有要链接的库都链接它们的静态库,这样,就可以在别人的系统上直接运行该程序了。虽然现在小乌还没有完全理解。。。但是,存在即合理。
在Windows系统下的执行文件格式是PE格式,动态库需要一个DllMain函数作为初始化的人口,通常在导出函数的声明时需要有_declspec(dllexport)关键字。Linux下的gcc编译的执行文件默认是ELF格式,不需要初始化入口,亦不需要到函数做特别声明,编写比较方便。
说说linux下生成动/静态链接库,下面是小乌的一个Makefile文件:
#makefile for libmy.so
libwuxian.so : getdate.o gettime.o
gcc -shared -o libwuxian.so getdate.o gettime.o
rm -f *.o
getdate.o : datetime.h
gcc -c getdate.c
gettime.o : datetime.h
gcc -c gettime.c
别被弄蒙了,这是小乌拿来练习的Makefile文件。最重要的一句话gcc -shared -o libwuxian.so getdate.o gettime.o,在shell下其实也就一句话:gcc -shared -o libwuxian.so getdate.c gettime.c,-shared说明生成的是动态链接库,-o后面接生成的动态链接库文件名,必须以lib打头,.so或者.so.x结尾,x为版本号。关于Makefile文件的写法,请看:Makefile的傻瓜写法。
对于静态库,则应该如下:
gcc -c xx.c
gcc -c ll.c
ar cqs libwx.a xx.o ll.o 或者ar r libwx.a xx.o ll.o
xx.c为源文件,xx.o为目标文件,ar cqs libwx.so xx.o ll.o是将目标文件xx.o及ll.o链接为libwx.so,静态库名必须以lib打头,.a结尾。

再说说动/静态链接库的使用。静态库是在编译时简单的将被用到的目标代码加入到可执行程序,所以我们先说它的使用:
# gcc -c main.c -o main.o
# gcc main.o -o qqq -L. -lwx
使用gcc编译,假设我们这里所有的文件都保存在同一个目录下,第一句是将main.c编译成目标文件,第二句则是将目标文件libwx.a和main.o链接到可执行程序中。

动态库的使用则分为显式调用和隐式调用,显式调用需要了解以下几个函数:
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系列函数的声明)和被调函数的声明。看起来还比较简单,但是当你对动态链接库函数使用比较频繁的时候,你就知道他的麻烦了,所以,不推崇。

隐式调用。所谓隐式调用,就是调用的时候直接使用动态库中的函数,并不区别对待。但是在隐式调用的时候必须要让程序能找到你所调用的函数的所属动态库。我们先来建立一个感性认识:
# 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查找动态链接库的地图,所以,要达到我们的目的有以下几种方法:
1. 将自己的动态链接库文件拷到以上路径的目录下。
# cp libwx.so.1 /usr/local/lib
2. 将自己动态链接库文件的路径加入到该文件中。
要么# vi /etc/ld.so.conf, 然后加入自己的路径
要么# pwd >>/etc/ld.so.conf
注意:千万不要将>>写成>,前者是添加,后者是覆盖,不相信你自己玩玩看。
3. 把当前路径加入环境变量LD_LIBRARY_PATH,其实就是/usr/bin/ld的环境变量。
# export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
编译的时候:
# gcc -o qqq main.c libmy.so.1
如果没有让/usr/bin/ld知道你的动态链接库在哪,编译的时候就要告诉它:
# gcc -o qqq main.c /root/wx/libmy.so.1
或者:# gcc -L/root/wx -o qqq main.c libmy.so.1
-L指定动态链接库所在的目录,有时候用gcc还会碰到-I,-l,他们分别指定头文件的目录和所链接的动态链接库。
另外说一个shell命令:
# ldd qqq
用来查看可执行文件qqq的动态链接库的依赖关系。

http://www.sinklow.com/fox/article.asp?id=22

创建共享库的过程如下所述:
1。编译目标文件时使用GCC的 -fPIC选项,这能产生于位置无关的代码并能加载到任何地址。
2。使用GCC的 -shared 和 -soname选项。
3。使用GCC的-Wl选项把参数传递给链接器ld。 
4。使用GCC的-l选项显示地链接C库,以保证可以得到所需的启动代码(startup)代码,从而避免程序在使用不同的,可能是
  不兼容版本的C库的系统上不能启动执行。

<------Makefile----->
CC=gcc
CFLAGS = -g -O2 -Wall
LIB_NAME=libtest.so
LIB_VER=1.0.0
OBJS=test1.o test2.o
all:$(OBJS)
$(CC) $(CFLAGS) -shared -Wl,-soname,$(LIB_NAME) -o $(LIB_NAME).$(LIB_VER) $(OBJS) -lc
%.o: %.c
%(CC) $(CFLAGS) -fPIC -c $< -o $@
<------EOF--------->

 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值