【问题标题】:Understanding the origin of a linker duplicate symbol error了解链接器重复符号错误的根源
【发布时间】:2011-09-01 06:02:47
【问题描述】:

我有一个以前编译过的 c++ 程序,但在使用 Jamfiles 后,程序不再编译,ld 发出了一个duplicate symbol error。在连续恢复到原始 Jamfiles、运行bjam clean、手动删除对象并在 MacOs 10.6.7 上从带有 gcc 前端的 clang 切换到 gcc 4.2.1 之后,这种情况仍然存在。

程序的简化描述是有main.cpp和四个文件a.h,cppb.h,cpp,它们被编译成一个静态库,链接到main.omain.cppb.cpp 都通过两个不同的中间文件依赖于包含违规符号 off.h 的文件,但 a.ha.cpp 都不依赖于 off.h

在你问之前,我确保所有文件都包含在多个定义保护中(#ifndef#define#endif),虽然我确实找到了一个缺少它们的文件,但它没有引用 @ 987654337@。更重要的是,b.h 不包含任何引用off.h 的内容,只有实现b.cppoff.h 进行任何引用。仅这一点就让我感到困惑。

为了增加我的困惑,我能够从b.cpp 中删除对off.h 的引用,并且正如预期的那样,它重新编译成功。但是,当我重新添加引用时,它也编译成功,并在清除目标文件后继续这样做。我仍然不知道为什么它无法编译,特别是考虑到符号不应该发生冲突,我已经防止了符号重复,并且我已经摆脱了任何先前/不完整的构建。

由于我能够成功编译我的程序,我怀疑我能否重现它来测试任何建议。但是,我很好奇这是如何发生的,如果我在未来遇到这种行为,如果有超出我所做的事情,我可以做些什么来解决它?

【问题讨论】:

  • @Neil,并非如此。注意:在我找到“解决方案”之前,我多次尝试编译都能够重现此问题。而且,由于问题不再出现,我希望答案更理论化,而不是具体化。但是,我试图更好地了解在不存在冲突时可能导致两个单独编译单元中引用的符号发生冲突的原因。以及我可以采取哪些额外步骤来诊断和缓解问题。
  • 我给这 90% 的机会,你实际上并没有清理所有的目标文件(可能是 libtool 或某些东西将它们隐藏在隐藏目录中?)。然而,如果你不能重现它,就没有办法追根究底。
  • @bdonlan,有趣的想法,如果 libtool 执行这种缓存会很烦人。据推测,应该通过bjam cleanrm *.o *.a 删除所有对象和库。如果不是,那么在重新编译时,它们应该被覆盖。此外,默认情况下,当您更改编译器时,bjam 会在不同的目录中编译,因此 libtool 或其他工具的任何缓存都会使这种分离毫无意义。此外,在我看来,这种缓存会使创建可靠的构建变得困难,从而使其相当令人反感。
  • @bdonlan,关于你关于不可约化的观点,作为前测试人员,这些类型的问题对测试人员和开发人员来说都是最令人沮丧的,他们经常会因此而被拒绝。但是,我认为这些问题是有道理的:尽管采取了预防措施,我怎么会陷入这种情况?一旦在这种情况下,可以做些什么来摆脱它?虽然缺乏具体的修复,但这些问题暴露了构建过程/语言中的潜在缺陷,新手/中级程序员可能不清楚。
  • @bdonlan,bjam 似乎使用rm -f,或操作系统的等价物,我正在为我的具有清除功能的 VCS 使用 mercurial。

标签: c++ gcc linker clang


【解决方案1】:

这通常是在头文件中定义对象的结果,而不仅仅是声明它。考虑:

h.h

#ifndef H_H_
#define H_H_
int i;
#endif

a.cpp

#include "h.h"

b.cpp

#include "h.h"
int main() {}

这将产生一个重复的符号i。解决方案是在头文件中声明对象:extern int i;,并在源代码文件之一中定义它:int i;

【讨论】:

  • 该符号是在标头中内联声明的函数,但缺少 this 建议可能需要的关键字 inline。但是,我对您的解决方案的问题是,为什么目标文件a.o 中的int i 以与b.o 中的冲突的方式暴露?据我了解,这不应该发生。我错过了什么?
  • 1) 在文件范围内声明的名称具有外部链接。 2) 一个对象可以在多个翻译单元中声明,但必须只定义一次。
  • 我越想这个,就越觉得这很可能是原因。但是,除非我可以重复一遍,否则我会一直困惑为什么它会在某一天编译,而不是下一个。
  • @Robᵩ:你能为头文件中的类声明提出一些解决方案吗?
  • @9000 - 你可以 #include 两个文件中的相同标题,如果它没有像int i;int i = 17; 这样的行。它只能有声明,不能有定义——extern int i; 可以。
猜你喜欢
  • 2012-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-26
  • 2014-01-16
  • 1970-01-01
相关资源
最近更新 更多