linux c动态库

2021-03-07

Linux下动态库文件的文件名形如 libxxx.so,其中so是 Shared Object 的缩写,即可以共享的目标文件。

在链接动态库生成可执行文件时,并不会把动态库的代码复制到执行文件中,而是在执行文件中记录对动态库的引用。

程序执行时,再去加载动态库文件。如果动态库已经加载,则不必重复加载,从而能节省内存空间。

动态库编译方法

示例程序

1
int add(int a, int b) { return a+b; };
1
gcc -fPIC -shared -o libadd.so add.c

动态库加载方式一

1
2
3
4
5
6
7
#include<stdio.h>

int main(void)
{
    add(1,2);
    return 0;
}

编译时链接

gcc -o main main.c -L . -ladd

直接运行会报错

1
./a1.out: error while loading shared libraries: libadd.so: cannot open shared object file: No such file or directory

我们有两种方法解决这个问题:

  1. 将libtest.so库放到系统路径下
  2. 指定当前进程动态库搜索路径

第一种方法:

1
$ cp libadd.so /usr/lib

第二种方法:

1
$ export LD_LIBRARY_PATH=./

导入LD_LIBRARY_PATH环境变量,指定库搜索路径,使得a.out程序能够找到libadd.so。

动态库加载方式二

采用dlopendlsymdlclose加载动态链接库

dlopen dlclose

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
#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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
#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

1
2
3
4
5
#include <dlfcn.h>

char *dlerror(void);

Link with -ldl.

示例

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// 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
words: 655 tags: linux c