PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [VC] DLL erstellt, aber LIB und EXP fehlen


Silpion
2007-05-12, 00:23:11
Hallo,

ich habe mal wieder ein Problem.

Eine Solution im Visual Studio 2005 besteht u.A. aus drei DLL Projekten:
A
B, benötigt A
C, benötigt A, B

A und B linken problemlos, mit folgendem Output
A: dll, exp, lib
B: dll

Das Linken von C scheitert daran, dass keine B.lib gefunden wird. Diese wird laut dem BuildLog von B auch nie erzeugt, die Zeile
"Creating library (...)\B.lib and object (...)\B.exp"
fehlt. Bei A ist sie vorhanden.

Ich bin die letzten Stunden die Project Properties akribisch durchgegangen, es gibt keinen Unterschied. Insbesondere ist der Eintrag unter Linker/Advanced/ImportLibrary gleich.

Ein kurz hinzugefügtes Test-DLL Projekt ohne Abhängigkeiten mit einer Dummy-Klasse erzeugt ebenfalls keine LIB-Datei.

dllexport-Kommandos sind nirgends vorhanden, es soll einfach alles exportiert werden. Wenn ich es recht verstanden habe, ist dies normalerweise auch der Fall (die Aufteilung in DLLs entsteht nachträglich).

Weshalb funktioniert dies bei A, aber nicht bei B oder anderen? *verzweifel*

SgtTynis
2007-05-12, 11:47:09
dllexport-Kommandos sind nirgends vorhanden, es soll einfach alles exportiert werden. Wenn ich es recht verstanden habe, ist dies normalerweise auch der Fall (die Aufteilung in DLLs entsteht nachträglich).

Wenn kein dllexport (dem bekannten "Deckelspeck" __declspec(dllexport)) geschieht muss ein .def File existieren, indem gesagt wird was wie exportiert werden soll...IMHO passiert sonst gar nichts in Bezug auf Export.

Silpion
2007-05-12, 12:05:37
Hmm... eine .def Datei wäre schon wesentlich praktischer als im kompletten Code überall __declspec(dllexport) einzufügen.

Aber wenn ich die MSDN-Library richtig verstanden habe, muss trotzdem überall __declspec(dllimport) verwendet werden. *verwirrt guck*

Gast
2007-05-12, 12:15:43
Hmm... eine .def Datei wäre schon wesentlich praktischer als im kompletten Code überall __declspec(dllexport) einzufügen.

Aber wenn ich die MSDN-Library richtig verstanden habe, muss trotzdem überall __declspec(dllimport) verwendet werden. *verwirrt guck*

Nein Nein, du mußt keine __declspec(dllimport) Anweisung schreiben. Das steht letztendlich in der Lib, ob es sich um DLL Imports handelt.

Übrigens hast du mit DEF-Dateien ein Problem, sobald C++ Code verwendet wird. Allerdings sollte es auch Tools geben, die aus *.obj oder *.o die Symbole herauslesen und daraus eine DEF-Datei machen.

Was, gibt es nicht? Na dann frage mich nochmal, falls du soetwas brauchst.

Silpion
2007-05-12, 14:17:02
Ah gut, danke.

Reiner C Code wird an keiner Stelle verwendet, die DLL enthält nur Klassen. Hmm... dann wohl doch überall dllexport, müsste mit Suchen und Ersetzen recht schnell gehen, auch wenn ich damit zig Dateien von Projektmitarbeitern ändern muss.

Dabei gibt es dann noch das Problem, dass das Projekt weiterhin auch unter Linux kompilieren muss, d.h. das dllexport müsste dann unsichtbar sein. Mir schwebt momentan sowas wie überall:class WINDLL LalalaUnter Linux dann -DWINDLL, unter Windows -DWINDLL=__declspec(dllexport).

Sollte damit alles funktionieren oder gibt es noch weitere Fettnäpfchen?

Gast
2007-05-12, 15:00:39
So sollte das funktionieren.

Das Problem mit C++ Klassen ist deren Namensdekoration (<-- kein Verschreiber). Einen C++ Funktions- oder Membernamen kann man nicht so einfach in ein DEF-File schreiben, weil man die Namensdekoration evtl. nicht kennt. Ausserdem ist diese nicht portabel. Die macht jeder C++ Compiler nämlich anders.

Ein Beispiel:

Aus

MImageDirectoryEntry::addValue(const void* pValue);

macht der GCC dieses:

_ZN20MImageDirectoryEntry8addValueEPKv

Und so muss der Name dann auch in der DEF-Datei stehen.

Also bei Klassenexport lieber mit __declspec(dllexport) arbeiten.

Silpion
2007-05-12, 15:42:56
Okay, dann mach ich mich mal an die Arbeit es überall einzufügen.

Noch ein paar kurze Fragen: Im DLL-Projekt ist WINDLL zu __declspec(dllexport) definiert. Muss es in den Projekten, die diese DLL nutzen auch so definiert sein oder leer? Bzw. ist dies die Stelle, an der es ggf. als dllimport definiert sein muss, wenn keine Import-Library zur Verfügung stehen sollte? Wie sieht es mit Forward-Deklarations aus? Wenn im Header "class Lala;" steht und diese erst im Source inkludiert wird, muss dort auch das WINDLL hinzugefügt werden?

