-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
[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'
[test1280@localhost jiang]$ gcc -o main main.c -lmymath -L.
[test1280@localhost jiang]$ ./main
add(20, 5)=25
sub(20, 5)=15
mul(20, 5)=100
div(20, 5)=4
我们已经完成编译 libmymath.so 动态库并编译 main 程序并成功执行。
查看 main 相关的信息:
查看 libmymath.so 相关信息:
SONAME = libmymath.1.so
[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。
[test1280@localhost jiang]$ gcc -o main main.c -lmymath -L.
[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 相关的信息:
可见,虽然编译链接生成 main 时指定的是 libmymath.so 这个动态库文件,但实际依赖的却是 libmymath.1.so 动态库。
查看 libmymath.so 相关信息:
在库文件中的 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
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