Pergunta

Ao criar uma biblioteca de classes em C ++, você pode escolher entre dinâmico (.dll, .so) e estática (.lib, .a) bibliotecas. Qual é a diferença entre eles e quando é apropriado para uso que?

Foi útil?

Solução

Bibliotecas estáticas aumentar o tamanho do código em seu binário. Eles estão sempre carregado e qualquer versão do código compilado com é a versão do código que será executado.

bibliotecas

dinâmicos são armazenados e versionadas separadamente. É possível que uma versão da biblioteca dinâmica a ser carregado que não era o original fornecido com o código de se a atualização é considerada binário compatível com a versão original.

Além disso bibliotecas dinâmicas não são necessariamente carregado - eles são geralmente carregados quando chamado pela primeira vez -. E podem ser compartilhados entre os componentes que utilizam a mesma biblioteca (várias cargas de dados, uma carga de código)

Bibliotecas dinâmicas foram considerada a melhor abordagem a maior parte do tempo, mas originalmente eles tinham uma grande falha (google DLL inferno), que tem tudo, mas foi eliminado por mais recentes sistemas operacionais do Windows (Windows XP, em particular).

Outras dicas

Outros têm adequadamente explicado o que é uma biblioteca estática é, mas eu gostaria de apontar algumas das dicas de uso de bibliotecas estáticas, pelo menos no Windows:

  • Singletons: Se algo precisa ser / static global e único, ser muito cuidadosos sobre colocá-lo em uma biblioteca estática. Se várias DLLs estão ligadas contra essa biblioteca estática eles vão cada obter a sua própria cópia do Singleton. No entanto, se seu aplicativo é um único EXE sem DLLs personalizadas, isso pode não ser um problema.

  • remoção de código Unreferenced: Quando você ligar com uma biblioteca estática, apenas as partes da biblioteca estática que são referenciados por seu DLL / EXE vai ficar ligado em sua DLL / EXE.

    Por exemplo, se mylib.lib contém a.obj e b.obj e seus / EXE apenas funções ou variáveis ??de a.obj referências DLL, a totalidade do b.obj serão descartados pelo vinculador. Se b.obj contém objetos globais / estáticos, os seus construtores e destruidores não serão executados. Se esses construtores / destruidores têm efeitos colaterais, você pode estar decepcionado com a sua ausência.

    Da mesma forma, se a biblioteca estática contém pontos de entrada especiais que você pode precisar de tomar cuidado para que eles realmente estão incluídos. Um exemplo disso na programação embutido (ok, não Windows) seria um manipulador de interrupção que está marcado como estando em um endereço específico. Você também precisa marcar o manipulador de interrupção como um ponto de entrada para se certificar de que ele não fique descartado.

    Outra consequência disto é que uma biblioteca estática pode conter arquivos de objetos que são completamente inutilizável devido a referências não resolvidas, mas não vai causar um erro de vinculador até que você referência a uma função ou variável a partir desses arquivos objeto. Isso pode acontecer muito tempo depois de a biblioteca está escrito.

  • símbolos de depuração: Você pode querer um APO separada para cada biblioteca estática, ou você pode querer os símbolos de depuração para ser colocado nos arquivos de objetos para que eles se enroladas em APO para a DLL / EXE. A documentação do Visual C ++ explica as opções necessárias .

  • RTTI: Você pode acabar com vários objetos type_info para a mesma classe se você ligar uma única biblioteca estática em várias DLLs. Se o seu programa assume que type_info é dados e usos "únicas" &typeid() ou type_info::before(), você pode obter resultados indesejáveis ??e surpreendentes.

A lib é uma unidade de código que é fornecido dentro do seu executável do aplicativo.

A dll é uma unidade autônoma de código executável. Ele é carregado no processo apenas quando é efectuada uma chamada para aquele código. Um dll pode ser utilizado por várias aplicações e carregado em vários processos, enquanto continua a ter apenas uma cópia do código no disco rígido.

