单个主机上的多个 glibc 库
我的 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
和
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
并且没有从我放置它们的位置拾取它们。
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.
Is it possible to have multiple glibcs installed on the same host?
This is the error I get when I run my program on the old 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:
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
首先,每个动态链接程序最重要的依赖就是链接器。 所有so库必须与链接器的版本匹配。
让我们举个简单的例子:我有 newset ubuntu 系统,我在其中运行一些程序(在我的例子中是 D 编译器 - ldc2)。 我想在旧的 CentOS 上运行它,但由于旧的 glibc 库,这是不可能的。 我
必须将所有依赖项从 ubuntu 复制到 centos。
正确的方法如下:
首先,让我们检查所有依赖项:
linux-vdso.so.1 不是一个真正的库,我们不必关心它。
/lib64/ld-linux-x86-64.so.2 是链接器,linux 使用它来将可执行文件与所有动态库链接。
其余文件是真正的库,所有这些文件连同链接器都必须复制到 centos 中的某个位置。
假设所有库和链接器都位于“/mylibs”目录中。
ld-linux-x86-64.so.2 - 正如我已经说过的 - 是链接器。 它不是动态库,而是静态可执行文件。 您可以运行它并看到它甚至有一些参数,例如 --library-path (我将返回它)。
在linux上,动态链接的程序可以仅通过其名称来启动,例如
Linux将此类程序加载到RAM中,并检查为其设置了哪个链接器。 通常,在 64 位系统上,它是 /lib64/ld-linux-x86-64.so.2 (在您的文件系统中,它是指向真正可执行文件的符号链接)。
然后linux运行链接器并加载动态库。
你也可以稍微改变一下,做这样的技巧:
这是强制linux使用特定链接器的方法。
现在我们可以回到前面提到的参数 --library-path
它将运行 ldc2 并从 /mylibs 加载动态库。
这是使用所选(非系统默认)库调用可执行文件的方法。
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.
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
I have to copy all dependencies from ubuntu to centos.
The proper method is following:
First, let's check all dependencies:
linux-vdso.so.1 is not a real library and we don't have to care about it.
/lib64/ld-linux-x86-64.so.2 is the linker, which is used by the linux do link the executable with all dynamic libraries.
Rest of the files are real libraries and all of them together with the linker must be copied somewhere in the centos.
Let's assume all the libraries and linker are in "/mylibs" directory.
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).
On the linux, dynamically linked program may be lunched just by its name, eg
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.
You can also change this a little and do such trick:
It is the method for forcing the linux to use specific linker.
And now we can return to the mentioned earlier parameter --library-path
It will run ldc2 and load dynamic libraries from /mylibs.
This is the method to call the executable with choosen (not system default) libraries.
使用LD_PRELOAD:
将您的库放在 man lib 目录之外的某个位置并运行:
请参阅:维基百科文章
Use LD_PRELOAD:
put your library somewhere out of the man lib directories and run:
See: the Wikipedia article
设置 1:在没有专用 GCC 的情况下编译您自己的 glibc 并使用它
此设置可能有效并且速度很快,因为它不会重新编译整个 GCC 工具链,而只是重新编译 glibc。
但它并不可靠,因为它使用 glibc 提供的主机 C 运行时对象,例如
crt1.o
、crti.o
和crtn.o
。 这在以下位置提到: https://sourceware.org /glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location 这些对象会进行 glibc 所依赖的早期设置,因此如果事情以奇妙且极其微妙的方式崩溃,我不会感到惊讶。要获得更可靠的设置,请参阅下面的设置 2。
构建 glibc 并在本地安装:
设置 1:验证构建
test_glibc.c
使用
test_glibc.sh
编译并运行:程序输出预期的:
命令改编自 https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21 #Compile_against_glibc_in_an_installed_location 但
--sysroot
导致它失败:所以我删除了它。
ldd
输出确认我们刚刚构建的ldd
和库实际上正在按预期使用:gcc
编译调试输出显示我的使用了主机运行时对象,这很糟糕,如前所述,但我不知道如何解决它,例如它包含:设置 1:修改 glibc
现在让我们修改 glibc:
然后重新编译并重新安装 glibc,然后重新编译并重新运行我们的程序:
我们看到
hacked
按预期打印了几次。这进一步证实了我们实际上使用了我们编译的 glibc 而不是主机。
在 Ubuntu 18.04 上测试。
设置 2:crosstool-NG 原始设置
这是设置 1 的替代方案,它是我迄今为止实现的最正确的设置:据我观察,一切都是正确的,包括 C 运行时对象,例如
crt1 .o
、crti.o
和crtn.o
。在此设置中,我们将编译一个完整的专用 GCC 工具链,该工具链使用我们想要的 glibc。
这种方法的唯一缺点是构建时间会更长。 但我不会冒险用更少的东西来进行生产设置。
crosstool-NG 是一组脚本,可以为我们从源代码下载和编译所有内容,包括 GCC、glibc 和 binutils。
是的,GCC 构建系统太糟糕了,我们需要一个单独的项目。
此设置并不完美,因为 crosstool-NG 不支持在没有额外内容的情况下构建可执行文件
-Wl
标志,这感觉很奇怪,因为我们已经构建了 GCC 本身。 但一切似乎都正常,所以这只是一个不便。获取 crosstool-NG,配置并构建它:
构建大约需要三十分钟到两个小时。
我可以看到的唯一强制配置选项是使其与您的主机内核版本匹配以使用正确的内核头。 使用以下命令查找您的主机内核版本:
它显示:
所以在
menuconfig
中我这样做:操作系统
Linux 版本
所以我选择:
这是第一个相同或更旧的版本。 它必须更旧,因为内核是向后兼容的。
设置 2:可选配置
我们使用
./ct-ng x86_64-unknown-linux-gnu
生成的.config
具有:要更改它,请在
menuconfig< /code> do:
C-library
glibc 版本
保存
.config
,然后继续构建。或者,如果您想使用自己的 glibc 源,例如使用最新 git 中的 glibc,请继续 像这样:
路径和其他选项
尝试标记为“实验”的功能
:设置为 trueC-library
glibc 来源
自定义位置
:说是自定义位置
自定义源位置
:指向包含 glibc 源的目录,其中 glibc 被克隆为:
设置 2:测试它
一旦您构建了所需的工具链,请使用以下命令进行测试:
一切似乎都正常与设置 1 一样,只不过现在使用了正确的运行时对象:
设置 2:高效 glibc 重新编译尝试失败
使用 crosstool-NG 似乎不可能,如下所述。
如果你只是重新构建;
那么您对自定义 glibc 源位置的更改就会被考虑在内,但它会从头开始构建所有内容,使其无法用于迭代开发。
如果我们这样做:
它很好地概述了构建步骤:
因此,我们看到 glibc 步骤与多个 GCC 步骤交织在一起,最值得注意的是
libc_start_files
出现在cc_core_pass_2
之前,这可能是与 cc_core_pass_1 一起使用时最昂贵的步骤。为了仅构建一个步骤,您必须首先在初始构建的
.config
选项中设置“保存中间步骤”:路径和其他选项
调试 crosstool-NG
保存中间步骤
,然后您可以尝试:
但不幸的是,需要的
+
如所述:https://github.com/crosstool-ng/crosstool-ng/issues/1033#issuecomment-424877536基本上仍然使重建太慢而无法进行开发,而且我不知道如何在不修补 crosstool-NG 的情况下克服这个问题。
此外,从
libc
步骤开始似乎没有从自定义源位置
再次复制源,这进一步使得该方法无法使用。额外奖励:stdlibc++
如果您也对 C++ 标准库感兴趣,那么额外奖励:如何编辑和重新构建 GCC libstdc++ C++ 标准库源?
Setup 1: compile your own glibc without dedicated GCC and use it
This setup might work and is quick as it does not recompile the whole GCC toolchain, just glibc.
But it is not reliable as it uses host C runtime objects such as
crt1.o
,crti.o
, andcrtn.o
provided by glibc. This is mentioned at: https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location Those objects do early setup that glibc relies on, so I wouldn't be surprised if things crashed in wonderful and awesomely subtle ways.For a more reliable setup, see Setup 2 below.
Build glibc and install locally:
Setup 1: verify the build
test_glibc.c
Compile and run with
test_glibc.sh
:The program outputs the expected:
Command adapted from https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location but
--sysroot
made it fail with:so I removed it.
ldd
output confirms that theldd
and libraries that we've just built are actually being used as expected:The
gcc
compilation debug output shows that my host runtime objects were used, which is bad as mentioned previously, but I don't know how to work around it, e.g. it contains:Setup 1: modify glibc
Now let's modify glibc with:
Then recompile and re-install glibc, and recompile and re-run our program:
and we see
hacked
printed a few times as expected.This further confirms that we actually used the glibc that we compiled and not the host one.
Tested on Ubuntu 18.04.
Setup 2: crosstool-NG pristine setup
This is an alternative to setup 1, and it is the most correct setup I've achieved far: everything is correct as far as I can observe, including the C runtime objects such as
crt1.o
,crti.o
, andcrtn.o
.In this setup, we will compile a full dedicated GCC toolchain that uses the glibc that we want.
The only downside to this method is that the build will take longer. But I wouldn't risk a production setup with anything less.
crosstool-NG is a set of scripts that downloads and compiles everything from source for us, including GCC, glibc and binutils.
Yes the GCC build system is so bad that we need a separate project for that.
This setup is only not perfect because crosstool-NG does not support building the executables without extra
-Wl
flags, which feels weird since we've built GCC itself. But everything seems to work, so this is only an inconvenience.Get crosstool-NG, configure and build it:
The build takes about thirty minutes to two hours.
The only mandatory configuration option that I can see, is making it match your host kernel version to use the correct kernel headers. Find your host kernel version with:
which shows me:
so in
menuconfig
I do:Operating System
Version of linux
so I select:
which is the first equal or older version. It has to be older since the kernel is backwards compatible.
Setup 2: optional configurations
The
.config
that we generated with./ct-ng x86_64-unknown-linux-gnu
has:To change that, in
menuconfig
do:C-library
Version of glibc
save the
.config
, and continue with the build.Or, if you want to use your own glibc source, e.g. to use glibc from the latest git, proceed like this:
Paths and misc options
Try features marked as EXPERIMENTAL
: set to trueC-library
Source of glibc
Custom location
: say yesCustom location
Custom source location
: point to a directory containing your glibc sourcewhere glibc was cloned as:
Setup 2: test it out
Once you have built he toolchain that you want, test it out with:
Everything seems to work as in Setup 1, except that now the correct runtime objects were used:
Setup 2: failed efficient glibc recompilation attempt
It does not seem possible with crosstool-NG, as explained below.
If you just re-build;
then your changes to the custom glibc source location are taken into account, but it builds everything from scratch, making it unusable for iterative development.
If we do:
it gives a nice overview of the build steps:
therefore, we see that there are glibc steps intertwined with several GCC steps, most notably
libc_start_files
comes beforecc_core_pass_2
, which is likely the most expensive step together withcc_core_pass_1
.In order to build just one step, you must first set the "Save intermediate steps" in
.config
option for the intial build:Paths and misc options
Debug crosstool-NG
Save intermediate steps
and then you can try:
but unfortunately, the
+
required as mentioned at: https://github.com/crosstool-ng/crosstool-ng/issues/1033#issuecomment-424877536and basically still makes the rebuild too slow to be feasible for development, and I don't see how to overcome this without patching crosstool-NG.
Furthermore, starting from the
libc
step didn't seem to copy over the source again fromCustom source location
, further making this method unusable.Bonus: stdlibc++
A bonus if you're also interested in the C++ standard library: How to edit and re-build the GCC libstdc++ C++ standard library source?
同一个系统上很可能有多个版本的 glibc(我们每天都这样做)。
但是,您需要知道 glibc 由许多部分(200 多个共享库)组成,所有部分都必须匹配。 其中之一是 ld-linux.so.2,它必须与 libc.so.6 匹配,否则您将看到所看到的错误。
ld-linux.so.2 的绝对路径在链接时被硬编码到可执行文件中,并且在链接完成后不能轻易更改(更新:可以使用 patchelf;请参阅下面的这个答案)。
要构建与新 glibc 一起使用的可执行文件,请执行以下操作:
-rpath
链接器选项将使运行时加载程序在/path/to/newglibc
中搜索库(所以你不必在运行之前设置LD_LIBRARY_PATH
),并且-dynamic-linker
选项将“烘焙”路径以正确的ld-linux.so .2
进入应用程序。如果您无法重新链接
myapp
应用程序(例如,因为它是第三方二进制文件),并非所有内容都会丢失,但会变得更加棘手。 一种解决方案是为其设置适当的 chroot 环境。 另一种可能性是使用 rtldi 和 二进制编辑器。更新:或者您可以在现有二进制文件上使用 patchelf 将它们重定向到备用文件libc。
It is very possible to have multiple versions of glibc on the same system (we do that every day).
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 must match libc.so.6, or you'll see the errors you are seeing.
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 (Update: can be done with patchelf; see this answer below).
To build an executable that will work with the new glibc, do this:
The
-rpath
linker option will make the runtime loader search for libraries in/path/to/newglibc
(so you wouldn't have to setLD_LIBRARY_PATH
before running it), and the-dynamic-linker
option will "bake" path to correctld-linux.so.2
into the application.If you can't relink the
myapp
application (e.g. because it is a third-party binary), not all is lost, but it gets trickier. One solution is to set a properchroot
environment for it. Another possibility is to use rtldi and a binary editor.Update: or you can use patchelf on existing binaries to redirect them to the alternate libc.
当我饶有兴趣地阅读Employed Russian's answer以及msb的回答,我发现了另一个相当简单的方法(在最初提出问题时可能不可用......)
首先,足以 构建而不安装您选择的 glibc 版本。
然后,要使用刚刚构建的 glibc 动态加载器(而不是系统上安装的动态加载器)启动您的应用程序,请使用提到的方法 此处:只需执行
/path/to/glibc-build/testrun.sh /path/to/test/application
As I was reading with a lot of interest Employed Russian's answer as well as msb's answer, I found another quite simple method (which perhaps wasn't available when the question was initially asked...)
First, it is sufficient to build without installing a glibc version of your choice.
Then, to start your app with the glibc dynamic loader that you've just built (rather than the dynamic loaded that's installed on your system), use the approach mentioned here: simply do
/path/to/glibc-build/testrun.sh /path/to/test/application
我不确定这个问题是否仍然相关,但还有另一种解决问题的方法:Docker。 人们可以安装一个几乎空的源发行版(用于开发的发行版)容器,并将文件复制到容器中。 这样您就不需要创建 chroot 所需的文件系统。
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.
如果仔细查看第二个输出,您可以看到使用了库的新位置。 也许 glibc 中仍然缺少一些库。
我还认为程序使用的所有库都应该针对该版本的 glibc 进行编译。 如果您有权访问该程序的源代码,那么重新编译似乎是最好的解决方案。
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.
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.
“受雇的俄罗斯人”是最好的答案之一,我认为所有其他建议的答案可能都行不通。 原因很简单,因为当应用程序首次创建时,其所需的所有 API 都在编译时解析。 使用“ldd”你可以看到所有静态链接的依赖项:
但是在运行时,firefox还将加载许多其他动态库,例如(对于firefox)加载了许多“glib”标记的库(即使静态链接没有) :
很多时候,您可以看到一个版本的名称被软链接到另一版本。 例如:
这意味着一个系统中存在不同版本的“库”——这不是问题,因为它是同一个文件,并且当应用程序具有多个版本依赖性时它将提供兼容性。
因此,在系统级别,所有库几乎都是相互依赖的,仅仅通过操作 LD_PRELOAD 或 LD_LIBRARY_PATH 来更改库加载优先级将无济于事 - 即使它可以加载,运行时它仍然可能崩溃。
http://lightofdawn.org/wiki/wiki.cgi/-wiki/NewAppsOnOldGlibc
最好的替代方案是 chroot(ER 简要提到过):但为此,您需要重新创建原始二进制执行的整个环境 - 通常从 /lib、/usr/lib/、/usr/lib/x86 开始您可以使用“Buildroot”或 YoctoProject,或者仅从现有的发行版环境中打包。 (如 Fedora/Suse 等)。
"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:
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):
Manytimes, you can see names of one version being soft-linked into another version. Eg:
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.
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).
当我想在 Ubuntu Precision (glibc-2.15) 上运行 chromium 浏览器时,我得到了
(典型)消息“...libc.so.6:未找到版本‘GLIBC_2.19'...”。
我考虑到这样一个事实:文件并不是永久需要的,而只是开始时需要的。
所以我收集了浏览器和sudo所需的文件并创建了一个mini-glibc-2.19-
环境,启动浏览器,然后将原始文件复制回来
再次。 需要的文件在RAM中,和原来的glibc是一样的。
mkdir -p /glibc-2.19/i386-linux-gnu
mkdir -p /glibc-2.15/i386-linux-gnu
运行浏览器的脚本:
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.
mkdir -p /glibc-2.19/i386-linux-gnu
mkdir -p /glibc-2.15/i386-linux-gnu
the script to run the browser:
@msb 提供了一个安全的解决方案。
当我在只有
glibc-2.12
的CentOS 6.5
的 conda 环境中import tensorflow as tf
时,我遇到了这个问题。我想提供一些细节:
首先将 glibc 安装到您的主目录:
其次,按照相同的方式安装 补丁;
第三,修补你的Python:
正如@msb提到的,
现在我可以在
CentOS 6.5
中使用tensorflow-2.0 alpha
。参考: https://serverkurma .com/linux/how-to-update-glibc-newer-version-on-centos-6-x/
@msb gives a safe solution.
I met this problem when I did
import tensorflow as tf
in conda environment inCentOS 6.5
which only hasglibc-2.12
.I want to supply some details:
First install
glibc
to your home directory:Second, follow the same way to install patchelf;
Third, patch your Python:
as mentioned by @msb
Now I can use
tensorflow-2.0 alpha
inCentOS 6.5
.ref: https://serverkurma.com/linux/how-to-update-glibc-newer-version-on-centos-6-x/
您可以考虑使用 Nix http://nixos.org/nix/ 吗?
Can you consider using Nix http://nixos.org/nix/ ?
这个问题很旧,其他答案也很旧。 Employed Russian 的答案非常好且内容丰富,但只有在您拥有源代码的情况下才有效。 如果你不这样做,那么当时的替代方案就非常棘手。 幸运的是,现在我们有一个简单的解决方案来解决这个问题(如 其中之一所述他的回复),使用 patchelf。 您所要做的就是:
这会将非工作可执行文件更改为其链接器使用不同的路径。 之后,您只需执行您的文件即可:
谢天谢地,无需 chroot 或手动编辑二进制文件。 但如果您不确定自己在做什么,请记住在修补之前备份您的二进制文件,因为它会修改您的二进制文件。 修补后,您无法恢复解释器/rpath 的旧路径。 如果它不起作用,你就必须不断地修补它,直到找到真正有效的路径......好吧,它不一定是一个反复试验的过程。 例如,在OP的示例中,他需要
GLIBC_2.3
,因此您可以使用string
轻松找到哪个库提供该版本:理论上,第一个grep将为空,因为系统libc没有他想要的版本,第二个应该输出GLIBC_2.3,因为它有
myapp
正在使用的版本,所以我们知道我们可以patchelf
我们的二进制文件使用该路径。 如果遇到分段错误,请阅读末尾的注释。当您尝试在 Linux 中运行二进制文件时,二进制文件会尝试加载链接器(又名加载器、解释器),然后加载库,并且它们都应该位于路径中和/或正确的位置。 如果您的问题出在链接器上,并且您想找出二进制文件正在寻找哪个路径,您可以使用以下命令找出答案:
如果您的问题出在库上,则将为您提供正在使用的库的命令是:
这将列出您的二进制文件所需的库,但您可能已经知道有问题的库,因为它们已经像 OP 的情况一样产生错误。 执行 patchelf 后,可能会发生
myapp
仍然无法工作的情况,当您运行ldd myapp
时,它会列出具有混合路径的库,其中一些是您设置的路径,其他的到原来的系统路径。 那是因为你的路径没有这些库。 rpath 将在您设置的路径中搜索库,但如果不存在,它仍然会在其他系统位置中查找。 在这种情况下,如果您在某处缺少 lib,只需将其复制到您选择的 rpath 即可,它应该可以工作。“patchelf”适用于您在尝试运行程序时可能遇到的许多不同问题,与这两个问题相关。 例如,如果您得到:
ELF file OS ABI invalid
,则可以通过设置新的加载程序(命令的--set-interpreter
部分)来修复它,就像我一样此处解释。 另一个例子是当您运行存在且可执行的文件时出现No such file or directory
的问题,如下所示 此处。 在这种特殊情况下,OP 缺少指向加载程序的链接,但也许在您的情况下您没有 root 访问权限并且无法创建链接。 设置一个新的口译员可以解决你的问题。感谢 Employ Russian 和 Michael Pankov 的见解和解决方案!
注意分段错误:您可能会遇到
myapp
使用多个库的情况,其中大多数都可以,但有些则不行; 然后你patchelf
它到一个新的目录,你会得到分段错误。 当您patchelf
二进制文件时,您会更改多个库的路径,即使某些库最初位于不同的路径中。 看一下我下面的示例:请注意,大多数库都位于
/lib/x86_64-linux-gnu/
中,但有问题的库 (libstdc++.so.6
) 位于/usr/lib/x86_64-linux-gnu
。 在我对myapp
进行 patchelf'ed 以指向/path/to/mylibs
后,我遇到了分段错误。 由于某种原因,这些库与二进制文件并不完全兼容。 由于myapp
没有抱怨原始库,因此我将它们从/lib/x86_64-linux-gnu/
复制到/path/to/mylibs2
code>,我还从/path/to/mylibs
复制了libstdc++.so.6
。 然后我将其修补到/path/to/mylibs2
,并且myapp
现在可以工作了。 如果您的二进制文件使用不同的库,并且您有不同的版本,则可能无法解决您的情况。 :( 但如果可能的话,混合库可能是一种方法。这并不理想,但也许它会起作用。祝你好运!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:
This changes the non-working executable to use a different path for its linker. And after that, you can just execute your file:
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 neededGLIBC_2.3
, so you can easily find which lib provides that version usingstrings
: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
myapp
is using, so we know we canpatchelf
our binary using that path. If you get a segmentation fault, read the note at the end.When you try to run a binary in linux, the binary tries to load the linker (aka loader, aka interpreter), 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:
If your problem is with the libs, commands that will give you the libs being used are:
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. After you do patchelf, it might happen that
myapp
is still not working, and when you runldd myapp
it lists the libs with mixed paths, some to the path you set, others to the original system path. That's because your path doesn't have those libs.rpath
will search for the lib in the path you set, but if it's not there, it still looks for it in the other system locations. In this case, if you have the missing lib somewhere, just copy it to therpath
that you chose and it should work."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 gettingNo 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.Thanks Employed Russian and Michael Pankov for the insight and solution!
Note for segmentation fault: you might be in the case where
myapp
uses several libs, and most of them are ok but some are not; then youpatchelf
it to a new dir, and you get segmentation fault. When youpatchelf
your binary, you change the path of several libs, even if some were originally in a different path. Take a look at my example below: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'edmyapp
to point to/path/to/mylibs
, I got segmentation fault. For some reason, the libs are not totally compatible with the binary. Sincemyapp
didn't complain about the original libs, I copied them from/lib/x86_64-linux-gnu/
to/path/to/mylibs2
, and I also copiedlibstdc++.so.6
from/path/to/mylibs
there. Then I patchelf'ed it to/path/to/mylibs2
, andmyapp
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!