2010-02-11 5 views
3

Je travaille sur l'obtention de rLog pour construire sous forme de DLL sous Windows, et j'obtenais des erreurs de symboles non définis concernant certains symboles globaux dans l'espace de noms rlog. Plus précisément dans ces RLogChannel.cpp:Comment utiliser correctement extern dans un espace de noms?

namespace rlog { 
... 
    RLogChannel *_RLDebugChannel = GetGlobalChannel("debug", Log_Debug); 
    RLogChannel *_RLInfoChannel = GetGlobalChannel("info", Log_Info); 
    RLogChannel *_RLWarningChannel = GetGlobalChannel("warning", Log_Warning); 
    RLogChannel *_RLErrorChannel = GetGlobalChannel("error", Log_Error); 
... 
}; 

Je suppose que le problème était que 1) ils ne sont pas exportés et 2) ils n'ont pas été déclarés dans l'en-tête pour que d'autres choses peuvent y accéder. Donc, j'ai ajouté un __declspec (dllexport) (via la macro RLOG_DECL) pour eux, et dans l'en-tête, mis:

namespace rlog { 
... 
    RLOG_DECL extern RLogChannel *_RLDebugChannel; 
    RLOG_DECL extern RLogChannel *_RLInfoChannel; 
    RLOG_DECL extern RLogChannel *_RLWarningChannel; 
    RLOG_DECL extern RLogChannel *_RLErrorChannel; 
... 
}; 

Mais peu importe comment je déclare les variables RLogChannel.cpp je reçois une erreur de redéfinition, en dépit mon externe les dans l'en-tête ... Quelle est la bonne façon de faire cela? On dirait que ça devrait être simple mais je ne peux pas tout à fait enrouler ma tête autour d'elle.

Edit: message d'erreur

Error 12 error C2086: 'rlog::RLogChannel *rlog::_RLDebugChannel' : redefinition rlog-1.4\rlog\RLogChannel.cpp 45 rlog 

(même pour les 4 symboles)

Edit: Je ne sais pas ce qui est arrivé, le code est exactement le même avant, mais maintenant il compilera (sent comme étrangeté MSVC ...), malheureusement les symboles apparaissent encore comme non résolus lors de la liaison dans ma bibliothèque

+1

ce qui est exactement un message d'erreur –

+0

Mise à jour ci-dessus il est formaté un peu plus agréable que moi? peut poster ici –

+0

On dirait quelque chose importa Il a été exclu de la question. Pouvez-vous fournir un cas de test concis et complet (par exemple un fichier que je peux transmettre au compilateur tel quel) qui donne cette erreur? –

Répondre

1

Une façon de contourner ce problème est de les définir une fois dans un endroit et dans l'en-tête. Mais si vous déplacez simplement toutes les définitions vers l'en-tête, vous finirez avec le problème de définition multiple.

Une solution à cela est la suivante. En supposant que les fichiers sont nommés rlog.c & rlog.h

--- (rlog.h) --- 
#ifdef RLOG_DEFINES 
#define EXTERN 
#else 
#define EXTERN extern 
#endif 


namespace rlog { 
... 
    RLOG_DECL EXTERN RLogChannel *_RLDebugChannel; 
    RLOG_DECL EXTERN RLogChannel *_RLInfoChannel; 
    RLOG_DECL EXTERN RLogChannel *_RLWarningChannel; 
    RLOG_DECL EXTERN RLogChannel *_RLErrorChannel; 
... 
}; 


--- (rlog.c) --- 
#define RLOG_DEFINES 
#include "rlog.h" 

... 

--- (other .c files) --- 
#include "rlog.h" 

La beauté de cette solution est que parce que les définitions ne sont définies une fois dans le projet, vous ne serez jamais les sortir de synchronisation les uns avec les autres et vous avez seulement besoin de les changer en un seul endroit. Imaginez si vous définissiez une variable comme longue mais dans la définition externe, elle a été déclarée comme un short? vous pourriez vous retrouver avec des effets secondaires inattendus. Donc, le faire de cette façon aide à prévenir ces types de problèmes.

Espérons que ça aide.

+0

Il a déjà dit qu'il les a définis une fois dans le fichier cpp et les a déclarés dans l'en-tête. – Potatoswatter

+0

Je reçois toujours plusieurs erreurs de définition quand je le fais malheureusement ... –

+0

La solution normale de les définir dans le fichier .c signifie également qu'elles ne sont jamais définies qu'une seule fois dans le projet. Y compris l'en-tête de ce fichier (avec les déclarations) garantit que vous n'avez pas de discordances accidentelles que le compilateur donnera des erreurs si vous le faites. Bref, je ne vois aucun avantage dans le code que vous donnez, mais il a l'inconvénient d'être plus compliqué et de ne pas suivre la convention normale. –

1

Je pense que Matt est assez proche. Je l'avais fait face à cette question un peu de temps un aller et correct (et la plupart des solutions portables est la suivante:

--- (rlog.h) --- 
#ifdef RLOG_DEFINES 
#define RLOG_DECL __declspec(dllexport) 
#else 
#define RLOG_DECL __declspec(dllimport) 
#endif 


namespace rlog { 
... 
    RLOG_DECL extern RLogChannel *_RLDebugChannel; 
    RLOG_DECL extern RLogChannel *_RLInfoChannel; 
    RLOG_DECL extern RLogChannel *_RLWarningChannel; 
    RLOG_DECL extern RLogChannel *_RLErrorChannel; 
... 
}; 


--- (rlog.c) --- 
#define RLOG_DEFINES 
#include "rlog.h" 

namespace rlog { 
... 
    __declspec(dllexport) RLogChannel *_RLDebugChannel = GetGlobalChannel("debug", Log_Debug); 
    __declspec(dllexport) RLogChannel *_RLInfoChannel = GetGlobalChannel("info", Log_Info); 
    __declspec(dllexport) RLogChannel *_RLWarningChannel = GetGlobalChannel("warning", Log_Warning); 
    __declspec(dllexport) RLogChannel *_RLErrorChannel = GetGlobalChannel("error", Log_Error); 
... 
}; 


--- (other .c files) --- 
#include "rlog.h" 

La règle est simple Lorsque vous compilez le dll qui fournit dllexport doit correspondre à la fois la déclaration de symbole et définition.. d'autre part, lorsque le monde extérieur utilise votre bibliothèque -. il doit apparaître comme dllimport symbole

Cordialement, Maciej Jablonski

Questions connexes