两个cpp文件。
//main.cpp
int cat = 3;
int main()
{
return 0;
}
//data.cpp
int cat = 10;
使用gcc分别编译成目标文件。gcc -c main.cpp
gcc -c data.cpp
然后执行gcc main.o data.o
结果报错:
data.o:(.data+0x0): multiple definition of `cat'
main.o:(.data+0x0): first defined here
collect2: error: ld returned 1 exit status
问题来了,如果我将data.cpp编译成动态库。gcc -fPIC -shared data.cpp -o libdata.so
然后执行gcc main.o libdata.so
就不会报错。
如果将data.o打包成静态库ar rcs libdata.a data.o
再执行gcc main.o libdata.a
也不会报错。
这是为什么?
使用nm命令查看libdata.so和libdata.a,都包含了符号'cat',gcc却没报multiple definition错误。
结论
强符号/弱符号
多个目标文件中含有相同名字全局符号的定义,那么这些目标文件链接的时候将会出现符号重复定义的错误。比如我们在目标文件A和目标文件B都定义了一个全局整形变量global,并将它们都初始化,那么链接器将A和B进行链接时会报错:
这种符号的定义可以被称为强符号(Strong Symbol)。有些符号的定义可以被称为弱符号(Weak Symbol)。对于C/C++语言来说,编译器默认函数和初始化了的全局变量为强符号,未初始化的全局变量为弱符号。
针对强弱符号的概念,链接器就会按如下规则处理与选择被多次定义的全局符号:
摘录来自《程序员的自我修养:链接、装载与库》 俞甲子 石凡 潘爱民
目标文件直接编译
main.o的符号表如下,可见cat为global类型
data.o符号表中cat也为global,强符号
初始化的全局变量是强符号,链接时如果有同名的强符号则会出现multiple definition的错误。
静态库
为了验证作为静态库时,data.o并未链接,现在我们在data.cpp中添加一个函数:
可见符号表中有_Z3foov,即我们定义的foo函数
链接该静态库输出a.out,过滤foo函数无内容,证明该data.o并没有被链接到a.out中,也就不存在冲突问题了。
PS: 可对比下修改data.cpp前后两次产生的a.out文件,两者的符号表是一样的,也证明了data.o并未链接。
推荐阅读
《程序员的自我修养:链接、装载与库》 俞甲子 石凡 潘爱民