我正在尝试编译一个非常基本的程序并在多个操作系统上运行。该程序只是尝试使用boost::filesystem
将其文件名打印为流,以便我可以验证加载.so
是否按预期工作。
我在Ubuntu框上编译它:
$ uname -a
Linux ubuntu 3.13.0-48-generic #80-Ubuntu SMP Thu Mar 12 11:16:15 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
我有一个CentOS盒子,我试图在它上面运行它:
$ uname -a
Linux localhost.localdomain 3.10.0-123.20.1.el7.x86_64 #1 SMP Thu Jan 29 18:05:33 UTC 2015 x86_64 x86_64 x86_64 GNU/Linux
我使用$ORIGIN
编译可执行文件,以便从我的目录中选择链接的boost库,然后我ldd
将boost库和cp
它们放在同一个库中。因此,lib目录如下所示:
deliverable/
deliverable/hello
deliverable/.lib/
deliverable/.lib/libc.so.6
deliverable/.lib/libboost_system.so.1.58.0
deliverable/.lib/libpthread.so.0
deliverable/.lib/libm.so.6
deliverable/.lib/libstdc++.so.6
deliverable/.lib/libboost_filesystem.so.1.58.0
deliverable/.lib/libboost_filesystem.so
deliverable/.lib/libfoo.so
deliverable/.lib/libboost_system.so
deliverable/.lib/libgcc_s.so.1
其中hello
是我想要运行的可执行文件。但是,在CentOs框中,我收到以下错误:
$ ./hello
$ ./hello: relocation error: ~/deliverable/.lib/libc.so.6: symbol _dl_find_dso_for_object, version GLIBC_PRIVATE not defined in file ld-linux-x86-64.so.2 with link time reference
如何解决这个问题?我还想知道这种模式是否违反了关于在Linux机器之间运送编译代码的最佳实践。 。
如果相关,请提供更多信息:
$ cat Makefile
CXX = g++
CPPFLAGS := -Wall -g -Wfatal-errors -std=c++11 -I./inc -fPIC
DELIVERABLE = $(CURDIR)/deliverable
LIB = $(DELIVERABLE)/.lib
all: $(DELIVERABLE)/hello
$(DELIVERABLE)/hello: main.o $(LIB)/libfoo.so
$(CXX) -L./deliverable/.lib -Wl,--allow-shlib-undefined -Wl,-rpath='$$ORIGIN/.lib' -o $@ $< -lfoo
main.o: main.cc
$(CXX) $(CPPFLAGS) -c $< -o $@
$(LIB)/libfoo.so: foo.o
$(CXX) -L./deliverable/.lib -Wl,--allow-shlib-undefined -Wl,-rpath='$$ORIGIN/.lib' -shared -o $@ $^ -lboost_system -lboost_filesystem
foo.o: foo.cc
$(CXX) $(CPPFLAGS) -c $< -o $@
clean:
rm -f *.o $(LIB)/libfoo.so $(DELIVERABLE)/hello
$ cat main.cc
#include "foo.hh"
int main()
{
hello();
}
$ cat foo.hh
#ifndef FOO_HH
#define FOO_HH
void hello();
#endif
$ cat foo.cc
#include "foo.hh"
#include <boost/filesystem.hpp>
#include <iostream>
void hello()
{
boost::filesystem::path p{__FILE__};
std::cout << "p.parent_path() " << p.parent_path() << '\n';
std::cout << "p.string() " << p.string() << '\n';
std::cout << "__FILE__ " << __FILE__ << '\n';
}
我也在RHEL盒子上试过这个,这给出了更糟糕的错误:
$ uname -a
Linux localhost.localdomain 2.6.18-164.6.1.el5 #1 SMP Tue Nov 3 ... EXT 2009 x86_64 x86_64 GNU/Linux
在这台计算机上运行它崩溃了:
$./hello
./hello: error while loading shared libraries: ~/deliverable/.lib/libm.so.6: unexpected PLT reloc type 0x25
答案 0 :(得分:0)
我想,在系统安装了额外的.so
个文件之后,你必须“告诉”他们是否在那里?
ldconfig是我想到的命令:
ldconfig creates the necessary links and cache (for use by the run-time linker, ld.so) to the most recent shared libraries found in the directories specified on the command line, in the file /etc/ld.so.conf, and in the trusted directories (/usr/lib and /lib). ldconfig checks the header and file names of the libraries it encounters when determining which versions should have their links updated. ldconfig ignores symbolic links when scanning for libraries.
http://linux.about.com/od/commands/l/blcmdl8_ldconfi.htm
答案 1 :(得分:0)
我想这是Linux发行版之间细微差别的典型案例:
基于Debian和基于RedHat的CentOS的Ubuntu已知使用不同的位置来存储系统库,并且 - 更糟糕的是 - 也使用不同的命名方案。
如果发行版的年龄变化很大(新的Ubuntu版本与旧版CentOS相反,反之亦然),则会出现更多并发症。
您在Ubuntu计算机上编译了所有库。运行ldd ~/deliverable/.lib/libc.so.6
将显示完整的依赖项列表,即找到所有依赖项。
我几乎可以肯定在CentOS计算机上运行相同的命令会显示一个不完整的列表(找不到一个或多个依赖项)。这很可能是由于上面提到的Linux发行版之间存在差异。
从头脑中,我看到以下方法来处理这种情况:
使用您在Ubuntu上ldd
显示的相同绝对路径来识别缺少的依赖项的特定于分发的位置和名称以及 sym-link 它们机。这是一个快速而肮脏的解决方案,可能或(可能)不起作用。我会提出反对意见。
编译deliverable/.lib/*
中针对特定目标平台的所有库并相应地链接它们。这也会导致必须运送libstd++
,因为它将与正确的链接相关联。