看起来GCC链接器并不关心在两个文件中定义的一个变量。我怀疑这是第三方图书馆造成麻烦的原因。
拿这个:
文件a.cpp包含:
int foo;
//do things with it.
文件b.cpp包含:
int foo;
//do other things with it.
文件c.cpp包含:
extern int foo;
//do other things with it.
它们都是由gcc编译为.o文件,然后作为共享对象链接。
gcc -fPIC -c a.cpp
gcc -fPIC -c b.cpp
gcc -fPIC -c c.cpp
ld *.o -shared -soname,mylib -o mylib
链接器根本没有抱怨,但结果二进制文件行为不端。我们怀疑至少有一些此类冲突,并希望找到它们。什么样的链接器选项可以让我们检测它们?
(有趣的是,如果两个文件中的变量都已初始化(int foo=0
),则会产生错误。)
答案 0 :(得分:1)
现在保持 - 你是否在这两个文件中将foo用于两个不同的目的?这肯定会导致运行时错误。如果foo需要是全局的,那么它应该只在一个模块中定义 - 链接器可以接受它,但你仍然只能获得一个foo副本。如果它不需要是全局的,则应将其声明为'static int foo;'
答案 1 :(得分:1)
这是gcc / ld中的严重设计错误,使用MSVC时不会发生这种情况。它不会发生链接程序,只有共享库。链接程序时,链接器确保满足所有外部引用,至少在链接时。链接共享库时,它不会。相反,没有定义的外部引用只是悬而未决,参数(在ld手册页中给出)是必须在加载时动态地解析符号,所以没有必要检查它。如果你使用共享库的愚蠢功能从可执行文件中获取符号,那也很难。
你的节目不会行为不端。如果指定在加载时必须满足库中的符号,则会出现加载时错误,如果指定延迟链接,则仍会出现错误,但仅在第一次使用符号时出现(AFAIK!)
一些较旧的操作系统,我相信BSD,例如,允许不满意的外部指针保留为NULL,以便您可以编写“在程序中”检查以查看符号是否已链接。 Linux ld至少不支持这种AFAIK。
有一个链接器开关可以强制满足共享库的外部引用,但是在可移植构建中很难正确使用它,因为它要求您显式链接处理器的启动库。
我认为这是一个非常严重的设计错误,并尝试提交错误报告。在我自己的产品中,我们很高兴能够在Cygwin下构建,因为它下面使用的MSVC链接器不允许这种行为,在我的代码中发现了很多错误。
答案 2 :(得分:0)
似乎编译器选项-fno-common
强制所有变量被初始化,因此它会在链接时触发错误。