【问题标题】:Avoiding duplicate symbol when compiling to multiple instruction sets编译为多个指令集时避免重复符号
【发布时间】:2015-08-10 23:43:30
【问题描述】:

我正在使用基于处理器特性的 CPU 调度来切换复杂数值算法的实现。我想包含我在同一个动态库中编译的两个版本(一个 sse2 和 sse3 版本)。

目前采用的方法是将所有架构特定的代码包装到一个命名空间中,例如namespace sse2namespace sse3 从而避免在链接到最终动态库时出现重复的符号名称。

但是,如果我在 sse2 和 ss3 版本中都使用了一些我无法控制的代码(例如 std::vector<int>),会发生什么情况。据我所知,std::vector 实现将出现在 sse2 和 sse3 目标文件中,但理论上可能包含不同的指令,具体取决于编译器执行的优化。当我将这些目标文件链接到动态库时,将使用其中一个,我可能会尝试在仅支持 sse2 的 cpu 上运行 sse3 指令。

除了编译成两个独立的动态库之外,还可以做些什么来解决这个问题?我需要在 windows、mac os x 和 linux 上同时使用 Visual Studio 和 clang 的解决方案。

【问题讨论】:

  • std::vector 将在链接到您自己的对象的动态库或静态库中实现(例如在 glibc 中)。您的目标文件应该只包含std::vector 的声明而不是实现/定义。有什么问题?
  • 首先,std::vector 只是一个例子。我也在谈论其他只能作为标题的第三方库。其次,std::vector 是一个模板,因此代码将出现在我自己的目标文件中。
  • This may interest you。如果您使用头文件中的库,请确保所有函数都是静态内联的。我就是这么做的。
  • 如果我被允许编辑第三方标题,那将起作用。或者我可以将它们包装在匿名命名空间等中。但是,这不是一个选项。

标签: c++ linker simd


【解决方案1】:

一种方法是在共享库级别而不是目标文件级别进行调度。这将需要使用不同的指令集支持多次编译整个库,然后根据您检测到的 CPU 功能在运行时分派到适当的共享库。我详细介绍了一种适用于 OS X 和 Linux in this previous answer 的方法。但是,我还没有尝试在 Windows 上实现这一点。

【讨论】:

  • 这当然是您在另一个答案中发布的一个有趣的解决方案。但是,正如我在问题中所说,我宁愿只使用一个动态库。我知道如何使用多个库来做到这一点,尽管方式不如你建议的那么聪明,
【解决方案2】:

该语言完全支持这种情况,不需要任何显式处理。您的动态调度方案与它没有太大关系 - 一个项目在多个翻译单元中实例化 std::vector 是非常典型的,并且仍然没有违反 ODR。一般来说,内联函数——尤其是模板实例化——对链接器是不可见的(即在 obj 文件表中不显示为“外部”)。

如果出于某些特殊原因需要显式控制此链接类型,则必须求助于特定于编译器的设备。 MSVC 设备是selectany,gcc 有some other devices。不知道 clang - 但关键是你很难找到使用其中任何一个的理由。

【讨论】:

  • OP 所指的问题与 ODR 无关。问题是std::vector<int> 的各种实例在他的场景中是不可互换的,因为它们是在不同的指令集支持下编译的。不能保证模板实例会被内联,因此链接器必须对特定符号的各种实例进行重复数据删除。在 OP 的情况下,链接器无法知道各种实例中的哪一个可以使用,因此会出现问题。
  • 没错,JasonR。似乎如果我首先链接最小的指令集目标文件/库,则选择这些实现,这至少消除了尝试执行不受支持的指令的问题。但是,这会消除该部分代码的任何性能优势。
猜你喜欢
  • 1970-01-01
  • 2015-09-01
  • 2015-06-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-31
  • 2019-05-24
相关资源
最近更新 更多