Linux动态库引用编译,编译小结(3) 动态库(.so)编译及二种调用技巧

动态库的概念和优势在这就不多说了,这里只说编译和调用。

下面会一步步演示如何用编译使用动态库及如何解决问题。

当然如何还会具体的演示调用技巧。

1.直接用编译方式使用动态库。

动态地将程序和动态库链接,并让其在执行时加载库(如果它已在内存中则不会重复加载)

2.直接在代码中加载动态库。

程序在需要时再去加载一个特定的库(已加载则不必),然后调用该库中的某一特定函数.

/*

例子目录结构如下,具体代码附在页面最后。

[root@ol64 test4]# ls *

main.c

lib:

add.c calc.h sub.c

操作系统: Oracle Linux 6.4

编译版本:

[root@ol64 test4]# gcc --version

gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-3)

*/

编译动态库:

直接用gcc命令行搞定:

[root@ol64 lib]# gcc -o libcalc.so -m64 -fPIC -shared add.c sub.c

[root@ol64 lib]# ldd libcalc.so

linux-vdso.so.1 => (0x00007fff811ff000)

libc.so.6 => /lib64/libc.so.6 (0x00007fc3c51e9000)

/lib64/ld-linux-x86-64.so.2 (0x0000003e66600000)

[root@ol64 lib]# size libcalc.so

text data bss dec hexfilename

1183 488 16 1687 697libcalc.so

1.直接用编译方式使用动态库:

gcc方式:

一步一步看我的演示过程:

//会说找不到头文件

[root@ol64 test4]# gcc -m64 -o demo2 main.c

main.c:3:18: error: calc.h: No such file or directory

//加上-I参数后可以找到头文件了,但会提示说找到被调用的两个函数 "sub"和"add"

[root@ol64 test4]# gcc -m64 -I./lib -o demo2 main.c

/tmp/ccWoakff.o: In function `main':

main.c:(.text+0x14): undefined reference to `sub'

main.c:(.text+0x25): undefined reference to `add'

collect2: ld returned 1 exit status

//把动态库参数加上,这次顺序编译成功了。但用ldd 查看,会发现 "libcalc.so => not found"

[root@ol64 test4]# gcc -m64 -L./lib -lcalc -I./lib -o demo2 main.c

[root@ol64 test4]# ldd demo2

linux-vdso.so.1 => (0x00007fff1612e000)

libcalc.so => not found

libc.so.6 => /lib64/libc.so.6 (0x0000003e66e00000)

/lib64/ld-linux-x86-64.so.2 (0x0000003e66600000)参数说明请看:编译小结(1) GCC多平台安装(Linux,Aix,HP-UX,Solaris)及编译参数

//不出所料,编译时会报找不到libcalc.so库文件

[root@ol64 test4]# ./demo2

./demo2: error while loading shared libraries: libcalc.so: cannot open shared object file: No such file or directory解决方法有好多种,

1. 在 LD_LIBRARY_PATH 中加入路径

export LD_LIBRARY_PATH=`pwd`/lib

2. /etc/ld.so.conf中用ldconfig载入

2.1 echo "/xcl/test4/lib" >> /etc/ld.so.conf

2.2 ldconfig

2.3 ldconfig -v|grep libcalc.so

3. 建个软链接到.lib或/usr/lib中

具体为什么可以查看后面附的动态库搜索路径顺序.

在编译时的解决方法:

关键在 " -Wl,-rpath" 参数。它可以同时指定多个路径,中间用","分隔

[root@ol64 test4]# gcc -m64 -L./lib -lcalc -I./lib -Wl,-rpath,lib/ -o demo3 main.c

[root@ol64 test4]# ldd demo3

linux-vdso.so.1 => (0x00007fff7a6e5000)

libcalc.so => lib/libcalc.so (0x00007f5f0f6db000)

libc.so.6 => /lib64/libc.so.6 (0x0000003e66e00000)

/lib64/ld-linux-x86-64.so.2 (0x0000003e66600000)

[root@ol64 test4]# ./demo3

add() = 8

sub() = 2

MAIL:xcl_168@

BLOG:外链网址已屏蔽    问题: 为什么加上这个参数就可以,我不是在编译中加上了"-L"参数吗?

参考:外链网址已屏蔽

"-L" 表示在编译时查找。

"-Wl,-rpath" 表示在程序运行时,优先查找的顺序。

Makefile方式:

请查看: 编译小结(5) Makefile实用小结

2.采用动态调用方式使用动态库.

代码 :

#include

#include

#include

//#include "lib/calc.h"

#include "calc.h"

int main(void)

{

//RTLD_LAZY表示暂时不去处理未定义函数,先把库装载到内存,等用到没定义的函数再说;

void *handle = dlopen("/xcl/test4/lib/libcalc.so",RTLD_LAZY);

if(!handle)

{

printf("[main] open failed! %s\n",dlerror());

return -1;

}

typedef int (*sofun_add)(int x,int y);

sofun_add cadd = (sofun_add)dlsym(handle,"add");

if(!cadd)

{

printf("[main] cadd() failed! %s\n",dlerror());

dlclose(handle);

return -2;

}

printf("[main] cadd() = %d\n",cadd(3,5));

dlclose(handle);

return 0;

}

[root@ol64 test4]# gcc -m64 -I./lib -ldl -o calldemo2 callso.c

[root@ol64 test4]# ./calldemo2

[main] cadd() = 8

如在编译时出现"undefined reference to `dlopen' "错误,说明你编译时没有加上"-ldl",即没指定dlopen所引用的库libdl.a库.

