O que devo fazer se eu tiver duas bibliotecas que fornecem funções com nomes equivalentes?
vorbis_...
, sf_...
, sdl_...
). Isso é essencialmente o que C ++ faz com os nomes dos símbolos para funções com espaço de nomes.
O que devo fazer se eu tiver duas bibliotecas que fornecem funções com nomes equivalentes?
vorbis_...
, sf_...
, sdl_...
). Isso é essencialmente o que C ++ faz com os nomes dos símbolos para funções com espaço de nomes.
Respostas:
A propósito dos comentários: Por "exportar", quero dizer tornar visíveis os módulos vinculados à biblioteca --- equivalente à extern
palavra-chave no escopo do arquivo. O modo como isso é controlado depende do sistema operacional e do vinculador. E é algo que sempre tenho que procurar.
É possível renomear símbolos em um arquivo de objeto usando objcopy --redefine-sym old=new file
(ver man objcopy).
Em seguida, basta chamar as funções usando seus novos nomes e vinculá-las ao novo arquivo objeto.
No Windows, você pode usar LoadLibrary () para carregar uma dessas bibliotecas na memória e, em seguida, usar GetProcAddress () para obter o endereço de cada função necessária para chamar e chamar as funções por meio de um ponteiro de função.
por exemplo
HMODULE lib = LoadLibrary("foo.dll");
void *p = GetProcAddress(lib, "bar");
// cast p to the approriate function pointer type (fp) and call it
(*fp)(arg1, arg2...);
FreeLibrary(lib);
obteria o endereço de uma função chamada bar em foo.dll e a chamaria.
Eu sei que os sistemas Unix oferecem suporte a funcionalidades semelhantes, mas não consigo pensar em seus nomes.
dlopen
dlsym
, e dlclose
. No entanto, o encapsulamento no Unix pode não ser tão eficaz quanto no Windows.
Aqui está uma ideia. Abra uma das bibliotecas ofensivas em um editor hexadecimal e altere todas as ocorrências das strings ofensivas para outra coisa. Você poderá então usar os novos nomes em todas as chamadas futuras.
ATUALIZAÇÃO: acabei de fazer isso e parece funcionar. Claro, eu não testei isso completamente - pode não ser mais do que uma boa maneira de explodir sua perna com uma espingarda hexedit.
Assumindo que você usa o Linux, você primeiro precisa adicionar
#include <dlfcn.h>
Declare a variável de ponteiro de função no contexto adequado, por exemplo,
int (*alternative_server_init)(int, char **, char **);
Como Ferruccio afirmou em https://stackoverflow.com/a/678453/1635364 , carregue explicitamente a biblioteca que deseja usar executando (escolha seus sinalizadores favoritos)
void* dlhandle;
void* sym;
dlhandle = dlopen("/home/jdoe/src/libwhatnot.so.10", RTLD_NOW|RTLD_LOCAL);
Leia o endereço da função que deseja chamar mais tarde
sym = dlsym(dlhandle, "conflicting_server_init");
atribuir e lançar da seguinte forma
alternative_server_init = (int (*)(int, char**, char**))sym;
Ligue de forma semelhante ao original. Finalmente, descarregue executando
dlclose(dlhandle);
Você não deve usá-los juntos. Se bem me lembro, o vinculador emite um erro nesse caso.
Eu não tentei, mas uma solução pode estar com dlopen()
, dlsym()
e dlclose()
que permite que você lide programaticamente com bibliotecas dinâmicas. Se você não precisa das duas funções ao mesmo tempo, pode abrir a primeira biblioteca, usar a primeira função e fechar a primeira biblioteca antes de usar a segunda biblioteca / função.
Se você tiver arquivos .o lá, uma boa resposta aqui: https://stackoverflow.com/a/6940389/4705766
Resumo:
objcopy --prefix-symbols=pre_string test.o
para renomear os símbolos no arquivo .o ou
objcopy --redefine-sym old_str=new_str test.o
para renomear o símbolo específico no arquivo .o.Esse problema é o motivo pelo qual c ++ tem namespaces. Não há realmente uma grande solução em c para 2 libs de terceiros com o mesmo nome.
Se for um objeto dinâmico, você poderá carregar explicitamente os objetos compartilhados (LoadLibrary / dlopen / etc) e chamá-lo dessa maneira. Alternativamente, se você não precisa de ambas as bibliotecas ao mesmo tempo no mesmo código, você pode fazer algo com link estático (se você tiver os arquivos .lib / .a).
Nenhuma dessas soluções se aplica a todos os projetos, é claro.
Xingar? Pelo que eu sei, não há muito que você possa fazer se tiver duas bibliotecas que expõem pontos de link com o mesmo nome e você precisa vincular a ambos.
Você deve escrever uma biblioteca de wrapper em torno de um deles. Sua biblioteca de wrapper deve expor símbolos com nomes exclusivos e não expor os símbolos de nomes não exclusivos.
Sua outra opção é renomear o nome da função no arquivo de cabeçalho e renomear o símbolo no arquivo do objeto da biblioteca.
De qualquer forma, para usar os dois, será um trabalho de hack.
A questão está se aproximando de uma década, mas há novas pesquisas o tempo todo ...
Como já respondido, objcopy com o sinalizador --redefine-sym é uma boa escolha no Linux. Veja, por exemplo, https://linux.die.net/man/1/objcopy para documentação completa. É um pouco desajeitado porque você está essencialmente copiando a biblioteca inteira enquanto faz alterações e cada atualização requer que esse trabalho seja repetido. Mas pelo menos deve funcionar.
Para o Windows, carregar dinamicamente a biblioteca é uma solução e permanente, como a alternativa dlopen no Linux seria. No entanto, tanto dlopen () quanto LoadLibrary () adicionam código extra que pode ser evitado se o único problema for nomes duplicados. Aqui, a solução do Windows é mais elegante do que a abordagem objcopy: basta dizer ao vinculador que os símbolos em uma biblioteca são conhecidos por algum outro nome e usar esse nome. Existem algumas etapas para fazer isso. Você precisa fazer um arquivo def e fornecer a tradução do nome na seção EXPORTS. Consulte https://msdn.microsoft.com/en-us/library/hyx1zcd3.aspx (VS2015, ele será eventualmente substituído por versões mais recentes) ou http://www.digitalmars.com/ctg/ctgDefFiles.html(provavelmente mais permanente) para detalhes completos da sintaxe de um arquivo def. O processo seria fazer um arquivo def para uma das bibliotecas e então usar esse arquivo def para construir um arquivo lib e então vincular a esse arquivo lib. (Para DLLs do Windows, os arquivos lib são usados apenas para vinculação, não para execução de código.) Consulte Como fazer um arquivo .lib quando tiver um arquivo .dll e um arquivo de cabeçalho para o processo de construção do arquivo lib. Aqui, a única diferença é adicionar os aliases.
Para Linux e Windows, renomeie as funções nos cabeçalhos da biblioteca cujos nomes estão sendo aliasados. Outra opção que deveria funcionar seria, em arquivos referentes aos novos nomes, # definir nome_antigo nome_novo, # incluir os cabeçalhos da biblioteca cujas exportações estão sendo alteradas, e então #undef nome_antigo no responsável pela chamada. Se houver muitos arquivos usando a biblioteca, uma alternativa mais fácil é fazer um cabeçalho ou cabeçalhos que envolvam os define, inclui e undefs e, em seguida, usar esse cabeçalho.
Espero que esta informação tenha sido útil!
Nunca usei dlsym, dlopen, dlerror, dlclose, dlvsym, etc., mas estou olhando a página de manual e ela dá um exemplo de como abrir libm.so e extrair a função cos. O dlopen passa pelo processo de procura de colisões? Do contrário, o OP poderia simplesmente carregar ambas as bibliotecas manualmente e atribuir novos nomes a todas as funções que suas bibliotecas fornecem.