告诉GCC不要链接libgomp,而是链接libiomp5

10

我需要找到一条编译器/链接器指令,可以在使用-fopenmp选项时不自动链接libgomp。原因是我正在尝试构建使用Intel的MKL BLAS的程序,而MKL需要添加一个单独的Intel库来处理多线程(例如libmkl_intel_thread或libmkl_gnu_thread)。然而,链接MKL与libgomp的库在包括我的操作系统在内的某些操作系统上不可用。这迫使我链接libmkl_intel_thread,而这又必须链接libiomp5。虽然我能够构建我的程序包,但有些二进制文件链接了libgomp和libiomp5。我不能确保这是否会引起问题,但已经发生了一些崩溃,链接组合很可疑,即使它没有引起崩溃,也肯定是一个可怕的低效率问题。我正在尝试使用gcc 4.9.1进行此操作。

避免使用-fopenmp不是一个选项,因为这是为编译由几个子包组成的相当大的软件包而设计的,这些子包的Makefile不是很完美,并且稍后可能会编译其他来源(插件)的附加软件包。强制使用通用编译器/链接器指令并不困难。然而,打开--enable-openmp选项会同时激活-fopenmp和用于触发与多线程相关的代码的定义。试图将这三个选项(--enable-openmp、-fopenmp和与--enable-openmp链接的代码)分开是不可行的。

我查看了手册页面,没有找到任何gcc指令可以允许选择一个openmp库。Intel的论坛有一个非常古老的讨论,他们建议在-fopenmp之后指定一个静态库,然后加上--as-needed。这似乎相当脆弱,并且很可能会干扰插件包。llvm-openmp似乎曾经考虑过一个-fopenmp=libiomp5的指令,但它似乎已经在3.5版本中被删除了,而且我还想使用gcc。

谢谢。

3个回答

8
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 Pragma并将代码转换为相应的调用到libgomp中;
  • 如果使用GCC链接可执行文件或共享库,在链接阶段不要传递-fopenmp选项,而是传递-L/path/to/libiomp5 -liomp5
  • 如果使用GNU ld链接可执行文件/模块,则将-lgomp替换为-liomp5

如果无法进行上述更改,则Intel论坛上的帖子有一些意义,因为链接器解析链接时的符号引用的方式,但实际上它更像是一个hack。传递-Wl,-as-needed可以确保GNU ld不会对命令行后跟随的任何库发出DT_NEEDED标签,除非该库满足未定义的符号引用,假设GCC驱动程序将在用户提供的选项之后插入-lgomp。其想法是即使没有未解决的GOMP_...引用,也要防止将libgomp与可执行文件链接起来,这通常不应该是问题,因为所有引用,甚至是从动态加载的模块中的引用,都应该被libiomp5满足。防止RTLD加载libgomp非常重要,因为其中有一些构造函数例程会被调用,无论是否导入符号,并且那些例程可能会干扰IOMP。

链接器技巧在像OS X这样的非ELF系统上无法使用。Mach-O链接编辑器不支持--as-needed,但在该操作系统上可能有不同的机制可以实现相同的结果。


我认为你的意思是无法告诉gcc在给出-fopenmp指令时不链接libgomp,而gcc将不可避免地将代码中的任何指令发送到libgomp而不是libiomp5。这样对吗?关于MKL,英特尔确认这不是安装错误,只是某些操作系统没有libmkl_gnu_thread,但他们也坚称应该可以使用gcc(尽管他们不会提供帮助)。如果我理解正确的话,这就是不可能的。我可以接受这一点,我只想确保我理解正确。 - Bob
那个英特尔的声明非常有趣。我刚刚检查了 ligiomp5.a 导出的符号,确实似乎有一个 GNU 兼容层暴露出来。我会相应地更新我的答案。 - Hristo Iliev
除非您能控制每个软件组件在链接阶段期间传递给编译器/链接器的选项,否则您无法防止这种库地狱。 - Hristo Iliev
谢谢Hristo - 虽然我可以控制编译和链接阶段,但是这个软件包中的一些可执行文件想要使用单个命令与gcc进行编译和链接,然后从编译器标志传递-fopenmp,从链接器标志传递-liomp5。我同意英特尔关于此问题的讨论非常hacky...也许明天我会尝试一下。再次感谢您。 - Bob
我不太想这样做。首先,我一直在使用支持OpenMP 4的最新libiomp5进行链接。(实际上,在写这篇文章时,我刚刚查看了网站,他们还声称与gcc具有“插拔式”兼容性。)其次,我认为这本书不值得如此大的代价。非常感谢您的帮助。我将尝试使用llvm,如果这不能解决所有问题,那么我就会放弃mkl。如果英特尔希望科学界采用其工具,他们可以记录如何这样做。 - Bob
显示剩余15条评论

