单个主机上的多个 glibc 库

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/847179/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 17:18:37  来源:igfitidea点击:

Multiple glibc libraries on a single host

linuxgccglibc

提问by dogbane

Multiple glibc libraries on a single host

单个主机上的多个 glibc 库

My linux (SLES-8) server currently has glibc-2.2.5-235, but I have a program which won't work on this version and requires glibc-2.3.3.

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

Is it possible to have multiple glibcs installed on the same host?

是否可以在同一主机上安装多个 glibcs​​?

This is the error I get when I run my program on the old 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)

So I created a new directory called newglibc and copied the following files in:

所以我创建了一个名为 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

But I get an error:

但我收到一个错误:

./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)

So it appears that they are still linking to /lib and not picking up from where I put them?

所以看起来它们仍然链接到 /lib 而不是从我放置它们的地方拿起?

Thanks

谢谢

采纳答案by Employed Russian

It is very possible to have multiple versions of glibc on the same system (we do that every day).

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

However, you need to know that glibc consists of many pieces (200+ shared libraries) which all must match. One of the pieces is ld-linux.so.2, and it mustmatch libc.so.6, or you'll see the errors you are seeing.

但是,您需要知道 glibc 由许多必须匹配的部分(200 多个共享库)组成。其中之一是 ld-linux.so.2,它必须与 libc.so.6 匹配,否则您将看到您所看到的错误。

The absolute path to ld-linux.so.2 is hard-coded into the executable at link time, and can not be easily changed after the link is done.

ld-linux.so.2 的绝对路径在链接时被硬编码到可执行文件中,并且在链接完成后不能轻易更改。

To build an executable that will work with the new glibc, do this:

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

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

The -rpathlinker option will make the runtime loader search for libraries in /path/to/newglibc(so you wouldn't have to set LD_LIBRARY_PATHbefore running it), and the -dynamic-linkeroption will "bake" path to correct ld-linux.so.2into the application.

-rpath连接选项将在库运行时加载器搜索/path/to/newglibc(这样你就不必组LD_LIBRARY_PATH运行前),并-dynamic-linker选择将“硬”路径正确ld-linux.so.2到应用程序中。

If you can't relink the myappapplication (e.g. because it is a third-party binary), not all is lost, but it gets trickier. One solution is to set a proper chrootenvironment for it. Another possibility is to use rtldiand a binary editor.

如果您无法重新链接myapp应用程序(例如,因为它是第三方二进制文件),则不会丢失所有内容,但会变得更加棘手。一种解决方案是为其设置适当的chroot环境。另一种可能性是使用rtldi二进制编辑器

回答by rsarro

If you look closely at the second output you can see that the new location for the libraries is used. Maybe there are still missing libraries that are part of the glibc.

如果仔细查看第二个输出,您会发现使用了库的新位置。也许仍然缺少属于 glibc 的库。

I also think that all the libraries used by your program should be compiled against that version of glibc. If you have access to the source code of the program, a fresh compilation appears to be the best solution.

我还认为您的程序使用的所有库都应该针对该版本的 glibc 进行编译。如果您可以访问程序的源代码,那么重新编译似乎是最好的解决方案。

回答by PiedPiper

Use LD_PRELOAD: put your library somewhere out of the man lib directories and run:

使用 LD_PRELOAD:将您的库放在 man lib 目录之外的某个位置并运行:

LD_PRELOAD='mylibc.so anotherlib.so' program

See: the Wikipedia article

参见:维基百科文章

回答by Employed Russian

Can you consider using Nix http://nixos.org/nix/?

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

Nix supports multi-user package management: multiple users can share a common Nix store securely, don't need to have root privileges to install software, and can install and use different versions of a package.

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

回答by Peter Teoh

"Employed Russian" is among the best answer, and I think all other suggested answer may not work. The reason is simply because when an application is first created, all its the APIs it needs are resolved at compile time. Using "ldd" u can see all the statically linked dependencies:

“Employed Russian”是最好的答案之一,我认为所有其他建议的答案可能都不起作用。原因很简单,因为当应用程序首次创建时,它需要的所有 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)

But at runtime, firefox will also load many other dynamic libraries, eg (for firefox) there are many "glib"-labelled libraries loaded (even though statically linked there are none):

但是在运行时,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

Manytimes, you can see names of one version being soft-linked into another version. Eg:

很多时候,您可以看到一个版本的名称被软链接到另一个版本。例如:

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

This therefore means different version of "libraries" exists in one system - which is not a problem as it is the same file, and it will provide compatibilities when applications have multiple versions dependencies.

因此,这意味着一个系统中存在不同版本的“库”——这不是问题,因为它是同一个文件,当应用程序具有多个版本依赖项时,它将提供兼容性。

Therefore, at the system level, all the libraries are almost interdependent on one another, and just changing the libraries loading priority via manipulating LD_PRELOAD or LD_LIBRARY_PATH will not help - even it can load, runtime it may still crash.

因此,在系统层面,所有的库几乎是相互依赖的,仅仅通过操纵 LD_PRELOAD 或 LD_LIBRARY_PATH 来改变库的加载优先级是没有帮助的——即使它可以加载,运行时它仍然可能崩溃。

http://lightofdawn.org/wiki/wiki.cgi/-wiki/NewAppsOnOldGlibc

http://lightofdawn.org/wiki/wiki.cgi/-wiki/NewAppsOnOldGlibc

Best alternative is chroot (mentioned by ER briefly): but for this you will need to recreate the entire environment in which is the original binary execute - usually starting from /lib, /usr/lib/, /usr/lib/x86 etc. You can either use "Buildroot", or YoctoProject, or just tar from an existing Distro environment. (like Fedora/Suse etc).

最好的选择是 chroot(ER 简要提到):但为此,您需要重新创建整个环境,在其中执行原始二进制文件 - 通常从 /lib、/usr/lib/、/usr/lib/x86 等开始。您可以使用“Buildroot”或 YoctoProject,也可以仅使用现有发行版环境中的 tar。(如 Fedora/Suse 等)。

回答by msb

This question is old, the other answers are old. "Employed Russian"s answer is very good and informative, but it only works if you have the source code. If you don't, the alternatives back then were very tricky. Fortunately nowadays we have a simple solution to this problem (as commented in one of his replies), using patchelf. All you have to do is:

这个问题很旧,其他答案也很旧。“Employed Russian”的回答非常好且内容丰富,但只有在您拥有源代码时才有效。如果你不这样做,那么当时的替代方案非常棘手。幸运的是,现在我们有一个简单的解决方案来解决这个问题(如他的一个回复中所评论),使用patchelf。您所要做的就是:

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

And after that, you can just execute your file:

之后,您可以执行您的文件:

$ ./myapp

No need to chrootor 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:

chroot谢天谢地,无需或手动编辑二进制文件。但是请记住在修补之前备份您的二进制文件,如果您不确定自己在做什么,因为它会修改您的二进制文件。修补后,您无法恢复解释器/rpath 的旧路径。如果它不起作用,您将不得不继续修补它,直到找到真正起作用的路径……嗯,它不必是一个反复试验的过程。例如,在 OP 的示例中,他需要GLIBC_2.3,因此您可以使用以下命令轻松找到提供该版本的库strings

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

In theory, the first grep would come empty because the system libc doesn't have the version he wants, and the 2nd one should output GLIBC_2.3 because it has the version myappis using, so we know we can patchelfour binary using that path.

理论上,第一个 grep 会变空,因为系统 libc 没有他想要的版本,第二个应该输出 GLIBC_2.3,因为它有myapp正在使用的版本,所以我们知道我们可以patchelf使用该路径我们的二进制文件。

When you try to run a binary in linux, the binary tries to load the linker, then the libraries, and they should all be in the path and/or in the right place. If your problem is with the linker and you want to find out which path your binary is looking for, you can find out with this command:

当您尝试在 linux 中运行二进制文件时,二进制文件会尝试加载链接器,然后是库,它们都应该在路径中和/或在正确的位置。如果您的问题与链接器有关,并且您想找出二进制文件正在寻找的路径,则可以使用以下命令找出:

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

