我需要弄清楚我可以提供给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.
谢谢.
GCC不支持链接到英特尔OpenMP运行时库.GCC的内部代码转换器将OpenMP指令转换为ligomp
特定的调用,并且那些API的方式与公开的方式不同libiomp
.此外,将两个单独的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编译指示并将代码转换为相应的调用libgomp
;
如果GCC用于链接可执行文件或共享库,请不要-fopenmp
在链接阶段将选项传递给它; 相反,通过-L/path/to/libiomp5 -liomp5
;
如果GNU ld用于链接可执行文件/模块,请替换-lgomp
为-liomp5
.
如果无法进行上述更改,那么英特尔论坛上的主题就会有所帮助,因为链接器解析了链接时符号引用的方式,尽管它实际上更像是一个黑客攻击.传递-Wl,--as-needed
强制GNU ld不会DT_NEEDED
在命令行上为其-lgomp
后面的任何库发出标记,除非该库满足未定义的符号引用,假设GCC驱动程序将在用户提供的选项之后插入某处.这个想法是防止libgomp
与可执行文件链接,即使没有未解析的引用GOMP_...
,这通常不应该是这种情况,因为所有引用,甚至是来自动态加载模块的引用都应该满足libiomp5
.防止libgomp
被RTLD加载是必不可少的,因为它中有一些构造函数例程被调用,无论是否导入符号,以及那些可能干扰IOMP的事情.
链接器技巧不适用于OS X等非ELF系统.Mach-O链接编辑器不支持,--as-needed
但可能有不同的机制在该OS上实现相同的结果.