DLL Import von globalen Variablen
-
Hallo,
ich habe ein Problem, eine globale Variable aus einem Namespace einer DLL in einem Modul (weitere DLL) zu importieren. Folgendes Szenario:
Ich will eine Logging-Library verwenden (rlog), die als DLL kompiliert einige Klassen und eben auch Variablen bereitstellt, die sich in einem Namespace befinden:
Header-File rlog.h:
/*! @file rlog.h @brief Defines macros for debug, warning, and error messages. */ // may be useful for checking from configuration files #define CURRENT_RLOG_VERSION 20040503 extern "C" int RLogVersion(); namespace rlog { class RLogChannel; class RLogPublisher; class RLogNode; /*! @enum LogLevel Logging level definitions. */ enum LogLevel { Log_Undef =0, //!< undefined level Log_Critical, //!< critical conditions Log_Error, //!< error conditions Log_Warning, //!< warning conditions Log_Notice, //!< normal, but significant, condition Log_Info, //!< informational Log_Debug //!< debug level messages }; void RLOG_DECL RLogInit(int &argc, char **argv); // Get channel with a particular component name RLOG_DECL RLogChannel *GetComponentChannel(const char *component, const char *path, LogLevel level = Log_Undef); // the global channel receives messages for all components RLOG_DECL RLogChannel *GetGlobalChannel( const char *path, LogLevel level = Log_Undef); #define DEF_CHANNEL(path,level) RLOG_CHANNEL_IMPL(RLOG_COMPONENT, path, level) #define RLOG_CHANNEL(path) RLOG_CHANNEL_IMPL(RLOG_COMPONENT, path, rlog::Log_Undef) #define RLOG_CHANNEL_IMPL(COMPONENT,path,level) \ rlog::GetComponentChannel(STR(COMPONENT),path,level) /* Pre-defined channels, "debug", "warning", and "error". You can of course defined sub-channels based on the predefined types, such as "debug/level1", or whatever. */ extern RLOG_DECL RLogChannel *_RLDebugChannel; extern RLOG_DECL RLogChannel *_RLInfoChannel; extern RLOG_DECL RLogChannel *_RLWarningChannel; extern RLOG_DECL RLogChannel *_RLErrorChannel; [...]In der Header-Datei werden vordefinierte Channels für Debug-Messages bereitgestellt, die mit
extern RLOG_DECL RLogChannel *_RLDebugChannel
definiert werden. Das RLOG_DECL ist das Makro
_declspec(dllexport)
, das angibt, dass diese Variable im Namespace rlog exportiert werden soll.
In meinem eigenen Programm versuche ich nun, mittels der Logging-Lib Debug-Messages auszugeben. Dazu definiert die rlog-Lib Makros
rDebug()
, mit denen Strings auf stderr etc. ausgegeben werden können.
rDebug ist ein Makro, das die Funktion_rMessage( LOGID, rlog::_RLDebugChannel, ##__VA_ARGS__ )aufruft, die wiederum die Variable
rlog::_RLDebugChannelals Referenz braucht. Ich definiere deshalb in meinem Programmteil (der wiederum ne DLL ist):
// RFIDWidget.cpp #include "rlog/rlog.h" #include "rlog/RLogChannel.h" #include "rlog/StdioNode.h" #include <windows.h> #include <winbase.h> #include <QtGui> #include <QtDebug> #include "RFIDWidget.hpp" using namespace rlog; extern StdioNode stdLog; _declspec( dllimport ) rlog::RLogChannel *rlog::_RLDebugChannel; [...] RFIDWidget::RFIDWidget(QWidget* parent) : QWidget( parent ) { rDebug( "RFIDWidget::RFIDWidget()" ); // setupUi(this); // connect( quitButton, SIGNAL(clicked()), this, SLOT( accept() ) ); // connect( bindButton, SIGNAL( clicked() ), this, SLOT( on_bindButton_clicked() ) ); // connect( openButton, SIGNAL( clicked() ), this, SLOT( on_openButton_clicked() ) ); // connect( closeButton, SIGNAL( clicked() ), this, SLOT( on_closeButton_clicked() ) ); } [...]Leider bekomme ich, wenn ich den Debug Channel so deklariere mit
_declspec( dllimport ) rlog::RLogChannel *rlog::_RLDebugChannel;eine Warnung beim Kompilieren, dass eine inkonsistente DLL-Bindung vorliegt:
warning C4273: 'rlog::_RLDebugChannel': Inkonsistente DLL-Bindung.
d:\projekt\work\Tools\test\RFIDTestApp2\common\rlog/rlog.h(136): Siehe vorherige Definition von '_RLDebugChannel'Falls ich das
_declspec (dllimport)ändere in
extern rlog::RLogChannel *rlog::_RLDebugChannel, bekomme ich ein nicht aufgelöstes Symbol beim Linken.
Laut MSDN http://support.microsoft.com/?scid=kb%3Ben-us%3B90530&x=3&y=9 ist der Weg mit
_declspec( dllimport)korrekt beim Zugriff auf globale/Namespace-Variablen aus einer DLL. Deshalb meine Frage, wieso kommt der o.g. Fehler?
Bin für alle Hinweise dankbar,
AlGaN
-
richtig beantworten kann ich es nicht, nur hinweise geben. afaik macht man das an besten mit dllexport und dllimport. nutze doch den präprozessor.
#ifdef DLL_BUILD # define RLOG_DECL __declspec(dllexport) #else # define RLOG_DECL __declspec(dllimport) #endifwird die variable korrekt exportiert? am besten "depency walker" mal nach schauen. ich dachte nämlich das das man nur variablen im globeln scope exportieren kann.
AlGaN schrieb:
Falls ich das
_declspec (dllimport)ändere in
extern rlog::RLogChannel *rlog::_RLDebugChannel, bekomme ich ein nicht aufgelöstes Symbol beim Linken.
rlog-Lib mitgelinkt

AlGaN schrieb:
eine Warnung beim Kompilieren, dass eine inkonsistente DLL-Bindung vorliegt:
http://forum.fachinformatiker.de/c-compiler-ides-apis/56410-inkonsistente-dll-bindung.html
-
Hi miller_m,
danke für Deine Antwort. Mir ist gerade eben aufgefallen, dass in meinem eigenen Projekt (da ebenfalls DLL), auch ein
#define _WINDLLautomatisch vom Qt-Buildsystem (qmake) erzeugt wird, weshalb in der rlog-Headerdatei
common.h
die Zeilen:
#ifdef _WIN32 # ifdef _WINDLL # define RLOG_DECL __declspec(dllexport) # else # define RLOG_DECL __declspec(dllimport) # endif // building/using DLL #else // !_WIN32 # define RLOG_DECL #endifdas falsche __declspec( dllexport ) statt __declspec( dllimport ) deklariert wird. Nachdem ich das geändert habe, linkt alles einwandfrei

Trotzdem danke nochmals,
AlGaNP.S.: Ich würde aber trotzdem gerne wissen, wie es mit der Exportierbarkeit globaler bzw. Variablen aus Namespaces aus DLLs bestellt ist? Falls mich da jemand aufklären könnte, wäre ich dankbar.
-
AlGaN schrieb:
P.S.: Ich würde aber trotzdem gerne wissen, wie es mit der Exportierbarkeit globaler bzw. Variablen aus Namespaces aus DLLs bestellt ist? Falls mich da jemand aufklären könnte, wäre ich dankbar.
Ich würde tippen: Garnicht, oder zumindestens nur Compiler-/Compilerversionsbezogen.
Namensräume sind nicht im Einklang mit C, und DLL-Schnittstellen müssen C-Kompatibel sein um nicht abhängig von Compiler-/Compilerversion zu sein.
cu André
-
Hallo asc,
danke für die Erklärung. Dass DLL-Schnittstellen C-kompatibel sein müssen, habe ich auch schon gelesen. In manchen Quellcodes sieht man deshalb ja, dass die __declspec-Deklarationen folgendermassen deklariert sind:
#define MYLIBAPI extern "C" _ _declspec(dllexport) #define MYLIBAPI extern "C" _ _declspec(dllimport)(o.g. Zeilen stammen aus Jeffrey Richter - Programming Applications for Windows)
D.h. es wird explizit eine C-Schnittstelle exportiert. Allerdings gibt es auch Bibliotheken (wie das von mir verwendete rlog), bei denen das fehlt, d.h. sie exportieren wohl eine C++-Schnittstelle...
Mir geht auch nicht in den Kopf, wie sich die C-Kompatibilität mit Klassen verträgt, die exportiert werden müssen.
Sorry, wenn dass zu naiv klingt, hab bisher nicht so viel mit Windows-DLLs zu tun gehabt,
AlGaN
-
AlGaN schrieb:
Mir geht auch nicht in den Kopf, wie sich die C-Kompatibilität mit Klassen verträgt, die exportiert werden müssen.
Garnicht, zumindestens nicht ohne Kompatibilitätseinschränkungen je nach Compiler etc. zu haben. Es gibt Mittel und Wege auch Klassen Kompatibel zu machen (im Prinzip macht dies z.B. COM), dies schränkt die Programmierung aber ein, beziehungsweise man muss bei der Programmierung zusätzliche Regeln beachten (Ich gehe darauf jetzt aber nicht genauer ein, solche Ausflüge liegen bei mir schon ein Weilchen zurück).