pros Dll : pode ser usado para reutilização de código / share entre vários produtos; carregar na memória processo sob demanda e pode ser descarregado quando não for necessário; pode ser atualizado independentemente do resto do programa.

Dll contras : impacto da carga de dll e rebasing código de desempenho; problemas de controle de versão ( "inferno dll")

pros Lib : nenhum impacto no desempenho como código é sempre carregado no processo e não é rebased; Sem controle de versão problemas.

Lib contras : processo executável / "inchaço" - todo o código está em seu executável e é carregado em cima de início do processo; sem reutilização / partilha - cada produto tem sua própria cópia do código

.

Além das implicações técnicas de estática vs bibliotecas dinâmicas (estático arquivos tudo o pacote em um grande binário vs bibliotecas dinâmicas que permitem a partilha de código entre vários executáveis ??diferentes), há implicações legais .

Por exemplo, se você estiver usando LGPL licenciado código e você link estaticamente contra uma biblioteca LGPL (e, assim, criar um grande binário), o código torna-se automaticamente de código aberto ( livre como em liberdade) código LGPL. Se você ligar contra um objetos compartilhados, então você só precisa LGPL as melhorias / correções de bugs que você faz para a própria biblioteca LGPL.

Isto torna-se uma questão muito mais importante se você está decidindo como compilar você aplicações móveis, por exemplo (no Android você tem uma escolha de estática vs dinâmica, no iOS você não - é sempre estática).


Criando uma biblioteca estática

$$:~/static [32]> cat foo.c
#include<stdio.h>
void foo()
{
printf("\nhello world\n");
}
$$:~/static [33]> cat foo.h
#ifndef _H_FOO_H
#define _H_FOO_H

void foo();

#endif
$$:~/static [34]> cat foo2.c
#include<stdio.h>
void foo2()
{
printf("\nworld\n");
}
$$:~/static [35]> cat foo2.h
#ifndef _H_FOO2_H
#define _H_FOO2_H

void foo2();

#endif
$$:~/static [36]> cat hello.c
#include<foo.h>
#include<foo2.h>
void main()
{
foo();
foo2();
}
$$:~/static [37]> cat makefile
hello: hello.o libtest.a
        cc -o hello hello.o -L. -ltest
hello.o: hello.c
        cc -c hello.c -I`pwd`
libtest.a:foo.o foo2.o
        ar cr libtest.a foo.o foo2.o
foo.o:foo.c
        cc -c foo.c
foo2.o:foo.c
        cc -c foo2.c
clean:
        rm -f foo.o foo2.o libtest.a hello.o

$$:~/static [38]>

criação de uma biblioteca dinâmica

$$:~/dynamic [44]> cat foo.c
#include<stdio.h>
void foo()
{
printf("\nhello world\n");
}
$$:~/dynamic [45]> cat foo.h
#ifndef _H_FOO_H
#define _H_FOO_H

void foo();

#endif
$$:~/dynamic [46]> cat foo2.c
#include<stdio.h>
void foo2()
{
printf("\nworld\n");
}
$$:~/dynamic [47]> cat foo2.h
#ifndef _H_FOO2_H
#define _H_FOO2_H

void foo2();

#endif
$$:~/dynamic [48]> cat hello.c
#include<foo.h>
#include<foo2.h>
void main()
{
foo();
foo2();
}
$$:~/dynamic [49]> cat makefile
hello:hello.o libtest.sl
        cc -o hello hello.o -L`pwd` -ltest
hello.o:
        cc -c -b hello.c -I`pwd`
libtest.sl:foo.o foo2.o
        cc -G -b -o libtest.sl foo.o foo2.o
foo.o:foo.c
        cc -c -b foo.c
foo2.o:foo.c
        cc -c -b foo2.c
clean:
        rm -f libtest.sl foo.o foo

2.o hello.o
$$:~/dynamic [50]>

