C/C++:GCC/G++ -Wl,-soname 链接选项作用

C/C++:GCC/G++ -Wl,-soname 链接选项作用

-Wl 在 GCC/G++ 中是为了将后面的 option 传递给 链接器。

Code:

mymath.h:

#ifndef _MYMATH_H
#define _MYMATH_H

int add(int, int);
int sub(int, int);
int mul(int, int);
int div(int, int);

#endif
mymath.c:

#include "mymath.h"

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

int sub(int a, int b)
{
    return a - b;
}

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

int div(int a, int b)
{
    return a / b;
}
main.c:

#include 
#include 

#include "mymath.h"

int main()
{
    int a = 20;
    int b = 5;

    printf("add(%d, %d)=%d\n", a, b, add(a, b));
    printf("sub(%d, %d)=%d\n", a, b, sub(a, b));
    printf("mul(%d, %d)=%d\n", a, b, mul(a, b));
    printf("div(%d, %d)=%d\n", a, b, div(a, b));

    return 0;
}
makefile:

SRC = mymath.c
OBJS = $(SRC:%.c=%.o)

LIB = libmymath.so
SONAME = $(LIB)
CC = gcc -std=gnu99 -fPIC
CFLAGS = -g -O2 -Wall -Wextra
LDFLAGS = -Wl,-soname,$(SONAME)
DEPLIBS =
SHARED = -shared

.c.o:
    $(CC) $(CFLAGS) -o $@ -c $<
    @echo "Compile $< to $@ OK"

all:
    @make libmymath

libmymath: $(OBJS)
    $(CC) -o $(LIB) $(SHARED) $(LDFLAGS) $(OBJS) $(DEPLIBS)

clean:
    @rm -f $(OBJS)
    @rm -f $(LIB)

.PHONY: all clean

CASE 1

1.编译 mymath 动态链接库:

[test1280@localhost jiang]$ make
make[1]: Entering directory `/home/test1280/jiang'
gcc -std=gnu99 -fPIC -g -O2 -Wall -Wextra -o mymath.o -c mymath.c
Compile mymath.c to mymath.o OK
gcc -std=gnu99 -fPIC -o libmymath.so -shared -Wl,-soname,libmymath.so mymath.o 
make[1]: Leaving directory `/home/test1280/jiang'

2.编译 main 并链接 libmymath.so 动态链接库:

[test1280@localhost jiang]$ gcc -o main main.c -lmymath -L.

3.执行

[test1280@localhost jiang]$ ./main
add(20, 5)=25
sub(20, 5)=15
mul(20, 5)=100
div(20, 5)=4

我们已经完成编译 libmymath.so 动态库并编译 main 程序并成功执行。

查看 main 相关的信息:

C/C++:GCC/G++ -Wl,-soname 链接选项作用_第1张图片

查看 libmymath.so 相关信息:

C/C++:GCC/G++ -Wl,-soname 链接选项作用_第2张图片


如果我们修改 makefile 中 SONAME 变量为其他值,将会发生什么?


CASE 2

1.修改 makefile 中 SONAME 变量

SONAME = libmymath.1.so

2.编译 mymath 动态链接库:

[test1280@localhost jiang]$ make
make[1]: Entering directory `/home/test1280/jiang'
gcc -std=gnu99 -fPIC -g -O2 -Wall -Wextra -o mymath.o -c mymath.c
Compile mymath.c to mymath.o OK
gcc -std=gnu99 -fPIC -o libmymath.so -shared -Wl,-soname,libmymath.1.so mymath.o 
make[1]: Leaving directory `/home/test1280/jiang'

注意:soname 后紧跟 libmymath.1.so。

3.编译 main 并链接 libmymath.so 动态链接库:

[test1280@localhost jiang]$ gcc -o main main.c -lmymath -L.

4.执行

[test1280@localhost jiang]$ ./main
./main: error while loading shared libraries: libmymath.1.so: cannot open shared object file: No such file or directory

链接器报错找不到动态链接库: libmymath.1.so。

这里明明有动态链接库文件 libmymath.so,而且编译链接时指定的动态库也是 libmymath.so,为什么在运行时,

链接器 ld 会去找 libmymath.1.so 而不是 libmymath.so 呢?

Bingo!这就是 soname 的作用:影响一个可执行文件在链接器 ld 加载动态链接库时实际查找的动态库文件名字。

查看 main 相关的信息:

C/C++:GCC/G++ -Wl,-soname 链接选项作用_第3张图片

可见,虽然编译链接生成 main 时指定的是 libmymath.so 这个动态库文件,但实际依赖的却是 libmymath.1.so 动态库。

查看 libmymath.so 相关信息:

C/C++:GCC/G++ -Wl,-soname 链接选项作用_第4张图片

在库文件中的 SONAME 字段,其值就是我们在链接生成动态链接库时,soname 选项的值。

所有链接生成可执行文件时使用了 libmymath.so ,实际生成的可执行文件将依赖于 libmymath.1.so,在运行时 ld 将会查找此库文件。


man ld 查找 soname:


soname 指定了动态链接库的简单共享名。

在链接中间文件(.o)生成动态链接库时,若设定此选项,则其值将会添加到动态链接库文件的 SONAME 字段中。

In Unix and Unix-like operating systems, a soname is a field of data in a shared object file.

参考:https://en.wikipedia.org/wiki/Soname

每个动态库库的 SONAME 字段可以将各个库独立区分开来。

参考:https://www.xuebuyuan.com/3121941.html

在链接动态库文件生成可执行文件 main 时,还会将指定的 libmymath.so 动态库的 SONAME 值写入到 main 可执行文件中。

当 ld 加载 main 依赖的动态库时,会查找 libmymath.1.so 这个文件,因为在 main 中其指明的是依赖于 libmymath.1.so。

所以,在运行 main 时,ld 找不到 libmymath.1.so 这个动态库文件,而 libmymath.so 又不是 ld 寻找的对象,故报错。

我们可以通过添加 libmymath.1.so 软链接解决链接器报错问题。

[test1280@localhost jiang]$ ln -s libmymath.so libmymath.1.so
[test1280@localhost jiang]$ ./main
add(20, 5)=25
sub(20, 5)=15
mul(20, 5)=100
div(20, 5)=4

C/C++:GCC/G++ -Wl,-soname 链接选项作用_第5张图片

soname 也常被用来实现提供动态库向后兼容的能力。

The soname is often used to provide version backwards-compatibility information.

参考:https://en.wikipedia.org/wiki/Soname


相关命令:

readelf -d $PROG

objdump -p $PROG

ldd $PROG

引用自:

1.https://en.wikipedia.org/wiki/Soname
2.https://www.xuebuyuan.com/3121941.html
3.http://www.cnblogs.com/tianzeng/p/9217465.html

你可能感兴趣的:(LINUX,C-C++,OTHER)