我在自己的 Ubuntu 系统上编译了一个程序。现在我想在具有相同架构但共享库略微过时的外国 Ubuntu 系统上运行它。如何让我自己系统中的库在外国系统上运行?我不是外国机器上的 root 用户。
到目前为止,我尝试将列出的文件me@mymachine> ldd myprogram
一起复制myprogram
到外部机器上的同一目录中。在me@foreignmachine> ./myprogram
那里执行时,我期望加载同一目录中的库,而不是库路径中过时的库。但是,我收到了错误消息
/usr/lib64/libgomp.so.1: version `GOMP_4.0' not found (required by ./myprogram)
/lib64/libc.so.6: version `GLIBC_2.14' not found (required by ./myprogram)
因此显然我复制的库尚未加载,因为它们在我的系统(我编译程序的地方)上有正确的版本。
还有其他可用的解决方案吗?静态链接也不起作用(如预期的那样)。
编辑:ldd myprogram
产生:
linux-vdso.so.1 => (0x00007ffccabf4000)
libgfortran.so.3 => /usr/lib/x86_64-linux-gnu/libgfortran.so.3 (0x00007f149b334000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f149b038000)
libgomp.so.1 => /usr/lib/x86_64-linux-gnu/libgomp.so.1 (0x00007f149ae15000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f149abfe000)
libquadmath.so.0 => /usr/lib/x86_64-linux-gnu/libquadmath.so.0 (0x00007f149a9bf000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f149a7a1000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f149a3e3000)
/lib64/ld-linux-x86-64.so.2 (0x00007f149b67d000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f149a1db000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f1499fd6000)
/lib/x86_64-linux-gnu/libdl.so.2
于是我将、/lib/x86_64-linux-gnu/librt.so.1
等10 个文件复制/lib64/ld-linux-x86-64.so.2
到外部系统。根据我的发现,似乎不需要关心,linux-vdso.so.1
因为它是在内核中自动生成的。
答案1
在 Linux 上,动态链接器默认不会在当前目录中查找。如果你确实在当前目录中包含了所有需要的库,它应该可以工作:
LD_LIBRARY_PATH=. ./myprogram
如果您没有提供所有必要的库,它可能会抱怨或者崩溃(由于链接器无法检测到的二进制不兼容性,仅比较库版本号)。
参考:man ld.so
LD_LIBRARY_PATH 以冒号分隔的目录列表,用于在执行时搜索 ELF 库。类似于 PATH 环境变量。在 set-user-ID 和 set-group-ID 程序中被忽略。
答案2
谢谢Julien 的这个回答,我向链接器添加了选项-L. -Wl,-rpath='$ORIGIN'
。-L
告诉链接器在编译的目录中查找共享库。第二个选项更重要,因为现在在运行时,将采用可执行文件所在的原始目录中的共享库。所以如果我现在ldd /home/on/foreign/machine/myprogram
在外部机器上执行此操作,我会得到例如
libgfortran.so.3 => /home/on/foreign/machine/libgfortran.so.3
但还有一个库,其条目没有改变:/lib64/ld-linux-x86-64.so.2
。这是@Stéphane 指出的别名。现在根据他教给我的知识,我决定在另一台机器上ld.so
尝试使用我自己机器上的 -file:ld-linux-x86-65.so.2
me@foreign:/home/on/foreign/machine> ./ld-linux-x86-64.so.2 ./myprogram
最后在国外的机器上也成功了,注意我没有改LD_LIBRARY_PATH
。
不过,我认为这是可行的,因为两台机器之间只有内核版本(而不是架构)不同。
答案3
在 Linux 上,人们在内核级别上为实现二进制兼容性付出了很大的努力,但在库级别上却付出了较少的努力。
我多次尝试,并且效果非常好,就是在开发机器上创建一个 chroot,其中包含目标机器环境(包括编译器)。(可以用虚拟机或任何类型的容器替换 chroot。)
在这种环境中制作的二进制文件将始终完美地适合目标机器。
优点/缺点是:
- chroot 或容器缺点:需要一些努力(特别是第一次)——chroot 是更传统的 Unix。
schroot
可能有助于调整和使用 chroot。 - chroot 或 container pro:资源占用少(尤其是 chroot)
- chroot 或 container pro:以某种方式更容易编写脚本(尤其是使用 schroot 或 sudo 配置)。
- 虚拟机专业版:对初学者来说更容易(例如 VirtualBox)。
- 虚拟机缺点:磁盘使用率和 CPU 占用较高
- 虚拟机的缺点:通常需要图形访问(足够高级的用户更喜欢通过 SSH 进行 shell 访问,可能足够精明的用户更喜欢使用容器或 chroot)。
无论如何,chroot/container/VM 可以保留并多次重复使用。