单个主机上有多个glibc库
单个主机上有多个glibc库
我的linux(SLES-8)服务器目前有glibc-2.2.5-235,但是我有一个程序不能在这个版本上运行,需要glibc-2.3.3。
是否有可能在同一主机上安装多个glibcs?
这是我在旧的glibc上运行我的程序时得到的错误:
./myapp: /lib/i686/libc.so.6: version `GLIBC_2.3' not found (required by ./myapp) ./myapp: /lib/i686/libpthread.so.0: version `GLIBC_2.3.2' not found (required by ./myapp) ./myapp: /lib/i686/libc.so.6: version `GLIBC_2.3' not found (required by ./libxerces-c.so.27) ./myapp: /lib/ld-linux.so.2: version `GLIBC_2.3' not found (required by ./libstdc++.so.6) ./myapp: /lib/i686/libc.so.6: version `GLIBC_2.3' not found (required by ./libstdc++.so.6)
于是我创build了一个名为newglibc的新目录,并将以下文件复制到:
libpthread.so.0 libm.so.6 libc.so.6 ld-2.3.3.so ld-linux.so.2 -> ld-2.3.3.so
和
export LD_LIBRARY_PATH=newglibc:$LD_LIBRARY_PATH
但是我得到一个错误:
./myapp: /lib/ld-linux.so.2: version `GLIBC_PRIVATE' not found (required by ./newglibc/libpthread.so.0) ./myapp: /lib/ld-linux.so.2: version `GLIBC_2.3' not found (required by libstdc++.so.6) ./myapp: /lib/ld-linux.so.2: version `GLIBC_PRIVATE' not found (required by ./newglibc/libm.so.6) ./myapp: /lib/ld-linux.so.2: version `GLIBC_2.3' not found (required by ./newglibc/libc.so.6) ./myapp: /lib/ld-linux.so.2: version `GLIBC_PRIVATE' not found (required by ./newglibc/libc.so.6)
所以看起来,他们仍然链接到/ lib,而不是从我把它们放在哪里?
谢谢
在同一个系统上,我们很可能有多个版本的glibc(我们每天都这样做)。
但是,您需要知道glibc包含许多必须匹配的部分(200多个共享库)。 其中一个是ld-linux.so.2,它必须匹配libc.so.6,否则你会看到你所看到的错误。
ld-linux.so.2的绝对path在链接时被硬编码到可执行文件中,链接完成后不能轻易改变。
要构build一个可以使用新的glibc的可执行文件,请执行以下操作:
g++ main.o -o myapp ... \ -Wl,--rpath=/path/to/newglibc \ -Wl,--dynamic-linker=/path/to/newglibc/ld-linux.so.2
-rpath
连接器选项将使运行时加载器在/path/to/newglibc
search库(因此在运行之前不需要设置LD_LIBRARY_PATH
),而-dynamic-linker
选项将“烘烤”path来更正ld-linux.so.2
进入应用程序。
如果您不能重新链接myapp
应用程序(例如,因为它是第三方二进制文件),并不是所有的都会丢失,但是会变得棘手。 一个解决scheme是为它设置合适的chroot
环境。 另一种可能是使用rtldi和二进制编辑器 。
使用LD_PRELOAD:把你的库放在man lib目录的某个地方并运行:
LD_PRELOAD='mylibc.so anotherlib.so' program
请参阅: 维基百科文章
你可以考虑使用Nix http://nixos.org/nix/ ?
Nix支持多用户软件包pipe理:多个用户可以安全地共享一个通用的Nix存储,不需要具有root权限来安装软件,并且可以安装和使用不同版本的软件包。
这个问题很老,这些答案很老。 “俄罗斯人的回答非常好,内容丰富,但幸运的是,现在我们有一个简单的解决scheme来解决这个问题(正如他的回复中所述),使用patchelf 。 你所要做的就是:
$ ./patchelf --set-interpreter /path/to/newglibc/ld-linux.so.2 --set-rpath /path/to/newglibc/ myapp
之后,你可以执行你的文件:
$ ./myapp
幸好没有必要chroot
或编辑二进制文件。 但是如果你不确定你在做什么,记得在修补它之前备份你的二进制文件。 在你修补它后,你不能恢复到解释器/ rpath的旧path。 如果它不起作用,你将不得不修补它,直到你find实际工作的path…呃,它不一定是一个试错的过程。 例如,在OP的例子中,他需要GLIBC_2.3
,所以你可以很容易地find哪个lib使用strings
提供该版本:
$ strings /lib/i686/libc.so.6 | grep GLIBC_2.3 $ strings /path/to/newglib/libc.so.6 | grep GLIBC_2.3
理论上,第一个grep会变成空的,因为系统libc没有他想要的版本,第二个应该输出GLIBC_2.3,因为它有myapp
使用的版本,所以我们知道我们可以使用path。
感谢雇用俄罗斯和迈克尔潘科夫的洞察力和解决scheme!
如果仔细观察第二个输出,可以看到使用了库的新位置。 也许还有遗漏的库是glibc的一部分。
我也认为你的程序使用的所有库都应该针对该版本的glibc进行编译。 如果您有权访问该程序的源代码,则新的编译看起来是最好的解决scheme。
“就业俄罗斯”是最好的答案之一,我认为所有其他build议的答案可能无法正常工作。 原因很简单,因为当第一次创build应用程序时,所有需要的API都会在编译时被parsing。 使用“ldd”你可以看到所有的静态链接的依赖关系:
ldd /usr/lib/firefox/firefox linux-vdso.so.1 => (0x00007ffd5c5f0000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f727e708000) libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f727e500000) libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f727e1f8000) libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f727def0000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f727db28000) /lib64/ld-linux-x86-64.so.2 (0x00007f727eb78000) libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f727d910000)
但在运行时,firefox也会加载许多其他的dynamic库,例如(对于firefox)有很多“glib”标签的库加载(即使静态链接没有):
/usr/lib/x86_64-linux-gnu/libdbus-glib-1.so.2.2.2 /lib/x86_64-linux-gnu/libglib-2.0.so.0.4002.0 /usr/lib/x86_64-linux-gnu/libavahi-glib.so.1.0.2
很多时候,你可以看到一个版本的名字被软链接到另一个版本。 例如:
lrwxrwxrwx 1 root root 23 Dec 21 2014 libdbus-glib-1.so.2 -> libdbus-glib-1.so.2.2.2 -rw-r--r-- 1 root root 160832 Mar 1 2013 libdbus-glib-1.so.2.2.2
因此,这意味着在一个系统中存在不同版本的“库” – 这不是问题,因为它是相同的文件,并且当应用程序具有多个版本依赖关系时它将提供兼容性。
因此,在系统层面上,所有库几乎相互依赖,只是通过操作LD_PRELOAD或LD_LIBRARY_PATH来改变库加载优先级将无济于事 – 即使它可以加载,运行时也可能会崩溃。
http://lightofdawn.org/wiki/wiki.cgi/-wiki/NewAppsOnOldGlibc
最好的select是chroot(简要地提到ER):但是为此,您将需要重新创build原始二进制执行的整个环境 – 通常从/ lib,/ usr / lib /,/ usr / lib / x86开始。您既可以使用“Buildroot”,也可以使用YoctoProject,或者从现有的Distro环境中使用tar。 (比如Fedora / Suse等)。
首先,每个dynamic链接程序最重要的依赖是链接器。 所有库都必须匹配链接器的版本。
让我们以简单的例子:我有新的Ubuntu系统,我运行一些程序(在我的情况下,它是D编译器 – ldc2)。 我想运行在旧的CentOS上,但由于旧的glibc库是不可能的。 我有
ldc2-1.5.0-linux-x86_64/bin/ldc2: /lib64/libc.so.6: version `GLIBC_2.15' not found (required by ldc2-1.5.0-linux-x86_64/bin/ldc2) ldc2-1.5.0-linux-x86_64/bin/ldc2: /lib64/libc.so.6: version `GLIBC_2.14' not found (required by ldc2-1.5.0-linux-x86_64/bin/ldc2)
我必须复制从Ubuntu的所有依赖到centos。 正确的方法如下:
首先,我们来检查所有的依赖关系:
ldd ldc2-1.5.0-linux-x86_64/bin/ldc2 linux-vdso.so.1 => (0x00007ffebad3f000) librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f965f597000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f965f378000) libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f965f15b000) libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f965ef57000) libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f965ec01000) libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f965e9ea000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f965e60a000) /lib64/ld-linux-x86-64.so.2 (0x00007f965f79f000)
linux-vdso.so.1不是一个真正的库,我们不必关心它。
/lib64/ld-linux-x86-64.so.2是链接器,它由linux使用链接可执行文件与所有dynamic库。
其余的文件是真正的库,它们连同链接器都必须复制到centos的某个地方。
假设所有的库和连接器都在“/ mylibs”目录中。
ld-linux-x86-64.so.2 – 正如我已经说过的 – 是链接器。 这不是dynamic库,而是静态可执行文件。 你可以运行它,看看它甚至有一些参数,例如–library-path(我会回到它)。
在Linux上,dynamic链接的程序可能只是由它的名字,例如
/bin/ldc2
Linux将这样的程序加载到RAM中,并检查为其设置了哪个链接程序。 通常,在64位系统上,它是/lib64/ld-linux-x86-64.so.2(在您的文件系统中,它是与真实可执行文件的符号链接)。 然后linux运行链接器,并加载dynamic库。
你也可以改变这一点,做这样的伎俩:
/mylibs/ld-linux-x86-64.so.2 /bin/ldc2
这是迫使linux使用特定链接器的方法。
现在我们可以回到前面提到的参数–library-path
/mylibs/ld-linux-x86-64.so.2 --library-path /mylibs /bin/ldc2
它将运行ldc2并从/ mylibs加载dynamic库。
这是通过select(不是系统默认)库来调用可执行文件的方法。