GCC 优化在运行时导致“未定义的符号”

Posted

技术标签:

【中文标题】GCC 优化在运行时导致“未定义的符号”【英文标题】:GCC Optimization results in "Undefined symbol" at runtime 【发布时间】:2011-03-30 12:06:08 【问题描述】:

我现在有一个让我很困惑的问题: 我有一个用 C++ 编写的软件,并且链接到 C 中的一个库。我使用通常的方法包含头类

extern "C" 
    #include <libheader.h>

只要我不使用 gcc 的优化,一切正常。一旦我打开偶数 -O1,即第一个优化级别,在运行期间我会收到来自该库的符号的“未定义符号”错误。但是,该名称已经过名称修改,应该由于extern "C" 而被禁用。

调用相关符号的函数是内联的,以防万一。使用的编译器是 gcc 4.4.3。

老实说,我什至不知道要搜索什么,所以如果你们中的某个人能给我一些这种行为的理由,我将不胜感激。

感谢您的支持。

【问题讨论】:

你能去掉内联(即使函数不内联),看看它是否开始工作? 替代@satuon 的建议,您能否让内联函数调用包装C 函数的C++ 函数,看看它是否开始工作? 感谢您的回复!我尝试了这两个建议,但是仍然找不到该符号。 在运行时???在 compiled 语言中,runtime 到底怎么会出现“未定义符号”错误?你在使用某种动态库吗? @AndreyT 我认为这是包含另一个共享库的共享库的常见行为。不止一次遇到过这个问题(尽管原因不同) 【参考方案1】:

您说您将 libheader.h 文件包含在 extern "C" 块中,但链接器正在寻找的符号已被名称损坏。

这表明libheader.h 也被包含在extern "C" 块之外(extern "C" 块内的包含可能是一个 nop,因为在 libheader.h 中包含守卫)。

寻找可能包含libheader.h 的其他方式。 GCC 的 -E 和/或各种 -M 选项可能会或可能不会对此有所帮助。或者(如果只是为了测试)将extern "C" 块移动到libheader.h 内:

// at start of libheader.h:
#ifdef __cplusplus
extern "C" 
#endif

/* existing contents of libheader.h */
// ...

// at end of libheader.h:
#ifdef __cplusplus

#endif

请注意,链接规范可以嵌​​套,因此您不必删除 #include 站点上现有的 extern "C" 块。

我不知道为什么问题只会发生在优化的构建中,除了可能包含调用函数的非内联版本的 .c 或 .cpp 文件获得正确的标题,并且只需要一个翻译单元获取错误的标题并内联调用函数以查看问题。

【讨论】:

谢谢!如果这是原因,那么如何追踪问题可能是一个好主意。可悲的是,我下周五才有时间调查,届时再报告。【参考方案2】:

如果你有一个函数在未内联时定义但在内联时未定义,那么问题应该很容易定义。

你在某个地方使用了这个函数,但没有包含它的头文件。

查看所有调用此函数的文件并确保包含标题。

【讨论】:

【参考方案3】:

是否有可能定义调用内联函数的标头包含库的标头没有extern "C" 包装器,并且在其他任何地方都使用了包装器行?

您是否尝试过其他级别,例如-O2

您是否尝试取消内联您的函数?

【讨论】:

感谢您的想法。是的,正确文件的标题肯定使用extern "C" 包装器。 -O2 和 -O3 具有相同的效果。如上所述,删除内联也无济于事。 @Thilo 具体来说,您删除了内联并将函数从头文件移动到源文件,因此编译器无法决定自动内联它? 啊...谢谢您的澄清。忘记将先前内联的函数移动到源文件。这解决了问题。然而,结果并不是很优雅,因为内联函数可能会明显更快。【参考方案4】:

extern "C" ... 包装C 头文件并不总是有效; 通常,需要将标头设计为可与两种语言一起使用 他们可以同时使用两种语言。

在这种情况下,如果没有更多细节,很难准确地说出是什么 发生了,但是 inline 关键字在 C 和 C++;我不希望带有 inline 函数的标头在此工作 方式。 (顺便说一句,我没想到你会出现这些症状,但他们 也不要让我特别惊讶。)

处理这个问题的正确方法是坚持让供应商 库提供了一个设计用于两种语言的标题。

否则,处理此问题的正确方法是编写自己的 C 代码,其中包含标头并包装了您的所有函数 需要,并为此 C 代码编写自己的标头,该标头旨在 被包括在两种语言中。我承认,这需要做很多工作; 让供应商完成他的工作,而不是只做一半 他。

【讨论】:

以上是关于GCC 优化在运行时导致“未定义的符号”的主要内容,如果未能解决你的问题,请参考以下文章

使用 gcc 11 构建的协议中未定义的符号

未定义的符号'BIO_ctrl @@ libcrypto.so.10'的引用

gcc编译器选项-Wl,--no-undefined(告诉链接器在链接过程中不允许有未定义的符号)(gcc编译器和链接器是分离的工具,它们需要通过选项来进行通信)

使用 numpy 和 gdal 的 Python C 扩展在运行时给出未定义的符号

Python ctypes加载错误:未定义的符号

imp : 符号查找错误 : 未定义的符号 sldext