让 GCC 链接器警告多个函数定义

Posted

技术标签:

【中文标题】让 GCC 链接器警告多个函数定义【英文标题】:Getting GCC linker to warn about multiple function definitions 【发布时间】:2012-12-09 06:13:54 【问题描述】:

考虑一下我的小示例 C 库:

#include <external_library.h>

void some_function(void)

    external_library_call();
    // Do other stuff...

它计划让 some_function() 可以公开调用。但是,该库不起作用,因为它所需的外部库也恰好使用了一个名为 some_function() 的函数,该函数恰好具有相同的原型。不过,GCC 的链接器并不关心 some_function 符号的来源有多少。它看似随机选择一个,外部库可能会也可能不会使用我的 some_function() 而不是它自己的。疯了吧。不是图书馆不工作的事实。这个库绝对不应该工作。更重要的是符号“some_function”有两个来源,但链接器对此没有做任何事情。而且你知道,这并没有让我太困扰,因为我习惯了 GCC 和 C 通常默认情况下是病态的鲁莽。但是,必须有一种方法可以让链接器在同一符号有两个来源时警告我。我已经尝试过 -Wall -Wextra -Wshadow,但这不会产生任何警告。

请注意,-fvisibility=hidden 在这里没有帮助,因为两个库都想导出 some_function()。我知道您可以对我在没有唯一前缀的情况下进行函数调用感到羞耻。你说得对。这是一个错误。我不在乎。这个错误可以被链接器捕获,因此应该被捕获。链接器没有理由不捕捉这个错误。此外,您使用的库可能会导出一些奇怪的意外符号,并且您不一定可以控制其他人的库导出的内容。只有在程序员停下来并着火之前,才能使前缀和前缀变得如此独特。

【问题讨论】:

【参考方案1】:

-Wall -Wextra -Wshadow 等选项是影响源代码分析的编译器标志;显然,您正在使用链接器选项。

但是,由于shutdown() 位于为应用程序保留的命名空间中(而且您甚至没有表明您已包含声明系统shutdown() 的标头),因此编译器没有什么或链接器可以做到。作为应用程序程序员,您有权创建一个名为shutdown() 的函数并调用它。您可以查看诸如 LSB(Linux 标准库)合规性套件之类的东西,以检查您没有定义由实现定义的功能。

我不得不追查的一个更难的错误涉及我们代码中的函数_bind(),它恰好与具有不同接口的系统函数_bind() 同名。当我们的函数被系统库的一部分调用时,一切都乱套了。这部分是我们使用系统保留名称的错误(不要以_ 开头的变量或函数名称),不幸的是只有一个平台发生名称冲突。我们的_bind() 的系统前缀解决了这个问题。

您可以查看 C 和 POSIX 标准中的保留名称列表。但是,您会发现 _t 后缀是保留的,但带有后缀的类型名称也广泛(ab)用于用户定义的类型。您还必须知道该类型的任何给定定义是“来自系统标头”(可能是 OK),还是来自用户定义的标头(可能不是 OK),或者是“提供缺失系统功能的用户定义标头” (边缘)。这变得非常棘手。

【讨论】:

关于 _bind() 错误:我认为这根本不是你的错。在某些时候,链接器一定已经意识到_bind() 有两个定义。链接器不可能不知道这一点。除非有一些关于链接器操作的详细信息,否则我不熟悉...... 实际上,是不是编译时的链接器从来没有检查过它所链接的共享对象的符号表?这是我能想到的唯一解释。即便如此,它仍然有点鲁莽。【参考方案2】:

添加:

-fvisibility=隐藏

到您的构建标志。但是,请注意一些警告;一些标题可能没有预料到这一点。在这些情况下,您需要在包含它们之前使用编译指示:

#pragma GCC visibility push(hidden)
#include <problematic_header>
#pragma GCC visibility pop

除了避免符号冲突之外,还有其他一些好处。见:

http://gcc.gnu.org/wiki/Visibility

如果你有兴趣。

【讨论】:

如果我没看错的话,我还必须在 main() 前面加上 __attribute__((visibility("default"))) 才能导出它。对吗? @enigmaticPhysicist 我不这么认为。 main() 似乎被 GCC 特殊对待并且总是被导出。 虽然这很有帮助而且我肯定会使用它,但它并不能解决原来的问题。链接器 /knew/ 有相同符号的两个单独实例。为什么它没有停止并传递错误?为什么它选择了一个而不是另一个?标准是什么?如果我需要导出一个符号并且我想确保它与我正在使用的任何其他符号发生冲突怎么办?我仍然称这个问题没有解决,直到我可以让链接器在这种情况下停止并出现错误。 @enigmaticPhysicist 这确实在您劫持并编辑它之前回答了这个问题。现在它要求不同的东西。您应该发布一个新问题。 它目前询问我一直想问的问题。你首先误解了我,因为我第一次写的时候并不清楚。我想我会知道我的意思,首先问了这个问题。这不是劫持。

以上是关于让 GCC 链接器警告多个函数定义的主要内容,如果未能解决你的问题,请参考以下文章

gcc 警告:已使用但未定义的函数

链接器不指出错误;多个定义警告指向同一行

使用编译器/链接器进行 C++ 代码清理

为啥链接器链接了错误的函数?

链接器下——链接器实战

GCC 常用编译选项