问题描述
我正在尝试使用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()
或类似的东西;只需让动态(运行时)链接器执行其工作即可。