Search code examples
c++staticopenblas

static linking to libopenblas


I am compiling a C++ program with -static so that I can take my program to a server and run it. The server has not all libraries installed I am linking with and when trying to run the program I get the error that libopenblas.so.0 can not be found as OpenBLAS is not installed:

error while loading shared libraries: libopenblas.so.0: cannot open shared object file: No such file or directory

I need OpenBLAS for the linear algebra library Armadillo and I compile with the flags

-std=c++11 -static -pthread -Ofast -march=native -mtune=native -m64 -Wall -Werror -Wextra -Wno-long-long -Ishared_methods -Icreate_codes/source_files -Ievaluate_codes/source_files -Igenomes/source_files -lopenblas -llapack -lgfortran

So is it not possible to statically link OpenBLAS or did I do something wrong?

EDIT: This is my makefile. I have removed the commands and definitions for other programs for simplicity.

CXX =       h5c++

CXXFLAGS=   -std=c++11 -static -pthread -Ofast -march=native -mtune=native -m64 -Wall -Werror -Wextra -Wno-long-long -Ishared_methods -Ievaluate_codes/source_files

ENDFLAGS = -lopenblas -llapack -lgfortran

RELDIR_E =  ./evaluate_codes/source_files
RELDIR_M =  ./shared_methods

HEADERS =       $(RELDIR_M)/methods.h   

SRCS_E_MIR =    $(RELDIR_E)/mir.cpp \
        $(RELDIR_M)/methods.cpp

OBJS_E_MIR =    $(SRCS_E_MIR:.cpp=.o)

TARGET_E_MIR = evaluate_codes/mir.out

e_mir:  $(OBJS_E_MIR) 
$(CXX) $(LDFLAGS) $(OBJS_E_MIR) $(LIBS) -o $(TARGET_E_MIR) $(ENDFLAGS)

clean_e_mir:
rm -f $(OBJS_E_MIR) $(TARGET_E_MIR)

EDIT 2: On my machine all the static (.a) and shared (.so) libraries exist and the program runs, but on the server I do not have all of the libraries. That is why I want to build it fully static, but it seems like the dependencies of the libraries are not fully included as shown by ldd mir.out:

linux-vdso.so.1 =>  (0x00007fff74532000)
libopenblas.so.0 => /usr/lib/libopenblas.so.0 (0x00007fe73dbc8000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fe73d9ab000)
libsz.so.2 => /usr/lib/x86_64-linux-gnu/libsz.so.2 (0x00007fe73d7a8000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007fe73d58e000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fe73d38a000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fe73d008000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fe73ccff000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fe73cae9000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe73c71f000)
libgfortran.so.3 => /usr/lib/x86_64-linux-gnu/libgfortran.so.3 (0x00007fe73c3f4000)
/lib64/ld-linux-x86-64.so.2 (0x00007fe73fc5c000)
libaec.so.0 => /usr/lib/x86_64-linux-gnu/libaec.so.0 (0x00007fe73c1ec000)
libquadmath.so.0 => /usr/lib/x86_64-linux-gnu/libquadmath.so.0 (0x00007fe73bfad000)

So how can I tell the compiler to include those dependencies in a static way?


Solution

  • Your -static option is having no effect.

    You have written no rule to compile your source files. You are allowing them to be compiled using make's built-in rule:

    %.o:%.cpp
        $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $@ S<
    

    in which:-

    • $(CXX) expands to your defined or default C++ compiler
    • $(CPPFLAGS) expands to your defined Preprocessor flags
    • $(CXXFLAGS) expands to your defined C++ compiler flags

    You have defined:

    CXXFLAGS=   -std=c++11 -static -pthread -Ofast -march=native -mtune=native \
     -m64 -Wall -Werror -Wextra -Wno-long-long \
     -Ishared_methods -Ievaluate_codes/source_files
    

    So -static is passed to the compilation command by the built-in recipe. However, it is not a compilation option. It is a linkage option. It is ignored in compilation. You do not pass it to the linkage command. So it has no effect.

    Two other important make variables that have conventional meanings to make (and are used with those meanings in built-in rules) are:

    • LDFLAGS is to be defined as your linkage options, excluding library options (-lfoo) and explicitly named libraries
    • LDLIBS is to be defined as your library options and explicitly named libraries.

    So -static, a linkage option, should properly be included in the value of LDFLAGS, not CXXFLAGS

    In many ways your makefile deviates from normal practice and suggests you may not yet be very knowledge about GNU Make. If would be impractical to pick out all the fluff here. Your linkage recipe is:

    e_mir:  $(OBJS_E_MIR) 
        $(CXX) $(LDFLAGS) $(OBJS_E_MIR) $(LIBS) -o $(TARGET_E_MIR) $(ENDFLAGS)
    

    The smallest (though not the best) set of corrections that will cause the -static option to take effect in the linkage is:

    • Remove -static from the definition of CXXFLAGS
    • Add it to the definition of ENDFLAGS

    Be aware that successfully getting -static to take effect in the linkage does not mean that the attempted static linkage will succeed: just that it will be attempted, which is not happening now.

    Be aware too that a fully static linkage is a drastic step and is unnecessarily drastic if the problem you are trying to solve is simply that some shared libraries you link with are not available on your target server.

    The effect of -static is require that static versions of all the libraries required by the linkage must be found by your linkage. Not just your:

    -lopenblas -llapack -lgfortran
    

    but also the C runtime library and the Standard C++ library that are linked by default, plus the Posix Threads library that is requested by -pthread. Have you installed the static versions of all those?

    If you merely need to link, say, the static versions of libopenblas and liblapack, and you have installed libopenblas.a liblapack.a on your system so that the linker will find them in its default search directories, then you can simply change:

    -lopenblas -llapack -lgfortran
    

    to:

    -l:libopenblas.a -l:liblapack.a -lgfortran
    

    Whereas -lname instructs the linker to search the specified (-Ldir) or default search directories for either libname.so (shared library) or libname.a (static library) and to prefer libfoo.so if it finds both in the same directory, -l:name instructs the linker to search for a file with the exact name name. So by specifiying -l:libopenblas.a you can request linkage of libopenblas.a with no larger effects than just that.