ar
No Linux, ar
é o arquivador de propósito geral do GNU. (Existem variantes não-GNU ar
em outros sistemas operacionais semelhantes ao Unix). Com a opçãoc
ar c... archive-name file...
Ele cria um arquivo contendo cópias de file...
. O archive-name
convencional, mas não necessariamente, tem a extensão .a
(para arquivamento ). Cada um file...
pode ser qualquer tipo de arquivo, não necessariamente um arquivo de objeto.
Quando os arquivos arquivados são todos arquivos de objetos, geralmente é a intenção usar o arquivo morto para entregar essa seleção de arquivos de objetos na vinculação de programas ou DSOs (Dynamic Shared Objects). Nesse caso archive-name
, também será dado o prefixo convencionalmente lib
, por exemplo
libfoo.a
, para que ele possa ser descoberto como um arquivo de entrada de vinculador candidato através da opção vinculador -lfoo
.
Usado como um arquivo de entrada do vinculador, libfoo.a
normalmente é chamado de biblioteca estática . Esse uso é uma fonte perpétua de confusão para programadores inexperientes, porque os leva a pensar que um arquivo libfoo.a
é o mesmo tipo de DSO libfoo.so
, normalmente chamado de biblioteca dinâmica / compartilhada , e a criar falsas expectativas com base nisso. De fato, uma "biblioteca estática" e uma "biblioteca dinâmica" não são coisas semelhantes e são usadas no vínculo de maneiras totalmente diferentes.
Uma diferença visível é que uma biblioteca estática não é produzida pelo vinculador , mas por ar
. Portanto, nenhuma ligação acontece, nenhuma resolução de símbolo acontece. Os arquivos de objetos arquivados permanecem inalterados: são apenas colocados em um saco.
Quando um arquivo é a entrada na ligação de algo que é produzido pelo vinculador - como um programa ou DSO - os olhares vinculador no saco para ver se há algum objeto arquivos nele que fornecem definições para referências símbolo não resolvido adquiridos no início da ligação. Se encontrar alguma, ele extrai os arquivos objeto do saco e liga -los no arquivo de saída, exatamente como se eles foram nomeados individualmente na linha de comando vinculador eo arquivo não mencionado. Portanto, todo o papel de um arquivo morto no vínculo é como um conjunto de arquivos de objetos dos quais o vinculador pode selecionar os que precisa para continuar o vínculo.
Por padrão, o GNU ar
prepara seus arquivos de saída para uso como entradas do vinculador. Ele adiciona um "arquivo" falso ao arquivo morto, com um nome de arquivo falso mágico e, nesse arquivo falso, grava conteúdo que o vinculador pode ler como uma tabela de pesquisa a partir dos símbolos globais que são definidos por quaisquer arquivos de objeto no arquivo morto. para os nomes e posições desses arquivos de objeto no arquivo morto. Esta tabela de pesquisa é o que permite ao vinculador procurar no arquivo morto e identificar quaisquer arquivos de objeto que definam as referências de símbolo não resolvidas que ele tem em mãos.
Você pode suprimir a criação ou atualização dessa tabela de pesquisa com a opção q
(=
quick ) - que de fato você usou em seu próprio ar
exemplo - e também com a opção (capital) S
(= tabela sem símbolos ). E se você invocar ar
para criar ou atualizar um arquivo que não possui uma tabela de símbolos (atualizada) por qualquer motivo, poderá escolher um com a s
opção
ranlib
ranlib
não cria bibliotecas. No Linux, ranlib
é um programa herdado que adiciona uma tabela de símbolos (atualizada) a um ar
arquivo morto, se ele não tiver uma. Seu efeito é exatamente o mesmo que ar s
, com o GNU ar
. Historicamente, antes de ar
ser equipado para gerar uma tabela de símbolos, ranlib
havia o argumento que injetava o arquivo falso mágico em um arquivo para permitir que o vinculador escolhesse os arquivos de objetos. Em sistemas operacionais que não sejam do tipo GNU Unix, ranlib
ainda pode ser necessário para esse fim. Seu exemplo:
ar qc libgraphics.a *.o
ranlib libgraphics.a
diz:
- Crie
libgraphics.a
anexando a um arquivo morto todos os *.o
arquivos no diretório atual, sem tabela de símbolos.
- Em seguida, adicione uma tabela de símbolos para
libgraphics.a
No linux, isso tem o mesmo efeito líquido que:
ar cr libgraphics.a *.o
Por si só, ar qc libgraphics.a *.o
cria um arquivo morto que o vinculador não pode usar porque não possui tabela de símbolos.
ld
Seu exemplo:
ld -r -o libgraphics.a *.o
é realmente pouco ortodoxo. Isso ilustra o uso bastante raro do vinculador ,
ld
para produzir um arquivo de objeto mesclado , vinculando vários arquivos de entrada em um único arquivo de objeto de saída, no qual a resolução do símbolo foi realizada na medida do possível , considerando os arquivos de entrada. A opção -r
(= relocatable ) direciona o vinculador para produzir um destino de arquivo de objeto (em vez de um programa ou DSO) vinculando as entradas o máximo possível e não falhar no linkaqe se referências de símbolos indefinidas permanecerem no arquivo de saída. Esse uso é chamado de link parcial .
O arquivo de saída ld -r ...
é um arquivo objeto, e não um ar
arquivo , e especificar um nome de arquivo de saída que olhares como o de um ar
arquivo não torná-lo um. Portanto, seu exemplo ilustra uma decepção. Este:
ld -r -o graphics.o *.o
seria sincero. Não está claro para mim qual poderia ser o objetivo de tal engano, porque mesmo que um arquivo de objeto ELF seja chamado libgraphics.a
e seja inserido em uma ligação por esse nome ou por -lgraphics
, o vinculador o identificará corretamente como um arquivo de objeto ELF , não um ar
arquivo morto, e o consumirá da maneira que consome qualquer arquivo de objeto na linha de comando: ele o vincula incondicionalmente ao arquivo de saída, enquanto o ponto de entrada de um arquivo morto genuíno é vincular os membros do arquivo morto apenas na condição de serem referenciados . Talvez você tenha apenas um exemplo de link mal informado aqui.
Empacotando...
Na verdade, só vimos uma maneira de produzir algo que é convencionalmente chamado de biblioteca , e essa é a produção da chamada biblioteca estática , arquivando alguns arquivos de objetos e colocando uma tabela de símbolos no arquivo.
E ainda não vimos como produzir o outro e mais importante tipo de coisa convencionalmente chamada de biblioteca , a saber, um Objeto Compartilhado Dinâmico / biblioteca compartilhada / biblioteca dinâmica.
Como um programa, um DSO é produzido pelo vinculador . Um programa e um DSO são variantes do binário ELF que o carregador do SO entende e pode usar para montar um processo em execução. Geralmente nós chamar o vinculador através de um um dos frontends do CCG ( gcc
, g++
, gfortran
, etc):
Vinculando um programa:
gcc -o prog file.o ... -Ldir ... -lfoo ...
Vinculando um DSO:
gcc -shared -o libbar.so file.o ... -Ldir ... -lfoo ...
As bibliotecas compartilhadas e as estáticas podem ser oferecidas ao vinculador pelo -lfoo
protocolo uniforme , quando você vincula algum outro programa ou DSO. Essa opção instrui o vinculador a varrer seus diretórios de pesquisa especificados ou padrão para localizar
libfoo.so
ou libfoo.a
. Por padrão, uma vez que encontre um deles, ele inserirá esse arquivo na ligação e, se encontrar os dois no mesmo diretório de pesquisa, preferirá libfoo.so
. Se libfoo.so
, for selecionado, o vinculador adicionará esse DSO à lista de dependências de tempo de execução de qualquer programa ou DSO que você esteja criando. Se libfoo.a
for selecionado, o vinculador usará o archive como uma seleção de arquivos de objeto para vinculação ao arquivo de saída, se necessário, ali mesmo. Nenhuma dependência de tempo de execução
libfoo.a
em si é possível; não pode ser mapeado em um processo; isso não significa nada para o carregador do SO.
Copiado de https://stackoverflow.com/a/47924864/195787 .