【问题标题】:GCC "multiple definition" errors when linking with external library与外部库链接时出现 GCC“多重定义”错误
【发布时间】:2015-10-28 02:08:34
【问题描述】:

我正在尝试使用一个库(Watt-32,如果相关),由于某种原因无法链接。我已经编译了库,作为一个快速的“hello world”测试,我正在尝试编译以下文件:

#include <tcp.h>
int main() { sock_init(); } 

这会导致 GCC 在库自己的源文件中生成一个 multiple definition 错误列表:

D:\projects\test-tcp>c++ -Iinclude test-tcp.cpp -Llib -lwatt

lib\libwatt.a(rs232.o): In function `_ntohl':
D:\msys64\home\JW\watt32\src/../inc/sys/swap.h:63: multiple definition of `__ntohl'
lib\libwatt.a(pctcp.o):D:\msys64\home\JW\watt32\src/../inc/sys/swap.h:63: first defined here
lib\libwatt.a(rs232.o): In function `_ntohs':
D:\msys64\home\JW\watt32\src/../inc/sys/swap.h:73: multiple definition of `__ntohs'
lib\libwatt.a(pctcp.o):D:\msys64\home\JW\watt32\src/../inc/sys/swap.h:73: first defined here
lib\libwatt.a(rs232.o): In function `get_fs_reg':
D:\msys64\home\JW\watt32\src/misc.h:736: multiple definition of `get_fs_reg'
lib\libwatt.a(pctcp.o):D:\msys64\home\JW\watt32\src/misc.h:736: first defined here
lib\libwatt.a(rs232.o): In function `get_gs_reg':
D:\msys64\home\JW\watt32\src/misc.h:744: multiple definition of `get_gs_reg'
lib\libwatt.a(pctcp.o):D:\msys64\home\JW\watt32\src/misc.h:744: first defined here
lib\libwatt.a(rs232.o): In function `set_fs_reg':
D:\msys64\home\JW\watt32\src/misc.h:751: multiple definition of `set_fs_reg'
lib\libwatt.a(pctcp.o):D:\msys64\home\JW\watt32\src/misc.h:751: first defined here
lib\libwatt.a(rs232.o): In function `set_gs_reg':
D:\msys64\home\JW\watt32\src/misc.h:757: multiple definition of `set_gs_reg'
lib\libwatt.a(pctcp.o):D:\msys64\home\JW\watt32\src/misc.h:757: first defined here
lib\libwatt.a(ports.o): In function `_ntohl':
D:\msys64\home\JW\watt32\src/../inc/sys/swap.h:63: multiple definition of `__ntohl'
lib\libwatt.a(pctcp.o):D:\msys64\home\JW\watt32\src/../inc/sys/swap.h:63: first defined here
lib\libwatt.a(ports.o): In function `_ntohs':
D:\msys64\home\JW\watt32\src/../inc/sys/swap.h:73: multiple definition of `__ntohs'
lib\libwatt.a(pctcp.o):D:\msys64\home\JW\watt32\src/../inc/sys/swap.h:73: first defined here
lib\libwatt.a(ports.o): In function `get_fs_reg':
D:\msys64\home\JW\watt32\src/misc.h:736: multiple definition of `get_fs_reg'
lib\libwatt.a(pctcp.o):D:\msys64\home\JW\watt32\src/misc.h:736: first defined here
lib\libwatt.a(ports.o): In function `get_gs_reg':
D:\msys64\home\JW\watt32\src/misc.h:744: multiple definition of `get_gs_reg'
lib\libwatt.a(pctcp.o):D:\msys64\home\JW\watt32\src/misc.h:744: first defined here
lib\libwatt.a(ports.o): In function `set_fs_reg':
D:\msys64\home\JW\watt32\src/misc.h:751: multiple definition of `set_fs_reg'
lib\libwatt.a(pctcp.o):D:\msys64\home\JW\watt32\src/misc.h:751: first defined here
lib\libwatt.a(ports.o): In function `set_gs_reg':
D:\msys64\home\JW\watt32\src/misc.h:757: multiple definition of `set_gs_reg'
lib\libwatt.a(pctcp.o):D:\msys64\home\JW\watt32\src/misc.h:757: first defined here
lib\libwatt.a(language.o): In function `_ntohl':
[... etc ...]

我一定是在这里做错了什么,但究竟是什么?这似乎是图书馆本身的问题..?

edit:这些函数在库源码中定义如下:(实现省略,都是内联汇编代码)

extern __inline__ WORD get_fs_reg (void)     { /* ... */ }
extern __inline__ WORD get_gs_reg (void)     { /* ... */ }
extern __inline__ void set_fs_reg (WORD sel) { /* ... */ }
extern __inline__ void set_gs_reg (WORD sel) { /* ... */ }
/*@unused@*/ extern __inline__ unsigned long __ntohl (unsigned long x)  { /* ... */ }
/*@unused@*/ extern __inline__ unsigned short __ntohs (unsigned short x) { /* ... */ }

【问题讨论】:

  • 问题可能出在头文件中的函数定义上。查看misc.h 中定义get_fs_regget_gs_reg 的代码(可能在问题中发布该代码)。也许他们应该被标记为inline。此外,C 和 C++ 的行为方式也不同。内联函数。因此,如果此库是 C 库,则可能需要对标头进行一些更改才能从 C++ 中使用。
  • 也尝试制作一个包含标题的 C 程序,看看是否出现相同的错误
  • @M.M,所有这些函数实际上都标记为__inline__,并用-O2编译。我已将他们的定义添加到问题中。将测试文件编译为纯 C 并没有任何区别。 (我猜这使得 c++ 标签有些无关紧要)
  • 查看是否有更新版本的库和头文件。更改日志提到“misc.h 更改:Watcom 使用 'i64' 后缀来表示 64 位值。”。我想知道 32 位和 64 位函数是否都以某种方式被编译到同一个库中。 watt-32.net/change.log

标签: c++ gcc static-libraries


【解决方案1】:

这些头文件有点旧/过时了。 extern inline 的用法随着更新的编译器而改变。 extern inline 多年来的首选方式。它在 gcc 上运行良好,但 clang 需要 static inline

现在,即使 gcc 也想要 static inline,即使使用 -O2 或者你会得到你所看到的。由于您是从源代码重新编译,您可能需要编辑 .h 并将它们全部更改为 static

我的代码样板是 #define craigs_inline extern inline,现在我已将其切换为 #define craigs_inline static inline 以保持和平。

请注意,我没有调查编译器 -foption_whatever 可能会消除对此的需求。如果你找到了,请给我留言,我很想知道。

【讨论】:

  • 刚刚在挖掘使用extern __inline__ __attribute__ ((__gnu_inline__)) 的系统标头时发现了这一点。 &lt;sys/cdefs.h&gt; 中的注释指出,此属性等效于使用 -fgnu89-inline 进行编译。是的,在使用此选项重新编译 Watt32 库后,我的测试文件也可以毫无错误地编译! :)
  • @user5434231 谢谢!!!正如柯克船长曾经对斯科蒂所说:你已经赚到了一周的工资
  • 更多信息:在 C 中,在 C99 之前正式没有 inline。 GCC 推出了自己的 ;对于相同的代码,C99 内联的行为与 gnu89 不同。一团糟。 C++ 再次不同。 Summary here。这个代码库显然是为 gnu89 内联编写的,但被编译为 C99。
  • 我对可移植代码的建议是不要在 C 和 C++ 都包含的头文件中使用内联函数;但是在实践中,我认为您可以在所有方言中使用static inline
  • 是的,一团糟。我的代码在 CLANG、OPTIMIZE cplusplus GNUC 等上执行 #ifdef,并定义了我的回答中提到的抽象宏。有一个 [并且只有一个地方] 这样做,并且 每个 其他 .h 文件都使用摘要。这已经并且确实有效。所以,不是乱七八糟的。对于新情况,我添加新的#ifdef [和/或简化]。摘要可以由 autoconf 等定义。顺便说一句,我在写内联 [~20 年前] 的第一天就定义了摘要,因为我预先看到了问题。不是唯一的,其他人也有类似的 INLINE。
【解决方案2】:

也许你需要include guards

【讨论】:

  • 对我来说这看起来像是一个链接器错误。也许首先使用 gcc -c 编译以仅编译 - 这应该证明它是失败的库链接..
猜你喜欢
  • 2022-01-03
  • 1970-01-01
  • 1970-01-01
  • 2018-04-30
  • 1970-01-01
  • 2012-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多