web-dev-qa-db-fra.com

Que dois-je faire si deux bibliothèques fournissent une fonction du même nom générant un conflit?

Que dois-je faire si j'ai deux bibliothèques qui fournissent des fonctions avec des noms équivalents?

81
qeek
  • Si vous contrôlez un ou les deux: éditez-en un pour changer le nom et recompilez Ou voir de manière équivalente les réponses de Ben et nknown qui fonctionneront sans = accès au code source.
  • Si vous ne contrôlez aucun d'eux, vous pouvez en conclure un. C'est-à-dire compiler un autre ( bibliothèque liée statiquement !) Qui ne fait que réexporter tous les symboles de l'original à l'exception de celui incriminé, qui est atteint via un wrapper avec un autre nom. Quelle galère.
  • Ajouté plus tard: Puisque qeek dit qu'il parle de bibliothèques dynamiques, les solutions suggérées par Ferruccio et mouviciel = sont probablement les meilleurs. (Il semble que j'aie vécu il y a longtemps, lorsque la liaison statique était la valeur par défaut. Cela colore ma pensée.)

Apropos les commentaires: Par "exporter", je veux dire rendre visible aux modules se liant à la bibliothèque --- équivalent au mot-clé extern à la portée du 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 toujours dois chercher.

47
dmckee

Il est possible de renommer des symboles dans un fichier objet en utilisant objcopy --redefine-sym old=new file (voir objcopy man).

Ensuite, il suffit d'appeler les fonctions en utilisant leurs nouveaux noms et de les lier au nouveau fichier objet.

48
Ben

Sous Windows, vous pouvez utiliser LoadLibrary () pour charger 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'appellerait.

Je sais que les systèmes Unix prennent en charge des fonctionnalités similaires, mais je ne peux pas penser à leurs noms.

13
Ferruccio

Voici une pensée. Ouvrez l'une des bibliothèques incriminées dans un éditeur hexadécimal et changez toutes les occurrences des chaînes incriminées en autre chose. Vous devriez alors pouvoir utiliser les nouveaux noms dans tous les appels futurs.

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 hexedit.

8
Sniggerfardimungus

En supposant que vous utilisez Linux, vous devez d'abord ajouter

#include <dlfcn.h>

Déclarez la variable de pointeur de fonction dans le contexte approprié, par exemple,

int (*alternative_server_init)(int, char **, char **);

Comme Ferruccio l'a déclaré 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 lancer 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);
6
vraa

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 permettent 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.

6
mouviciel

Ce problème est la raison pour laquelle c ++ possède des espaces de noms. Il n'y a pas vraiment une excellente solution dans c pour 2 bibliothèques tierces ayant le même nom.

S'il s'agit d'un objet dynamique, vous pourrez peut-être explicitement charger les objets partagés (LoadLibrary/dlopen/etc) et l'appeler de cette façon. 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 une liaison statique (si vous avez les fichiers .lib/.a).

Bien entendu, aucune de ces solutions ne s'applique à tous les projets.

4
Brian Mitchell

Jurer? Pour autant que je sache, vous ne pouvez pas faire grand-chose si vous avez deux bibliothèques qui exposent des points de lien avec le même nom et que vous devez établir un lien avec les deux.

3
Vatine

Si vous avez des fichiers .o là-bas, une bonne réponse ici: https://stackoverflow.com/a/6940389/4705766

Sommaire:

  1. objcopy --prefix-symbols=pre_string test.o pour renommer les symboles dans le fichier .o

ou

  1. objcopy --redefine-sym old_str=new_str test.o pour renommer le symbole spécifique dans le fichier .o.
3
Jee lee

Vous devez écrire une bibliothèque wrapper autour de l'un d'eux. Votre bibliothèque d'encapsuleur doit exposer les 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'objet de bibliothèque.

Quoi qu'il en soit, pour utiliser les deux, ça va être un hack.

2
James Caccese

La question approche d'une dizaine d'années, mais il y a tout le temps de nouvelles recherches ...

Comme déjà répondu, objcopy avec le drapeau --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. Cependant, dlopen () et LoadLibrary () ajoutent du code supplémentaire qui peut être évité si le seul problème est les noms en double. 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 finira par être 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 consiste à créer un fichier def pour l'une des bibliothèques, puis à utiliser ce fichier def pour créer un fichier lib, puis à établir un lien avec ce fichier lib. (Pour les DLL Windows, les fichiers lib ne sont utilisés que pour la liaison, pas pour l'exécution de code.) Voir Comment créer un fichier .lib avec un fichier .dll et un fichier d'en-tête pour le processus de construction de la lib fichier. 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. 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 à l'aide de la bibliothèque, une alternative plus simple consiste à créer un en-tête ou des en-têtes qui encapsule les définitions, inclut et annule et utilise ensuite cet en-tête.

J'espère que ces informations vous ont été utiles!

1
Jim Monte

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.

0
Sniggerfardimungus