Quando eu compilo algo no meu Ubuntu Lucid 10.04 PC, ele é vinculado ao glibc. Lucid usa 2,11 de glibc. Quando executo este binário em outro PC com uma glibc mais antiga, o comando falha dizendo que não há glibc 2.11 ...
Pelo que eu sei, a glibc usa versão de símbolo. Posso forçar o gcc a vincular a uma versão de símbolo específica?
Em meu uso concreto, tento compilar um conjunto de ferramentas cruzadas gcc para ARM.
Respostas:
Você está correto ao dizer que a glibc usa versão de símbolo. Se você estiver curioso, a implementação de versão de símbolo introduzida na glibc 2.1 é descrita aqui e é uma extensão do esquema de versão de símbolo da Sun descrito aqui .
Uma opção é vincular estaticamente seu binário. Esta é provavelmente a opção mais fácil.
Você também pode construir seu binário em um ambiente de construção chroot, ou usando um cross-compiler glibc- new => glibc- old .
De acordo com a postagem do blog http://www.trevorpounds.com Linking to Older Versioned Symbols (glibc) , é possível forçar qualquer símbolo a ser vinculado a um mais antigo, desde que seja válido usando o mesmo
.symver
pseudo -op que é usado para definir símbolos com versão em primeiro lugar. O exemplo a seguir foi extraído da postagem do blog .O exemplo a seguir usa o realpath do glibc, mas garante que ele esteja vinculado a uma versão 2.2.5 mais antiga.
fonte
libc.a
continua a existir, glibc suporta isso em alguns casos, embora não seja recomendado (Drepper) . Você terá problemas com programas não triviais, especialmente qualquer coisa que use NSS (solução alternativa no FAQ ).Faça a ligação com -static . Quando você vincula com -static, o vinculador incorpora a biblioteca dentro do executável, então o executável será maior, mas pode ser executado em um sistema com uma versão mais antiga da glibc porque o programa usará sua própria biblioteca em vez da do sistema .
fonte
Configuração 1: compilar seu próprio glibc sem GCC dedicado e usá-lo
Visto que parece impossível fazer apenas com os hacks de versão de símbolo, vamos dar um passo adiante e compilar o glibc nós mesmos.
Esta configuração pode funcionar e é rápida, pois não recompila todo o conjunto 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 inicial em que a glibc depende, então eu não ficaria surpreso se as coisas travassem de forma maravilhosa e maneiras incrivelmente sutis.Para uma configuração mais confiável, consulte a Configuração 2 abaixo.
Construa o glibc e instale localmente:
Configuração 1: verifique a construção
test_glibc.c
Compile e execute com
test_glibc.sh
:O programa produz 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
A saída confirma que asldd
bibliotecas e que acabamos de construir 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, conforme mencionado anteriormente, mas não sei como contornar isso, por exemplo, contém:Configuração 1: modificar glibc
Agora vamos modificar o glibc com:
Em seguida, recompile e reinstale o glibc, e recompile e execute novamente o nosso programa:
e vemos
hacked
impresso algumas vezes conforme o esperado.Isso confirma ainda mais que realmente usamos a glibc que compilamos e não a do host.
Testado no Ubuntu 18.04.
Configuração 2: configuração do crosstool-NG pristine
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 um conjunto de ferramentas GCC dedicado e completo que usa a glibc que desejamos.
A única desvantagem desse método é que a construção levará mais tempo. Mas eu não arriscaria uma configuração de produção com nada menos.
crosstool-NG é um conjunto de scripts que baixa e compila tudo do código-fonte para nós, incluindo GCC, glibc e binutils.
Sim, o sistema de compilação do GCC é tão ruim que precisamos de um projeto separado para isso.
Esta configuração só não é perfeita porque crosstool-NG não suporta a construção de executáveis sem
-Wl
sinalizadores extras , o que parece estranho já que construímos o próprio GCC. Mas tudo parece funcionar, então isso é apenas um inconveniente.Obtenha o crosstool-NG e configure-o:
A única opção obrigatória que posso ver é fazer com que corresponda à versão do kernel do host para usar os cabeçalhos de kernel corretos. Encontre a versão do kernel do host com:
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.
Agora você pode construir com:
e agora aguarde cerca de trinta minutos a duas horas para a compilação.
Configuração 2: configurações opcionais
O
.config
que geramos com./ct-ng x86_64-unknown-linux-gnu
tem:Para mudar isso,
menuconfig
faça:C-library
Version of glibc
salve o
.config
e continue com a construção.Ou, se você quiser usar seu próprio código-fonte glibc, por exemplo, para usar glibc do git mais recente, proceda assim :
Paths and misc options
Try features marked as EXPERIMENTAL
: definido como verdadeiroC-library
Source of glibc
Custom location
: diga simCustom location
Custom source location
: aponta para um diretório contendo seu código-fonte glibconde glibc foi clonado como:
Configuração 2: teste
Depois de criar o conjunto de ferramentas que deseja, teste-o com:
Tudo parece funcionar como na Configuração 1, exceto que agora os objetos de tempo de execução corretos foram usados:
Configuração 2: falha na tentativa de recompilação eficiente de glibc
Não parece possível com o crosstool-NG, conforme explicado abaixo.
Se você apenas reconstruir;
então, suas alterações no local de origem glibc customizado são levadas em consideração, mas ele constrói tudo do zero, tornando-o inutilizável para desenvolvimento iterativo.
Se nós fizermos:
dá uma boa visão geral das etapas de construção:
portanto, vemos que há etapas glibc entrelaçadas com várias etapas GCC, mais notavelmente
libc_start_files
vem antescc_core_pass_2
, que é provavelmente a etapa mais cara junto comcc_core_pass_1
.Para construir apenas uma etapa, você deve primeiro definir a opção "Salvar etapas intermediárias"
.config
para a construçã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 corrigir o crosstool-NG.
Além disso, começar a partir da
libc
etapa não parece copiar a fonte novamenteCustom source location
, tornando esse método inutilizável.Bônus: stdlibc ++
Um bônus se você também estiver interessado na biblioteca padrão C ++: Como editar e reconstruir a fonte da biblioteca padrão GCC libstdc ++ C ++?
fonte
musl-libc
é outra opção no que diz respeito ao tempo de execução C.Na minha opinião, a solução mais preguiçosa (especialmente se você não depende dos recursos C / C ++ mais recentes ou dos recursos mais recentes do compilador) ainda não foi mencionada, então aqui está:
Basta construir no sistema com o GLIBC mais antigo que você ainda deseja oferecer suporte.
Na verdade, isso é muito fácil de fazer hoje em dia com tecnologias como chroot, ou KVM / Virtualbox ou docker, mesmo se você realmente não quiser usar uma distro tão antiga diretamente em qualquer PC. Em detalhes, para criar um binário portátil máximo de seu software, recomendo seguir estas etapas:
Basta escolher o seu veneno de sandbox / virtualização / ... seja o que for, e usá-lo para obter um Ubuntu LTS virtual mais antigo e compilar com o gcc / g ++ que ele tem por padrão. Isso limita automaticamente o seu GLIBC ao disponível naquele ambiente.
Evite depender de libs externas fora das básicas: como, você deve vincular dinamicamente coisas do sistema no nível do solo como glibc, libGL, libxcb / X11 / wayland things, libasound / libpulseaudio, possivelmente GTK + se você usar isso, mas de outra forma, preferencialmente link externo estaticamente libs / envie-os junto, se puder. Principalmente bibliotecas independentes, como carregadores de imagens, decodificadores de multimídia, etc, podem causar menos falhas em outras distros (falhas podem ser causadas, por exemplo, se estiverem presentes em algum lugar em uma versão principal diferente) se você os enviar estaticamente.
Com essa abordagem, você obtém um binário compatível com GLIBC antigo sem nenhum ajuste manual de símbolo, sem fazer um binário totalmente estático (que pode falhar para programas mais complexos porque a glibc odeia isso e pode causar problemas de licenciamento para você) e sem configuração qualquer conjunto de ferramentas personalizado, qualquer cópia glibc personalizada ou qualquer outra coisa.
fonte