Qual versão da biblioteca C meu sistema usa?

43

Como posso saber com certeza que biblioteca userland C meu sistema usa? Possíveis razões para precisar desta informação incluem:

  • Existe um pacote fonte gigantesco que estou pensando em fazer o download, o qual tenho certeza de que fará verificações adequadas e listará uma versão mínima da biblioteca, mas eu prefiro me poupar de um possível problema verificando primeiro se isso funcionará. / p>

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

  • Eu tenho um pacote fonte 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 verificações.

  • Estou criando um compilador cruzado visando um sistema específico e não quero arriscar problemas de compatibilidade com versões futuras .

por goldilocks 19.03.2014 / 13:43

6 respostas

50

Os sistemas GNU / Linux geralmente usam glibc (família Fedora / Redhat, Arch) ou seu primo próximo, eglibc (família Debian / Ubuntu); já que o eglibc está sendo fundido novamente na glibc ( veja EGLIBC 2.19 Branch Created em "News" ), no futuro próximo, todos serão glibc novamente.

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

No Fedora 20:

> ldd --version
ldd (GNU libc) 2.18

Isso é glibc 2.18.

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

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

Isso é eglibc 2.13.

Se, por qualquer motivo, você tiver misturado e combinado algumas partes ou não tiver certeza sobre 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 desses é 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 whereis pode encontrá-lo.

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

Infelizmente, a página man não fornece um número de versão. ldd ainda é útil, pois qualquer executável vinculado dinamicamente no sistema (por exemplo, quase tudo em /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.
    
por 19.03.2014 / 13:43
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ê está preocupado.

Comece com um programa trivial:

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

compile-o usando o compilador que você vai usar para o código-fonte, então use ldd para descobrir onde a biblioteca C está:

$ 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 em seu gerenciador de pacotes para encontrar o pacote (por exemplo, dpkg -S /lib/x86_64-linux-gnu/libc.so.6 ou 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 de objdump -p /lib/x86_64-linux-gnu/libc.so.6 , procurando na seção 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 possui o número de versão mais recente entre os símbolos listados, e a versão da biblioteca é de fato 2.18. É eglibc, no entanto (ele pretende ser compatível com binários com o glibc 2.18, então ele usa as mesmas versões de símbolos).

Você também pode tentar usar strings para descobrir algo sobre isso. Você vai querer especificar um comprimento mínimo mais longo ( -n ), ou usar grep para procurar por 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-shlibdeps usa objdump sob o capô, junto com informações de símbolos armazenados nos pacotes de bibliotecas do Debian para determinar as versões mínimas das dependências requeridas pelos pacotes binários Debian no momento da construção. Basicamente, ele olha para os símbolos exportados pelo pacote Debian binário, e então encontra as versões mínimas das bibliotecas que contêm esses símbolos.

    
por 19.03.2014 / 18:40
9

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

rpm -qi glibc
dpkg -l libc6

(Infelizmente, a glibc não tem um arquivo pkconfig .pc , então pkgconfig --modversion glibc é um não-corredor.) Veja também a excelente sugestão getconf do @Gnouc.

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

Uma maneira simples de dizer exatamente o que seu gcc fará é 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 <features.h> , que define as macros GLIBC relevantes, você precisa de <gnu/libc-version.h> para as declarações de função.)

Isso captura casos mais complexos (vários libc's e / ou múltiplos compiladores), supondo que você esteja usando o compilador (e sinalizadores) corretos, é claro. (Eu suspeito que não vai distinguir entre eglibc e glibc propriamente dita.)

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

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

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

gcc -print-file-name=libc.so dirá a você qual arquivo o compilador utilizará para " -lc ", isso é quase certamente um script de vinculador dentro da sua 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ê passar bandeiras como -m32 ou -m64 .

Se você estiver usando uclibc (como usado pelo OpenWRT e mais), ele define __UCLIBC_MAJOR__ , __UCLIBC_MINOR__ e __UCLIBC_SUBLEVEL__ , bem como __UCLIBC__ em <features.h> , por isso é facilmente detectado usando uma pequena variação no trecho de código C acima. No interesse da compatibilidade, uClibc também pode definir as macros GNU / GLIBC como usado acima, atualmente finge ser glib-2.2. Atualmente, ele não implementa as funções gnu_get_libc_X() , mas faz implementar getconf , o que também pode induzir em erro (suspeito que ele retorne uma resposta vazia para getconf GNU_LIBC_VERSION , meu build é ruim hoje, então não pode confirmar.)

No caso improvável de você estar usando o dietlibc , a execução de diet -v exibirá a versão.

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

    
por 20.03.2014 / 00:40
5

O GNU libc (que a maioria das distribuições Linux usa de uma forma ou de outra) faz grandes esforços para manter a estrita compatibilidade 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, backportando correções e mantendo uma compatibilidade binária rústica) . Acredito que você esteja muito mais sujeito a problemas com outras bibliotecas (o C ++ teve algumas alterações na API / ABI na memória recente, algumas outras bibliotecas apenas não se preocupam com compatibilidade retroativa).

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

    
por 19.03.2014 / 15:53
5

(Isto é essencialmente o mesmo que a resposta de Cachinhos Dourados, mas com mais algumas explicações sobre o que está acontecendo sob o capô.)

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

$ /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.6 mora não está em $PATH , então você precisa saber onde procurá-lo. Pode estar em /lib , /lib64 , /usr/lib ou algo ainda mais estranho (como neste caso). Convenientemente, ldd dirá:

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

Para que isso funcione, é claro, você precisa saber o caminho completo de um executável binário vinculado dinamicamente. O executável sh é garantido como /bin (porque muitos scripts #! esperam que ele seja) e não pode ser um script #! . Ele poderia estar vinculado estaticamente, mas eu não encontrei um sistema que fez isso em muitos anos.

Eu não sei o que você faz se você está usando o uClibc ou musl ou algo mais exótico.

    
por 19.03.2014 / 18:57
5

Outra maneira de obtê-lo:

getconf GNU_LIBC_VERSION
    
por 20.03.2014 / 19:27