静态链接到 libopenblas

Ste*_*fan 4 c++ static openblas

我正在编译一个C++程序,-static以便我可以将程序带到服务器并运行它。服务器尚未安装我链接的所有库,当尝试运行该程序时,我收到由于未安装libopenblas.so.0而无法找到的错误:OpenBLAS

error while loading shared libraries: libopenblas.so.0: cannot open shared object file: No such file or directory
Run Code Online (Sandbox Code Playgroud)

我需要OpenBLAS线性代数库Armadillo,并使用标志进行编译

-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
Run Code Online (Sandbox Code Playgroud)

那么是不可能静态链接OpenBLAS还是我做错了什么?

编辑:这是我的生成文件。为了简单起见,我删除了其他程序的命令和定义。

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)
Run Code Online (Sandbox Code Playgroud)

编辑2:在我的机器上,所有静态(.a)和共享(.so)库都存在并且程序运行,但在服务器上我没有所有库。这就是为什么我想将其构建为完全静态的,但似乎库的依赖项并未完全包含在内,如下所示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)
Run Code Online (Sandbox Code Playgroud)

那么我如何告诉编译器以静态方式包含这些依赖项呢?

Mik*_*han 7

你的-static选择没有任何作用。

您没有编写任何规则来编译源文件。您允许使用 make 的内置规则来编译它们:

%.o:%.cpp
    $(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $@ S<
Run Code Online (Sandbox Code Playgroud)

其中:-

  • $(CXX)扩展到您定义的或默认的 C++ 编译器
  • $(CPPFLAGS)扩展到您定义的预处理器标志
  • $(CXXFLAGS)扩展为您定义的 C++ 编译器标志

您已定义:

CXXFLAGS=   -std=c++11 -static -pthread -Ofast -march=native -mtune=native \
 -m64 -Wall -Werror -Wextra -Wno-long-long \
 -Ishared_methods -Ievaluate_codes/source_files
Run Code Online (Sandbox Code Playgroud)

所以-static通过内置配方传递给编译命令。但是,它不是编译选项。这是一个链接选项。它在编译时被忽略。您不将其传递给链接命令。所以没有效果。

另外两个重要的 make 变量具有常规含义(并在内置规则中与这些含义一起使用)是:

  • LDFLAGS被定义为您的链接选项,不包括库选项 ( -lfoo) 和显式命名的库
  • LDLIBS被定义为您的库选项和显式命名的库。

因此-static,链接选项 应该正确包含在 的值中LDFLAGS,而不是CXXFLAGS

在很多方面,您的 makefile 都偏离了正常做法,这表明您可能还不太了解 GNU Make。如果把这里所有的绒毛都挑出来是不切实际的。您的链接配方是:

e_mir:  $(OBJS_E_MIR) 
    $(CXX) $(LDFLAGS) $(OBJS_E_MIR) $(LIBS) -o $(TARGET_E_MIR) $(ENDFLAGS)
Run Code Online (Sandbox Code Playgroud)

导致该-static 选项在链接中生效的最小(尽管不是最好)的更正集是:

  • -static从定义中删除CXXFLAGS
  • 将其添加到定义中ENDFLAGS

请注意,成功-static在链接中生效并不意味着尝试的静态链接将会成功:只是会尝试它,但现在不会发生。

还要注意,完全静态链接是一个激烈的步骤,并且如果您要解决的问题只是您链接的某些共享库在目标服务器上不可用,则不必要的激烈。

的效果-static是要求链接必须找到链接所需的所有库的静态版本。不只是你的:

-lopenblas -llapack -lgfortran
Run Code Online (Sandbox Code Playgroud)

还有默认链接的 C 运行时库和标准 C++ 库,以及-pthread. 您安装了所有这些的静态版本吗?

如果您只需要链接 和 的静态版本libopenblasliblapack并且您已经安装libopenblas.a liblapack.a在系统上,以便链接器可以在其默认搜索目录中找到它们,那么您只需更改:

-lopenblas -llapack -lgfortran
Run Code Online (Sandbox Code Playgroud)

到:

-l:libopenblas.a -l:liblapack.a -lgfortran
Run Code Online (Sandbox Code Playgroud)

指示-lname链接器在指定 ( -Ldir) 或默认搜索目录中搜索libname.so(共享库) 或libname.a (静态库),并优先选择libfoo.so在同一目录中找到两者, -l:name指示链接器搜索具有确切名称的文件name。因此,通过指定,-l:libopenblas.a您可以请求链接,而libopenblas.a 不会产生比这更大的影响。