linux c动态库
2021-03-07
Linux下动态库文件的文件名形如 libxxx.so,其中so是 Shared Object 的缩写,即可以共享的目标文件。
在链接动态库生成可执行文件时,并不会把动态库的代码复制到执行文件中,而是在执行文件中记录对动态库的引用。
程序执行时,再去加载动态库文件。如果动态库已经加载,则不必重复加载,从而能节省内存空间。
动态库编译方法
示例程序
int add(int a, int b) { return a+b; };
gcc -fPIC -shared -o libadd.so add.c
动态库加载方式一
#include<stdio.h>
int main(void)
{
add(1,2);
return 0;
}
编译时链接
gcc -o main main.c -L . -ladd
直接运行会报错
./a1.out: error while loading shared libraries: libadd.so: cannot open shared object file: No such file or directory
我们有两种方法解决这个问题:
- 将libtest.so库放到系统路径下
- 指定当前进程动态库搜索路径
第一种方法:
$ cp libadd.so /usr/lib
第二种方法:
$ export LD_LIBRARY_PATH=./
导入LD_LIBRARY_PATH环境变量,指定库搜索路径,使得a.out程序能够找到libadd.so。
动态库加载方式二
采用dlopen
、dlsym
、dlclose
加载动态链接库
dlopen dlclose
#include <dlfcn.h>
void *dlopen(const char *filename, int flags);
int dlclose(void *handle);
#define _GNU_SOURCE
#include <dlfcn.h>
void *dlmopen (Lmid_t lmid, const char *filename, int flags);
Link with -ldl.
dlsym
#include <dlfcn.h>
void *dlsym(void *handle, const char *symbol);
#define _GNU_SOURCE
#include <dlfcn.h>
void *dlvsym(void *handle, char *symbol, char *version);
Link with -ldl.
dlerror
#include <dlfcn.h>
char *dlerror(void);
Link with -ldl.
示例
// file : add.c
int add(int a, int b) { return a+b; };
// cmd: gcc -fPIC -shared -o libadd.so add.c
// 编译生成动态库文件
// file : demo.c
#include <stdio.h>
#include <stdlib.h> // EXIT_FAILURE
#include <dlfcn.h> // dlopen, dlerror, dlsym, dlclose
typedef int(* FUNC_ADD)(int, int); // 定义函数指针类型的别名
const char* dllPath = "./libadd.so";
int main()
{
void* handle = dlopen( dllPath, RTLD_LAZY );
if( !handle )
{
fprintf( stderr, "[%s](%d) dlopen get error: %s\n", __FILE__, __LINE__, dlerror() );
exit( EXIT_FAILURE );
}
do{ // for resource handle
FUNC_ADD add_func = (FUNC_ADD)dlsym( handle, "add" );
printf( "1 add 2 is %d \n", add_func(1,2) );
}while(0); // for resource handle
dlclose( handle );
}
// cmd : gcc -o demo demo.c -ldl; ./demo
// output: 1 add 2 is 3