Pergunta

No meu projeto há uma dependência de uma biblioteca estática (chamada apenas libsomething a partir de agora) de terceiros.Recentemente, libsomething ficou disponível em outra versão.Minha tarefa é fornecer ao meu software suporte para a versão antiga e a nova.Apenas uma versão de libsomething é usado em tempo de execução a qualquer momento, mas qual versão deve ser configurada entre as execuções do programa.

Estou usando o MSVC2005 no WinXP, um objetivo secundário é estar preparado para mudar para Linux e GCC.

Como ambas as versões libsomething estão usando os mesmos símbolos, vinculá-los ao meu executável está fora de questão, pois os símbolos de ambas as versões entrarão em conflito no momento do link.

Embora eu pudesse criar dois executáveis ​​(um vinculado à versão antiga e outro usando a nova versão), não posso implementar uma decisão sobre qual executável chamar no ambiente de implantação final (motivos legados).

Tive a ideia de criar um wrapper de biblioteca dinâmico para cada versão do libsomething e vinculá-los em tempo de execução dependendo de algum arquivo de configuração.Com o MSCV, isso significaria seguir o caminho da utilização LoadLibrary(), GetProcAddress(), etc., enquanto no Linux eu teria que usar dlopen() e dlsym().

Eu entendo que usar libtool (ou seja, libtldl) está agrupando essa dependência de plataforma para usar bibliotecas compartilhadas.Este é um caminho adequado a seguir?Existem maneiras melhores (ou, pelo menos, diferentes)?Faça alternativas para libtldl existe como código aberto?

Foi útil?

Solução

Já se passaram alguns anos, mas gostaria de mencionar outra solução para completar.Em vez de manual dlopen e dlsym você pode gerar stubs simples para todas as funções necessárias e na primeira chamada (ou na inicialização do programa) decidir qual versão da biblioteca é necessária, carregá-la e resolver os endereços.

Você pode escrever um script adaptado especificamente para o seu projeto ou usar Implib.so ferramenta:

# This will generate mylib.so.init.c and mylib.so.tramp.S
# which implement stubs. These need to be linked to your
# executable.
$ implib-gen.py mylib.so

Implib.so é apenas para Linux, mas deve ser facilmente adaptável ao Windows.

Outras dicas

Eu sei que você disse que não poderia usar dois executáveis ​​devido à decisão de qual executar, mas não poderia? exec ir e voltar entre executáveis, dependendo de qual versão está selecionada na configuração?

No Linux, seria mais fácil vincular-se à biblioteca compartilhada e usar links simbólicos para corrigir a versão - IMO é muito mais fácil do que usar dlopen() + dlsym().

Assim, você criaria bibliotecas compartilhadas para as versões antigas e novas da sua biblioteca:

g++ -shared -o libshared.so.1.1 -Wl,-soname=libshared.so.1 -L. -Wl,--whole-archive libstatic.a.old -Wl,-no-whole-archive

e

g++ -shared -o libshared.so.1.2 -Wl,-soname=libshared.so.1 -L. -Wl,--whole-archive libstatic.a.new -Wl,-no-whole-archive

Crie os links simbólicos:

ln -s libshared.so.1.1 libshared.so.1
ln -s libshared.so.1 libshared.so

Construa sua aplicação, vinculando-a à versão antiga da biblioteca.Suponho que ambas as versões sejam compatíveis com binários (ABI não quebrada), mas a nova pode ter alguns símbolos novos.

g++ -o myapp myapp.cpp -L. -lshared

Como a biblioteca compartilhada SONAME é libshared.so.1 sua aplicação dependerá disso e irá pesquisar libshared.so.1 em caminhos de /etc/ld.so.conf ou LD_LIBRARY_PATH

Antes de executar seu aplicativo, você pode definir o libshared.so.1 link simbólico para apontar para libshared.so.1.2 ou libshared.so.1.1.


Poucas informações sobre as opções do vinculador usadas aqui:

--arquivo inteiro
Para cada arquivo mencionado na linha de comando após a opção --whole-archive, inclua cada arquivo de objeto no arquivo morto no , em vez de procurar os arquivos de objeto necessários no arquivo.Isso normalmente é usado para transformar um arquivo morto em um compartilhado biblioteca, forçando cada objeto a ser incluído na biblioteca compartilhada resultante.Esta opção pode ser usada mais de uma vez.
Duas notas ao usar esta opção do gcc:Primeiro, o gcc não conhece esta opção, então você deve usar -Wl,-whole-archive.Em segundo lugar, não se esqueça de usar -Wl,-no-whole-archive após sua lista de arquivos, porque o gcc adicionará sua própria lista de arquivos à sua e você pode não querer que essa bandeira afete esses também.

-sonome=nome
Ao criar um objeto compartilhado ELF, defina o campo interno DT_SONAME com o nome especificado.Quando um executável é vinculado a um objeto compartilhado que tem um campo DT_SONAME, em seguida, quando o executável é executado o vinculador dinâmico tentará carregar o objeto compartilhado especificado pelo campo DT_SONAME em vez de usar o nome de arquivo fornecido ao vinculador.

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