Estou ciente de que objetos compartilhados no Linux usam "so numbers", ou seja, que versões diferentes de um objeto compartilhado recebem extensões diferentes, por exemplo:
example.so.1
example.so.2
Entendo que a idéia é ter dois arquivos distintos, de modo que duas versões de uma biblioteca possam existir em um sistema (em oposição a "DLL Hell" no Windows). Gostaria de saber como isso funciona na prática? Muitas vezes, vejo que example.so
é de fato um link simbólico para example.so.2
Onde .2
é a versão mais recente. Como então um aplicativo depende de uma versão mais antiga de example.so
identificá-lo corretamente? Existem regras sobre quais números se deve usar? Ou isso é simplesmente uma convenção? É o caso de que, diferentemente do Windows, onde os binários de software são transferidos entre sistemas, se um sistema tiver uma versão mais recente de um objeto compartilhado, ele é vinculado à versão mais antiga automaticamente ao compilar a partir da origem?
Eu suspeito que isso esteja relacionado a ldconfig
, mas não sei ao certo como.
Os próprios binários sabem de qual versão de uma biblioteca compartilhada eles dependem e solicitam-na especificamente. Você pode usar ldd
para mostrar as dependências; o meu para ls
é:
$ ldd /bin/ls
linux-gate.so.1 => (0xb784e000)
librt.so.1 => /lib/librt.so.1 (0xb782c000)
libacl.so.1 => /lib/libacl.so.1 (0xb7824000)
libc.so.6 => /lib/libc.so.6 (0xb76dc000)
libpthread.so.0 => /lib/libpthread.so.0 (0xb76c3000)
/lib/ld-linux.so.2 (0xb784f000)
libattr.so.1 => /lib/libattr.so.1 (0xb76bd000)
Como você pode ver, ele aponta para libpthread.so.0
, não apenas libpthread.so
.
O motivo do link simbólico é para o vinculador. Quando você deseja vincular contra libpthread.so
diretamente, você fornece a gcc
a flag -lpthread
e adiciona o prefixo lib
e .so
sufixo automaticamente. Você não pode dizer para adicionar no .so.0
, então o link simbólico aponta para a versão mais recente da lib para facilitar essa
Os números nas bibliotecas compartilhadas são convenção usada no Linux para identificar a API de uma biblioteca. Normalmente, o formato é:
libFOO.so.MAJOR.MINOR
E, como você notou, geralmente há um link simbólico de libFOO.so para libFOO.so.MAJOR.MINOR. O ldconfig é responsável por atualizar este link para a versão mais recente.
O MAJOR normalmente é incrementado quando a API é alterada (novos pontos de entrada são removidos ou os parâmetros ou tipos alterados). Normalmente, o MINOR é incrementado para lançamentos de correções de erros ou quando novas APIs são introduzidas sem quebrar as APIs existentes.
Uma discussão mais extensa pode ser encontrada aqui: Dissecando bibliotecas compartilhadas
As bibliotecas compartilhadas devem ter versão de acordo com o seguinte esquema:
blah.so.X.Y.Z
onde
Normalmente, você vê apenas o primeiro dígito como hello.so.1
Porque o primeiro dígito é a única coisa necessária para identificar a "versão" da biblioteca, pois todos os outros dígitos são compatíveis com versões anteriores.
ldconfig
mantém uma tabela de quais bibliotecas compartilhadas estão disponíveis em um sistema e onde existe o caminho para essa biblioteca. Você pode verificar isso executando:
ldconfig -p
Quando um pacote é criado para algo como o Red Hat, as bibliotecas compartilhadas chamadas no binário serão pesquisadas e adicionadas como dependências do pacote no tempo de criação do RPM. Portanto, quando você instala o pacote, o instalador verifica se hello.so.1
Está instalado ou não no sistema, marcando ldconfig
.
Você pode ver as dependências de um pacote fazendo algo como:
rpm -qpR hello.rpm
Esse sistema (diferente do Windows) permite que várias versões do hello.so
Sejam instaladas em um sistema e sejam usadas por diferentes aplicativos ao mesmo tempo.
libNAME.so é o nome do arquivo usado pelo compilador/vinculador ao procurar pela primeira vez uma biblioteca especificada por -lNAME. Dentro de um arquivo de biblioteca compartilhada, há um campo chamado SONAME. Este campo é definido quando a própria biblioteca é primeiro vinculada a um objeto compartilhado pelo processo de construção. Na verdade, esse SONAME é o que um vinculador armazena em um executável, dependendo do objeto compartilhado que está vinculado a ele. Normalmente, o SONAME está na forma de libNAME.so.MAJOR e é alterado sempre que a biblioteca se torna incompatível com os executáveis existentes vinculados a ela e as duas versões principais da biblioteca podem ser mantidas instaladas conforme necessário (embora apenas uma seja apontada para desenvolvimento). como libNAME.so) Além disso, para oferecer suporte à atualização fácil entre versões secundárias de uma biblioteca, libNAME.so.MAJOR normalmente é um link para um arquivo como libNAME.so.MAJOR.MINOR. Uma nova versão secundária pode ser instalada e, uma vez concluída, o link para a versão secundária antiga é aumentado para apontar para a nova versão secundária, atualizando imediatamente todas as novas execuções para usar a biblioteca atualizada. Além disso, veja minha resposta para Linux, GNU GCC, ld, scripts de versão e o formato binário ELF - Como isso funciona?