Linux中共享库的建立
Linux中共享库的建立
大多数LINUX程序都使用共享库。如果你感觉不到的话,大多数的C程序要用到的共享库libc.so.X,其中X是版本号。
1、检查程序的共享库
用ldd程序可以查询可执行程序所需要的共享库。下面是对一个用gcc2.96编译器编译的一般C程序做的查询(该程序使用的是ELF二进制格式):
ldd a.out
libc.so.6 => /lib/libc.so.6 (0x4003a000)
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
2、建立共享库
用ELF建立应用程序的共享库是比较容易的,下面以一个简单的例子来说明:
/*
File: lddemo.c
Demonstrate use of dynamic linking.
*/
#include
#include
/* demo Data structure */
typede tagUSERINFO {
char *name;
int age;
}USERINFO;
typedef USERINFO* PUSERINFO;
void* Init(char *name)
{
PUSERINFO pUserInfo = (PUSERINFO)calloc(1, sizeof(USERINFO));
if( name ) pUserInfo->name = malloc(strlen(name)+1);
strcpy( pUserInfo->name, name );
printf("created: %s\n", name);
return pUserInfo;
}
void Show(void *pVar)
{
PUSERINFO pUserInfo = ( PUSERINFO )pVar;
printf( "Show: %s\n", pUserInfo->name );
}
void Free(void *pVar)
{
PUSERINFO pUserInfo = (PUSERINFO)pVar;
if ( !pUserInfo ) return;
if ( pVar->name ) {
printf( "Free: %s\n",pVar->name );
free(pVar->name);
}
free(pVar);
}
该文件中有三个函数:
Init: 分配必要的存储空间,初始化数据
Show: 显示数据
Free: 释放所有的存储空间
以下是建立共享库libddemo.so的具体过程:
a、用-fPIC选项编译所有的源文件,本例只有lddemo.c
$ gcc -fIPC -c lddemo.c
b、用-share选项将目标连成共享库,并为连接器提供合适的连接选项。为建立libddemo.so.1共享库,使用如下命令:
$ gcc -shared -Wl,-soname,libddemo.so.1 -o libddemo.so.1.0 lddemo.o
c、建立一系列的符号链接,以便使用共享库的程序根据标准名来引用它,对于示例,其标准名为libddemo.so,可以用ln建立符号链接:
$ ln -s libddemo.so.1.0 libddemo.so.1
$ ln -s libddemo.so.1 libddemo.so
d、测试共享库时,用下列命令定义和输出LD_LIBRARY_PATH环境变量:
$ export LD_LIBRARY_PATH=pwd:$LD_LIBRARY_PATH
至此,共享库已经建立完毕,下面是将它添加到系统中,一般将它复制到linux标准库目录,如/usr/local/lib,然后运行ldconfig程序将它添加到linux共享库中。下面的操作可以安装供所有用户使用的共享库( 必须有root权限):
# cp libddemo.so.1.0 /usr/local/lib
# ldconfig
# cd /usr/local/lib
# ln -s libddemo.so.1 libddemo.so
3、动态加载共享库
通过ELF很容易在程序中加载共享库并使用共享库中的函数。头文件说明了加载和使用共享库的函数。在dlfcn.h头文件中说明了四个用于动态加载的函数:
void *dlopen(const char *filename, int flag): 加载filename指定的共享库,并返回共享库指针。该标志可以是RTD_LAZY(当执行库的代码时还原未定义的符号)或RTD_NOW(执行dlopen前还原所有未定义符号)。失败返回NULL。
const char *dlerror(void),如果dlopen失败,调用dlerror以获取包含错误信息的字符串。
void *dlsym(void *handle,char *symbol),从handle标识的共享库(由dlopen返回)中特定symbol(函数名)的地址。
int dlclose(void *handle), 如果没有其他人使用共享库,就无需加载。
当使用这些函数时, 用下列预处理器指令包含头文件
#include
下面是一简单的测试程序表明如何加载和使用在上一节建立的共享库libddemo.so中定义的目标函数:
/*
* File dltest.c
*Test dynamic linking
*/
#include
#include
int main(void)
{
void *dlobj;
void *(*InitCall)(char *name);
void (*ShowCall)(void *pUserInfo);
void (*FreeCall)(void *pUserInfo);
/* open the shared library and set up the function pointers */
if( dlobj = dlopen("libddemo.so.1",RTLD_LAZY))
{
void *pUserInfo;
InitCall = dlsym(dlobj, "Init");
ShowCall = dlsym(dlobj, "Show");
FreeCall = dlsym(dlobj, "Free");
/* Call the interfaces */
pUserInfo = (*InitCall)("stonepine");
(*ShowCall)(pUserInfo);
(*FreeCall)(pUserInfo);
}
return (0);
}
测试程序非常明了:加载共享库,获取库函数指针,通过指针调用函数。
通过在添加gcc编译选项-ldl来编译程序,以便使用中说明的函数,下面是如何建立程序dltest:
$ gcc -o dltest dltest.c -ldl
运行dltest:
$./ldtest
created: stonepine
Show: stonepine
Free: stonepine
以上通过一个简单的示例程序说明了如何建立和使用共享库,如果用于复杂的工程中,可以通过建立shell脚本文件,以及对Makefile的修改等方法来实现,对此不再细说。
使用共享库的优点是共享库的更新独立于应用程序,另外可以发行不带原代码的函数库,对于某些商业运作这是必须的,还有就是降低了用户的二次开发的复杂度,二次开发的用户只是通过标准库函数调用形式,而动态库的动态加载特性更能降低对运行环境的存储设备、内存的要求。
发布人:stonepine 来自: