2009-03-25 2 views
4

en double de la question suivante: C function conflictComment utiliser 2 C libs qui exportent les mêmes noms de fonction


Salut, dans mon projet actuel, je dois utiliser une sorte de lib interface. Les noms des fonctions sont donnés par cette interface, ce que font ces fonctions est le choix des développeurs. Autant que je sache, un projet doit utiliser cette fonction et quand il s'agit de compiler, choisissez la lib et la fonctionnalité. Ce que je tente de faire est d'utiliser une lib existante et mon lib en même temps en enveloppant l'autre et l'appeler dans les fonctions mein:

otherlib:

int function1 (int a) { 
// do something 
} 

mylib:

int function1 (int a) { 
//my code here 
    otherlib::function1(a); 
} 

Le problème est que je n'ai pas accès à l'autre lib et l'autre lib n'a aucun espace de noms. Je l'ai déjà essayé

namespace old { 
    #include "otherlib.h" 
} 

puis appeler l'ancienne fonction par le vieux :: function1 dans ma fonction. Cela fonctionne tant que c'est seulement le fichier d'en-tête. La lib exporte son symbole dans l'espace global. Également quelque chose comme

namespace new { 
    function1 (int a) { 
     ::function1(a); 
    } 
} 

ne fonctionnait pas. Last but not least, j'ai essayé ifdefs et définit here

mais je n'ai pas réussi.

Des idées pour résoudre ce problème? Merci d'avance.

EDIT:. Je n'ai pas accès à l'ancien lib, ni le projet les deux libs doivent être utilisés dans

EDIT2: au moins l'ancien lib est un

+0

J'ai vu cela mais je n'ai pas accès au projet dans lequel ils doivent être utilisés. – DaClown

Répondre

6

statiques Namespaces en C résolus en utilisant les noms de bibliothèque préfixes comme:

libfoo -> foo_function1
libbar -> bar_function1

Ces préfixes sont namespaces réels. donc si vous écrivez libbar

int bar_function1(int a) { 
    function1(a); 
} 

Ceci est le moyen de résoudre les problèmes.

C a namespaces --- ils ont juste appelés préfixes;)

Une autre option est de faire plusieurs tours sales avec le chargement dynamique des bibliothèques comme:

h1=dlopen("libfoo.so") 
foo_function1=dlsym(h1,"function1") 

h2=dlopen("libbar.so") 
bar_function1=dlsym(h2,"function1") 
+0

Merci pour votre réponse. Malheureusement, je n'ai pas accès à l'ancienne bibliothèque ni au projet dans lequel elle sera utilisée. Et au moins l'ancienne bibliothèque est statique. – DaClown

3

Il semble que si l'autre est lib C et votre code est C++. Vous pouvez être confronté à un problème de mangling (les compilateurs C++ mangent les symboles - ajouter des éléments supplémentaires dans le nom du symbole différencient les surcharges et autres).

Si la bibliothèque est pur C, vous pouvez essayer:

extern "C" { // disable mangling of symbol names in the block 
#include "otherlib.h" 
} 

namespace new_lib { // new is a reserved word 
    int function1(int a) { 
     ::function1(a); 
    } 
} 

Je ne l'ai pas essayé. Pensez également à fournir les messages d'erreur que vous recevez.

Une autre option serait (si la bibliothèque est dynamique) charger dynamiquement la lib et appeler la fonction. Dans linux (je ne sais pas sur les fenêtres) que vous pouvez utiliser dlopen pour ouvrir la bibliothèque, dlsym pour obtenir le symbole et l'appeler:

// off the top of my head, not tried: 
int function1(int a) 
{ 
    int (*f)(int); // define the function pointer 
    void * handle = dlopen("library.so"); 
    f = dlsym(handle, "function1"); 
    f(a); // calls function1(a) in the dynamic library 
} 

Dans ce cas, comme vous n'êtes pas liaison avec la bibliothèque que vous avez gagné N'obtenez pas un conflit de symbole, mais encore une fois, il n'est valable que pour les bibliothèques dynamiques et il est assez lourd pour une utilisation régulière.

MISE À JOUR

Si vos utilisateurs ne seront pas utiliser « otherlib » directement (ils ne comprennent pas leurs têtes) et ils ne seront que C++, la première pourrait être possible approche (même si horrible à lire):

// newlib.h 
namespace hideout { 
    int f(int a); 
} 
using namespace hideout; // usually I would not put this on the header 

// newlib.cpp 
extern "C" { // if otherlib is C, else remove this line 
#include "otherlib.h" 
} 
namespace hideout { 
    int f(int a) { return ::f(a*2); } 
} 

// main.cpp 
#include "newlib.h" 
int main() 
{ 
    std::cout << f(5) << std::endl; 
} 

Comment ça marche? Le code utilisateur ne verra qu'une déclaration de function1 (dans l'exemple f()) car ils n'incluent pas otherlib.h. À l'intérieur de votre unité de compilation, vous voyez les deux déclarations, mais vous vous différenciez en utilisant l'espace de noms. L'instruction using dans l'en-tête ne vous dérange pas car vous êtes pleinement qualifié dans votre cpp. L'utilisateur main.cpp inclura seulement votre en-tête, donc le compilateur ne verra que hideout :: f, et le verra n'importe où en raison de l'instruction using. L'éditeur de liens n'aura aucun problème comme le C++ symbole est mutilée identifier le véritable espace de noms:

// g++ 4.0 in macosx: 
00002dbe T __ZN7hideout9function1Ei // namespace hideout, function1 takes int, returns int 
00002db0 T _function1 

Si le code utilisateur comprendra à la fois votre tête et otherlib.h alors il devra se qualifier la fonction qu'elle veut appeler .

+0

Merci pour votre réponse. Votre première suggestion ne fonctionne pas pour moi. Je n'ai aucun contrôle sur les noms des fonctions qui devraient changer la portée en utilisant 'namespace new_lib;', et cela met les new_lib ns dans le global où la fonction est déjà définie. Je vais essayer la deuxième façon. – DaClown

1

Exactement cette question a été posée hier, mais le centre de recherche de SO a foxed toutes mes tentatives de le trouver - quand au nom des dieux sont-ils goinmg pour le remplacer par une recherche qui trouve effectivement des choses ?????

+0

Une partie du fardeau est sur nous. Nous devons utiliser (et éviter d'utiliser) les mots-clés qui se rapportent (ne se rapportent pas) à notre sujet. – Les

+0

"Exactement cette question a été posée seulement hier, mais la fonction de recherche de SO a roussi toutes mes tentatives pour le trouver" << c'est tellement vrai :) je n'aime pas chercher des facils soit :) –

1

Si vous êtes vraiment désespéré, vous pouvez écrire une bibliothèque wrapper qui utilise des espaces de noms ou des préfixes ou permet le tour dlsym. Cette bibliothèque d'encapsuleur doit être liée dynamiquement (pour éviter les conflits de symboles). La bibliothèque dynamique pourrait alors avoir l'ancienne bibliothèque statique intégrée en toute sécurité. Assurez-vous de ne pas exporter les symboles de la bibliothèque statique lors de la création de la bibliothèque de wrapper dynamique.

1

Vous ne pouvez pas résoudre ce problème au moment de la liaison, vous devrez donc le résoudre au moment de l'exécution via des bibliothèques dynamiques. Le symbole de ces fonctions est essentiellement cuit une fois que la bibliothèque a été générée. Si deux bibliothèques exportent le même symbole, elles ne peuvent pas être liées statiquement.

Questions connexes