2009-08-24 13 views
3

J'ai un problème avec les variables globales dans un projet de bibliothèque partagée C++. ma bibliothèque doit fonctionner comme une bibliothèque partagée g ++ standard (.so) ainsi qu'une DLL. Je l'ai fait en créant des fichiers libiup_dll.cpp et libiup_dll.h, où j'ai quelque chose commeProblèmes avec les variables globales dans le projet de bibliothèque partagée (C++)

#ifdef BUILD_DLL 

// code for the dll: wrapper functions around the classes in my shared library 

#endif 

dans mon dll, j'ai besoin des fonctions setLogLevel (int) et geterrormsg(). dans toutes mes classes, j'ajouterais alors à une variable globale errormsg tous les messages d'erreur. cette variable devrait ensuite être retournée par la fonction geterrormsg(). i mis en œuvre en utilisant ce

std::string errormsg; 
int loglevel; 

à libiup_dll.h (extérieur et #ifdefs, il devrait donc être disponible au niveau mondial), puis mettre

extern std::string errormsg; 
extern int loglevel; 

dans les fichiers .h de mes classes (en dehors de la classe, en haut des fichiers)

maintenant j'ai deux problèmes:

1) lors de la compilation d'un programme de ligne de commande avec g ++, qui utilise ma bibliothèque, je reçois des erreurs

cible de construction: libiup_test Invoquer: GCC C++ Linker g ++ -L "/ home/hilboll/src/libiup/Release" -L/usr/-o local/lib "libiup_test" ./src/stratcalc /SimpleStratosphericColumnCalculatorTest.o ./src/interp/SimpleInterpolatorTest.o ./src/Test.o -lgsl -lhdf5 -lhdf5_cpp -lblas -liup /home/hilboll/src/libiup/Release/libiup.so: non définie référence à loglevel' /home/hilboll/src/libiup/Release/libiup.so: undefined reference to errormsg » collect2: ld retourné 1 état de sortie make: *** [libiup_test] erreur 1

même si dans mon programme de ligne de commande, il n'y a aucune référence à errormsg ou loglevel.

2) en essayant de compiler les dll sous Windows avec VS2008, je reçois

z: \ src \ vs \ libiup_dll \ libiup_dll.h (229) : erreur C2086: « std :: string errormsg ': Neudefinition z: \ src \ libiup \ src \ ../ stratcalc interp/SimpleInterpolator.h (16): Siehe Deklaration von 'errormsg' z: \ src \ vs \ libiup_dll \ libiup_dll.h (234 : erreur C2086: 'int loglevel': Neudéfinition z: \ src \ libiup \ src \ stratcalc ../ interp/SimpleInterpolator.h (17): Deklaration von 'loglevel'

autant que je comprenne, cela signifie que VS pense que je définis deux fois les deux variables. Cependant, dans SimpleInterpolator.h 16/17, il n'y a que les déclarations extern ...

il semble que je n'ai pas encore compris comment fonctionnent les variables globales, pour le moment. Toute aide est grandement appréciée!

+0

en utilisant un compilateur qui parle anglais pourrait être un bon début. – shoosh

+0

montrant la source réelle plutôt que de la décrire serait bien. –

Répondre

2

L'astuce consiste à savoir que chaque fichier .cpp est une unité de compilation - c'est-à-dire les éléments compilés. Chacun est un individu total et ne sait rien l'un de l'autre. C'est seulement au stade de la liaison que ceux-ci sont réunis. Maintenant, extern dit "cette variable peut être trouvée ailleurs" dans le fichier cpp compilé, le compilateur place juste un indice de référence à l'éditeur de liens pour trier les choses. Donc, comme vous avez placé les définitions de variables dans un fichier d'en-tête, il est probable que vous incluez cet en-tête dans 2 fichiers cpp (ou plus).Donc, chacun de ces fichiers cpp, lorsqu'ils sont compilés, pense qu'ils ont la vraie variable. L'éditeur de liens arrive ensuite et en voit trop.

Placez les variables dans un fichier cpp qui leur est propre (ou dans le fichier cpp principal), et ne placez que des références externes dans les fichiers d'en-tête. Vous devriez alors être d'accord avec les symboles multi-définis.

3

Les globaux peuvent être déclarés plusieurs fois mais doivent défini une seule fois.

Le mot-clé "extern" indique ce qui serait autrement une définition en tant que déclaration.

L'idiome général pour la façon dont vous le faites est la suivante:

// In a header file (declaration) 
extern int myGlobal; 

// In a source file (definition) 
int myGlobal; 

Alors, où vous voulez faire référence à l'échelle mondiale, vous devez soit répéter la déclaration extern, ou inclure le fichier d'en-tête qui a déjà déclaration externe.

Ce que vous devez absolument pas faire est de mettre le « int myGlobal » définition (sans le « extern ») dans un en-tête. Si vous faites cela, alors chaque fichier qui inclut cet entête va essayer de définir son propre myGlobal, et vous vous retrouverez avec des conflits de symboles lorsque vous liez. La définition devrait être dans un et un seul fichier source. La déclaration extern peut apparaître dans autant de fichiers ou d'en-têtes que vous le souhaitez.

En particulier, ce qui se passe avec vos deux erreurs est la suivante:

  • Lorsque vous compilez sous Linux, l'en-tête de DLL qui définit globals est éliminé par vos macros préprocesseur, de sorte que vos globals ont une déclaration, mais aucune définition, et l'éditeur de liens se plaint.
  • Lorsque vous compilez sous Windows, l'en-tête DLL est inclus dans plusieurs unités de compilation (fichier source). Les globales ont donc plusieurs définitions et l'éditeur de liens se plaint.
0

Vous dites que vous avez:

std::string errormsg; 
int loglevel; 

à libiup_dll.h en dehors de toute #ifdefs. Ceci est un problème si libiup_dll.h est inclus plusieurs fois (directement ou indirectement), et est probablement la cause de votre problème # 2.

Je pense que cela pourrait aussi être la cause du problème # 1 si l'en-tête est inclus - vous avez les définitions des variables introduites par l'en-tête même si vous ne pourriez pas les utiliser ailleurs.

La définition de ces 2 variables doit généralement se trouver dans un fichier .c ou .cpp, et non dans un en-tête. Avoir une déclaration extern pour ceux-ci est OK dans un en-tête.

0

Vous avez dit,

I implemented this by using 

    std::string errormsg; 
    int loglevel; 

in libiup_dll.h (outside and #ifdefs, so it should be globally available), 
and then putting 

    extern std::string errormsg; 
    extern int loglevel; 

in my classes' .h files (outside the class, at the top of the files) 

Au lieu de cela, je pense que vous devriez déclarer les variables à l'aide extern dans un certain nombre de fichiers d'en-tête, puis définir les variables sans extern dans une et unique, un Fichier C ou CPP.

Questions connexes