我的linux (SLES-8)服务器目前有glibc-2.2.5-235,但我有一个程序不能在这个版本上工作,需要glibc-2.3.3。

是否可以在同一台主机上安装多个glibc ?

这是我在旧的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)

所以我创建了一个名为newglibc的新目录,并复制了以下文件:

libpthread.so.0
libm.so.6
libc.so.6
ld-2.3.3.so
ld-linux.so.2 -> ld-2.3.3.so

and

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,而不是从我放置它们的位置拾取。


当前回答

“受雇的俄罗斯人”是最好的答案之一,我认为所有其他建议的答案可能都行不通。原因很简单,因为当应用程序第一次创建时,它需要的所有api都在编译时解析。使用"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也会加载许多其他动态库,例如(对于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

最好的替代方案是chroot (ER简要提到过):但为此你需要重新创建原始二进制执行的整个环境——通常从/lib, /usr/lib/x86等开始。你可以使用“builroot”,或者YoctoProject,或者直接从现有的发行版环境中tar。(比如Fedora/Suse等)。

其他回答

首先,每个动态链接程序最重要的依赖项是链接器。所有这些库必须与链接器的版本相匹配。

让我们举一个简单的例子:我有一个newset 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.。2是链接器,Linux使用它将可执行文件与所有动态库链接起来。

其余的文件都是真正的库,所有这些文件和链接器都必须复制到centos中的某个地方。

让我们假设所有的库和链接器都在“/mylibs”目录下。

ld - linux - x86 - 64.。2 -我已经说过了-是连接器。它不是动态库,而是静态可执行文件。您可以运行它并查看它甚至有一些参数,例如library-path(我将返回它)。

在linux上,动态链接的程序可以只根据它的名字来发布

/bin/ldc2

Linux将这样的程序加载到RAM中,并检查为它设置了哪个链接器。通常,在64位系统上,它是/lib64/ld-linux-x86-64.so.2(在您的文件系统中,它是到实际可执行文件的符号链接)。 然后linux运行链接器并加载动态库。

你也可以稍微改变一下,这样做:

/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加载动态库。

这是使用选择(不是系统默认)库调用可执行文件的方法。

你可以考虑使用Nix http://nixos.org/nix/吗?

Nix支持多用户包管理:多个用户可以共享一个 普通Nix存储安全,不需要有root权限即可 安装软件,并可以安装和使用不同版本的一个 包中。

在同一个系统上有多个glibc版本是很可能的(我们每天都这样做)。

但是,您需要知道glibc包含许多必须匹配的部分(200多个共享库)。其中一个是ld-linux.so。2,它必须匹配lib .so。6,否则你会看到你所看到的错误。

linux.so的绝对路径。2是在链接时硬编码到可执行文件中,并且在链接完成后不能轻易更改(更新:可以用patchelf完成;请看下面的答案)。

要构建一个可以与新的glibc一起工作的可执行文件,请执行以下操作:

g++ main.o -o myapp ... \
   -Wl,--rpath=/path/to/newglibc \
   -Wl,--dynamic-linker=/path/to/newglibc/ld-linux.so.2

-rpath linker选项将使运行时加载器搜索/path/to/newglibc中的库(因此您不必在运行它之前设置LD_LIBRARY_PATH),而-dynamic-linker选项将“烤”路径以纠正ld-linux.so。2 .进入应用。

如果不能重新链接myapp应用程序(例如,因为它是第三方二进制文件),并不是全部都丢失了,但它会变得更棘手。一种解决方案是为它设置适当的chroot环境。另一种可能是使用rtldi和二进制编辑器。更新:或者你可以使用patchelf。

我不确定这个问题是否仍然相关,但有另一种解决问题的方法:Docker。可以安装源发行版(用于开发的发行版)的一个几乎空的容器,并将文件复制到容器中。这样就不需要创建chroot所需的文件系统。

