Search code examples
linuxfortranshared-librariesintel-mkl

How do I pack a function from a static library into an .so file with fortran (MKL)


I'm trying to speed up an optimization routine using MKL's blas implementation in fortran. I need to have the result in a shared library so that it is accessible from a larger script. I can compile and link my code without any warnings, but the resulting .so file has an undefined reference to the blas routine I'm trying to call, namely dgemm.

relevant section of the fortran code:

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

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

and the corresponding 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

As I said, I can run make without any warnings, but when I run nm sumsquares.so | grep dgemm I see U dgemm_, and when I try to load the .so file, I crash with a segfault (while calling an unrelated subroutine, so I don't think it's related to this code). How do I get the linker to put in the relevant function into the so file?

Update

I am loading the so file in an R script by calling dyn.load in R as follows:

Variation 1:

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

Variation 2:

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

Both variations lead to the same result, with a segfault.

Update # 2

I should point out that intel MKL static libaries are compiled with the -fPIC flag, at least according to the documentation. I clearly don't know what I'm doing, but from what I can tell, something like this should be possible.

As blas is used extensively in scientific computing, I am concerned about collisions with different versions. If I'm linking statically within my so file, and load that so file into a program that uses a different blas implementation, would that lead to a collision, or would my library play nice?


Solution

  • If the library is really static, you cannot put in a shared library. Shared object code is compiled in a different way, so that it can work independent of the position. Flags like -fPIC must be used that are not used for static libraries.

    Either compile your BLAS with dgemm as a dynamic library and load it before you load your custom library (perhaps the R dyn.load will load the dependencies automatically, I do not know, you can try) or just include the code of DGEMM into your own library and compile everything together into one .so.

    Do not forget you have to use the MKL Linking Advisor https://software.intel.com/content/www/us/en/develop/articles/intel-mkl-link-line-advisor.html Do NOT link with the ILP64 library, unless you know what you are doing and have a good reason to do so.

    Also, although most of the MKL is shipped with static libraries built using -fPIC, the Fortran 95 interfaces to LAPACK and BLAS are not. The source files for the interfaces are included, so you need to compile them yourself with -fPIC if you want to use them. They are found at $MKLROOT/interfaces/blas95 and $MKLROOT/interfaces/lapack95.