Qual versão da biblioteca C meu sistema usa?


43

Como posso saber com certeza que biblioteca C da terra do usuário meu sistema usa? Os possíveis motivos para precisar essas informações incluem:

  • Estou pensando em fazer o download de um pacote de origem gigantesco que, com certeza, fará verificações adequadas e lista uma versão mínima da biblioteca, mas prefiro me poupar de um possível aborrecimento, verificando primeiro se ele funcionará.

  • Estou preocupado com a compatibilidade da ABI com alguns binários de terceiros que quero tentar instalar fora do sistema de gerenciamento de pacotes do sistema.

  • Eu tenho um pacote de origem cuja documentação menciona a necessidade de uma versão mínima da biblioteca do meu sistema, mas o processo de compilação não executa nenhuma verificação.

  • Estou criando um compilador cruzado direcionado a um sistema específico e não quero arriscar problemas de compatibilidade futuros .


Por que não tentar e ver. Não sei se a versão conta tudo; e as correções? Ou as distrubuções são cuidadosas ao alterar a ABI? O problema não é se os símbolos exportados foram resolvidos ou algo assim?
Faheem Mitha

Respostas legais, mas ninguém aborda como fazer isso em um Mac, onde não há ldd. Não tenho certeza se isso otool --versionpode dar a mesma informação.
dubiousjim

@dubiousjim Alguém poderia; só não eu, porque não sou usuário de Mac. Por aqui, talvez você precise perguntar especificamente sobre isso - parte do problema talvez seja que as pessoas geralmente não usam muito C em OSX? Mas tenho certeza que haverá um regular que sabe. Você também pode postar um link para isso no chat e ver o que acontece, mas provavelmente uma pergunta nova e mais específica seria melhor.
goldilocks

Respostas:


50

Os sistemas GNU / Linux geralmente usam glibc (família Fedora / Redhat, Arch) ou seu primo próximo, eglibc (família Debian / Ubuntu); Como o eglibc agora está sendo mesclado de novo no glibc ( consulte EGLIBC 2.19 Branch Criado em "Notícias" ), em um futuro próximo todos eles serão glibc novamente.

A maneira mais fácil de verificar a versão exata é perguntar ldd, que acompanha a biblioteca C.

No Fedora 20:

> ldd --version
ldd (GNU libc) 2.18

Isso é glibc 2.18.

No Raspbian (porta Debian 7 para ARMv6 Broadcom SoC):

> ldd --version
ldd (Debian EGLIBC 2.13-38+rpi2) 2.13

Isso é o eglibc 2.13.

Se, por qualquer motivo, você tiver misturado e correspondido algumas partes ou não tiver certeza ldd, poderá consultar a biblioteca C diretamente.

> whereis libc.so
libc: /usr/lib64/libc.a /usr/lib64/libc.so /usr/share/man/man7/libc.7.gz

Nenhum deles é executável, mas eles fornecem uma pista sobre onde encontrar um.

> $(find /usr/lib64/ -executable -name "*libc.so*") --version
GNU C Library (GNU libc) stable release version 2.18, by Roland McGrath et al.

No entanto, não é necessariamente tão fácil, porque a biblioteca C não precisa residir em algum lugar whereispara encontrá-lo.

> whereis libc.so
libc: /usr/share/man/man7/libc.7.gz

Infelizmente, a página do manual não fornece um número de versão. lddainda é útil, pois qualquer executável dinamicamente vinculado no sistema (por exemplo, quase tudo incluído /usr/bin) será vinculado à biblioteca C.

> ldd /usr/bin/touch
    /usr/lib/arm-linux-gnueabihf/libcofi_rpi.so (0xb6eed000)
    librt.so.1 => /lib/arm-linux-gnueabihf/librt.so.1 (0xb6ed0000)
    libc.so.6 => /lib/arm-linux-gnueabihf/libc.so.6 (0xb6da1000)
    /lib/ld-linux-armhf.so.3 (0xb6efb000)
    libpthread.so.0 => /lib/arm-linux-gnueabihf/libpthread.so.0 (0xb6d82000)

libc.so.6 está na terceira linha.

> /lib/arm-linux-gnueabihf/libc.so.6 --version
GNU C Library (Debian EGLIBC 2.13-38+rpi2) stable release version 2.13, by Roland McGrath et al.

O que torna um sistema GNU / Linux "normal"? E as distribuições usando musl ?
22714 Elliott Frisch

1
@ElliottFrisch Pretendia aplicar-se ao GNU / Linux, como em "GNU / Linux normal" (adjetivo, substantivo), pois pode haver (existem, tenho certeza) sistemas que não usam (e) glibc, mas sim use o restante da pilha GNU (bash, binutils, etc.). Eu consideraria esses sistemas GNU / Linux "incomuns". Mas eu removi o "normal" e mudei para "Sistemas GNU / Linux normalmente usam ...". Nota: deixei intencionalmente a pergunta em aberto, especificando o sistema operacional WRT (não há linux, GNU ou tag glibc); portanto, se você quiser adicionar uma resposta sobre qualquer sistema apropriado para U&L, faça.
18714

