表态库的代码编译时链接到应用程序中, 因此编译是表态库文件必须存在并且用'-l'参数传递给编译器.程序执行过程中就不再需要静态库了.
1.2 动态库
也称为共享库, 其代码不会链接到应用程序目标文件中. 程序执行过程中动态加载库文件调用里面的函数.分为隐式调用和显式调用
1) 隐式调用: 又称静态加载, 动态库会在应用程序开始执行时自动载入内存,进程结束时自动卸载。
2)显示调用: 双称动态加载, 编译时可以不显示提供动态库的路径, 但要用dlopen等函数实现调用,可以在程序中任意载入或释放动态库。
2.表态库编程
2.1 表态库的生成
可分为三个步骤: 编写源文件(*.c) -> 编译生成.o文件 -> 使用 'ar' 命令生成库文件.
下面写个例子说明:
a.首先写一个源文件 pr1.c:
#include
void print1()
{
printf("This is the first lib src!\n");
}
b. 然后编译生成.o文件:
gcc -O -c pr1.c
ls查看一下, 已经有了一个pr1.o文件.
c.用'ar'工具生成表态库,为了编译程序时能正确找到库文件,表态库必须按照lib[name].a的规则命名.
ar -rvs libpr.a pr1.o
OK! ls查看一下, 已经有了个表态库文件libpr.a
2.2 表态库的应用
写一个测试函数(test.c)调用libpr.a里的函数:
int main()
{
print1();//调用libpr.a里的print1()函数.
}
编译文件,用'-l'选项将静态库libpr.a的路径传给编译器.
gcc -O -o test test.c -L./ -lpr
或者:
gcc -O -o test test.c ./libpr.a
其中'-lpr'就是要链接静态库libpr.a(命名规则:lib[name].a),'-L.'/是指在当前目录下查找库文件.
现在执行目标文件:
./test
This is the first lib src!
OK!very easy~~~
符上静态库的操作命令'ar'的几个参数说明:
调用格式: ar [drqtpmx] [options] archivefile objfile ......
-r 将objfile文件插入静态库尾或替换静态库中同名文件.
-x 从静态库文件中抽取文件objfile.
-t 打印静态成员文件列表.
-d 从静态库中删除文件objfile.
-s 重置静态库文件索引.
-v 创建文件冗余信息.
-c 创建静态库文件.
3.动态库的生成
分为三个步骤: 编写源文件(.c) -> 编译生成位置无关码型.o文件(PIC) -> 链接生成动态库.
下面定个例子说明:
a) 编写源代码
... ... 这里就省事了, 就用刚写的那个pr1.c文件.
b) 使用gcc的'-fpic' 选项生成PIC中间文件
gcc -fpic -c pr1.c
c) 使用gcc的'-shared' 选项生成创建动态库文件pr1.so文件
gcc -shared -o pr1.so pr1.o
或者也可以一步到位:
gcc -O -fpic -shared -o pr1.so pr1.c
4.动态库的应用
4.1 动态库的隐式调用. 与静态库的调用接近:
编写调用动态库函数的代码, ~~~ 这里继续使用刚才的test.c
编译时,直接将动态库的路径作为参数传到编译器:
gcc -O -o test test.c ./pr1.so
执行目标文件: ./test
This is the first lib src!
OK!成功了.
4.2 动态库的显式调用
显式调用编译时无需库文件, 库文件可以在任意位置.是用系统库函数还操作动态库的.
a) 打开动态库
#include
void *dlopen(const char *pathname, int mode);
函数dlopen 加载动态库,成功返回指向动态库的指针,否则返回NULL.
pathname: 动态库路径.
mode: 加载方式: RTLD_ALZY(对象符号在被调用时解析),RTLD_NOW(所有符号在函数dlopen返回前解析)
b) 获取动态库对象地址
#include
void *dlsym(void *handle, const char *name);
函数dlsym在动态库中搜索与字符串name同名的对象(包括函数和全局变量等),成功返回对象地址,否则返回NULL.
handle: 同函数dlopen返回成功的动态库句柄.
name: 动态库对象名称.
c) 错误检查
#include
char * dlerror(void);
函数dlerror返回最近的显式操作动态库的错误信息, 无错误时返回NULL.本函数执行后会将错误信息重置为NULL.
d) 关闭动态库
#include
int dlclose(void *handle);
关闭handle指向的动态库.
下面写一个测试函数实践一下(test.c):
#include
#include
int main()
{
void *pHandle; //指向动态库的指针
void (*pFunc)(); //指向函数的指针
pHandle = dlopen("dll/pr1.so",RTLD_NOW); //打开动态库
if(!pHandle){
printf("Can't find pr1.so");
return;
}
pFunc = (void (*)())dlsym(pHandle, "print1");
if(!pFunc){
printf("Can't find func printf\n");
return;
}
pFunc();
dlclose(pHandle); //关闭动态库
}
编译:
cp pr1.so dll/
gcc -O -o test test.c
./ test
This is first dll src!
OK! 成功了。
上面的例子都是经我测试通过的。
动态调用动态库那那几个函数在ubuntu上面编译不通过,
报错信息是: undefined reference to `dlopen'
不知道还得装哪个库, 希望有高手指点一下