Múltiples bibliotecas glibc en un solo host
Mi servidor Linux (SLES-8) actualmente tiene glibc-2.2.5-235, pero tengo un programa que no funcionará en esta versión y requiere glibc-2.3.3.
¿Es posible tener múltiples glibcs instalados en el mismo host?
Este es el error que obtengo cuando ejecuto mi programa en el viejo 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)
Así que creé un nuevo directorio llamado newglibc y copié los siguientes archivos en:
libpthread.so.0
libm.so.6
libc.so.6
ld-2.3.3.so
ld-linux.so.2 -> ld-2.3.3.so
y
export LD_LIBRARY_PATH=newglibc:$LD_LIBRARY_PATH
Pero me sale un 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)
Entonces, ¿parece que todavía están vinculados a / lib y no se están recuperando de donde los puse?
Gracias
export LD_LIBRARY_PATH=newglibc:$LD_LIBRARY_PATH
hizo resolver el problema para mí! Ciertamente no funcionará para todos, ¡pero es una solución fácil si funciona! ¡Gracias! :)Respuestas:
Es muy posible tener múltiples versiones de glibc en el mismo sistema (lo hacemos todos los días).
Sin embargo, debe saber que glibc consta de muchas piezas (más de 200 bibliotecas compartidas) que todas deben coincidir. Una de las piezas es ld-linux.so.2, y debe coincidir con libc.so.6, o verá los errores que está viendo.
La ruta absoluta a ld-linux.so.2 está codificada en el ejecutable en el momento del enlace, y no se puede cambiar fácilmente una vez que se realiza el enlace.
Para construir un ejecutable que funcione con el nuevo glibc, haga esto:
La
-rpath
opción del vinculador hará que el cargador de tiempo de ejecución busque bibliotecas en/path/to/newglibc
(para que no tenga que configurarLD_LIBRARY_PATH
antes de ejecutarlo), y la-dynamic-linker
opción "horneará" la ruta para corregirld-linux.so.2
en la aplicación.Si no puede volver a vincular la
myapp
aplicación (por ejemplo, porque es un binario de terceros), no todo se pierde, pero se vuelve más complicado. Una solución es establecer unchroot
entorno adecuado para ello. Otra posibilidad es usar rtldi y un editor binario .fuente
-Wl,--dynamic-linker=file
(toma dos '-') solo funciona al compilar ejecutables ELF. Comprobación/sbin/ldconfig -p | grep ld
patchelf
( nixos.org/patchelf.html ), que le permite modificar rpath e intérprete de ELF ya compilado.-Wl,--rpath
lugar deLD_LIBRARY_PATH
puede ser importante por razones distintas a la conveniencia: si el programa inicia procesos secundarios, el valor deLD_LIBRARY_PATH
usualmente será heredado por ellos, pero si no están compilados para usar el glibc más nuevo (por ejemplo, si son binarios de stock comobash
), no se lanzarán./path/to/newglibc/ld-linux.so.2 --library-path /path/tonewglibc/lib64:/path/to/newglibc/usr/lib64 /path/to/myapp
-I
y-L
: stackoverflow.com/a/52454603/895245Esta pregunta es antigua, las otras respuestas son antiguas. La respuesta de "Empleado ruso" es muy buena e informativa, pero solo funciona si tiene el código fuente. Si no lo haces, las alternativas en ese entonces eran muy complicadas. Afortunadamente hoy en día tenemos una solución simple a este problema (como se comentó en una de sus respuestas), usando patchelf . Todo lo que tienes que hacer es:
Y después de eso, puedes ejecutar tu archivo:
chroot
Afortunadamente, no es necesario editar manualmente los binarios. Pero recuerde hacer una copia de seguridad de su binario antes de parchearlo, si no está seguro de lo que está haciendo, porque modifica su archivo binario. Después de parcharlo, no puede restaurar la ruta anterior al intérprete / rpath. Si no funciona, tendrá que seguir parcheándolo hasta que encuentre la ruta que realmente funcionará ... Bueno, no tiene que ser un proceso de prueba y error. Por ejemplo, en el ejemplo de OP, él necesitabaGLIBC_2.3
, para que pueda encontrar fácilmente qué lib proporciona esa versión usandostrings
:En teoría, el primer grep quedaría vacío porque el sistema libc no tiene la versión que desea, y el segundo debería generar GLIBC_2.3 porque tiene la versión
myapp
está utilizando, por lo que sabemos que podemospatchelf
usar nuestro binario con esa ruta.Cuando intenta ejecutar un binario en Linux, el binario intenta cargar el enlazador, luego las bibliotecas, y todos deben estar en la ruta y / o en el lugar correcto. Si su problema es con el enlazador y desea averiguar qué ruta está buscando su binario, puede averiguarlo con este comando:
Si su problema es con las bibliotecas, los comandos que le darán las bibliotecas que se utilizan son:
Esto enumerará las bibliotecas que necesita su binario, pero probablemente ya conozca las problemáticas, ya que ya están produciendo errores como en el caso de OP.
"patchelf" funciona para muchos problemas diferentes que puede encontrar al intentar ejecutar un programa, relacionados con estos 2 problemas. Por ejemplo, si obtiene:,
ELF file OS ABI invalid
puede solucionarse configurando un nuevo cargador (la--set-interpreter
parte del comando) como explico aquí . Otro ejemplo es el problema de obtenerNo such file or directory
cuando ejecuta un archivo que está allí y es ejecutable, como se ejemplifica aquí . En ese caso particular, a OP le faltaba un enlace al cargador, pero tal vez en su caso no tiene acceso de root y no puede crear el enlace. Establecer un nuevo intérprete resolvería su problema.Gracias Empleado ruso y Michael Pankov por el conocimiento y la solución!
fuente
patchelf
), pero la frase "No es necesario ... editar binarios" puede ser un poco engañosa (ya que en realidad está editando sus binarios).Use LD_PRELOAD: coloque su biblioteca en algún lugar fuera de los directorios man lib y ejecute:
Ver: el artículo de Wikipedia
fuente
En primer lugar, la dependencia más importante de cada programa vinculado dinámicamente es el vinculador. Todas las bibliotecas deben coincidir con la versión del vinculador.
Tomemos un ejemplo simple: tengo el nuevo sistema ubuntu donde ejecuto algún programa (en mi caso es el compilador D - ldc2). Me gustaría ejecutarlo en el viejo CentOS, pero debido a la antigua biblioteca glibc es imposible. tengo
Tengo que copiar todas las dependencias de ubuntu a centos. El método adecuado es el siguiente:
Primero, verifiquemos todas las dependencias:
linux-vdso.so.1 no es una biblioteca real y no tenemos que preocuparnos por eso.
/lib64/ld-linux-x86-64.so.2 es el enlazador, que es utilizado por Linux para vincular el ejecutable con todas las bibliotecas dinámicas.
El resto de los archivos son bibliotecas reales y todos ellos junto con el enlazador deben copiarse en algún lugar de los centos.
Supongamos que todas las bibliotecas y el enlazador están en el directorio "/ mylibs".
ld-linux-x86-64.so.2, como ya he dicho, es el enlazador. No es una biblioteca dinámica sino un ejecutable estático. Puede ejecutarlo y ver que incluso tiene algunos parámetros, por ejemplo, --library-path (volveré sobre él).
En Linux, el programa vinculado dinámicamente se puede almorzar solo por su nombre, p. Ej.
Linux carga dicho programa en la RAM y comprueba qué enlazador está configurado para ello. Por lo general, en un sistema de 64 bits, es /lib64/ld-linux-x86-64.so.2 (en su sistema de archivos es un enlace simbólico al ejecutable real). Luego, Linux ejecuta el enlazador y carga bibliotecas dinámicas.
También puedes cambiar esto un poco y hacer tal truco:
Es el método para obligar a Linux a usar un enlazador específico.
Y ahora podemos volver al parámetro mencionado anteriormente --library-path
Ejecutará ldc2 y cargará bibliotecas dinámicas desde / mylibs.
Este es el método para llamar al ejecutable con las bibliotecas elegidas (no las predeterminadas del sistema).
fuente
Configuración 1: compila tu propio glibc sin GCC dedicado y úsalo
Esta configuración podría funcionar y es rápida ya que no recompila toda la cadena de herramientas de GCC, solo glibc.
Pero no es fiable, ya que utiliza anfitrión tiempo de ejecución C objetos tales como
crt1.o
,crti.o
ycrtn.o
proporcionado por glibc. Esto se menciona en: https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location Esos objetos realizan una configuración temprana en la que se basa Glibc, por lo que no me sorprendería si las cosas se estrellaran de maravilla y formas asombrosamente sutiles.Para una configuración más confiable, vea la Configuración 2 a continuación.
Construya glibc e instálelo localmente:
Configuración 1: verifique la compilación
test_glibc.c
Compila y ejecuta con
test_glibc.sh
:El programa genera lo esperado:
Comando adaptado de https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location pero
--sysroot
falló con:así que lo quité
ldd
La salida confirma que lasldd
bibliotecas y que acabamos de construir se están utilizando realmente como se esperaba:El
gcc
resultado de la depuración de compilación muestra que se usaron mis objetos de tiempo de ejecución de host, lo cual es malo como se mencionó anteriormente, pero no sé cómo solucionarlo, por ejemplo, contiene:Configuración 1: modificar glibc
Ahora modifiquemos glibc con:
Luego recompile y reinstale glibc, y recompile y vuelva a ejecutar nuestro programa:
y vemos
hacked
impreso algunas veces como se esperaba.Esto confirma aún más que en realidad usamos el glibc que compilamos y no el host.
Probado en Ubuntu 18.04.
Configuración 2: configuración prístina de crosstool-NG
Esta es una alternativa a la configuración 1, y es la configuración más correcta que he logrado mucho: todo es correcto por lo que yo puedo observar, incluyendo el tiempo de ejecución C objetos tales como
crt1.o
,crti.o
ycrtn.o
.En esta configuración, compilaremos una cadena de herramientas GCC dedicada que use el glibc que queramos.
El único inconveniente de este método es que la construcción llevará más tiempo. Pero no arriesgaría una configuración de producción con nada menos.
crosstool-NG es un conjunto de scripts que descarga y compila todo de origen para nosotros, incluidos GCC, glibc y binutils.
Sí, el sistema de compilación de GCC es tan malo que necesitamos un proyecto separado para eso.
Esta configuración no es perfecta porque crosstool-NG no admite la construcción de ejecutables sin
-Wl
banderas adicionales , lo que se siente extraño ya que hemos creado GCC. Pero todo parece funcionar, así que esto es solo un inconveniente.Obtenga crosstool-NG, configúrelo y compílelo:
La construcción lleva entre treinta minutos y dos horas.
La única opción de configuración obligatoria que puedo ver es hacer que coincida con la versión del núcleo del host para utilizar los encabezados del núcleo correctos. Encuentre su versión de kernel host con:
que me muestra
entonces en lo
menuconfig
que hago:Operating System
Version of linux
entonces selecciono:
cual es la primera versión igual o anterior. Tiene que ser anterior ya que el núcleo es compatible con versiones anteriores.
Configuración 2: configuraciones opcionales
El
.config
que generamos con./ct-ng x86_64-unknown-linux-gnu
tiene:Para cambiar eso, en
menuconfig
do:C-library
Version of glibc
salva el
.config
y continúe con la compilación.O, si desea usar su propia fuente de glibc, por ejemplo, para usar glibc del último git, proceda de esta manera :
Paths and misc options
Try features marked as EXPERIMENTAL
: establecido en verdaderoC-library
Source of glibc
Custom location
: decir que síCustom location
Custom source location
: apunte a un directorio que contenga su fuente glibcdonde glibc fue clonado como:
Configuración 2: pruébelo
Una vez que haya creado la cadena de herramientas que desea, pruébela con:
Todo parece funcionar como en la Configuración 1, excepto que ahora se usaron los objetos de tiempo de ejecución correctos:
Configuración 2: intento de recompilación glibc eficiente fallido
No parece posible con crosstool-NG, como se explica a continuación.
Si solo reconstruyes;
entonces sus cambios en la ubicación de origen de glibc personalizada se tienen en cuenta, pero construye todo desde cero, por lo que es inutilizable para el desarrollo iterativo.
Si lo hacemos:
da una buena visión general de los pasos de compilación:
por lo tanto, vemos que hay pasos glibc entrelazados con varios pasos GCC, más notablemente
libc_start_files
antescc_core_pass_2
, que es probablemente el paso más costoso junto concc_core_pass_1
.Para compilar solo un paso, primero debe establecer la
.config
opción "Guardar pasos intermedios" en la compilación inicial:Paths and misc options
Debug crosstool-NG
Save intermediate steps
y luego puedes probar:
pero desafortunadamente, lo
+
requerido como se menciona en: https://github.com/crosstool-ng/crosstool-ng/issues/1033#issuecomment-424877536y, básicamente, todavía hace que la reconstrucción sea demasiado lenta para ser factible para el desarrollo, y no veo cómo superar esto sin parchear crosstool-NG.
Además, comenzar desde el
libc
paso no parecía volver a copiar la fuenteCustom source location
, lo que hace que este método sea inutilizable.Bono: stdlibc ++
Una ventaja adicional si también está interesado en la biblioteca estándar de C ++: ¿Cómo editar y reconstruir la fuente de la biblioteca estándar GCC libstdc ++ C ++?
fuente
¿Puedes considerar usar Nix http://nixos.org/nix/ ?
fuente
@msb ofrece una solución segura.
Encontré este problema cuando lo hice
import tensorflow as tf
en un entorno conda en elCentOS 6.5
que solo lo ha hechoglibc-2.12
.Quiero proporcionar algunos detalles:
Primero instale
glibc
en su directorio de inicio:En segundo lugar, siga el mismo camino para instalar patchelf ;
Tercero, parchea tu Python:
como lo menciona @msb
Ahora puedo usar
tensorflow-2.0 alpha
enCentOS 6.5
.ref: https://serverkurma.com/linux/how-to-update-glibc-newer-version-on-centos-6-x/
fuente
No estoy seguro de que la pregunta siga siendo relevante, pero hay otra forma de solucionar el problema: Docker. Se puede instalar un contenedor casi vacío de la Distribución de origen (La distribución utilizada para el desarrollo) y copiar los archivos en el Contenedor. De esa manera, no necesita crear el sistema de archivos necesario para chroot.
fuente
Si observa detenidamente la segunda salida, puede ver que se utiliza la nueva ubicación para las bibliotecas. Quizás todavía faltan bibliotecas que forman parte de glibc.
También creo que todas las bibliotecas utilizadas por su programa deben compilarse con esa versión de glibc. Si tiene acceso al código fuente del programa, una nueva compilación parece ser la mejor solución.
fuente
"Empleado ruso" es una de las mejores respuestas, y creo que todas las demás respuestas sugeridas pueden no funcionar. La razón es simplemente porque cuando se crea una aplicación por primera vez, todas sus API que necesita se resuelven en el momento de la compilación. Usando "ldd" puede ver todas las dependencias vinculadas estáticamente:
Pero en el tiempo de ejecución, Firefox también cargará muchas otras bibliotecas dinámicas, por ejemplo (para Firefox) hay muchas bibliotecas etiquetadas con "glib" cargadas (aunque no estén vinculadas estáticamente):
Muchas veces, puede ver que los nombres de una versión están vinculados a otra versión. P.ej:
Por lo tanto, esto significa que existen diferentes versiones de "bibliotecas" en un sistema, lo cual no es un problema ya que es el mismo archivo y proporcionará compatibilidades cuando las aplicaciones tengan dependencias de múltiples versiones.
Por lo tanto, en el nivel del sistema, todas las bibliotecas son casi interdependientes entre sí, y solo cambiar las prioridades de carga de las bibliotecas mediante la manipulación de LD_PRELOAD o LD_LIBRARY_PATH no ayudará, incluso si puede cargarse, el tiempo de ejecución puede bloquearse.
http://lightofdawn.org/wiki/wiki.cgi/-wiki/NewAppsOnOldGlibc
La mejor alternativa es chroot (mencionado brevemente por ER): pero para esto necesitará recrear todo el entorno en el que se ejecuta el binario original, generalmente a partir de / lib, / usr / lib /, / usr / lib / x86, etc. Puede usar "Buildroot", o YoctoProject, o simplemente alquitrán de un entorno de distribución existente. (como Fedora / Suse, etc.)
fuente
Cuando quería ejecutar un navegador de cromo en Ubuntu preciso (glibc-2.15), recibí el mensaje (típico) "... libc.so.6: versión 'GLIBC_2.19' no encontrada ...". Consideré el hecho de que los archivos no son necesarios de forma permanente, sino solo para comenzar. Así que recopilé los archivos necesarios para el navegador y sudo y creé un entorno mini-glibc-2.19-, inicié el navegador y luego volví a copiar los archivos originales. Los archivos necesarios están en RAM y el glibc original es el mismo.
mkdir -p /glibc-2.19/i386-linux-gnu
mkdir -p /glibc-2.15/i386-linux-gnu
El script para ejecutar el navegador:
fuente