总结一下上周讲的库的编译流程。 linux下的库作用 对于编程人员就不必说了吧,linux下有两种库:动态库(共享库)和静态库
1.两者区别:
静态库的代码在编译过程中已经被载入可执行程序,因此体积比较大。
动态库(共享库)的代码在可执行程序运行时才载入内存,在编译过程中仅简单的引用,因此代码体积比较小。不同的应用程序如果调用相同的库,那么在内存中只需要有一份该动态库(共享库)的实例。
静态库和共享库的最大区别,静态情况下,把库直接加载到程序中,而共享库链接的时候,它只是保留接口,将动态库与程序代码独立,这样就可以提高代码的可复用度,和降低程序的耦合度。
静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库。动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在
2.静态库
2.1 基础概念与相关命令
a:库名格式lib<name>.a,例如libmytest.a
b:ar命令创建静态库文件
d -----从指定的静态库文件中删除文件
m -----把文件移动到指定的静态库文件中
p -----把静态库文件中指定的文件输出到标准输出
q -----快速地把文件追加到静态库文件中
r -----把文件插入到静态库文件中
t -----显示静态库文件中文件的列表
x -----从静态库文件中提取文件
还有多个修饰符修改以上基本选项,详细请man ar 以下列出三个:
a -----把新的目标文件(*.o)添加到静态库文件中现有文件之后
b -----***************************************之前
v -----使用详细模式
ar 命令的命令行格式如下:
ar [-]{dmpqrtx}[abcfilNoPsSuvV] [membername] [count] archive files... 参数archive定义库的名称, files是库文件中包含的目标文件的清单, 用空格分隔每个文件
cc 参数cc -l把库做链接,静态库名称-L制定静态库路径
2.2 静态库制作及编译流程:
2.2.1.首先我们编写一个test.c程序代码,内容如下:
//#include<stdio.h>
int test(void){
printf(" xiaolin hello");
}
2.2.2.编译test.c生成test.o文件
cc test.c -c
执行完成之后会生成一个test.o的二进制文件
2.2.3.把.o文件打成.a静态库文件
ar crs libmytest.a test.o
ar操作可以跟多个.o文件,需要空格,一起打成 mytest,使用ar -t libmytest.a 显示库包含的.o文件
2.2.4.进行静态库编译并执行
编写一个man.c程序代码,内容如下:
int main(int argc,char **argv){
printftest();}
编译main.c加载静态库
cc main.c -lmytest -L.
-l静态库名称 -L静态库路径 .指当前目录
编译完成执行./a.out输出xiaolin hello
3.动态库(共享库so)
3.1 基础概念与相关命令
a:库名格式lib<name>.so,例如libmyshare.so
b:设置环境变量export LD_LIBRARY_PATH=`pwd`
c: 重要的dlfcn.h头文件
LINUX下使用动态链接库,源程序需要包含dlfcn.h头文件,此文件定义了调用动态链接库的函数的原型。下面详细说明一下这些函数。
3.c.1 dlerror
原型为: const char *dlerror(void);
当动态链接库操作函数执行失败时,dlerror可以返回出错信息,返回值为NULL时表示操作函数执行成功。
3.c.2 dlopen
原型为: void *dlopen (const char *filename, int flag);
dlopen用于打开指定名字(filename)的动态链接库,并返回操作句柄。
filename: 如果名字不以/开头,则非绝对路径名,将按下列先后顺序查找该文件。
(1) 用户环境变量中的LD_LIBRARY值;
(2) 动态链接缓冲文件/etc/ld.so.cache
(3) 目录/lib,/usr/lib
flag表示在什么时候解决未定义的符号(调用)。取值有两个:
1) RTLD_LAZY : 表明在动态链接库的函数代码执行时解决。
2) RTLD_NOW : 表明在dlopen返回前就解决所有未定义的符号,一旦未解决,dlopen将返回错误。
dlopen调用失败时,将返回NULL值,否则返回的是操作句柄。
3.c.3 dlsym : 取函数执行地址
原型为: void *dlsym(void *handle, char *symbol);
dlsym根据动态链接库操作句柄(handle)与符号(symbol),返回符号对应的函数的执行代码地址。由此地址,可以带参数执行相应的函数。
如程序代码: void (*add)(int x,int y); /* 说明一下要调用的动态函数add */
add=dlsym("xxx.so","add"); /* 打开xxx.so共享库,取add函数地址 */
add(89,369); /* 带两个参数89和369调用add函数 */
3.c.4 dlclose : 关闭动态链接库
3.2静态库制作及编译流程:
3.2.1首先生成 具有地址无关代码(PIC).o文件,使用上个例子的test.c文件演示gcc -fPIC test.c -c 会生成test.o文件
3.2.2生成so共享库
gcc -shared test.o -o libmytest.so
检查共享库是否生成是否正确ldd libmytest.so
3.2.3编写main.c文件并编译
#include<stdio.h>
#include<stdlib.h>
#include<dlfcn.h>
int (*xiaolin)(void);
int main(int agrc,char *argv){
//打开共享库
void *handle = dlopen("libmytest.so",RTLD_LAZY);
// RTLD_NOW
if(handle == (void *)0){
fputs(dlerror(),stderr);
exit(-1);
}
xiaolin= dlsym(handle,"test");
//取test函数地址赋给xiaolin函数,此时xiaolin函数具有test函数功能
printf("%d",xiaolin());
return 0;
}
dlclose(handle );//关闭共享库
3.2.4 生成可执行文件cc main.c -ldl
3.2.5执行./a.out 可能提示 No such file ,因为环境变量问题,先查看环境变量执行env 如果没有 LD_LIBRARY_PATH 需要设置这个变量,执行export LD_LIBRARY_PATH=`pwd` 具体查看http://www.51testing.com/?uid-466471-action-viewspace-itemid-822972 ,查看 LD_LIBRARY_PATH执行echo $LD_LIBRARY_PATH 如果存在的话 再执行./a.out 应该输出 xiaolin hello