如何为自编译程序提供匹配的共享库?

如何为自编译程序提供匹配的共享库?

我在自己的 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 可以保留并多次重复使用。

相关内容