在我的开源软件项目中,我调用gcc atomic builtins:__sync_add_and_fetch 和 __sync_sub_and_fetch 来实现某些变量的原子增量和减量。我定期收到试图编译我的代码的人的电子邮件,但他们收到以下链接器错误:
refcountobject.cpp:(.text+0xb5): undefined reference to `__sync_sub_and_fetch_4'
refcountobject.cpp:(.text+0x115): undefined reference to `__sync_add_and_fetch_4'
经过一番挖掘,我将根本原因缩小到他们的旧版本 gcc (4.1) 默认为 i386 的目标架构这一事实。显然,gcc 实际上并没有在 80386 上进行原子加法的内在函数,因此它隐式地在其中注入了一个未定义的 __sync_add_and_fetch_4 调用。这里有一个很好的描述它是如何工作的。
正如这里所讨论的,简单的解决方法是告诉他们修改 Makefile 以附加-march=pentium作为编译器标志之一。一切都很好。
那么什么是长期修复,所以用户不必手动修复 Makefile?
我正在考虑一些想法:
我不想将 -march=pentium 作为编译器标志硬编码到 Makefile 中。我猜这会破坏任何不是基于英特尔的东西。但是如果 Makefile 有一个规则来检测默认目标是 i386,我当然可以添加它。我正在考虑在 Makefile 中有一个规则,它是一个调用 gcc -dumpmachine 并解析出第一个三元组的脚本。如果字符串是 i386,它将添加编译器标志。我假设没有人会真正为 80386 机器构建。
另一种选择是实际提供 __sync_add_and_fetch_4 的实现,以供链接器使用。它甚至可以根据定义的 GCC_HAVE_SYNC_COMPARE_AND_SWAP 宏的存在有条件地编译。我使用全局 pthread_mutex 对实现进行了原型设计。可能不是最好的性能,但它可以很好地解决问题。如果为 x86 编译,一个更好的想法可能是自己编写内联程序集以调用“lock xadd”来实现。