动态链接库文件在windows平台下往往以.dll为后缀,而在linux平台则一般以.so为后缀,so是shared object的缩写。
LINUX系统中,为了让动态链接库能被系统中其它程序共享,其名字应符合“lib*.so*”这种格式.如果某个动态链接库不符合此格式,则LINUX的动态链接库自动装入程序(ld.so)将搜索不到此链接库,其它程序也无法共享之.
格式中,第一个*通常表示为简写的库名,第二个*通常表示为该库的版本号.如:在我的系统中,基本C动态链接库的名字为libc.so.6,线程pthread动态链接库的名字为libpthread.so.0等等.本文例子所生成的动态链接库的名字为libmy.so,虽没有版本号,但也符合所要求的格式.
当前目录下包括Makefile 、test.c 和test.h三个文件
cyf@cyf-Lenovo:~/workspace/c/study/so$ ls
Makefile test.c test.h
其中Makefile:
.SUFFIXEX:.c.o
CC = gcc
LIB = test
CFLAGS = -g -O2 -Wall -L. -l$(LIB)
SRCS = test_demo.c
OBJS = $(SRCS:.c=.o)
EXE = test_demo
all:$(OBJS)
$(CC) $(OBJS) -o $(EXE) $(CFLAGS)
.c.o:
$(CC) -o $@ -c $(CFLAGS) $<
clean:
rm -rf $(OBJS) $(EXE)
test.c:
/*************************************************************************
> File Name: test.c
> Author: cyf
> Mail: XXX@qq.com
> Created Time: 20160519 143131
************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "test.h"
int max(int a, int b)
{
return (a>b?a:b);
}
int add(int a, int b)
{
return a+b;
}
test.h:
/*************************************************************************
> File Name: test.h
> Author: cyf
> Mail: XXX@qq.com
> Created Time: 20160518 183355
************************************************************************/
#ifndef _TEST_H
#define _TEST_H
#ifdef __cplusplus
extern "C"
{
#endif
int max(int a, int b);
int add(int a, int b);
#ifdef __cplusplus
}
#endif
#endif
一、创建动态链接库
创建动态链接库有两种方法:
1.
gcc test.c -fPIC -shared -o libtest.so
-shared 该选项指定生成动态连接库(让连接器生成T类型的导出符号表,有时候也生成弱连接W类型的导出符号),不用该标志外部程序无法连接。
-fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。
创建成功后,在当前目录下多出一个libtest.so的文件。
cyf@cyf-Lenovo:~/workspace/c/study/so$ ls
libtest.so Makefile test.c test.h
2. 使用makefile-lib文件
生成该动态链接库的维护文件makefile-lib内容如下:
.SUFFIXES:.c.o
CC = gcc
all:libtest.so
SRCS = test.c
OBJS = $(SRCS:.c=.o)
libtest.so:$(OBJS)
$(CC) -s -shared -o $@$(OBJS)
.c.o:
$(CC) -o $@ -c $<
运行命令:
make -f makefile-lib
二、共享动态链接库
为了让动态链接库为系统所使用,需要维护动态链接库的配置文件--/etc/ld.so.conf.此文件内,存放着可被LINUX共享的动态链接库所在目录的名字(系统目录/lib,/usr/lib除外),各个目录名间以空白字符(空格,换行等)或冒号或逗号分隔.一般的LINUX发行版中,此文件均含一个共享目录/usr/X11R6/lib,为X window窗口系统的动态链接库所在的目录.
2.1 动态链接库配置文件
使用动态链接库管理命令ldconfig,ldconfig命令主要是在默认搜寻目录(/lib和/usr/lib)以及动态库配置文件/etc/ld.so.conf内所列的目录下,搜索出可共享的动态链接库(格式如前绍,lib*.so*),进而创建出动态装入程序(ld.so)所需的连接和缓存文件。缓存文件默认为/etc/ld.so.cache,此文件保存已排好序的动态链接库名字列表。
cyf@cyf-Lenovo:~/workspace/c/study/adatetime$ cat /etc/ld.so.conf
include /etc/ld.so.conf.d/*.conf
/home/cyf/workspace/c/study/so
2.2动态链接库管理命令
为了让动态链接库为系统所共享,还需运行动态链接库的管理命令--ldconfig.此执行程序存放在/sbin目录下.
ldconfig命令的用途,主要是在默认搜寻目录(/lib和/usr/lib)以及动态库配置文件/etc/ld.so.conf内所列的目录下,搜索出可共享的动态链接库(格式如前介绍,lib*.so*),进而创建出动态装入程序(ld.so)所需的连接和缓存文件.缓存文件默认为/etc/ld.so.cache,此文件保存已排好序的动态链接库名字列表.
ldconfig通常在系统启动时运行,而当用户安装了一个新的动态链接库时,就需要手工运行这个命令.
ldconfig命令行用法如下:
ldconfig [-v|--verbose] [-n] [-N] [-X] [-f CONF] [-C CACHE] [-r ROOT] [-l][-p|--print-cache] [-c FORMAT] [--format=FORMAT] [-V] [-?|--help|--usage]path...
ldconfig可用的选项说明如下:
(1) -v或--verbose : 用此选项时,ldconfig将显示正在扫描的目录及搜索到的动态链接库,还有它所创建的连接的名字.
(2) -n : 用此选项时,ldconfig仅扫描命令行指定的目录,不扫描默认目录(/lib,/usr/lib),也不扫描配置文件/etc/ld.so.conf所列的目录.
(3) -N : 此选项指示ldconfig不重建缓存文件(/etc/ld.so.cache).若未用-X选项,ldconfig照常更新文件的连接.
(4) -X : 此选项指示ldconfig不更新文件的连接.若未用-N选项,则缓存文件正常更新.
(5) -f CONF : 此选项指定动态链接库的配置文件为CONF,系统默认为/etc/ld.so.conf.
(6) -C CACHE : 此选项指定生成的缓存文件为CACHE,系统默认的是/etc/ld.so.cache,此文件存放已排好序的可共享的动态链接库的列表.
(7) -r ROOT : 此选项改变应用程序的根目录为ROOT(是调用chroot函数实现的).选择此项时,系统默认的配置文件/etc/ld.so.conf,实际对应的为ROOT/etc/ld.so.conf.如用-r /usr/zzz时,打开配置文件/etc/ld.so.conf时,实际打开的是/usr/zzz/etc/ld.so.conf文件.用此选项,可以大大增加动态链接库管理的灵活性.
(8) -l : 通常情况下,ldconfig搜索动态链接库时将自动建立动态链接库的连接.选择此项时,将进入专家模式,需要手工设置连接.一般用户不用此项.
(9) -p或--print-cache : 此选项指示ldconfig打印出当前缓存文件所保存的所有共享库的名字.
(10) -c FORMAT 或 --format=FORMAT : 此选项用于指定缓存文件所使用的格式,共有三种:old(老格式),new(新格式)和compat(兼容格式,此为默认格式).
(11) -V : 此选项打印出ldconfig的版本信息,而后退出.
(12) -? 或 --help 或 --usage : 这三个选项作用相同,都是让ldconfig打印出其帮助信息,而后退出.
2.3动态链接库如何共享
了解了以上知识,我们可以采用以下三种方法来共享动态链接库:(注:均须在超级用户状态下操作,以我的动态链接库libmy.so共享过程为例)
(1)将动态链接库所在目录名追加到动态链接库配置文件/etc/ld.so.conf中.
cyf@cyf-Lenovo:~/workspace/c/study/so$ su
密码:
root@cyf-Lenovo:/home/cyf/workspace/c/study/so# ldconfig
root@cyf-Lenovo:/home/cyf/workspace/c/study/so# pwd>>/etc/ld.so.conf
root@cyf-Lenovo:/home/cyf/workspace/c/study/so# ldconfig 'pwd'
/sbin/ldconfig.real: relative path `pwd' used to build cache
cyf@cyf-Lenovo:~/workspace/c/study/so$ ldd test_demo
linux-vdso.so.1 => (0x00007ffe647be000)
libtest.so =>/home/cyf/workspace/c/study/so/libtest.so (0x00007f6adfc0e000)
libc.so.6 =>/lib/x86_64-linux-gnu/libc.so.6 (0x00007f6adf849000)
/lib64/ld-linux-x86-64.so.2(0x00007f6adfe10000)
(2)拷贝动态链接库到系统共享目录下,或在系统共享目录下为该动态链接库建立个连接(硬连接或符号连接均可,常用符号连接).这里说的系统共享目录,指的是LINUX动态链接库存放的目录,它包含/lib,/usr/lib以及/etc/ld.so.conf文件内所列的一系列目录.
cp libmy.so /home/cyf/workplace/c/study/so
ldconfig
或:
ln -s `pwd`/libmy.so /lib
ldconfig
(3)利用动态链接库管理命令ldconfig,强制其搜索指定目录,并更新缓存文件,便于动态装入.
ldconfig `pwd`
三、动态函数的程序的编译
将test.c与动态库libtest.so链接生成执行文件test,我在Makefile文件已经写好
cyf@cyf-Lenovo:~/workspace/c/study/so$ make
gcc -o test_demo.o -c -g -O2 -Wall -L. -ltest test_demo.c
gcc test_demo.o -o test_demo -g -O2 -Wall -L. -ltest
单独执行下面命令亦可生成test_demo
gcc test_demo.c -L. -ltest -o test_demo
-L.:表示要连接的库在当前目录中
-ltest:编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.so来确定库的名称
这时候找不到libtest.so, 是动态链接库的查找路径出问题.
二、运行
cyf@cyf-Lenovo:~/workspace/c/study/so$ ./test_demo
max=5
add=9
Linux下动态库文件的扩展名为".so"(Shared Object)。按照约定,所有动态库文件名的形式是libname.so(可能在名字中加入版本号)。这样,线程函数库被称作libthread.so。静态库的文件名形式是libname.a。共享archive的文件名形式是libname.sa。共享archive只是一种过渡形式,帮助人们从静态库转变到动态库。
在《LINUX下动态链接库的创建与应用》一文中,我介绍了LINUX动态链接库的基本知识.其要点是:用户根据实际情况需要,利用dlopen,dlsym,dlclose等动态链接库操作函数,装入指定的动态链接库中指定的函数,然后加以执行.程序中使用很少的动态函数时,这样的做法尚可.如果程序需要调用大量的动态函数,那么采用这样的编程手段将是非常繁复的,所以我们必须使用一种更为聪明的办法,以减少代码量,提高工作效率.这就是现在我要举例介绍的《LINUX动态链接库高级应用》.
参考:http://www.cnblogs.com/hoys/archive/2010/10/28/1863253.html