Várias bibliotecas glibc em um único host
Meu servidor linux (SLES-8) atualmente possui glibc-2.2.5-235, mas eu tenho um programa que não funciona nesta versão e requer glibc-2.3.3.
É possível ter vários glibcs instalados no mesmo host?
Este é o erro que recebo quando executo meu programa na glibc antiga:
./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)
Então, criei um novo diretório chamado newglibc e copiei os seguintes arquivos em:
libpthread.so.0
libm.so.6
libc.so.6
ld-2.3.3.so
ld-linux.so.2 -> ld-2.3.3.so
e
export LD_LIBRARY_PATH=newglibc:$LD_LIBRARY_PATH
Mas eu recebo um erro:
./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)
Então parece que eles ainda estão vinculando a / lib e não pegando de onde eu os coloquei?
obrigado
export LD_LIBRARY_PATH=newglibc:$LD_LIBRARY_PATH
fez resolver o problema para mim! Certamente não funcionará para todos, mas é uma solução fácil se funcionar! Obrigado! :)Respostas:
É muito possível ter várias versões do glibc no mesmo sistema (fazemos isso todos os dias).
No entanto, você precisa saber que o glibc consiste em várias partes (mais de 200 bibliotecas compartilhadas) às quais todas devem corresponder. Uma das partes é ld-linux.so.2, e deve corresponder à libc.so.6, ou você verá os erros que está vendo.
O caminho absoluto para ld-linux.so.2 é codificado no executável no momento do link e não pode ser facilmente alterado depois que o link for concluído.
Para criar um executável que funcione com a nova glibc, faça o seguinte:
A
-rpath
opção vinculador fará com que o carregador de tempo de execução procure bibliotecas/path/to/newglibc
(para que você não precise configurá-LD_LIBRARY_PATH
lo antes de executá-lo), e a-dynamic-linker
opção irá "assar" o caminho para corrigirld-linux.so.2
o aplicativo.Se você não pode vincular novamente o
myapp
aplicativo (por exemplo, porque é um binário de terceiros), nem tudo está perdido, mas fica mais complicado. Uma solução é definir umchroot
ambiente adequado para isso. Outra possibilidade é usar o rtldi e um editor binário .fonte
-Wl,--dynamic-linker=file
(leva dois '-') só funciona ao compilar para executáveis do ELF. Verifique/sbin/ldconfig -p | grep ld
patchelf
( nixos.org/patchelf.html ), que permite modificar o rpath e o intérprete do ELF já compilado.-Wl,--rpath
vez deLD_LIBRARY_PATH
pode ser importante por outros motivos que não sejam convenientes: se o programa iniciar processos filhos, o valor deLD_LIBRARY_PATH
geralmente será herdado por eles, mas se eles também não forem compilados para uso o glibc mais recente (por exemplo, se eles são binários de açõesbash
), eles não serão lançados./path/to/newglibc/ld-linux.so.2 --library-path /path/tonewglibc/lib64:/path/to/newglibc/usr/lib64 /path/to/myapp
-I
e-L
: stackoverflow.com/a/52454603/895245Esta pergunta é antiga, as outras respostas são antigas. A resposta do "russo empregado" é muito boa e informativa, mas só funciona se você tiver o código-fonte. Caso contrário, as alternativas naquela época eram muito complicadas. Felizmente hoje em dia temos uma solução simples para esse problema (como comentado em uma de suas respostas), usando o patchelf . Tudo o que tem a fazer é:
E depois disso, você pode simplesmente executar seu arquivo:
Não é necessário
chroot
editar manualmente os binários, felizmente. Mas lembre-se de fazer backup do seu binário antes de corrigi-lo, se você não tiver certeza do que está fazendo, porque ele modifica seu arquivo binário. Depois de corrigi-lo, você não pode restaurar o caminho antigo para o interpretador / rpath. Se não funcionar, você precisará corrigi-lo até encontrar o caminho que realmente funcionará ... Bem, não precisa ser um processo de tentativa e erro. Por exemplo, no exemplo do OP, ele precisavaGLIBC_2.3
, para que você possa encontrar facilmente qual lib fornece essa versão usandostrings
:Em teoria, o primeiro grep ficaria vazio porque o libc do sistema não possui a versão que ele deseja, e o segundo deve gerar GLIBC_2.3 porque possui a versão em
myapp
uso, portanto sabemos que podemospatchelf
usar nosso binário nesse caminho.Quando você tenta rodar um binário no linux, o binário tenta carregar o vinculador, depois as bibliotecas, e todas elas devem estar no caminho e / ou no lugar certo. Se o seu problema está no vinculador e você deseja descobrir qual o caminho que seu binário está procurando, você pode descobrir com este comando:
Se o seu problema for com as bibliotecas, os comandos que fornecerão as bibliotecas que estão sendo usadas são:
Isso listará as bibliotecas que seu binário precisa, mas você provavelmente já conhece as problemáticas, pois elas já estão gerando erros, como no caso do OP.
"patchelf" funciona para muitos problemas diferentes que você pode encontrar ao tentar executar um programa, relacionado a esses 2 problemas. Por exemplo, se você obtiver
ELF file OS ABI invalid
:, pode ser corrigido configurando um novo carregador (a--set-interpreter
parte do comando), como explico aqui . Outro exemplo é o problema de obterNo such file or directory
quando você executa um arquivo que está lá e é executável, como exemplificado aqui . Nesse caso específico, o OP estava sem um link para o carregador, mas talvez no seu caso você não tenha acesso root e não possa criar o link. Definir um novo intérprete resolveria seu problema.Obrigado Empregado russo e Michael Pankov pela visão e solução!
fonte
patchelf
), mas a frase "Não há necessidade de ... editar binários" pode ser um pouco enganadora (já que você está realmente editando seus binários).Use LD_PRELOAD: coloque sua biblioteca em algum lugar fora dos diretórios man lib e execute:
Veja: o artigo da Wikipedia
fonte
Primeiro de tudo, a dependência mais importante de cada programa vinculado dinamicamente é o vinculador. Todas as bibliotecas devem corresponder à versão do vinculador.
Vamos dar um exemplo simples: eu tenho o sistema ubuntu newset onde eu corro algum programa (no meu caso é o compilador D - ldc2). Gostaria de executá-lo no antigo CentOS, mas por causa da biblioteca glibc mais antiga, é impossível. Eu tenho
Eu tenho que copiar todas as dependências do ubuntu para centos. O método adequado é o seguinte:
Primeiro, vamos verificar todas as dependências:
O linux-vdso.so.1 não é uma biblioteca real e não precisamos nos preocupar com isso.
/lib64/ld-linux-x86-64.so.2 é o vinculador, que é usado pelo linux vincula o executável a todas as bibliotecas dinâmicas.
O restante dos arquivos são bibliotecas reais e todos eles, juntamente com o vinculador, devem ser copiados em algum lugar dos centos.
Vamos supor que todas as bibliotecas e vinculadores estejam no diretório "/ mylibs".
ld-linux-x86-64.so.2 - como eu já disse - é o vinculador. Não é uma biblioteca dinâmica, mas executável estática. Você pode executá-lo e ver que ele ainda possui alguns parâmetros, por exemplo - --library-path (retornarei a ele).
No Linux, o programa vinculado dinamicamente pode ser almoçado apenas por seu nome, por exemplo
O Linux carrega esse programa na RAM e verifica qual vinculador está configurado para ele. Normalmente, no sistema de 64 bits, é /lib64/ld-linux-x86-64.so.2 (no seu sistema de arquivos é um link simbólico para o executável real). Em seguida, o linux executa o vinculador e carrega bibliotecas dinâmicas.
Você também pode mudar isso um pouco e fazer esse truque:
É o método para forçar o linux a usar o vinculador específico.
E agora podemos retornar ao parâmetro mencionado anteriormente --library-path
Ele executará o ldc2 e carregará bibliotecas dinâmicas em / mylibs.
Este é o método para chamar o executável com bibliotecas escolhidas (não padrão do sistema).
fonte
Configuração 1: compile seu próprio glibc sem o GCC dedicado e use-o
Essa configuração pode funcionar e é rápida, pois não recompila toda a cadeia de ferramentas do GCC, apenas glibc.
Mas não é confiável, pois usa anfitrião C runtime objetos como
crt1.o
,crti.o
ecrtn.o
fornecido pela glibc. Isso é mencionado em: https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location Esses objetos fazem a configuração antecipada em que a glibc depende, portanto, não ficaria surpreso se algo acontecesse de maneira maravilhosa. e maneiras incrivelmente sutis.Para uma configuração mais confiável, consulte a Instalação 2 abaixo.
Crie o glibc e instale localmente:
Instalação 1: verifique a compilação
test_glibc.c
Compile e execute com
test_glibc.sh
:O programa gera o esperado:
Comando adaptado de https://sourceware.org/glibc/wiki/Testing/Builds?action=recall&rev=21#Compile_against_glibc_in_an_installed_location, mas
--sysroot
falhou com:então eu o removi.
ldd
output confirma que asldd
bibliotecas e que acabamos de criar estão realmente sendo usadas conforme o esperado:A
gcc
saída de depuração da compilação mostra que meus objetos de tempo de execução do host foram usados, o que é ruim como mencionado anteriormente, mas não sei como contornar isso, por exemplo, ele contém:Configuração 1: modificar glibc
Agora vamos modificar o glibc com:
Em seguida, recompile e reinstale o glibc, recompile e execute novamente o nosso programa:
e vemos
hacked
impressos algumas vezes conforme o esperado.Isso confirma ainda mais que usamos o glibc que compilamos e não o host.
Testado no Ubuntu 18.04.
Configuração 2: configuração intacta crosstool-NG
Esta é uma alternativa para a configuração 1, e é a configuração mais correta que consegui agora: tudo está correto, tanto quanto eu posso observar, incluindo o tempo de execução C objetos como
crt1.o
,crti.o
ecrtn.o
.Nesta configuração, compilaremos uma cadeia de ferramentas GCC dedicada completa que usa a glibc que queremos.
A única desvantagem desse método é que a compilação levará mais tempo. Mas eu não arriscaria uma instalação de produção com nada menos.
O crosstool-NG é um conjunto de scripts que baixa e compila tudo da fonte para nós, incluindo GCC, glibc e binutils.
Sim, o sistema de criação do GCC é tão ruim que precisamos de um projeto separado para isso.
Essa configuração não é perfeita porque o crosstool-NG não suporta a criação de executáveis sem
-Wl
sinalizadores extras , o que é estranho desde que criamos o próprio GCC. Mas tudo parece funcionar, então isso é apenas um inconveniente.Obtenha crosstool-NG, configure e construa:
A construção leva cerca de trinta minutos a duas horas.
A única opção de configuração obrigatória que posso ver é fazer com que ela corresponda à sua versão do kernel do host para usar os cabeçalhos corretos do kernel. Encontre a sua versão do kernel host com:
o que me mostra:
então
menuconfig
eu faço:Operating System
Version of linux
então eu seleciono:
qual é a primeira versão igual ou mais antiga. Tem que ser mais antigo, pois o kernel é compatível com versões anteriores.
Instalação 2: configurações opcionais
O
.config
que geramos com./ct-ng x86_64-unknown-linux-gnu
:Para mudar isso,
menuconfig
faça:C-library
Version of glibc
Salve o
.config
e continue com a compilação.Ou, se você quiser usar sua própria fonte glibc, por exemplo, para usar glibc a partir do git mais recente, proceda da seguinte maneira :
Paths and misc options
Try features marked as EXPERIMENTAL
: definido como trueC-library
Source of glibc
Custom location
: diga simCustom location
Custom source location
: aponte para um diretório que contém sua fonte glibconde glibc foi clonado como:
Instalação 2: teste
Depois de criar a cadeia de ferramentas desejada, teste-a com:
Tudo parece funcionar como na Instalação 1, exceto que agora os objetos de tempo de execução corretos foram usados:
Configuração 2: falha na tentativa eficiente de recompilação glibc
Não parece possível com o crosstool-NG, conforme explicado abaixo.
Se você apenas reconstruir;
suas alterações no local de origem glibc personalizado são levadas em consideração, mas ele cria tudo do zero, tornando-o inutilizável para o desenvolvimento iterativo.
Se nós fizermos:
fornece uma boa visão geral das etapas de compilação:
portanto, vemos que há etapas glibc entrelaçadas com várias etapas do GCC, mais notavelmente
libc_start_files
anteriorescc_core_pass_2
, o que provavelmente é a etapa mais caracc_core_pass_1
.Para criar apenas uma etapa, primeiro defina a opção "Salvar etapas intermediárias" na
.config
opção para a compilação inicial:Paths and misc options
Debug crosstool-NG
Save intermediate steps
e então você pode tentar:
mas, infelizmente, o
+
exigido conforme mencionado em: https://github.com/crosstool-ng/crosstool-ng/issues/1033#issuecomment-424877536e basicamente ainda torna a reconstrução muito lenta para ser viável para o desenvolvimento, e não vejo como superar isso sem aplicar o patch crosstool-NG.
Além disso, a partir da
libc
etapa parecia não copiar novamente a fonteCustom source location
, tornando ainda mais inutilizável esse método.Bônus: stdlibc ++
Um bônus se você também estiver interessado na biblioteca padrão do C ++: Como editar e recriar a fonte da biblioteca padrão do GCC libstdc ++ C ++?
fonte
Você pode considerar usar o Nix http://nixos.org/nix/ ?
fonte
O @msb oferece uma solução segura.
Eu conheci esse problema quando o fiz
import tensorflow as tf
no ambiente conda emCentOS 6.5
que apenas o possuiglibc-2.12
.Quero fornecer alguns detalhes:
Primeiro instale
glibc
no seu diretório inicial:Segundo, siga o mesmo caminho para instalar o patchelf ;
Terceiro, corrija seu Python:
como mencionado por @msb
Agora eu posso usar
tensorflow-2.0 alpha
noCentOS 6.5
.ref: https://serverkurma.com/linux/how-to-update-glibc-newer-version-on-centos-6-x/
fonte
Não tenho certeza de que a pergunta ainda seja relevante, mas há outra maneira de corrigir o problema: Docker. Pode-se instalar um contêiner quase vazio da distribuição de origem (a distribuição usada para desenvolvimento) e copiar os arquivos no contêiner. Dessa forma, você não precisa criar o sistema de arquivos necessário para o chroot.
fonte
Se você olhar atentamente para a segunda saída, poderá ver que o novo local para as bibliotecas é usado. Talvez ainda existam bibliotecas ausentes que fazem parte da glibc.
Eu também acho que todas as bibliotecas usadas pelo seu programa devem ser compiladas contra essa versão do glibc. Se você tiver acesso ao código fonte do programa, uma nova compilação parece ser a melhor solução.
fonte
"Russo empregado" está entre as melhores respostas e acho que todas as outras respostas sugeridas podem não funcionar. O motivo é simplesmente porque, quando um aplicativo é criado pela primeira vez, todas as APIs necessárias são resolvidas no momento da compilação. Usando "ldd", você pode ver todas as dependências vinculadas estaticamente:
Mas em tempo de execução, o firefox também carregará muitas outras bibliotecas dinâmicas, por exemplo (para o firefox) existem muitas bibliotecas marcadas com "glib" carregadas (mesmo que vinculadas estaticamente não existam):
Muitas vezes, você pode ver os nomes de uma versão sendo vinculados a outra versão. Por exemplo:
Portanto, significa que existe uma versão diferente de "bibliotecas" em um sistema - o que não é um problema, pois é o mesmo arquivo e fornecerá compatibilidade quando os aplicativos tiverem dependências de várias versões.
Portanto, no nível do sistema, todas as bibliotecas são quase interdependentes entre si, e apenas alterar a prioridade de carregamento das bibliotecas através da manipulação de LD_PRELOAD ou LD_LIBRARY_PATH não ajudará - mesmo que seja possível carregar, o tempo de execução ainda pode falhar.
http://lightofdawn.org/wiki/wiki.cgi/-wiki/NewAppsOnOldGlibc
A melhor alternativa é o chroot (mencionado brevemente por ER): mas para isso, você precisará recriar todo o ambiente em que a execução binária original - geralmente iniciando em / lib, / usr / lib /, / usr / lib / x86 etc. Você pode usar "Buildroot", ou YoctoProject, ou apenas tar de um ambiente Distro existente. (como Fedora / Suse etc).
fonte
Quando eu queria rodar um navegador chromium no Ubuntu preciso (glibc-2.15), recebi a mensagem (típica) "... libc.so.6: versão` GLIBC_2.19 'não encontrada ... ". Eu considerei o fato de que os arquivos não são necessários permanentemente, mas apenas para iniciar. Então, coletei os arquivos necessários para o navegador e o sudo e criei um ambiente mini-glibc-2.19-, iniciei o navegador e depois copiei os arquivos originais novamente. Os arquivos necessários estão na RAM e a glibc original é a mesma.
mkdir -p /glibc-2.19/i386-linux-gnu
mkdir -p /glibc-2.15/i386-linux-gnu
o script para executar o navegador:
fonte