7

我相信我现在有了答案;我已经与英特尔的人进行了几次交流,现在想分享一下结果。这是他们的建议和我自己的想法的结合:

  1. 简短的回答是,你不能这样做。gcc在链接阶段想要强制使用libgomp。如果同时链接了libiomp,则两个库都将被链接。哪一个会被调用?我不知道。

  2. 更长的答案是,在某些发行版上,可能可以通过创建自定义的libgomp.spec或修改安装在gcc中的libgomp.spec来改变gcc的默认行为(每当设置-fopenmp时增加libgomp)。在我的发行版(homebrew)上,这是不可行的;“libgomp.spec”文件为空,而libgomp的spec已内置于gcc中。所有这些都必须被覆盖。并且这必须在每次更新gcc时重新执行。

  3. 在某些操作系统上,可能有可能将每个副本和链接到libgomp的内容替换为指向libiomp5的符号链接。二进制文件将具有指向同一库的多个链接,名称不同。那么会发生什么呢?我不知道。

  4. 我最终所做的是从gcc转移到了llvm的clang-omp实现。除非另有说明,否则它使用libiomp5。我的担忧是我的项目的一部分使用fortran,而且没有llvm fortran编译器。然而,事实证明,即使将-fopenmp给gfortran,只要最终由llvm进行链接,它就会清除任何对libgomp的引用,并将其替换为libiomp5。clang-omp也可能有一个选项,在-fopenmp = [libiomp5 | libgomp]下选择omp库,但我无法始终使其正常工作。无论如何,llvm 3.5的clang-omp实现几乎覆盖了所有的openmp规范,到目前为止似乎没有任何东西在转换中丢失。事实上,性能有所提高。

  5. 为了记录,我确实尝试使用dragonegg将gfortran作为llvm前端。这本书不值得一读。Dragonegg与gcc 4.9不兼容,因此它强制使用gcc 4.8。它很难设置;似乎难以随版本更改而维护;llvm的人员对dragonegg未来的支持程度并不确定;在所有事件中,性能都不如仅使用llvm。

  6. 驱使我来到这里的问题是如何编译使用OpenMP的C和fortran组件的包,这些组件针对MKL进行编译,而我的操作系统的MKL库与iomp5硬链接在一起,不接受gomp。答案是唯一的可行选项是从gcc转移到clang-omp。

  7. 这确实留下了一个问题,“iomp5是否与gcc 4.9“drop-in compatible””,正如OpenMP网站上所述。答案很简单,“不是”,iomp5和gcc 4.9将无法相互使用 --- 至少在没有对工具链进行实质性修改的情况下,没有可用的指导或文档,并且不清楚是否有人成功地完成了此操作。


gcc 4.9和Intel OpenMP lib之间存在兼容性问题。请参见链接 - toddwz

4
我是英特尔MKL团队的技术支持工程师。我们最近注意到了这篇文章。英特尔MKL的线程层确实需要libiomp5,即Intel OpenMP运行库。为了正确地使用GCC链接libiomp5,代码需要在不使用“-fopenmp”的情况下编译。然后链接行需要明确包含libmkl_intel_thread和libiomp5。
当前的MKL文档对这种用法模型没有提供足够的解释。而MKL链接行顾问完全失效了。对于所有的不便和困惑,我深感抱歉。我们将尽快修复链接行顾问,并改进用户指南以更好地帮助OS X上的GCC用户。

谢谢!但是...libiomp5不应该与gcc“插入式”兼容吗?如果我们不使用-fopenmp指令,那么我们不是在关闭所有-MKL代码中的openmp吗? - Bob
现在,我系统中大约一半的自行编译部分链接了libiomp5和libgomp。Jim Crownie建议将iomp5链接到libgomp,如果可行的话,可能会解决部分问题。这样做是否有效? - Bob
1
这些天一切都破了。我们应该从头开始构建所有软件。但还是谢谢你的建议。 - mip

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接