我想运送和归档二进制文件(带有库的可执行文件),这些二进制文件应与尽可能多的Linux发行版本向后和向前兼容,并且整个软件包都可重定位。
据我了解,还需要交付libc
之类的系统库,因为在libc
的其他版本下,可执行文件将崩溃。同时libc
似乎与ld-linux
耦合
(例如,在Debian测试中编译的二进制文件已经无法在Ubuntu 18.04 LTS上运行),因此我也需要打包ld-linux
。
我的解决方案是将所有可执行文件和库放入一个目录,并将rpath设置为$ORIGIN
(通过与-Wl,rpath=$ORIGIN
链接或通过chrpath
或patchelf
进行设置)。这样可以使这些库与可执行文件一起重新定位,并且可以对除链接器本身的ld-linux
以外的所有库使用。
可以通过-Wl,--dynamic-linker=/my/path/ld-linux.so
更改动态链接器路径,也可以使用patchelf
设置动态链接器路径,但该路径必须是绝对路径:
$ORIGIN
技巧不起作用./
这样的相对路径有效,但仅当当前目录与加载器本身相同时(从其他位置启动时,可执行文件崩溃并出现错误)/my/path/ld-linux.so /my/path/myexecutable $@
启动可执行文件,但这意味着我还要避免另一层间接和开销。是否可以将相对于可执行文件的ld-linux路径直接设置为可执行文件?
也许有一种方法可以静态链接ld-linux加载程序?
答案 0 :(得分:0)
据我了解,像libc这样的系统库也需要交付,因为在使用其他版本的libc时,可执行文件将崩溃。
那是不正确:GLIBC保证了向后兼容性(在较旧版本的系统上构建的可执行文件将继续在较新版本的GLIBC上运行)。
实现所需目标的唯一明智方法是针对您希望支持的最旧版本的GLIBC进行编译。
同时libc似乎与ld-linux结合
正确的:libc.so.6
和ld-linux
是GLIBC的一部分,必须来自同一内部版本,任何不匹配都可能导致灾难性的故障(内部的SIGSEGV
libc.so.6
或ld-linux
内部。)
我也需要打包ld-linux。
这很复杂:ld-linux
的 absolute 路径被硬编码到a.out
中,并且不能更改。使可重定位 a.out
可以容忍对ld-linux
路径的更改是不可能的(缺少您已经尝试过的显式加载程序调用;这对于可执行文件不起作用自己重新执行)。
更新:
我可以尝试在旧的Ubuntu LTS上构建并获得大多数向后兼容性,但是后来我没有获得新的C ++ 17编译器,这基本上使现代软件工程学的观点败了。
您可以在较旧的系统上安装较新的编译器,并使用较旧的GLIBC获得C ++ 17。
这样做的一个困难是您可能需要更新的libstdc++.so.6
。
好消息是-Wl,-rpath=$ORIGIN
可以正常工作-只有GLIBC很难重定位。您也可以将libstdc++.a
的可执行文件与--static-libstdc++
链接。
但是,在任何一种情况下都可能涉及许可问题(但是,您的计划又一次已经包括分发所有库,因此,这不是新问题)。