1
Depois que encontrei como você mostrou e consultei a versão, ela também imprimiu as extensões disponíveis! (no meu caso, stubs, crypt, libidn, threads nativos e bind) e se refere a ABI: libc ABIs: UNIQUE IFUNC.

O Debian usa o /lib/`uname -m`*caminho. Assim maneira portátil seria: find /lib/`uname -m`* /usr/lib* -executable -name "*libc.so*" | xargs --version. Obrigado pela boa explicação.
pevik 28/10/2015

@pevik: Errado, no braço é /lib/arm-linux-gnueabihf/libc.so.6, e não /lib/armv7l/libc.so.6
Quandary

14

Na verdade, um sistema não está limitado a uma biblioteca C. A maioria, no entanto, usa principalmente apenas um, que também será o usado pelo compilador padrão. E como você está baixando o código-fonte para compilar, é com isso que você se preocupa.

Comece com um programa trivial:

#include <stdio.h>
int main() {
    printf("Hello, world\n");
    return 0;
}

compile-o usando o compilador que você usará para o código-fonte e use lddpara descobrir onde está a biblioteca C:

$ ldd ./libc-test 
        linux-vdso.so.1 (0x00007fff2e5fe000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8c8ad98000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f8c8b171000)

Agora você tem o caminho para a biblioteca C. Você pode procurar isso no seu gerenciador de pacotes para encontrar o pacote (por exemplo, dpkg -S /lib/x86_64-linux-gnu/libc.so.6ou rpm -q -f /lib/x86_64-linux-gnu/libc.so.6).

Pelo menos no caso do eglibc / glibc, você pode executá-lo:

$ /lib/x86_64-linux-gnu/libc.so.6  
GNU C Library (Debian EGLIBC 2.18-4) stable release version 2.18, by Roland McGrath et al.
Copyright (C) 2013 Free Software Foundation, Inc.

Por fim, você pode ver se consegue obter dicas objdump -p /lib/x86_64-linux-gnu/libc.so.6, procurando na seção de definições de versão :

Version definitions:
1 0x01 0x0865f4e6 libc.so.6
2 0x00 0x09691a75 GLIBC_2.2.5
3 0x00 0x09691a76 GLIBC_2.2.6
⋮
21 0x00 0x06969197 GLIBC_2.17
        GLIBC_2.16 
22 0x00 0x06969198 GLIBC_2.18
        GLIBC_2.17 
23 0x00 0x0963cf85 GLIBC_PRIVATE
        GLIBC_2.18 

Observe como o símbolo GLIBC_2.18 tem o número da versão mais recente entre os símbolos listados e a versão da biblioteca é realmente 2.18. É o eglibc, no entanto (ele visa ser compatível com binários com o glibc 2.18, por isso usa as mesmas versões de símbolos).

Você também pode tentar usar stringspara descobrir algo sobre isso. Você deseja especificar um comprimento mínimo mais longo ( -n) ou usar grep para procurar algo:

$ strings  /lib/x86_64-linux-gnu/libc.so.6 | grep 'version [0-9]'
$ strings  /lib/x86_64-linux-gnu/libc.so.6 | grep -iC1 'copyright'

ambos trabalham para este eglibc.

NOTA: O utilitário de pacotes Debian dpkg-shlibdepsusa objdumpsob o capô, juntamente com informações de símbolos armazenados nos pacotes de bibliotecas da Debian para determinar as versões mínimas de dependências exigidas pelos pacotes binários da Debian no momento da construção. Basicamente, ele examina os símbolos exportados pelo pacote binário do Debian e, em seguida, encontra as versões mínimas das bibliotecas que contêm esses símbolos.


9

A resposta óbvia, embora não seja a mais abrangente, é verificar o seu gerenciador de pacotes, por exemplo

rpm -qi glibc
dpkg -l libc6

(Infelizmente, o glibc não possui um .pcarquivo pkconfig , também pkgconfig --modversion glibcnão é um corredor.) Veja também a excelente getconfsugestão do @ Gnouc .

O caso mais simples, com gcc + glibc, e o que mais uso primeiro é apenas executar libc.so, conforme descrito em algumas das outras respostas aqui. Não há necessidade de passar nenhum argumento, ele exibe sua versão por padrão. Isso funciona desde o glibc-2.1 (glibc-2.0 seg-faults, embora na época você pudesse verificar o glibcbugscript (agora aposentado) para confirmar a versão). Este método também funciona com versões recentes (> 0.9.15) do musl-libc (que foi 1.0 hoje, 20 de março). Ele não funciona com o uClibc, é segmentado por falhas.

Uma maneira simples de saber exatamente o que você gccfará é compilar:

#include <gnu/libc-version.h>
#include <stdio.h>
int main(int argc, char *argv[]) {
    printf("%s %s\n",gnu_get_libc_version(),gnu_get_libc_release());
    printf("glibc v%i %i.%i\n",__GNU_LIBRARY__,__GLIBC__,__GLIBC_MINOR__);
    return 0;
}

(com glibc, <stdio.h>inclui o <features.h>que define as macros GLIBC relevantes, você precisa <gnu/libc-version.h>das declarações de função.)

