告诉GCC不要链接libgomp,这样它就会链接libomp5



我需要找到一个编译器/链接器指令,我可以将其提供给gcc,这样它就不会在指定-fopenmp时自动链接libgomp。

原因是我试图建立英特尔的MKL BLAS。MKL需要添加一个单独的英特尔库来处理多线程(例如,libmkl_Intel_thread或libmkl_gnu_thread)。然而,并不是每个操作系统(包括我的操作系统)都可以使用MKL与libgomp链接的库。这迫使我链接libmkl_intel_thread,而它又必须针对libomp5进行链接。

虽然我可以构建我的包,但一些二进制文件是针对libgomp和libomp5链接的。我不是肯定这会导致问题,但已经发生了一些崩溃,链接组合是可疑的,即使它没有导致崩溃,也肯定是效率低下。

我正试图用gcc 4.9.1来做到这一点。

不幸的是,避免fopenmp不是一种选择。原因是,这是为了编译一个由几个子包组成的相当大的包,这些子包的Makefile不是最好的,并且以后可能会编译来自其他源(插件)的其他包。强制执行通用编译器/链接器指令并不困难。然而,打开--enable openmp会激活-fopenmp和用于触发与多线程相关的代码的定义。尝试将这三者(-enable-openmp、-fopenmp和链接到-enable-openmp的代码)分开是不可行的。

我看过手册页,没有看到任何允许选择openmp库的gcc指令。英特尔的论坛有一个非常古老的讨论,他们建议根据需要在-fopenmp后面紧跟着指定一个静态库。这看起来相当不稳定,也有很大的潜力干扰插件包。llvm-openmp似乎曾经考虑过-fopenmp=libomp5指令,但它似乎在3.5版本中被删除了,我无论如何都在尝试使用gcc。

谢谢。

GCC不支持针对Intel OpenMP运行库的链接。GCC的内部代码转换器将OpenMP指令转换为特定于ligomp的调用,并且这些调用具有与libiomp公开的API不同的方式。此外,将两个独立的OpenMP运行时混合到一个可执行文件中(或者如果启用OpenMP的模块是动态加载的,则混合到单个进程中)是一种灾难。这就是为什么MKL的多线程驱动程序有两种风格——英特尔和GNU。后者在某些机器上丢失可能是安装缺陷。

编辑:显然,Intel OpenMP运行时提供了GNU兼容层,这意味着它可能被用作libgomp的替代品。至少符号在那里:

$ nm libiomp5.a | sort | grep GOMP_
0000000000000000 T GOMP_barrier@@VERSION
0000000000000000 T GOMP_barrier@GOMP_1.0
0000000000000000 T __kmp_api_GOMP_barrier
0000000000000000 T __kmp_api_GOMP_barrier_10_alias
...

在这种情况下,你必须做的是:

  • 在编译代码时保留-fopenmp,以便GCC识别OpenMP杂注并将代码转换为相应的libgomp调用
  • 如果GCC用于链接可执行文件或共享库,则在链接阶段不要-fopenmp选项传递给它;而是通过-L/path/to/libiomp5 -liomp5
  • 如果使用GNU ld链接可执行文件/模块,请将-lgomp替换为-liomp5

如果无法进行上述更改,英特尔论坛上的线程是有意义的,因为链接器解析链接时间符号引用的方式,尽管这实际上更像是一种黑客攻击。传递-Wl,--as-needed会强制GNU ld不在命令行上为其后面的任何库发出DT_NEEDED标记,除非该库满足未定义的符号引用,假设GCC驱动程序将在用户提供的选项后面的某个位置插入-lgomp。其思想是,即使没有对GOMP_...的未解析引用,也要防止libgomp与可执行文件链接,这通常不应该是这样,因为所有引用,甚至是来自动态加载模块的引用,都应该由libiomp5来满足。防止libgomp被RTLD加载是至关重要的,因为无论符号是否被导入,其中都有一些构造函数例程被调用,并且这些例程所做的事情可能会干扰IOMP。

链接器技巧在OS X等非ELF系统上不起作用。Mach-O链接编辑器不支持--as-needed,尽管可能有不同的机制可以在该操作系统上实现相同的结果。

我想我已经有了答案;我已经和英特尔的人进行了几次交流,我想分享一下结果。这是他们的一些建议和我自己提出的建议的混合体:

  1. 简单的答案是,你不能。Gcc希望在链接器阶段强制使用libgomp。如果libiomp也被链接,那么两个库都将被链接。会叫哪一个?我不知道。

  2. 更长的答案是,在某些发行版上,可以通过创建自定义libgomp.spec或更改与gcc一起安装的libgomp-spec来更改gcc的默认行为(无论何时设置-fopenmp,都可以添加libgomp)。在我的发行版(自制)上,这是不可行的;"libgomp.spec"文件是空的,libgomp的spec是gcc内置的。所有这些都必须被推翻。每当gcc更新时,就必须重新进行此操作。

  3. 在某些操作系统上,可能会替换到libgomp的每个副本和链接,以及到libomp5的符号链接。然后,二进制文件将有多个链接,以两个不同的名称指向同一个库。届时会发生什么?我不知道。

  4. 我最终做的是从gcc转移到llvm的clang-omp实现。除非另有说明,否则它使用libomp5。我担心的是,我的项目中有一部分使用了fortran,而且没有llvm fortran编译器。然而,事实证明,即使将-fopenmp赋予gfortran,只要llvm最终进行链接,它也会删除对libgomp的任何引用,并用libomp5替换它们。clang omp也可以选择-fopenmp=[Libomp5|libgomp]的omp库,但我无法始终做到这一点。无论如何,llvm 3.5的clang-omp实现几乎涵盖了所有的openmp规范,到目前为止,交换机中似乎没有丢失任何东西。事实上,性能有所提高。

  5. 为了记录在案,我使用dragonegg进行了使用gfortran作为llvm前端的实验。这本书不值一支蜡烛。Dragonegg与gcc 4.9不兼容,所以它强制使用gcc 4.8。设置起来很困难;随着版本的变化,似乎很难进行维护;llvm的人不确定dragonegg在未来会得到多少支持;而且在所有情况下,性能都不如仅使用llvm。

  6. 驱使我来到这里的问题是,如何获得一个包含C和fortran组件的包,该包使用OpenMP,根据MKL编译,我的操作系统的MKL库与iomp5硬链接,不接受gomp。答案是,唯一可行的选择是从gcc转移到clang omp。

  7. 正如OpenMP网站上所说,这确实留下了一个问题,"iomp5‘drop-in-compatible’with gcc 4.9"。答案很简单,"不",iomp5和gcc 4.9将不会相互工作——至少在没有对工具链进行实质性修改的情况下,因为没有可用的指导或文档,也不清楚是否有人成功地做到了这一点。

我是"英特尔MKL"团队的技术支持工程师。这篇文章最近引起了我们的注意。"英特尔MKL"的线程层确实需要libomp5,即"英特尔OpenMP"运行库。要使用GCC与libomp5正确链接,需要在不使用"-fopenmp"的情况下编译代码。然后链接行需要显式地包括libmkl_intel_thread和libomp5。

当前的MKL文档没有对此使用模型提供足够的解释。MKL链接线顾问彻底崩溃了。对于给您带来的不便和困惑,我深表歉意。我们将尽快修复链接线顾问,并将改进用户指南,以更好地帮助OS X上的GCC用户。

相关内容

  • 没有找到相关文章

最新更新