这个问题老了,其他答案也老了。“受雇的俄罗斯人”的回答是非常好的和信息丰富的,但它只有在你有源代码的情况下才有效。如果你不这样做,那时候的选择是非常棘手的。幸运的是,现在我们对这个问题有了一个简单的解决方案(正如他在回复中评论的那样),使用patchelf。你所要做的就是:

$ ./patchelf --set-interpreter /path/to/newglibc/ld-linux.so.2 --set-rpath /path/to/newglibc/ myapp

在那之后,你可以执行你的文件:

$ ./myapp

No need to chroot or manually edit binaries, thankfully. But remember to backup your binary before patching it, if you're not sure what you're doing, because it modifies your binary file. After you patch it, you can't restore the old path to interpreter/rpath. If it doesn't work, you'll have to keep patching it until you find the path that will actually work... Well, it doesn't have to be a trial-and-error process. For example, in OP's example, he needed GLIBC_2.3, so you can easily find which lib provides that version using strings:

$ strings /lib/i686/libc.so.6 | grep GLIBC_2.3
$ strings /path/to/newglib/libc.so.6 | grep GLIBC_2.3

理论上,第一个grep会是空的,因为系统libc没有他想要的版本,而第二个grep应该输出glibc2.3,因为它有myapp正在使用的版本,所以我们知道可以使用该路径修补我们的二进制文件。如果你得到一个分割错误,阅读末尾的说明。

当你尝试在linux中运行二进制文件时,二进制文件会尝试加载链接器,然后加载库,它们都应该在路径和/或在正确的位置。如果你的问题是链接器,你想知道你的二进制文件在寻找哪个路径,你可以用这个命令来找到:

$ readelf -l myapp | grep interpreter
  [Requesting program interpreter: /lib/ld-linux.so.2]                                                                                                                                                                                   

如果你的问题是库,命令会给你正在使用的库:

$ readelf -d myapp | grep Shared
$ ldd myapp 

这将列出二进制文件需要的库,但您可能已经知道有问题的库,因为它们已经产生错误,就像OP的情况一样。

"patchelf" works for many different problems that you may encounter while trying to run a program, related to these 2 problems. For example, if you get: ELF file OS ABI invalid, it may be fixed by setting a new loader (the --set-interpreter part of the command) as I explain here. Another example is for the problem of getting No such file or directory when you run a file that is there and executable, as exemplified here. In that particular case, OP was missing a link to the loader, but maybe in your case you don't have root access and can't create the link. Setting a new interpreter would solve your problem.

感谢受雇于俄罗斯和Michael Pankov的洞察力和解决方案!


注意分割错误:你可能在myapp使用几个库的情况下,他们中的大多数是可以的,但有些不是;然后你修补它到一个新的目录,你得到分割错误。当你修补你的二进制文件时,你改变了几个库的路径,即使有些原本在不同的路径。看看下面的例子:

$ ldd myapp
./myapp: /usr/lib/x86_64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.20' not found (required by ./myapp)
./myapp: /usr/lib/x86_64-linux-gnu/libstdc++.so.6: version `GLIBCXX_3.4.21' not found (required by ./myapp)
        linux-vdso.so.1 =>  (0x00007fffb167c000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f9a9aad2000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f9a9a8ce000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f9a9a6af000)
        libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f9a9a3ab000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f9a99fe6000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f9a9adeb000)
        libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f9a99dcf000)

Note that most libs are in /lib/x86_64-linux-gnu/ but the problematic one (libstdc++.so.6) is on /usr/lib/x86_64-linux-gnu. After I patchelf'ed myapp to point to /path/to/mylibs, I got segmentation fault. For some reason, the libs are not totally compatible with the binary. Since myapp didn't complain about the original libs, I copied them from /lib/x86_64-linux-gnu/ to /path/to/mylibs2, and I also copied libstdc++.so.6 from /path/to/mylibs there. Then I patchelf'ed it to /path/to/mylibs2, and myapp works now. If your binary uses different libs, and you have different versions, it might happen that you can't fix your situation. :( But if it's possible, mixing libs might be the way. It's not ideal, but maybe it will work. Good luck!