Que dois-je faire si j'ai deux bibliothèques qui fournissent des fonctions avec des noms équivalents?
vorbis_...
, sf_...
, sdl_...
). C'est essentiellement ce que fait C ++ aux noms de symboles pour les fonctions d'espacement de noms.
Que dois-je faire si j'ai deux bibliothèques qui fournissent des fonctions avec des noms équivalents?
vorbis_...
, sf_...
, sdl_...
). C'est essentiellement ce que fait C ++ aux noms de symboles pour les fonctions d'espacement de noms.
Réponses:
À propos des commentaires: Par "exporter", j'entends rendre visible les modules liés à la bibliothèque --- équivalent au extern
mot - clé à portée de fichier. La façon dont cela est contrôlé dépend du système d'exploitation et de l'éditeur de liens. Et c'est quelque chose que je dois toujours rechercher.
Il est possible de renommer des symboles dans un fichier objet en utilisant objcopy --redefine-sym old=new file
(voir man objcopy).
Ensuite, appelez simplement les fonctions en utilisant leurs nouveaux noms et créez un lien avec le nouveau fichier objet.
Sous Windows, vous pouvez utiliser LoadLibrary () pour charger l'une de ces bibliothèques en mémoire, puis utiliser GetProcAddress () pour obtenir l'adresse de chaque fonction que vous devez appeler et appeler les fonctions via un pointeur de fonction.
par exemple
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);
obtiendrait l'adresse d'une fonction nommée bar dans foo.dll et l'appelait.
Je sais que les systèmes Unix prennent en charge des fonctionnalités similaires, mais je ne peux pas penser à leurs noms.
dlopen
dlsym
et dlclose
. Cependant, l'encapsulation sous Unix peut ne pas être aussi efficace que sous Windows.
Voici une pensée. Ouvrez l'une des bibliothèques incriminées dans un éditeur hexadécimal et remplacez toutes les occurrences des chaînes incriminées par autre chose. Vous devriez alors pouvoir utiliser les nouveaux noms dans tous les futurs appels.
MISE À JOUR: Je viens de le faire à cette fin et cela semble fonctionner. Bien sûr, je n'ai pas testé cela à fond - ce n'est peut-être qu'un très bon moyen de vous faire sauter la jambe avec un fusil de chasse hexedit.
En supposant que vous utilisez Linux, vous devez d'abord ajouter
#include <dlfcn.h>
Déclarez la variable de pointeur de fonction dans le bon contexte, par exemple,
int (*alternative_server_init)(int, char **, char **);
Comme Ferruccio indiqué dans https://stackoverflow.com/a/678453/1635364 , chargez explicitement la bibliothèque que vous souhaitez utiliser en exécutant (choisissez vos indicateurs préférés)
void* dlhandle;
void* sym;
dlhandle = dlopen("/home/jdoe/src/libwhatnot.so.10", RTLD_NOW|RTLD_LOCAL);
Lisez l'adresse de la fonction que vous souhaitez appeler ultérieurement
sym = dlsym(dlhandle, "conflicting_server_init");
attribuer et cast comme suit
alternative_server_init = (int (*)(int, char**, char**))sym;
Appelez de la même manière que l'original. Enfin, déchargez en exécutant
dlclose(dlhandle);
Vous ne devez pas les utiliser ensemble. Si je me souviens bien, l'éditeur de liens émet une erreur dans un tel cas.
Je n'ai pas essayé, mais une solution peut être avec dlopen()
, dlsym()
et dlclose()
qui vous permet de gérer par programmation des bibliothèques dynamiques. Si vous n'avez pas besoin des deux fonctions en même temps, vous pouvez ouvrir la première bibliothèque, utiliser la première fonction et fermer la première bibliothèque avant d'utiliser la deuxième bibliothèque / fonction.
Si vous avez des fichiers .o, une bonne réponse ici: https://stackoverflow.com/a/6940389/4705766
Résumé:
objcopy --prefix-symbols=pre_string test.o
pour renommer les symboles dans le fichier .o ou
objcopy --redefine-sym old_str=new_str test.o
pour renommer le symbole spécifique dans le fichier .o.Ce problème est la raison pour laquelle c ++ a des espaces de noms. Il n'y a pas vraiment de bonne solution en c pour 2 bibliothèques tierces ayant le même nom.
S'il s'agit d'un objet dynamique, vous pourrez peut-être charger explicitement les objets partagés (LoadLibrary / dlopen / etc) et l'appeler de cette manière. Alternativement, si vous n'avez pas besoin des deux bibliothèques en même temps dans le même code, vous pouvez peut-être faire quelque chose avec des liens statiques (si vous avez les fichiers .lib / .a).
Aucune de ces solutions ne s'applique à tous les projets, bien entendu.
Jurer? Pour autant que je sache, vous ne pouvez pas faire grand-chose si vous avez deux bibliothèques qui exposent des points de liaison avec le même nom et que vous devez établir un lien entre les deux.
Vous devriez écrire une bibliothèque de wrapper autour de l'un d'eux. Votre bibliothèque d'encapsuleurs doit exposer des symboles avec des noms uniques et ne pas exposer les symboles des noms non uniques.
Votre autre option consiste à renommer le nom de la fonction dans le fichier d'en-tête et à renommer le symbole dans l'archive d'objets de bibliothèque.
Quoi qu'il en soit, pour utiliser les deux, ça va être un travail de piratage.
La question approche une décennie, mais il y a de nouvelles recherches tout le temps ...
Comme déjà répondu, objcopy avec l'indicateur --redefine-sym est un bon choix sous Linux. Voir, par exemple, https://linux.die.net/man/1/objcopy pour une documentation complète. C'est un peu maladroit car vous copiez essentiellement la bibliothèque entière tout en apportant des modifications et chaque mise à jour nécessite que ce travail soit répété. Mais au moins ça devrait marcher.
Pour Windows, le chargement dynamique de la bibliothèque est une solution et une solution permanente comme l'alternative dlopen sous Linux le serait. Cependant, dlopen () et LoadLibrary () ajoutent du code supplémentaire qui peut être évité si le seul problème est la duplication des noms. Ici, la solution Windows est plus élégante que l'approche objcopy: dites simplement à l'éditeur de liens que les symboles d'une bibliothèque sont connus sous un autre nom et utilisez ce nom. Il y a quelques étapes pour le faire. Vous devez créer un fichier def et fournir la traduction du nom dans la section EXPORTS. Voir https://msdn.microsoft.com/en-us/library/hyx1zcd3.aspx (VS2015, il sera éventuellement remplacé par des versions plus récentes) ou http://www.digitalmars.com/ctg/ctgDefFiles.html(probablement plus permanent) pour les détails complets de la syntaxe d'un fichier def. Le processus consisterait à créer un fichier def pour l'une des bibliothèques, puis à utiliser ce fichier def pour créer un fichier lib, puis à créer un lien avec ce fichier lib. (Pour les DLL Windows, seuls les fichiers lib sont utilisés pour la liaison, pas pour l'exécution de code.) Consultez Comment créer un fichier .lib lorsque vous disposez d'un fichier .dll et d'un fichier d'en-tête pour le processus de création du fichier lib. Ici, la seule différence est l'ajout des alias.
Pour Linux et Windows, renommez les fonctions dans les en-têtes de la bibliothèque dont les noms sont aliasés. Une autre option qui devrait fonctionner serait, dans les fichiers faisant référence aux nouveaux noms, de #define old_name new_name, #include les en-têtes de la bibliothèque dont les exportations sont aliasées, puis #undef old_name dans l'appelant. S'il y a beaucoup de fichiers utilisant la bibliothèque, une alternative plus simple est de créer un en-tête ou des en-têtes qui encapsulent les définitions, les inclus et les undefs, puis d'utiliser cet en-tête.
J'espère que cette information vous a été utile!
Je n'ai jamais utilisé dlsym, dlopen, dlerror, dlclose, dlvsym, etc., mais je regarde la page de manuel, et elle donne un exemple d'ouverture de libm.so et d'extraction de la fonction cos. Dlopen passe-t-il par le processus de recherche de collisions? Si ce n'est pas le cas, l'OP pourrait simplement charger les deux bibliothèques manuellement et attribuer de nouveaux noms à toutes les fonctions fournies par ses bibliothèques.