If your problem is with the libs, commands that will give you the libs being used are:

如果您的问题与库有关,那么将为您提供正在使用的库的命令是:

$ readelf -d myapp | grep Shared
$ ldd myapp 

This will list the libs that your binary needs, but you probably already know the problematic ones, since they are already yielding errors as in OP's case.

这将列出您的二进制文件需要的库,但您可能已经知道有问题的库,因为它们已经在 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-interpreterpart of the command) as I explain here. Another example is for the problem of getting No such file or directorywhen 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.

“patchelf”适用于您在尝试运行程序时可能遇到的与这两个问题相关的许多不同问题。例如,如果你得到: ELF file OS ABI invalid,它可以通过设置一个新的加载器(--set-interpreter命令的一部分)来修复,正如我在这里解释的那样。另一个例子是No such file or directory当你运行一个存在且可执行的文件时获取的问题,如这里所示。在这种特殊情况下,OP 缺少指向加载程序的链接,但在您的情况下,您可能没有 root 访问权限并且无法创建链接。设置一个新的解释器可以解决你的问题。

Thanks Employed Russian and Michael Pankov for the insight and solution!

感谢 Employed Russian 和 Michael Pankov 的洞察力和解决方案!

回答by Arkadiusz Rychliński

First of all, the most important dependency of each dynamically linked program is the linker. All so libraries must match the version of the linker.

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

Let's take simple exaple: I have the newset ubuntu system where I run some program (in my case it is D compiler - ldc2). I'd like to run it on the old CentOS, but because of the older glibc library it is impossible. I got

让我们举个简单的例子:我有一个 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)

I have to copy all dependencies from ubuntu to centos. The proper method is following:

我必须将所有依赖项从 ubuntu 复制到 centos。正确的方法如下:

First, let's check all dependencies:

首先,让我们检查所有依赖项:

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 is not a real library and we don't have to care about it.

linux-vdso.so.1 不是一个真正的库,我们不必关心它。

/lib64/ld-linux-x86-64.so.2 is the linker, which is used by the linux do link the executable with all dynamic libraries.

/lib64/ld-linux-x86-64.so.2 是链接器,linux 使用它来将可执行文件与所有动态库链接起来。

Rest of the files are real libraries and all of them together with the linker must be copied somewhere in the centos.

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

Let's assume all the libraries and linker are in "/mylibs" directory.

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

