静态链接到 libopenblas

static linking to libopenblas

我正在用 -static 编译一个 C++ 程序,这样我就可以将我的程序带到服务器并 运行 它。服务器没有安装我正在 link 使用的所有库,当尝试 运行 程序时,我收到错误消息 libopenblas.so.0 找不到,因为 OpenBLAS 未安装:

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

我需要 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

那么是不是不能静态linkOpenBLAS还是我做错了什么?

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

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)

编辑 2:在我的机器上存在所有静态 (.a) 和共享 (.so) 库和程序 运行s,但在服务器上我没有所有的图书馆。这就是为什么我想完全静态地构建它,但似乎没有完全包含库的依赖项,如 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)

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

您的 -static 选项无效。

您没有编写编译源文件的规则。您允许使用 make 的 built-in rule:

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

其中:-

  • $(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

所以-static被built-in传递给编译命令 食谱。但是,它不是一个编译选项。这是一个 linkage 选项。它 在编译中被忽略。您不会将其传递给 linkage 命令。所以 没有效果。

另外两个重要的 make 变量具有常规意义 make(并被使用 built-in 规则中的那些含义)是:

  • LDFLAGS 将定义为您的 link 年龄选项,不包括图书馆选项 (-lfoo) 和明确命名的库
  • LDLIBS 将定义为您的库选项并明确命名库。

所以 -static,一个 linkage 选项,应该正确地包含在 LDFLAGS 的值中,而不是 CXXFLAGS

您的 makefile 在许多方面都偏离了正常做法,并建议您 可能还不是很了解 GNU Make。如果挑出来不切实际 这里所有的绒毛。您的link年龄配方是:

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

将导致 -static 的最小(虽然不是最好)一组更正 在link年龄生效的选项是:

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

请注意,成功让-static在link年龄生效 并不意味着尝试的静态 linkage 会 成功 :只是它将是 尝试过,但现在没有发生。

还要注意,完全静态 linkage 是一个激烈的步骤,没有必要 如果你试图解决的问题仅仅是一些共享 您 link 使用的库在您的目标服务器上不可用。

-static的效果是要求所有库的静态版本 link年龄要求的必须根据您的link年龄找到。不只是你的:

-lopenblas -llapack -lgfortran

还有 linked 的 C 运行时库和标准 C++ 库 默认情况下,加上 -pthread 请求的 Posix 线程库。 您是否安装了所有这些的静态版本?

如果您只需要 link,比如 libopenblasliblapack 的静态版本,那么您有 在您的系统上安装了 libopenblas.a liblapack.a 以便 linker 将在其默认搜索目录中找到它们,然后您只需更改:

-lopenblas -llapack -lgfortran

至:

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

-lname 指示 linker 搜索指定的 (-Ldir) 或 libname.so(共享库)或 libname.a 的默认搜索目录 (静态库),如果在同一目录中找到两者,则更喜欢 libfoo.so-l:name 指示 link 用户搜索具有确切名称 name 的文件。 因此,通过指定 -l:libopenblas.a,您可以请求 linkage of libopenblas.a 没有比这更大的影响了。