programas C ++ são construídos em duas fases

  1. Compilation - produz o código objeto (obj)
  2. Linking - produz código executável (.exe ou .dll)

biblioteca estática (lib) é apenas um feixe de obj arquivos e, portanto, não é um programa completo. Ele não sofreu a segunda fase (ligando) de construção de um programa. DLLs, por outro lado, são como exe do e, portanto, são programas completos.

Se você construir uma biblioteca estática, não é ligada ainda e, portanto, os consumidores de sua biblioteca estática terá que usar o mesmo compilador que você usou (se você usou g ++, eles terão de usar g ++).

Se em vez você construiu uma dll (e construiu corretamente ), você construiu um programa completo que todos os consumidores podem usar, não importa qual compilador que eles estão usando. Há várias restrições, porém, sobre a exportação de uma DLL, se a compatibilidade compilador cruzado é desejada.

Você deve pensar cuidadosamente sobre as mudanças ao longo do tempo, controle de versões, estabilidade, compatibilidade, etc.

Se houver dois aplicativos que usam o código compartilhado, você quer forçar os aplicativos para mudar juntos, no caso de eles precisam ser compatíveis uns com os outros? Em seguida, use a dll. Todos os do exe estará usando o mesmo código.

Ou você quer para isolá-los uns dos outros, de modo que você pode mudar e ter certeza que você não ter quebrado o outro. Em seguida, use o lib estático.

DLL inferno é quando você provavelmente deveria ter usado uma lib estático, mas você usou uma dll em vez disso, e nem todos os exes são comaptible com ele.

A biblioteca estática é compilado para o cliente. A lib é usado em tempo de compilação e os conteúdos da biblioteca tornar-se parte do consumo de executável.

A biblioteca dinâmica é carregado em tempo de execução e não compilado para o executável do cliente. Bibliotecas dinâmicas são mais flexíveis como vários executáveis ??cliente pode carregar uma DLL e utilizar sua funcionalidade. Isso também mantém o tamanho geral e manutenção de seu código de cliente para um mínimo.

A biblioteca estática deve ser vinculado para o executável final; torna-se parte do executável e o segue aonde quer que vá. A biblioteca dinâmica é carregado toda vez que o executável é executado e restos separar o executável como um arquivo DLL.

Você usaria um DLL quando você quer ser capaz de mudar a funcionalidade fornecida pela biblioteca sem ter que re-ligação do executável (basta substituir o arquivo DLL, sem ter de substituir o arquivo executável).

Você usaria uma biblioteca estática sempre que você não tem uma razão para usar uma biblioteca dinâmica.

O trabalho de Ulrich Drepper em " Como escrever bibliotecas compartilhadas " também é bom recurso que detalhes a melhor forma de tirar partido das bibliotecas compartilhadas, ou o que ele se refere como "Dynamic Shared Objects" (ORD). Ele se concentra mais em bibliotecas compartilhadas no ELF formato binário, mas algumas discussões são adequados para DLLs do Windows como bem.

Para uma excelente discussão sobre este tema ter uma leitura de este artigo a partir do Sol.

Ele entra em todos os benefícios, sendo inclusive capaz de inserir bibliotecas de interposição. Mais detalhes sobre a interposição pode ser encontrada no este artigo aqui .

Realmente o trade-off que você está fazendo (em um grande projeto) está em tempo de carregamento inicial, as bibliotecas estão indo para ficar ligado em um momento ou outro, a decisão que tem de ser feita é se o link leva muito tempo suficiente para que as necessidades do compilador que morder a bala e fazê-lo na frente, ou o vinculador dinâmico pode fazê-lo em tempo de carregamento.

Se a sua biblioteca vai ser compartilhado entre vários executáveis, que muitas vezes faz sentido para torná-lo dinâmico para reduzir o tamanho dos executáveis. Caso contrário, definitivamente torná-lo estático.

