在linux环境下的链接库分为静态链接库(.a库)和动态链接库(.so库),其作用是把C程序编译好做成一种可执行链接文件,主程序文件调用这些程序的函数接口是可以使用a库或so库,在主程序中只需要include含有库中提供的函数接口声明的头文件即可。所以学会如何将自己的源代码封装成库进行使用很重要,接下来就来介绍一下然后进行库的封装:
1、动态链接库的制作:
首先,生成一个简单的函数实现mymax(a,b),将它封装成库来进行举例:
代码如下:
1 int mymax(int a, int b) 2 { 3 if(a > b) 4 return a; 5 return b; 6 }
这里可以通过gcc命令才生成.so库,也可以编写Makefile生成so库,Makefile如下:
1 CC = gcc 2 SRCS = mymax.c 3 OBJS = $(SRCS:.c=.o) 4 EXEC = libmymax.so//这里要注意生成的库文件开头必须lib开头,后缀.so 5 start:$(OBJS) 6 $(CC) -o $(EXEC) $(OBJS) -shared//这表明是一个动态库 7 .c.o: 8 $(CC) -o $@ -c $< -fPIC//表示编译函数时没有偏移地址 9 clean: 10 rm -rf $(OBJS)
当然也可以直接使用指令:
这里一定要注意so库的前缀必须为lib,然后将.so库链接到主程序main.c中,这里需要注意一下,因为动态库的特性,编译器会到指定的目录去寻找动态库,目录的地址在/etc/ld.so.conf.d/ 目录里的libc.conf文件里,你可以在里面加一行地址表示你so库的位置,更改完conf文件里的内容,记得输入命令行:ldconfig。
你还可以将so库复制到默认的目录下。这里是将so库复制到了默认目录下,生成可执行文件并运行,最后进行编译链接使用Makefile如下:
1 CC = gcc 2 SRCS = mylib.c 3 OBJS = $(SRCS:.c=.o) 4 EXEC = myapp 5 start:$(OBJS) 6 $(CC) -o $(EXEC) $(OBJS) -L. -lmymax 7 .c.o: 8 $(CC) -o $@ -c $< 9 clean: 10 rm -rf $(OBJS)
这样就生成了可执行程序myapp,
注意:在加载动态链接库的时候,有可能会遇到加载不到的错误,原因在于系
统默认加载的动态链接库路径里没有找到你的动态库,有三种解决方法:
**1.在执行gcc main.c -L. -ltest -o main 前,执行 export **
LD_LIBRARY_PATH=$(pwd)
2.将你so所在的目录写到/etc/ld.so.conf文件里,然后执行ldconfig。
3.将你的so放在/etc/ld.so.conf里的路径位置里。
最后可以通过指令ldd查看执行程序的链接库都有哪些:
静态链接库和动态链接库的区别在于,主程序在运行前,静态链接库的链接固定写入在程序中,而动态链接库则是在每次程序运行再加载链接。
接下来制作静态链接库:
最后使用nm命令可以查看程序依赖的库信息:
从中可以找到我们进行链接的静态库信息。
最后,如果对其他一些细节还需要详细了解的话,推荐一个博客,我觉得写得真的很相信,http://www.cnblogs.com/skynet/p/3372855.html
加载动态库需要指定路径的问题
gcc中的rpath参数可以用编译时指定动态库的搜索路径,这样运行时就不需要export LD_LIBRARY_PATH了。
解决方案
- 方案一
编译时增加参数-Wl,-rpath=’.’
可执行程序运行时会搜索当前工作目录(不是进程所在目录),所以如果在其它目录运行该可执行程序时会提示找不到动态库(同样,如果建立一个软连接ln -s时,也会提示找不到动态库)。
- 方案二
编译时增加参数-Wl,-z,origin -Wl,-rpath=’$ORIGIN’
O R I G I N 表 示 会 搜 索 进 程 所 在 目 录 ( 同 样 也 可 以 设 置 − r p a t h = ’ ORIGIN表示会搜索进程所在目录(同样也可以设置-rpath=’ORIGIN表示会搜索进程所在目录(同样也可以设置−rpath=’ORIGIN/lib’)。此方案不会出现方案一中软链接找不到动态库的情况。
- 补充
通常情况下使用第二种方案是比较理想的,但是为了防止提升权限的漏洞,一旦进行了提升权限操作(比如chown root ping ;chmod u+s ping),则ORIGIN的设置会失效,运行可执行程序,会提示找不到动态库,即使使用export LD_LIBRARY_PATH设置了路径也无效。
要解决此问题:
- 使用绝对路径(此方案不可取,所以没有亲自试验,应该是-rpath时指定绝对路径)
- 将所依赖的so文件拷贝到操作系统默认会搜索的目录下,比如/lib或者/lib64等目录
查看编译好的动态库或者进程的rpath的方法
linux readelf -d xxx.lib solaris greadelf -d xxx.lib
动态库的搜索路径的顺序
编译目标代码时指定的动态库搜索路径; 环境变量 LD_LIBRARY_PATH 指定的动态库搜索路径; 配置文件 /etc/ld.so.conf 中指定的动态库搜索路径; 默认的动态库搜索路径 /lib ; 默认的动态库搜索路径 /usr/lib
大家共同进步