如何使用fortranMKL将静态库中的函数打包到.so文件中

问题描述

我正在尝试使用Fortran中MKL的blas实现来加速优化例程。我需要将结果保存在共享库中,以便可以从较大的脚本访问它。我可以编译和链接我的代码而没有任何警告,但是生成的.so文件对我要调用的blas例程有未定义的引用,即dgemm

fortran代码的相关部分:

subroutine sumsquares(params,Mx,flen,glen,numr,numcols,g,lambda,res)
 implicit none
 integer,intent(in):: flen,numcols
 real(8),dimension(flen,numcols) :: params
 real(8),numcols) :: g
 real(8),numcols) :: gc
 real(8),glen) :: Mx 

 gc = -g
 call dgemm('N','N',1,params,gc,flen)
 return
end subroutine sumsquares

和相应的makefile

FC=ifort
LD_LIBRARY_PATH=/opt/intel/composerxe-2011.1.107/compiler/lib/intel64:/opt/intel/composerxe-2011.1.107/mkl/lib/intel64
LIBRARY_PATH=/opt/intel/composerxe-2011.1.107/compiler/lib/intel64:/opt/intel/composerxe-2011.1.107/mkl/lib/intel64
INCLUDE=/opt/intel/composerxe-2011.1.107/mkl/include
FPATH=/opt/intel/composerxe-2011.1.107/mkl/include
CPATH=/opt/intel/composerxe-2011.1.107/mkl/include
FFLAGS=-i8 -I$(MKLROOT)/include/intel64/ilp64 -I$(MKLROOT)/include
LDFLAGS= -shared -nofor-main -fPIC
LINKLIBS=-fPIC -shared -L$(MKLROOT)/lib/intel64 $(MKLROOT)/lib/intel64/libmkl_blas95_ilp64.a -lmkl_rt -lpthread -lm

sumsquares: sumsquares.f90
    $(FC) $(FFLAGS) -c -fPIC /opt/intel/composerxe-2011.1.107/mkl/include/blas.f90 -o blas95.o
    $(FC) $(FFLAGS) -nofor-main -c -fPIC sumsquares.f90
    $(FC) $(LDFLAGS) sumsquares.o $(LINKLIBS) sumsquares.o

正如我所说,我可以在没有任何警告的情况下运行make,但是当我运行nm sumsquares.so | grep dgemm时会看到U dgemm_,并且在尝试加载.so文件时,我因段错误而崩溃(在调用不相关的子例程时,因此我认为它与此代码无关)。如何获得链接器以将相关功能放入so文件中?

更新

我通过在R中调用so来在R脚本中加载dyn.load文件,如下所示:

变化1:

dyn.load("/home/me/path/sumsquares.so")

变化2:

dyn.load("/opt/intel/composerxe-2011.1.107/mkl/lib/intel64/libmkl_rt.so")
dyn.load("/home/me/path/sumsquares.so")

两种变化都会导致相同的结果,但存在段错误。

更新#2

我应该指出,英特尔MKL静态库 是使用-fPIC标志(至少为according to the documentation)编译的。我显然不知道我在做什么,但是据我所知,这样的事情应该是可能的。

由于blas在科学计算中得到广泛使用,因此我担心与不同版本的冲突。如果我要在so文件中进行静态链接,并将该so文件加载到使用其他blas实现的程序中,会导致冲突,或者我的库会播放好吗?

解决方法

如果该库确实是静态的,则不能放入共享库。共享的目标代码以不同的方式编译,因此它可以独立于位置运行。必须使用-fPIC之类的标记,这些标记不可用于静态库。

要么使用dgemm作为动态库编译BLAS,然后在加载自定义库之前将其加载(也许R dyn.load将自动加载依赖项,我不知道,您可以尝试)或者只是将DGEMM的代码包含到您自己的库中,然后将所有内容一起编译为一个.so。

不要忘记您必须使用MKL链接顾问https://software.intel.com/content/www/us/en/develop/articles/intel-mkl-link-line-advisor.html请勿与ILP64库链接,除非您知道自己在做什么并且有充分的理由这样做。

此外,尽管大多数MKL随附使用-fPIC构建的静态库,但Fortran 95到LAPACK和BLAS的接口却没有。包含了接口的源文件,因此,如果要使用它们,则需要自己用-fPIC进行编译。它们位于$MKLROOT/interfaces/blas95$MKLROOT/interfaces/lapack95

,

如何使链接器将相关功能放入so文件?

这不是共享库的工作方式;您需要将so与其他文件一起发送(并设置适当的RPATH),或链接到库的静态版本。

当你说:

当我尝试加载.so文件时,我因段错误而崩溃

听起来您正在尝试直接dlopen()或类似的东西;只需让动态(运行时)链接器执行其工作即可。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...