A criação e o uso de biblioteca de link estático C (C ++) compilado GCC (gcc -L, gcc -l) e biblioteca de link dinâmico (gcc -fPIC -shared)

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 Cbiblioteca 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 stringclasse 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 Clinguagem 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 GCCcompilador 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 Linuxversão de lançamento do sistema, a extensão dos arquivos de biblioteca de link estático geralmente .arepresenta;
  • No Windowssistema, 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 maina 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.cppO 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.cppO 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.cppe greeting.cppestã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:

  1. 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$ 
  1. Em seguida, usando arinstruçõ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 aras instruções de compactação, bem como rcso 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
  • LinuxNo sistema, o sufixo da biblioteca de links estáticos é .a;
  • WindowsNo sistema, o sufixo da biblioteca de links estáticos é .lib;

Entre eles, xxxem nome de que jogou para o nome da biblioteca, tais como Linuxo sistema vem com algum nome biblioteca de vínculo estático libc.a,, libgcc.a, libm.aseus nomes são c, gcce m.

Em seguida, empacote greeting.oe name.oempacote 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.aisto é name.o, greeting.oempacotados juntos geraram biblioteca de links estáticos, myfunctionuma 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.cpparquivo é 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, -statica opção de forçar GCCo compilador a usar uma biblioteca de links estáticos.

Observe que se GCCo 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,

  • -LA Lopção (maiúsculas ) é usada para GCCespecificar 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úsculas Lopção) é usado para indicar o nome da biblioteca de vínculo estático necessário, prestar atenção aos nomes usados aqui refere-se à xxxparte, e irá recomendar -le xxxconjunção direta (ou seja -lxxx), sem espaços intermediários.

Como resultado, ele gera a.outum 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 GCCcompilador 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 GCCcompilador 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 Linuxversão de lançamento do sistema, a biblioteca de vínculo dinâmico de extensão geralmente é .sorepresentada;
  • No Windowssistema, o sufixo da biblioteca de vínculo dinâmico denominado .dll;

GCCQuando 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 GCCcompilador selecionará a biblioteca de links estáticos correspondente. Se ambos não forem (ou o GCCcompilador 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.

  1. Crie diretamente os arquivos de origem da biblioteca de vínculo dinâmico, usando o gccformato 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 -fPICfunção) opção é fazer GCCo 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.cppesses 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 Linuxsistema de lançamento, sua extensão com .sorepresentação; Windowssufixo do sistema .dll.

  1. Primeiro use a gcc -cinstruçã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 -fpicopçã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.cppempacotados em uma libmyfunction.sobiblioteca de vínculo dinâmico, caso em que o projeto permanece com os main.cpparquivos fonte, de forma que evoluiu para a implementação da demonstração do projeto main.cppe do libmyfunction.solink, 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 maingeralmente 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.soa biblioteca de vínculo dinâmico. Ao executar a ldd maininstruçã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, maino 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 maina 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 xxxo 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 ~/.bashrcou ~/.bash_profilearquivar, 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 bashrccomando 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 mainimplementaçã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$ 

Acho que você gosta

Origin blog.csdn.net/wohu1104/article/details/110789570
Recomendado
Clasificación