Vielen Dank schonmal, habe heute einiges über DLLs gelernt. :up:

Gast
2007-05-12, 16:05:57
Im DLL-Projekt ist WINDLL zu __declspec(dllexport) definiert. Muss es in den Projekten, die diese DLL nutzen auch so definiert sein oder leer? Bzw. ist dies die Stelle, an der es ggf. als dllimport definiert sein muss, wenn keine Import-Library zur Verfügung stehen sollte? Wie sieht es mit Forward-Deklarations aus? Wenn im Header "class Lala;" steht und diese erst im Source inkludiert wird, muss dort auch das WINDLL hinzugefügt werden?

Punkt 1. Man muß dllimport verwenden, wenn du mit dllexport gearbeitet hast. Der Grund ist, das diese beiden Anweisungen mit in die Signatur aufgenommen werden, das gilt auch bei Typ- und Klassnnamen. Übrigens habe ich weiter oben Quatsch erzählt, man müsse dllimport nicht verwenden. Das gilt nämlich nur, wenn man mit einem DEF-File gearbeitet hat.

Zu Punkt 2. ist eindeutig zu sagen, dass du auch bei Forward-Deklarationen dllimport oder dllexport verwenden musst. Der Grund ist schon in Punkt 1. beantwortet. Die Signaturen würden sonst nicht passen ;).

Silpion
2007-05-12, 16:19:45
Hmm... dann gibt es Probleme, wenn eine DLL sowohl Funktionen aus einer anderen importiert als auch eigene exportiert. D.h. ich brauche zwei Stichworte, wie WINDLLimp und WINDLLexp.

Wie sieht es aus, wenn in einer Klasse eine "friend class Lala;" steht, ich nehme an hier muss es dann auch eingefügt werden?

Gast
2007-05-12, 19:47:47
Hmm... dann gibt es Probleme, wenn eine DLL sowohl Funktionen aus einer anderen importiert als auch eigene exportiert. D.h. ich brauche zwei Stichworte, wie WINDLLimp und WINDLLexp.

Wie sieht es aus, wenn in einer Klasse eine "friend class Lala;" steht, ich nehme an hier muss es dann auch eingefügt werden?

Du kannst doch alles trotzdem alles in WINDLL packen. Bei make definierst du einmal dllexport fürs Bauen der DLL und dllimport für Programme die die DLL verwenden wollen.

Für friend gilt das gleiche, richtig.

Silpion
2007-05-12, 20:21:51
Ich meinte z.B. falls es DLLs D1 und D2 gibt und D1 von D2 benötigt wird.
Dann muss D1 beim Bauen auf Export stehen. Wenn dann D2 gebastelt wird, muss ich zum einen WINDLL auf Import stellen, weil aus D1 importiert wird, aber auch auf Export, weil D2 exportieren soll.

Hmm... dann brauche ich nicht WINDLLimp und WINDLLexp, aber WINDLL1 für D1 und WINDLL2 für D2. Also ein Define für jede DLL.

Chris Lux
2007-05-13, 09:16:20
Ich meinte z.B. falls es DLLs D1 und D2 gibt und D1 von D2 benötigt wird.
Dann muss D1 beim Bauen auf Export stehen. Wenn dann D2 gebastelt wird, muss ich zum einen WINDLL auf Import stellen, weil aus D1 importiert wird, aber auch auf Export, weil D2 exportieren soll.

Hmm... dann brauche ich nicht WINDLLimp und WINDLLexp, aber WINDLL1 für D1 und WINDLL2 für D2. Also ein Define für jede DLL.
hi,
typischerweise macht man das folgendermaßen:

// windows related
#ifdef _WIN32 // sind wir auf einer windows platform

#ifdef _MSC_VER // sind wir unter visual studio
#ifdef _WINDLL // bauen wir gerade die dll
#define PLAH_EXPORT __declspec(dllexport)
#else // _WINDLL
#define PLAH_EXPORT __declspec(dllimport)
#endif // _WINDLL
#else // _MSC_VER
#pragma error "unsupported compiler"
#endif // _MSC_VER

#endif // _WIN32


das _WINDLL wird fuer das dll projekt automatisch erzeugt und deutet darauf hin, ob man gerade die dll baut. ist es nicht definiert baut man gerade etwas, was die dll als abhaengigkeit benutzt, also muss dort das import definiert sein. vor seine klassen schreibt man einfach das PLAH_EXPORT und das sollte es dann auch gewesen sein...

Gast
2007-05-13, 14:00:28
Ich meinte z.B. falls es DLLs D1 und D2 gibt und D1 von D2 benötigt wird.
Dann muss D1 beim Bauen auf Export stehen. Wenn dann D2 gebastelt wird, muss ich zum einen WINDLL auf Import stellen, weil aus D1 importiert wird, aber auch auf Export, weil D2 exportieren soll.

Hmm... dann brauche ich nicht WINDLLimp und WINDLLexp, aber WINDLL1 für D1 und WINDLL2 für D2. Also ein Define für jede DLL.

Du mußt ja nicht WINDLL schreiben. Du kannst für jede DLL auch ein eigenes Präfix für Im- und Export verwenden. Z.B.: D1DLL, D2DLL etc.