Isso captura casos mais complexos (vários libc e / ou vários compiladores), supondo que você esteja usando o compilador (e sinalizadores) certo, é claro. (Suspeito que não faça distinção entre eglibc e glibc propriamente dito.)

Se você tiver certeza de que está usando o glibc (ou eglibc), ldtambém confirmará a versão (desculpe, isso não está correto).

Se __GNU_LIBRARY__não estiver definido, você receberá erros, é hora do plano B.

gcc -dumpmachinepode ajudar, por exemplo, para uclibc, ele tem um -uclibcsufixo, como pode gcc -dumpspecs | grep dynamic-linker. Isso também pode implicar a ABI.

gcc -print-file-name=libc.solhe dirá qual arquivo o compilador usará para " -lc", este é quase certamente um script vinculador dentro da instalação do gcc, que você pode ler como texto simples. Isso mostrará o caminho exato para libc.so. Isso também funcionará se você estiver passando bandeiras como -m32ou -m64.

No caso de você estiver usando uClibc (como o usado por OpenWRT e mais), define __UCLIBC_MAJOR__, __UCLIBC_MINOR__e __UCLIBC_SUBLEVEL__, assim como __UCLIBC__em <features.h>, por isso é facilmente detectada usando uma pequena variação no exposto C trecho de código. No interesse da compatibilidade, o uClibc também pode definir as macros GNU / GLIBC, conforme usado acima, atualmente fingindo ser glibc-2.2. Ele atualmente não implementar as gnu_get_libc_X()funções, mas não implementar getconfo que também pode induzir em erro (Eu suspeito que ele retorna uma resposta vazia para getconf GNU_LIBC_VERSION, meu construir env está de mau humor hoje, por isso não posso confirmar.)

No caso improvável de usar dietlibc , a execução diet -vexibirá a versão.

(FWIW, durante vários anos com software usando o autoconf, tive mais problemas com requisitos gcce g++requisitos não verificados do que com os recursos glibc verificados.)


5

O GNU libc (o que a maioria das distribuições Linux usa de uma forma ou de outra) se esforça bastante para manter uma compatibilidade estrita com versões anteriores. Portanto, você deve ter problemas apenas se tentar executar um binário muito novo em uma versão antiga (ou em uma distribuição "corporativa", eles normalmente congelam versões, particularmente as básicas como a biblioteca C, corrigindo backport enquanto mantêm uma compatibilidade binária rigorosa) . Eu acredito que você é muito mais suscetível a ter problemas com outras bibliotecas (o C ++ teve algumas alterações de API / ABI na memória recente, outras bibliotecas simplesmente não se importam com a compatibilidade com versões anteriores).

Infelizmente, a única maneira de descobrir com certeza é tentar.


+1 Na verdade, eles têm um gráfico sobre compatibilidade com versões anteriores e eu diria que a única razão pela qual não é 100% é por causa do código que explora extensões esotéricas do GNU. No entanto, não tenho esse gráfico em relação à compatibilidade com a frente , o que, como você observa, é mais uma preocupação real.
Goldilocks

5

(Isso é essencialmente o mesmo que a resposta dos cachinhos dourados, mas com mais algumas explicações sobre o que está acontecendo sob o capô.)

A biblioteca compartilhada principal para GNU libc, libc.so.6(no Linux; Hurd tem um SONAME diferente), possui a propriedade incomum (para bibliotecas compartilhadas) que você pode invocá-la como executável. Se o fizer, ele imprime o tipo de coisa que os utilitários GNU geralmente imprimem quando executados --version, como este:

$ /lib/x86_64-linux-gnu/libc.so.6 
GNU C Library (Debian EGLIBC 2.18-4) stable release version 2.18, by Roland McGrath et al.
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
Compiled by GNU CC version 4.8.2.
Compiled on a Linux 3.12.6 system on 2014-03-02.
Available extensions:
    crypt add-on version 2.1 by Michael Glad and others
    GNU Libidn by Simon Josefsson
    Native POSIX Threads Library by Ulrich Drepper et al
    BIND-8.2.3-T5B
libc ABIs: UNIQUE IFUNC
For bug reporting instructions, please see:
<http://www.debian.org/Bugs/>.

Mas é claro que o diretório em que libc.so.6vive não está $PATH, então você precisa saber onde procurar. Pode ser em /lib, /lib64, /usr/lib, ou algo ainda mais malucos (como neste caso). Convenientemente, lddirá dizer-lhe:

$ ldd /bin/sh | grep libc
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5660b93000)

Para que isso funcione, é claro, você precisa conhecer o nome completo do caminho de um executável binário vinculado dinamicamente. O shexecutável é garantido para estar em /bin(porque muitos #!scripts de esperar que ele seja), e não pode ser ele próprio um #!script. Ele pode ser ligado estaticamente, mas eu não encontrei um sistema que fez isso em muitos anos.

Não sei o que você faz se estiver usando uClibc ou musl ou algo mais exótico.


2
Bem, você não precisa saber o caminho completo para / bin / sh ou o que quer. Você pode sempre $ ldd $(which sh) | grep libc. : D
Matt Nordhoff

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.