当前位置:  开发笔记 > 编程语言 > 正文

链接器为什么不抱怨重复的符号?

如何解决《链接器为什么不抱怨重复的符号?》经验,为你挑选了1个好方法。

我有一个dummy.hpp

#ifndef DUMMY
#define DUMMY
void dummy();
#endif

和一个dummy.cpp

#include 
void dummy() {
      std::cerr << "dummy" << std::endl;
}

和main.cpp使用dummy()

#include "dummy.hpp"
int main(){

    dummy();
    return 0;
}

然后,我编dummy.cpp三个库libdummy1.alibdummy2.alibdummy.so

g++ -c -fPIC dummy.cpp
ar rvs libdummy1.a dummy.o
ar rvs libdummy2.a dummy.o
g++ -shared -fPIC -o libdummy.so dummy.cpp

    当我尝试编译main并链接虚拟库时

    g++ -o main main.cpp -L. -ldummy1 -ldummy2
    

    链接器不会产生重复的符号错误。当我静态链接两个相同的库时,为什么会发生这种情况?

    当我尝试

    g++ -o main main.cpp -L. -ldummy1 -ldummy
    

    也没有重复的符号错误,为什么?

加载程序似乎总是选择动态库,而不是选择.o文件中编译的代码。

.so如果它同时存在于.a.so文件中,是否意味着始终从文件加载相同的符号?

这是否意味着静态库中的静态符号表中的符号永远不会与.so文件中的动态符号表中的符号冲突?



1> Jonathan Lef..:

方案1(双静态库)或方案2(静态和共享库)都没有错误,因为链接器会从遇到的静态库或第一个共享库中获取第一个目标文件,从而提供符号定义它还没有一个定义。它只是忽略了以后对同一符号的任何定义,因为它已经有了一个好的符号。通常,链接器仅从库中获取所需的内容。对于静态库,这是完全正确的。对于共享库,如果共享库满足任何缺少的符号,则所有符号都可用。对于某些链接器,共享库的符号无论如何都可以使用,但是其他版本仅在共享库提供至少一个定义的情况下记录对共享库的使用。

这也是为什么您需要在目标文件之后链接库。您可以添加dummy.o链接命令,只要这些命令出现在库之前,就不会有麻烦。将dummy.o文件添加到库之后,您将得到双重定义的符号错误。

你这双定义遇到问题的唯一情况是,如果有图书馆1的对象文件定义了dummyextra,并且有一个目标文件在图书馆2种规定dummyalternative,并且代码需要两者的定义extraalternative-那么你有重复的定义dummy会引起麻烦。实际上,目标文件可能在单个库中,并且会引起麻烦。

考虑:

/* file1.h */
extern void dummy();
extern int extra(int);

/* file1.cpp */
#include "file1.h"
#include 
void dummy() { std::cerr << "dummy() from " << __FILE__ << '\n'; }
int extra(int i) { return i + 37; }

/* file2.h */
extern void dummy();
extern int alternative(int);

/* file2.cpp */
#include "file2.h"
#include 
void dummy() { std::cerr << "dummy() from " << __FILE__ << '\n'; }
int alternative(int i) { return -i; }

/* main.cpp */
#include "file1.h"
#include "file2.h"
int main()
{
    return extra(alternative(54));
}

由于的双重定义dummy,即使主代码未调用,您也无法从显示的三个源文件中链接目标文件dummy()

关于:

加载程序似乎总是选择动态库,而不是在.o文件中进行编译。

没有; 链接器始终尝试无条件加载目标文件。当在命令行遇到库时,它将扫描库,并收集所需的定义。如果目标文件在库之前,则没有问题,除非两个目标文件定义相同的符号(“一个定义规则”会响起钟声吗?)。如果某些目标文件遵循库文件,那么如果库文件定义了后来的目标文件所定义的符号,则可能会发生冲突。请注意,启动时,链接器正在寻找的定义main。它从被告知的每个目标文件中收集定义的符号和参考符号,并不断添加代码(从库中),直到定义了所有参考符号为止。

它意味着同样的符号总是从加载.so的文件,如果是在双方.a.so文件?

没有; 这取决于首先遇到的那个。如果.a首先遇到,则.o文件会有效地从库中复制到可执行文件中(并且共享库中的符号会被忽略,因为可执行文件中已经存在该文件的定义)。如果.so最先遇到,.a则会忽略中的定义,因为链接器不再在寻找该符号的定义-它已经存在。

这是否意味着静态库中的静态符号表中的符号永远不会与.so文件中的动态符号表中的符号冲突?

您可能会有冲突,但是遇到的第一个定义将解析链接器的符号。如果满足引用的代码通过定义所需的其他符号引起冲突,则只会发生冲突。

如果我链接了2个共享库,是否会发生冲突并且链接阶段失败?

正如我在评论中指出的:

我的立即反应是“是的,您可以”。这将取决于两个共享库的内容,但是我相信您可能会遇到问题。 […沉思…]您将如何显示此问题?……这并不像乍看起来那样容易。证明这种问题需要什么?…或者我是否对此思考过多?… […该玩一些示例代码了…]

经过一些试验,我的临时经验性回答是“不,您不能”(或“不,至少在某些系统上,您不会遇到冲突”)。我很高兴我发了言。

取得上面显示的代码(2个标头,3个源文件),并在Mac OS X 10.10.5(Yosemite)上与GCC 5.3.0一起运行,我可以运行:

$ g++ -O -c main.cpp
$ g++ -O -c file1.cpp
$ g++ -O -c file2.cpp
$ g++ -shared -o libfile2.so file2.o
$ g++ -shared -o libfile1.so file1.o
$ g++ -o test2 main.o -L. -lfile1 -lfile2
$ ./test2
$ echo $?
239
$ otool -L test2
test2:
    libfile2.so (compatibility version 0.0.0, current version 0.0.0)
    libfile1.so (compatibility version 0.0.0, current version 0.0.0)
    /opt/gcc/v5.3.0/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 7.21.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1213.0.0)
    /opt/gcc/v5.3.0/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1.0.0)
$

.so用作Mac OS X上的扩展名是常规的(通常是.dylib),但它似乎可以工作。

然后,我修改了.cpp文件中的代码,以便在和之前extra()调用。重新编译并重建共享库后,我运行了程序。输出的第一行来自的调用。然后,您将获得和按此顺序生成的其他两行,因为调用顺序要求这样做。dummy()returnalternative()main()dummy()main()alternative()extra()return extra(alternative(54));

$ g++ -o test2 main.o -L. -lfile1 -lfile2
$ ./test2
dummy() from file1.cpp
dummy() from file2.cpp
dummy() from file1.cpp
$ g++ -o test2 main.o -L. -lfile2 -lfile1
$ ./test2
dummy() from file2.cpp
dummy() from file2.cpp
dummy() from file1.cpp
$

请注意,by调用的函数main()是与其链接的库中出现的第一个函数。但是(至少在Mac OS X 10.10.5上)链接器不会发生冲突。但是请注意,每个共享库中的代码都调用“自己的”版本dummy()-两个共享库之间关于哪个函数是不一致dummy()。(将dummy()函数放在共享库中的单独目标文件中会很有趣;然后dummy()调用哪个版本的?)但是在所示的极其简单的情况下,该main()函数仅能调用其中一个。dummy()功能。(请注意,对于这种行为,发现平台之间的差异并不奇怪。我已经确定了在哪里测试代码。如果您在某些平台上发现不同的行为,请告诉我。)

推荐阅读
手机用户2402852307
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有