-soname= --version-script 函数接口导出控制和版本控制


从glibc 源码中学习到的,库函数接口的 版本控制。主要使用soname和 version-script 两个知识点

相关源码:

https://github.com/zhiwei122126/zzwlib 

目标:假设我们创建一个 名称为 zzw 的库。

1、它的大版本号为 1

2、只导出我们想要导出的接口,其他接口不能导出。

3、第一版为 1.1 ,即libzzw.so.1.1,里面有一个接口add

4、第二版为 1.2, 即大版本号不变,即保持接口向前兼容。新增一个接口 mul。

5、main.elf 作为测试程序,它编译时,使用 libzzw.so.1 名称进行库的链接。

5.1 如果main.elf 中只使用 1.1 版本的接口,那么1.1 和 1.2 版本的so 都支持 main.elf 的运行。

5.2 如果main.elf 中使用 1.2 版本才加入的接口,那么编译时有 1.2 版本的库支持才可以链接通过,否则会包 找不到符号。

5.3 如果 main.elf 编译时使用 1.2 版本的库【也成功了】,后来又因为xx原因,把 zzw 库的版本降低到了 1.1 ; 那么main.elf 运行错误,报找不到对应版本的接口。

1、目录设置

.
├── README.md
├── build.sh
├── main.c
└── zzwlib
        ├── a.c
        ├── a.h
        └── ver.map

2、1.1 版本

a.c

int add_local(int a, int b) // 不希望 add_local 接口导出
{
    return a+b;
}

int add(int a, int b){
    return add_local(a,b);
}

a.h

extern int add(int a, int b);

ver.map

ZZWLIB_1.1{
    global:
        add;
    local:
        *;
};

编译

gcc -fPIC -shared zzwlib/a.c -Wl,-soname=libzzw.so.1 -o zzwlib/libzzw.so.1.1 -Wl,--version-script zzwlib/ver.map

main.c

#include 

#include "zzwlib/a.h"

int main(void){
    printf("add result is %d \n", add(2,3) );
    return 0;
}

测试

zhiwei@LAPTOP-CVSMCC72:~/work/c/version$ ./main.elf
add result is 5

导出符号和非导出符号

1、a.h 中只导出了 add 符号,不导出 add_local 【但是 objdump 还可以看到 add_local; 并没限制 main.c 里面使用 add_local 】。

2、ver.map 中只把 add 加入到global 中,add_local 不导出 【非导出符号,在 strip 时会被删除掉; objdump 时看到add_local 函数符号为local 类型,main.c 中无法使用

3、ver.map 中定义了 add 符号的版本为 ZZWLIB_1.1

用 没有 strip 的libzzw.so.1.1测试 - 还可以找到 非导出符号

gdb 调试时,可以直接在符号 add_local 上面下断点 - 3 

用 strip 后的libzzw.so.1.1测试 - 没导出的符号被删除

从7 可以看出,strip 后,libzzw.so 里面,add_local 符号已经删除掉了。无法使用了。

3、1.2 版本

a.c - 增加

int mul(int a, int b){
    return a*b;
}

a.h 

extern int add(int a, int b);

extern int mul(int a, int b); 

ver.map

ZZWLIB_1.1{
    global:
        add;
    local:
        *;
};

ZZWLIB_1.2{
    global:
        mul;
} ZZWLIB_1.1;

编译

gcc -fPIC -shared zzwlib/a.c -Wl,-soname=libzzw.so.1 -o zzwlib/libzzw.so.1.2 -Wl,--version-script zzwlib/ver.map

main.c

#include 

#include "zzwlib/a.h"

int main(void){
    printf("add result is %d \n", add(2,3) );
    printf("mul result is %d \n", mul(2,3) );
    return 0;
}

测试

zhiwei@LAPTOP-CVSMCC72:~/work/c/version$ ./main.elf
add result is 5
mul result is 6

4、版本交错测试

1.1 的 main.c 使用 1.2 的 libzzw,ok

1.2 的main.c 使用 1.2 的libzzw, OK

1.1 的main.c 使用 1.1 的libzzw OK

1.2 的main.c 使用 1.1 的libzzw,编译错误

1.2 的main.c 【编译使用1.2,编译完成后,手动修改链接到1.1】 运行错误