1. Arquivos de biblioteca
O chamado arquivo de biblioteca, os leitores podem ser equivalentes a um arquivo de pacote compactado, o arquivo geralmente contém mais de um arquivo de objeto (ou seja, arquivo binário).
Vale ressaltar que o código armazenado em cada arquivo-objeto do arquivo da biblioteca não é um programa completo, mas sim um módulo funcional prático. Por exemplo, uma C
biblioteca de linguagem fornece um número de funções (como scanf()
, printf()
, strlen()
etc.), C++
funções de biblioteca fornecem não só tem que usar, há um grande número de classes pré-concebidos (como string
classe String).
A geração do arquivo de biblioteca melhora muito a eficiência de desenvolvimento do programador, pois muitas funções não precisam ser desenvolvidas a partir de 0, basta chamar o arquivo de biblioteca que contém a função diretamente. Além disso, chamar o método de biblioteca também é muito simples para a função de saída de C
linguagem printf()
, por exemplo, o programa acaba de introduzir <stdio.h>
o arquivo de cabeçalho, você pode chamar a printf()
função.
Por que o arquivo de cabeçalho está envolvido ao chamar o arquivo de biblioteca? Em primeiro lugar, arquivos de cabeçalho e arquivos de biblioteca não são a mesma coisa. A maior diferença entre eles é:
- O arquivo de cabeçalho armazena apenas a parte da declaração desses módulos funcionais, como variáveis, funções ou classes;
- O arquivo de biblioteca é responsável por armazenar as partes específicas de implementação de cada módulo;
Os leitores podem entender desta forma: todos os arquivos de biblioteca são fornecidos com arquivos de cabeçalho correspondentes como a interface para chamá-lo. Em outras palavras, os arquivos de biblioteca não podem ser usados diretamente e só podem ser chamados indiretamente por meio de arquivos de cabeçalho.
A maior vantagem do mecanismo de acesso combinado de arquivos de cabeçalho e arquivos de biblioteca é que às vezes queremos apenas que outros usem as funções que implementamos e não queremos divulgar o código-fonte das funções. Podemos torná-los como arquivos de biblioteca para que os usuários podem obter. É um arquivo binário, e o arquivo de cabeçalho contém apenas a parte da declaração, de forma que o propósito de "ocultar o código-fonte" seja realizado sem afetar o uso do usuário.
Na verdade, os arquivos de biblioteca são apenas um termo geral, referindo-se a um tipo de pacote compactado, todos eles contêm arquivos de objetos funcionais e práticos. Você deve saber que, embora o arquivo de biblioteca seja usado na fase de vinculação do programa, o compilador fornece duas maneiras de obter a vinculação, que são chamadas de vinculação estática e vinculação dinâmica.
- Os arquivos de biblioteca que usam vinculação estática para obter operações de vinculação são chamados de bibliotecas de vínculo estático;
- Um arquivo de biblioteca que usa vínculo dinâmico para obter operações de vínculo é chamado de biblioteca de vínculo dinâmico;
Em C
, C++
o processo de desenvolvimento real, além de usar os arquivos da biblioteca do sistema, podemos criar uma biblioteca de vínculo estático ou DLL de acordo com as necessidades reais, manualmente.
2. Biblioteca de links estáticos
A biblioteca de link estático realiza a operação de link de uma maneira muito simples, ou seja, onde o módulo de função no arquivo de biblioteca é usado no arquivo de programa, o GCC
compilador copiará diretamente o código do modelo para o local apropriado do arquivo de programa, e finalmente gere um arquivo executável.
Usar arquivos de biblioteca estática para implementar operações de vinculação de programa tem vantagens e desvantagens:
- A vantagem é que o arquivo executável gerado pode ser executado de forma independente, sem o suporte de qualquer arquivo de biblioteca estática (portabilidade forte);
- A desvantagem é que, se o mesmo módulo de função na biblioteca for chamado várias vezes no arquivo de programa, o código do módulo será inevitavelmente copiado várias vezes e o arquivo executável gerado conterá várias partes de código idêntico, causando redundância de código.
Comparado com o arquivo executável gerado pela biblioteca de link dinâmico, o arquivo executável gerado pela biblioteca de link estático tem um volume maior.
- Na
Linux
versão de lançamento do sistema, a extensão dos arquivos de biblioteca de link estático geralmente.a
representa; - No
Windows
sistema, o sufixo nome do arquivo da biblioteca de link estático.lib
;
2.1 Criar uma biblioteca de links estáticos
Uma biblioteca de link estático é, na verdade, equivalente a um pacote compactado, que pode conter vários arquivos de origem. Porém, deve-se observar que nenhum arquivo de origem pode ser processado em uma biblioteca de links estáticos, ele precisa atender a pelo menos as duas condições a seguir:
- Os arquivos de origem fornecem apenas o código pode ser reutilizado, como funções, etc. projetado, não pode conter
main
a função principal; - Embora o arquivo de origem realize a função do módulo, ele também fornece uma interface para acessá-lo, ou seja, o arquivo de cabeçalho que contém a parte da declaração de cada módulo de função;
Amostra de estrutura de código:
wohu@ubuntu:~/cpp/src$ tree
.
├── function.h
├── greeting.cpp
├── main.cpp
└── name.cpp
0 directories, 4 files
wohu@ubuntu:~/cpp/src$
function.h
Código
void sayGreetings();
void sayName();
greeting.cpp
O código que o contém #include "function.h"
não precisa incluir o arquivo de cabeçalho quando a biblioteca estática não é criada.
#include <iostream>
#include "function.h"
void sayGreetings()
{
std::cout << "hello,world" << std::endl;
}
name.cpp
O código, que está incluído #include "function.h"
, não precisa incluir o arquivo de cabeçalho quando a biblioteca estática não é criada.
#include <iostream>
#include "function.h"
void sayName()
{
std::cout << "My name is wohu" << std::endl;
}
main.cpp
Código
#include <iostream>
#include "function.h"
int main()
{
sayGreetings();
sayName();
return 0;
}
Para name.cpp
e greeting.cpp
estão de acordo com as duas condições acima, ele pode ser processado em uma biblioteca de links estáticos. E de acordo com as necessidades reais, podemos compactá-los coletivamente em uma biblioteca de links estáticos ou cada um pode ser compactado em uma biblioteca de links estáticos.
O processo de empacotar o arquivo de origem como uma biblioteca de links estáticos é muito simples, basta seguir as 2 etapas a seguir:
- Compilar todos os arquivos de origem especificados em arquivos de destino correspondentes
wohu@ubuntu:~/cpp/src$ g++ -c greeting.cpp name.cpp
wohu@ubuntu:~/cpp/src$ ls
function.h greeting.cpp greeting.o main.cpp name.cpp name.o
wohu@ubuntu:~/cpp/src$
- Em seguida, usando
ar
instruções compactadas, os arquivos de objeto gerados em uma biblioteca de link estático, o formato básico é o seguinte:
ar rcs 静态链接库名称 目标文件1 目标文件2 ...
Sobre ar
as instruções de compactação, bem como rcs
o significado e a função de cada opção, consulte o comando ar do Linux
O ponto importante é que a biblioteca de links estáticos não pode ser nomeada arbitrariamente e as seguintes regras de nomenclatura devem ser seguidas:
libxxx.a
Linux
No sistema, o sufixo da biblioteca de links estáticos é.a
;Windows
No sistema, o sufixo da biblioteca de links estáticos é.lib
;
Entre eles, xxx
em nome de que jogou para o nome da biblioteca, tais como Linux
o sistema vem com algum nome biblioteca de vínculo estático libc.a
,, libgcc.a
, libm.a
seus nomes são c
, gcc
e m
.
Em seguida, empacote greeting.o
e name.o
empacote em uma biblioteca de links estáticos:
wohu@ubuntu:~/cpp/src$ ar rcs libmyfunction.a name.o greeting.o
wohu@ubuntu:~/cpp/src$ ls
function.h greeting.cpp greeting.o libmyfunction.a main.cpp name.cpp name.o
wohu@ubuntu:~/cpp/src$
Entre eles, libmyfunction.a
isto é name.o
, greeting.o
empacotados juntos geraram biblioteca de links estáticos, myfunction
uma biblioteca de nome nosso personalizado.
2.2 Usar biblioteca de links estáticos
A utilização da biblioteca de links estáticos é muito simples, ou seja, na etapa de vinculação do programa, a biblioteca de links estáticos e outros arquivos-objeto são vinculados para gerar um arquivo executável.
Usando o código anterior como exemplo, primeiro o main.cpp
arquivo é compilado em arquivos-objeto:
wohu@ubuntu:~/cpp/src$ g++ -c main.cpp
wohu@ubuntu:~/cpp/src$ ls
function.h greeting.cpp greeting.o libmyfunction.a main.cpp main.o name.cpp name.o
wohu@ubuntu:~/cpp/src$
Com base nisso, podemos executar diretamente os seguintes comandos para concluir a operação de link:
wohu@ubuntu:~/cpp/src$ g++ -static main.o libmyfunction.a
wohu@ubuntu:~/cpp/src$ ls
a.out function.h greeting.cpp greeting.o libmyfunction.a main.cpp main.o name.cpp name.o
wohu@ubuntu:~/cpp/src$
Entre eles, -static
a opção de forçar GCC
o compilador a usar uma biblioteca de links estáticos.
Observe que se GCC
o compilador não conseguir encontrar as dicas libmyfunction.a
, você também pode usar a seguinte operação de link:
wohu@ubuntu:~/cpp/src$ g++ -static main.o -L /home/wohu/cpp/src -lmyfunction
wohu@ubuntu:~/cpp/src$ ls
a.out function.h greeting.cpp greeting.o libmyfunction.a main.cpp main.o name.cpp name.o
entre eles,
-L
AL
opção (maiúsculas ) é usada paraGCC
especificar o local de armazenamento da biblioteca de links do compilador estático (pode usar o comando pwd para visualizar o local de armazenamento específico);-l
(MinúsculasL
opção) é usado para indicar o nome da biblioteca de vínculo estático necessário, prestar atenção aos nomes usados aqui refere-se àxxx
parte, e irá recomendar-l
exxx
conjunção direta (ou seja-lxxx
), sem espaços intermediários.
Como resultado, ele gera a.out
um arquivo executável:
wohu@ubuntu:~/cpp/src$ ./a.out
hello,world
My name is wohu
wohu@ubuntu:~/cpp/src$
3. Biblioteca de link dinâmico
Biblioteca de links dinâmicos, também conhecida como biblioteca de links compartilhados. Diferente da biblioteca de link estático, quando a biblioteca de link dinâmico é usada para realizar a operação de link, onde o módulo de função do arquivo de biblioteca é necessário no arquivo de programa, o GCC
compilador não copiará diretamente o código do módulo de função para o arquivo, mas as informações de localização do módulo de função Gravar no arquivo e gerar diretamente o arquivo executável.
Obviamente, o arquivo executável gerado desta forma não pode ser executado de forma independente. Quando o arquivo executável gerado pela biblioteca de vínculo dinâmico é executado, o GCC
compilador carrega a biblioteca de vínculo dinâmico correspondente na memória juntos. Como as informações de posição do módulo de função necessário são gravadas no arquivo executável com antecedência, a biblioteca de vínculo dinâmico existente Ele também pode ser executado com sucesso com o apoio de.
As vantagens e desvantagens de usar a biblioteca de link dinâmico para realizar a operação de conexão do programa são exatamente o oposto daquelas da biblioteca de link estático:
- A vantagem é que, como o arquivo executável registra o endereço do módulo de função, o código de implementação real será carregado na memória quando o programa estiver em execução, o que significa que mesmo se o módulo de função for chamado várias vezes, o mesmo código de implementação será usado (esse também é o motivo pelo qual a biblioteca de vínculo dinâmico é chamada de biblioteca de vínculo compartilhado).
- A desvantagem é que o arquivo executável gerado por este método não pode ser executado de forma independente e o arquivo de biblioteca correspondente deve ser usado (portabilidade deficiente).
Comparado com o arquivo executável gerado pela biblioteca de vínculo estático, o arquivo executável gerado pela biblioteca de vínculo dinâmico tem um volume menor, porque vários códigos redundantes não serão copiados para dentro.
- Na
Linux
versão de lançamento do sistema, a biblioteca de vínculo dinâmico de extensão geralmente é.so
representada; - No
Windows
sistema, o sufixo da biblioteca de vínculo dinâmico denominado.dll
;
GCC
Quando o compilador gera um arquivo executável, ele dará prioridade ao uso da biblioteca de vínculo dinâmico para realizar a operação de vínculo por padrão. A menos que não haja uma biblioteca de vínculo dinâmico exigida pelo arquivo de programa no ambiente do sistema atual, o GCC
compilador selecionará a biblioteca de links estáticos correspondente. Se ambos não forem (ou o GCC
compilador não for encontrado), o link falhará.
3.1 Criar uma biblioteca de links dinâmicos
Em geral, existem duas maneiras de criar uma biblioteca de vínculo dinâmico.
- Crie diretamente os arquivos de origem da biblioteca de vínculo dinâmico, usando o
gcc
formato básico do comando implementado da seguinte maneira:
gcc -fpic -shared 源文件名... -o 动态链接库名
entre eles,
-shared
A opção é usada para gerar a biblioteca de vínculo dinâmico;-fpic
(Também escrito como-fPIC
função) opção é fazerGCC
o compilador gerar biblioteca de vínculo dinâmico (arquivar vários arquivos de objeto), indica o endereço de cada função de arquivo de objeto, classes e outros módulos funcionais usam um endereço relativo, em vez de endereço absoluto. Dessa forma, não importa onde a biblioteca de links seja carregada na memória no futuro, ela pode ser usada normalmente.
Por exemplo, na frente do projeto greeting.cpp
, name.cpp
esses dois arquivos de origem para gerar uma biblioteca de vínculo dinâmico, execute o comando da seguinte forma:
wohu@ubuntu:~/cpp/src$ g++ -fPIC -shared name.cpp greeting.cpp -o libmyfunction.so
wohu@ubuntu:~/cpp/src$ ls
function.h greeting.cpp libmyfunction.a libmyfunction.so main.cpp name.cpp
wohu@ubuntu:~/cpp/src$
Observe que a nomenclatura de bibliotecas de vínculo dinâmico e bibliotecas vinculadas estaticamente são idênticas, mas no Linux
sistema de lançamento, sua extensão com .so
representação; Windows
sufixo do sistema .dll
.
- Primeiro use a
gcc -c
instrução para especificar que os arquivos de origem são compilados em arquivos de objeto e, em seguida, crie um arquivo de biblioteca de vínculo dinâmico a partir do destino
Observe que quando o acompanhamento para gerar biblioteca de vínculo dinâmico e pode ser usado normalmente, os arquivos de origem são compilados em arquivos objeto, também precisa usar a -fpic
opção.
wohu@ubuntu:~/cpp/src$ g++ -c -fPIC name.cpp greeting.cpp
wohu@ubuntu:~/cpp/src$ ls
function.h greeting.cpp greeting.o libmyfunction.a main.cpp name.cpp name.o
wohu@ubuntu:~/cpp/src$
Com base nisso, use o arquivo-objeto gerado na etapa anterior para gerar uma biblioteca de vínculo dinâmico:
wohu@ubuntu:~/cpp/src$ g++ -shared greeting.o name.o -o libmyfunction.so
wohu@ubuntu:~/cpp/src$ ls
function.h greeting.cpp greeting.o libmyfunction.a libmyfunction.so main.cpp name.cpp name.o
wohu@ubuntu:~/cpp/src$
3.2 Usar biblioteca de link dinâmico
Por meio do estudo dos capítulos anteriores, sabemos que o cenário de uso da biblioteca de vínculo dinâmico é participar da vinculação com outros arquivos de origem ou de destino no projeto. Utilizando o exemplo anterior, por exemplo, estaremos na frente greeting.cpp
, name.cpp
empacotados em uma libmyfunction.so
biblioteca de vínculo dinâmico, caso em que o projeto permanece com os main.cpp
arquivos fonte, de forma que evoluiu para a implementação da demonstração do projeto main.cpp
e do libmyfunction.so
link, e então geraremos um arquivo executável.
Observe que o arquivo de cabeçalho function.h não participa diretamente da compilação, pois na etapa de pré-processamento do programa foram processados os arquivos de cabeçalho que precisam ser usados no projeto.
Execute as seguintes instruções para gerar com êxito um arquivo executável com a ajuda da biblioteca de vínculo dinâmico:
wohu@ubuntu:~/cpp/src$ g++ main.cpp libmyfunction.so -o main
wohu@ubuntu:~/cpp/src$ ls
function.h greeting.cpp greeting.o libmyfunction.a libmyfunction.so main main.cpp name.cpp name.o
wohu@ubuntu:~/cpp/src$
Observe que os arquivos executáveis gerados main
geralmente não podem ser implementados diretamente, como:
wohu@ubuntu:~/cpp/src$ ./main
./main: error while loading shared libraries: libmyfunction.so: cannot open shared object file: No such file or directory
wohu@ubuntu:~/cpp/src$
Podemos ver, o processo de implementação não pode encontrar libmyfunction.so
a biblioteca de vínculo dinâmico. Ao executar a ldd main
instrução, você pode visualizar todos os arquivos de biblioteca de vínculo dinâmico que estão atualmente em necessidade de implementação, bem como o local de armazenamento de cada arquivo de biblioteca:
wohu@ubuntu:~/cpp/src$ ldd main
linux-vdso.so.1 => (0x00007fffb17ea000)
libmyfunction.so => not found
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f548673a000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f5486370000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f5486067000)
/lib64/ld-linux-x86-64.so.2 (0x00007f5486abc000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f5485e51000)
wohu@ubuntu:~/cpp/src$
Você pode ver, main
o arquivo executável precisa do suporte de sete bibliotecas de vínculo dinâmico, incluindo libmyfunction.so
, mas o arquivo não pode ser encontrado, então main
a implementação irá falhar.
Ao executar o arquivo executável gerado pela biblioteca de vínculo dinâmico, você deve garantir que o programa possa localizar a biblioteca de vínculo dinâmico quando estiver em execução. As soluções comumente usadas são as seguintes:
- O arquivo de biblioteca de vínculo para o diretório biblioteca padrão (por exemplo
/usr/lib
,/usr/lib64
,/lib
,/lib64
); - Digite no terminal
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:xxx
Em que xxx
o caminho absoluto armazenado no arquivo de biblioteca de vínculo dinâmico (nesta modalidade é válido apenas no terminal atual, o terminal é inválido após o fechamento);
- Modificar
~/.bashrc
ou~/.bash_profile
arquivar, o arquivo é adicionado na última linha
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:xxx
Que xxx
, após um caminho absoluto para o armazenamento do arquivo da biblioteca de vínculo dinâmico, preservação, source bashrc
comando de execução (desta forma apenas o usuário logado atual é válido).
Neste exemplo, a segunda opção é usada, que é entrar no terminal
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/wohu/cpp/src
Para a main
implementação bem - sucedida.
wohu@ubuntu:~/cpp/src$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/wohu/cpp/src
wohu@ubuntu:~/cpp/src$ ldd main
linux-vdso.so.1 => (0x00007ffddc5fa000)
libmyfunction.so (0x00007f017bec9000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f017bb47000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f017b77d000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f017b474000)
/lib64/ld-linux-x86-64.so.2 (0x00007f017c0cb000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f017b25e000)
wohu@ubuntu:~/cpp/src$ ./main
hello,world
My name is wohu
wohu@ubuntu:~/cpp/src$