我需要弄清楚我可以输入gcc的编译器/链接器指令,以便在指定-fopenmp时它不会自动链接libgomp。
原因是我正在尝试与英特尔的MKL BLAS建立对比。 MKL需要添加单独的英特尔库来处理多线程(例如,libmkl_intel_thread或libmkl_gnu_thread)。但是,用于链接MKL和libgomp的库并不适用于包括我在内的每个操作系统。这迫使我链接libmkl_intel_thread,而libmkl_intel_thread又必须链接libiomp5。
虽然我能够构建我的包,但是一些二进制文件链接到libgomp和libiomp5。我不是肯定这导致了问题,但是有一些崩溃,连锁组合是可疑的,即使它没有导致崩溃,它肯定是一个可怕的低效率。
我正在尝试使用gcc 4.9.1。
不幸的是,避免-fopenmp不是一种选择。原因是这是用于编译由几个子包组成的相当大的包,其Makefile不是最好的形状,并且可以在以后编译来自其他源(插件)的其他包。强制通用编译器/链接器指令并不困难。但是,启用--enable-openmp会激活-fopenmp和定义用于触发与多线程相关的代码的定义。试图将三者(--enable-openmp,-fopenmp和链接到--enable-openmp的代码)分开是不可行的。
我查看了手册页,我没有看到任何允许选择openmp库的gcc指令。英特尔的论坛有一个非常古老的讨论,他们建议在-fopenmp之后立即指定一个静态库,然后是--as-needed。这似乎非常摇摇晃晃,并且还有很多潜在的干扰插件包。 llvm-openmp似乎在某一点上考虑了-fopenmp = libiomp5指令,但它似乎已经在3.5版本中被删除了,我还是试图使用gcc。
感谢。
答案 0 :(得分:7)
GCC不支持链接到英特尔OpenMP运行时库。 GCC的内部代码转换器将OpenMP指令转换为ligomp
特定的调用,这些调用的API与libiomp
公开的API不同。此外,将两个单独的OpenMP运行时混合到一个可执行文件中(或者,如果动态加载启用OpenMP的模块,则将其混合到单个进程中)是一种灾难。这就是为什么MKL的多线程驱动程序有两种版本 - 英特尔版和GNU版。某些机器上缺少后者可能是安装的缺陷。
编辑:显然,英特尔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
的相应调用; -fopenmp
选项传递给它;相反,通过-L/path/to/libiomp5 -liomp5
; -lgomp
替换为-liomp5
。如果无法进行上述更改,英特尔论坛上的主题就会有所帮助,因为链接器解析了链接时符号引用的方式,尽管它实际上更像是一个黑客攻击。传递-Wl,--as-needed
迫使GNU ld在命令行上为其后面的任何库发出DT_NEEDED
标记,除非该库满足未定义的符号引用,假设GCC驱动程序将插入{{1}在用户提供的选项之后的某个地方。这个想法是防止-lgomp
与可执行文件链接,即使没有未解析的libgomp
引用,这通常不应该是这种情况,因为所有引用,甚至是来自动态加载模块的引用都应该是GOMP_...
满意。防止RTLD加载libiomp5
是必不可少的,因为无论是否导入符号,都会调用其中的一些构造函数例程,而这些例程可能会干扰IOMP。
链接器技巧不适用于OS X等非ELF系统.Mach-O链接编辑器不支持libgomp
尽管可能有不同的机制在该OS上实现相同的结果
答案 1 :(得分:4)
我想我现在有一个答案;我和英特尔人有过几次交流,我想分享结果。这是他们的一些建议和我自己提出的建议的混合:
简短的回答是,你做不到。 Gcc希望在链接器阶段强制使用libgomp。如果libiomp也已链接,则两个库都将链接。哪一个会被称为?我不知道。
更长的答案是,在某些发行版中,可以通过创建自定义libgomp.spec或更改使用gcc安装的libgomp.spec来更改gcc的默认行为(每当设置-fopenmp时添加libgomp)。在我的发行版(自制软件)中,这是不可行的; “libgomp.spec”文件为空,libgomp的规范是内置于gcc的。所有这些都必须被覆盖。每当gcc更新时,都必须重做。
在某些操作系统上可能会将每个副本和链接替换为libgomp,并将其替换为libiomp5的符号链接。然后,二进制文件将具有多个链接,这两个链接以两个不同的名称指向同一个库。那会发生什么?我不知道。
我最终做的是从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规范,到目前为止看来交换机中没有任何东西丢失。实际上性能有所提高。
我做了记录,尝试使用gfortran作为使用dragonegg的llvm前端。这本书不值得一试。 Dragonegg与gcc 4.9不兼容,所以它强制gcc 4.8。很难设置;似乎随着版本的变化难以维持; llvm的人们不确定dragonegg会向前推进多少支持;而且在所有情况下,表现都不如仅仅使用llvm。
驱动我的问题是如何获得一个包含C和fortran组件的软件包,它使用OpenMP,针对MKL编译,我的操作系统的MKL库与iomp5硬连接,不接受gomp 。答案是,唯一可行的选择是从gcc转移到clang-omp。
这确实留下了一个问题,“就像iMP5'与gcc 4.9兼容”,正如OpenMP网站所声称的那样。答案很简单,“不,”iomp5和gcc 4.9将不彼此合作 - 至少没有对一个工具链进行实质性修改,因为没有任何指导或文档,它是不清楚是否有人成功完成了这项工作。
答案 2 :(得分:2)
我是英特尔MKL团队的技术支持工程师。这篇文章最近引起了我们的注意。英特尔MKL的线程层确实需要libiomp5,即。英特尔OpenMP运行时库。要使用GCC与libiomp5正确链接,需要在不使用' -fopenmp'的情况下编译代码。然后链接行需要明确包含libmkl_intel_thread和libiomp5。
当前的MKL文档未对此使用模型提供足够的解释。并且MKL链接线顾问完全被打破了。我很抱歉给您带来的不便和困惑。我们将尽快修复链接线顾问,并改进用户指南,以便更好地帮助GCC用户使用OS X.