ld-linux-x86-64.so.2 - as I've already said - is the linker. It's not dynamic library but static executable. You can run it and see that it even have some parameters, eg --library-path (I'll return to it).

ld-linux-x86-64.so.2 - 正如我已经说过的 - 是链接器。它不是动态库,而是静态可执行文件。你可以运行它并看到它甚至有一些参数,例如--library-path(我会回到它)。

On the linux, dynamically linked program may be lunched just by its name, eg

在 linux 上,动态链接的程序可能只是以其名字命名,例如

/bin/ldc2

Linux loads such program into RAM, and checks which linker is set for it. Usually, on 64-bit system, it is /lib64/ld-linux-x86-64.so.2 (in your filesystem it is symbolic link to the real executable). Then linux runs the linker and it loads dynamic libraries.

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

You can also change this a little and do such trick:

你也可以稍微改变一下并做这样的把戏:

/mylibs/ld-linux-x86-64.so.2 /bin/ldc2

It is the method for forcing the linux to use specific linker.

它是强制 linux 使用特定链接器的方法。

And now we can return to the mentioned earlier parameter --library-path

现在我们可以回到前面提到的参数 --library-path

/mylibs/ld-linux-x86-64.so.2 --library-path /mylibs /bin/ldc2

It will run ldc2 and load dynamic libraries from /mylibs.

它将运行 ldc2 并从 /mylibs 加载动态库。

This is the method to call the executable with choosen (not system default) libraries.

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

回答by dudu

When I wanted to run a chromium-browser on Ubuntu precise (glibc-2.15), I got the (typical) message "...libc.so.6: version `GLIBC_2.19' not found...". I considered the fact, that files are not needed permamently, but only for start. So I collected the files needed for the browser and sudo and created a mini-glibc-2.19- environment, started the browser and then copied the original files back again. The needed files are in RAM and the original glibc is the same.

当我想在 Ubuntu precision (glibc-2.15) 上运行一个 Chromium 浏览器时,我收到了(典型的)消息“...libc.so.6: version `GLIBC_2.19' not found...”。我考虑过这样一个事实,文件不是永久需要的,而只是开始时需要。所以我收集了浏览器和 sudo 所需的文件并创建了一个 mini-glibc-2.19- 环境,启动浏览器,然后再次复制原始文件。所需文件在 RAM 中,原始 glibc 是相同的。

as root
the files (*-2.15.so) already exist 

mkdir -p /glibc-2.19/i386-linux-gnu

mkdir -p /glibc-2.19/i386-linux-gnu

/glibc-2.19/ld-linux.so.2 -> /glibc-2.19/i386-linux-gnu/ld-2.19.so
/glibc-2.19/i386-linux-gnu/libc.so.6 -> libc-2.19.so
/glibc-2.19/i386-linux-gnu/libdl.so.2 -> libdl-2.19.so
/glibc-2.19/i386-linux-gnu/libpthread.so.0 -> libpthread-2.19.so

mkdir -p /glibc-2.15/i386-linux-gnu

mkdir -p /glibc-2.15/i386-linux-gnu

/glibc-2.15/ld-linux.so.2 -> (/glibc-2.15/i386-linux-gnu/ld-2.15.so)
/glibc-2.15/i386-linux-gnu/libc.so.6 -> (libc-2.15.so)
/glibc-2.15/i386-linux-gnu/libdl.so.2 -> (libdl-2.15.so)
/glibc-2.15/i386-linux-gnu/libpthread.so.0 -> (libpthread-2.15.so)

the script to run the browser:

运行浏览器的脚本:

#!/bin/sh
sudo cp -r /glibc-2.19/* /lib
/path/to/the/browser &
sleep 1
sudo cp -r /glibc-2.15/* /lib
sudo rm -r /lib/i386-linux-gnu/*-2.19.so

回答by user1396055

I am not sure that the question is still relevant, but there is another way of fixing the problem: Docker. One can install an almost empty container of the Source Distribution (The Distribution used for development) and copy the files into the Container. That way You do not need to create the filesystem needed for chroot.

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

回答by Belter

@msb gives a safe solution.

@msb 提供了一个安全的解决方案。

I met this problem when I did import tensorflow as tfin conda environment in CentOS 6.5which only has glibc-2.12.

import tensorflow as tfCentOS 6.5只有glibc-2.12.

ImportError: /lib64/libc.so.6: version `GLIBC_2.16' not found (required by /home/

I want to supply some details:

我想提供一些细节:

First install glibcto your home directory:

首先安装glibc到您的主目录:

mkdir ~/glibc-install; cd ~/glibc-install
wget http://ftp.gnu.org/gnu/glibc/glibc-2.17.tar.gz
tar -zxvf glibc-2.17.tar.gz
cd glibc-2.17
mkdir build
cd build
../configure --prefix=/home/myself/opt/glibc-2.17  # <-- where you install new glibc
make -j<number of CPU Cores>  # You can find your <number of CPU Cores> by using **nproc** command
make install

Second, follow the same way to install patchelf;

其次,按照同样的方式安装patchelf

Third, patch your Python:

第三,修补你的 Python:

[myself@nfkd ~]$ patchelf --set-interpreter /home/myself/opt/glibc-2.17/lib/ld-linux-x86-64.so.2 --set-rpath /home/myself/opt/glibc-2.17/lib/ /home/myself/miniconda3/envs/tensorflow/bin/python

as mentioned by @msb

正如@msb 所提到的

Now I can use tensorflow-2.0 alphain CentOS 6.5.

现在我可以tensorflow-2.0 alphaCentOS 6.5.

ref: https://serverkurma.com/linux/how-to-update-glibc-newer-version-on-centos-6-x/

参考:https: //serverkurma.com/linux/how-to-update-glibc-newer-version-on-centos-6-x/