小技巧:

出现这类错误时,可能通过 man 函数名 可查到要链接的库。

如 man dlopen 时出现下面一行,告知你编译时要加上 "-ldl"

Link with -ldl.

再附一些常用的:

lc 是link libc

lm 是link libm

lz 是link libz

动态调用相关的函数说明:

在dlopen的()函数以指定模式打开指定的动态连接库文件,并返回一个句柄给调用进程。

dlopen函数常用模式:

RTLD_LAZY 暂缓决定,表示暂时不去处理未定义函数,

先把库装载到内存,等用到没定义的函数再说.

RTLD_NOW 立即决定,表示马上检查是否存在未定义的函数,

若存在,则dlopen以失败告终.

dlsym()的第一个参数为dlopen()返回的句柄,即符号在库中的地址。

使用这个地址,就可以获得库中特定函数的指针,并且调用装载库中的相应函数。

dlclose()用于关闭指定句柄的动态链接库,不过只有当此动态链接库的使用计数为0时,

才会真正被系统卸载。

上面这些函数都归属于头文件:#include .

附录 :

动态链接,执行时搜索路径顺序:

1. 编译目标代码时指定的动态库搜索路径

2. 环境变量LD_LIBRARY_PATH指定的动态库搜索路径

3. 配置文件/etc/ld.so.conf中指定的动态库搜索路径

4. 默认的动态库搜索路径/lib

5. 默认的动态库搜索路径/usr/lib

相关环境变量:

LIBRARY_PATH环境变量:指定程序静态链接库文件搜索路径

LD_LIBRARY_PATH环境变量:指定程序动态链接库文件搜索路径

演示代码:

[root@ol64 lib]# cat calc.h

#ifndef __CALC_H_

#define __CALC_H_

int add(int x,int y);

int sub(int x,int y);

[root@ol64 lib]# cat add.c

#include "calc.h"

int add(int x,int y)

{

return (x + y);

}

[root@ol64 lib]# cat sub.c

#include "calc.h"

int sub(int x,int y)

{

return (x - y);

}

[root@ol64 test4]# cat main.c

#include

#include "calc.h"

int main(void)

{

printf("add() = %d \nsub() = %d\n",add(5,3),sub(5,3));

printf("MAIL:xcl_168@ \nBLOG:外链网址已屏蔽\n");

return 0;

}

MAIL: xcl_168@

BLOG:外链网址已屏蔽

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值