Existem várias desvantagens do uso de uma dll. Existe uma sobrecarga adicional para o carregamento e descarregamento. Há também uma dependência adicional. Se você alterar a dll para torná-lo incompatível com seus executalbes, eles vão parar de trabalhar. Por outro lado, se você alterar uma biblioteca estática, seus executáveis ??compilados usando a versão antiga não será afetado.

Se a biblioteca é estático, em seguida, em tempo de ligação o código está ligada com seu executável. Isso faz com que seu executável maior (do que se passou a rota dinâmica).

Se a biblioteca é dinâmico, em seguida, em referências de tempo apontam para os métodos necessários são construídos para o seu executável. Isso significa que você tem que enviar o seu executável e biblioteca dinâmica. Você também deve considerar se o acesso compartilhado para o código na biblioteca é seguro, endereço de carga preferido entre outras coisas.

Se você pode viver com a biblioteca estática, ir com a biblioteca estática.

Bibliotecas estáticas são arquivos que contêm o código objeto para a biblioteca, quando ligado a um aplicativo que o código é compilado para o executável. bibliotecas compartilhadas são diferentes em que eles não são compilados no executável. Em vez disso as pesquisas vinculador dinâmico alguns diretórios olhando para a biblioteca (s) de que necessita, então cargas que na memória. Mais de um executável pode usar a mesma biblioteca compartilhada ao mesmo tempo, reduzindo assim o uso de memória e tamanho do executável. No entanto, há então mais arquivos para distribuir com o executável. Você precisa ter certeza de que a biblioteca é instalado no lugar sistema de usos onde o vinculador pode encontrá-lo, vinculação estática elimina este problema, mas resulta em um arquivo executável maior.

Se o seu trabalho em projetos incorporados ou plataformas especializadas bibliotecas estáticas são o único caminho a percorrer, também muitas vezes eles são menos de um aborrecimento para compilar em sua aplicação. Também ter projetos e makefile que incluem tudo, torna a vida mais feliz.

Nós usamos um monte de DLL (> 100) em nosso projeto. Estes DLL tem dependências entre si e, portanto, nós escolhemos a configuração de ligação dinâmica. No entanto, tem as seguintes desvantagens:

  • inicialização lenta (> 10 segundos)
  • DLL teve que ser versionadas, desde módulos Windows carrega na singularidade de nomes. Possui componentes escritos de outra forma, obter a versão errada da DLL (isto a um já carregado em vez de seu próprio conjunto distribuído)
  • otimizador só pode otimizar dentro dos limites DLL. Por exemplo, as tentativas otimizador ao lugar frequentemente utilizados dados e código ao lado do outro, mas isso não vai funcionar através de limites de DLL

Talvez uma configuração melhor era fazer tudo uma biblioteca estática (e, portanto, você só tem um executável). Isso funciona somente se não houver duplicação de código ocorre. Um teste parece apoiar esta hipótese, mas eu não poderia encontrar uma cotação oficial MSDN. Assim, por exemplo, fazer um exe com:

  • exe usos shared_lib1, shared_lib2
  • uso shared_lib1 shared_lib2
  • shared_lib2

O código e variáveis ??de shared_lib2 deve estar presente na final fundiu executável apenas uma vez. Pode apoiar qualquer um esta pergunta?

Eu daria uma regra geral que se você tem uma grande base de código, todo construído em cima de bibliotecas de nível inferior (por exemplo, um Utils ou Gui quadro), o qual pretende partição em bibliotecas mais gerenciáveis, em seguida, fazê-los estática bibliotecas. bibliotecas dinâmicas realmente não comprar-lhe qualquer coisa e há menos surpresas - haverá apenas uma instância de singletons, por exemplo.

Se você tem uma biblioteca que é completamente separado do resto do código base (por exemplo, uma biblioteca de terceiros), em seguida, considerar a possibilidade de uma dll. Se a biblioteca é LGPL você pode precisar usar uma dll de qualquer maneira devido às condições de licenciamento.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top