Funktionalität in eine lib auslagern



  • Hallo,
    ich bin hier grad am Verzweifeln.

    Ich wollte mein Projekt ein bisschen besser gliedern und dafür eine Funktionalität aus meinem aktuellen Projekt rausziehen, da dies von den verschiedensten Projekten genutzt wird (und im Moment mit Copy-Paste rüber kopiert wurde).

    Dafür hab ich den ganzen Teil in ein eigenes Projekt gesteckt und es als statische Bibliothek kompiliert ("Verwendung von MFC": in einer statischen bib, "Zeichensatz": Multi-Byte, "Laufzeitbibliothek": Multithreaded.Debug-DLL).
    Dieses Projekt ansich ist schon komplexer, bindet selbst auch einige libs ein.
    Es lässt sich auch wunderbar kompilieren.

    Nun wollte ich die ganze lib testen (dass sie sich kompilieren lässt muss ja noch nichts heißen).
    Also habe ich mir nur kurz ein Testprogramm geschrieben, das bis jetzt nur ein Objekt der Lib erstellen und anschließend eine Methode aufrufen soll.
    Hab als zusätzliches Includeverzeichnis den Ordner angegeben, in dem die .h-Datei der lib liegt.
    Unter Linker als zusätzliches Bibliotheksverzeichnis habe ich den /Debug Ordner angegeben, in dem die .lib liegt und diese .lib habe ich bei Zusätzliche Abhängigkeiten hinzugefügt.

    Im Programm an sich steht nun

    #include <meinelib.h>
    ...
    [cpp]MeineLib* test = new MeineLib();
    MeineLib->funktionsname();
    

    Jetzt hagelt es nur so von Linker-Fehlern.
    Ständig "LNK2019 nicht aufgelöstes Symbol" oder LNK1104, dass er eine Lib nicht öffnen kann die als include in "MeineLib" ist.

    Paar nichtaufgelöste Symbol-Fehler habe ich beseitigen können, in dem ich includes in einigen Klassen (von "MeineLib") Vorwärtsdeklarationen machte und in der cpp-Datei include hinzugefügt habe. Wieso genau es nun geht, verstehe ich nicht.

    Aber an die Fehlermeldung, dass er eine .lib nicht öffnen kann (die in "MeineLib" eingefügt wurde) versteh ich nicht. Es ist in den Projekteinstellungen von "MeineLib" nicht mal ein relativer Pfad dahin.
    Wenn ich den lib-Include in meinem Testprogramm nochmals hinzufüge, bekomme ich tausende von nicht aufgelösten Symbolen wieder.

    Ich könnte kotzen. Bin kurz davor, mein Vorhaben das Programm schöner zu Modularisieren aufzugeben und es wie die Kollegen hier mit copy and paste einfach überall rein zu kopieren....

    Ich weiß, ohne dem Projekt könnt ihr mir wohl auch wenig helfen.

    Aber vielleicht habt ihr Tipps wie man Funktionalität (die auch komplexer sein kann) richtig in eine Lib rauszieht und anschließend einbindet, ohne dass man in Zukunft, wenn man diese Lib in einem Projekt einbindet, sich mit tausenden von Linker-Fehlern rumschlagen muss.



  • hm, ich hab auch das Gefühl, dass er vorkompilierte Header meiner .lib Ignoriert.

    Also habe wie immer in der MeineLib.cpp erst StdAfx.h inkludiert und dann die .h Datei.
    In der .h Datei werden Klassen verwendet, die durch die StdAfx-Datei eigentlich bekannt sind.
    Wenn ich allerdings von meinem Tester aus kompiliere mäckert er rum, dass die Bezeichner nicht bekannt sind.



  • Du verwendest Visual Studio? Dann verwende:

    #pragma comment(lib,"MeinLibName.lib")
    

    am besten ganz oben in deinem Quelltext. Wenn das nicht funktioniert, solltest du wenigstens eine vernünftige Fehlermeldung.



  • .. bekommen.



  • Mal wild geraten: So was passiert mit MSVC gern, wenn man seine Projekte in C:\Dokumente und Einstellungen\... aufbewahrt und vergisst um seine Pfadangaben Anführungszeichen zu machen (etwa (SolutionDir)\\Debug statt "(SolutionDir)\Debug"). Scheinbar parst der das intern ähnlich wie die Shell oder reicht es an sie weiter.

    Allerdings sollte das gar nicht nötig sein. Wenn du in den Projektmappeneinstellungen das Bibliotheksprojekt als Abhängigkeit des Programms einträgst, sollte er (wenn du es ihm nicht ausdrücklich verbietest) die Bibliothek autmatisch in das Programm linken. Bibliotheksverzeichnisse oder zusätzliche Abhängigkeiten werden damit überflüssig, nur das Headerverzeichnis musst du ihm ggf. von Hand beibiegen.



  • danke für die antworten

    Glühbrine schrieb:

    #pragma comment(lib,"MeinLibName.lib")
    

    was macht das genau?
    wo soll das rein? ganz oben in dem test-programm? hab ich gemacht, hat sich nichts verändert.

    seldon schrieb:

    und vergisst um seine Pfadangaben Anführungszeichen zu machen (etwa (SolutionDir)\\Debug statt "(SolutionDir)\Debug")

    das ist überall gemacht.

    seldon schrieb:

    Allerdings sollte das gar nicht nötig sein. Wenn du in den Projektmappeneinstellungen das Bibliotheksprojekt als Abhängigkeit des Programms einträgst

    ist schon drin.

    Es kommen ständig andere Fehler, allein wenn ich nur ein include wo anders hinschreibe und es in meinem Lib-Projekt ohne fehler kompiliert.

    Im Moment ist immer noch der Fehler aktuell, dass der Kompilier mir beim Kompilieren des Testprogramms sagt "fatal error LNK1104: Datei "....lib" kann nicht geöffnet werden". Das ist aber eine lib, die von dem Testprogramm gar nicht eingebunden wird, sondern von dem Projekt der lib die ich erstellt habe.

    Ah kompliziert, ich versuchs mal Beispielhaft zu zeigen:

    Libs die nicht von mir sind:
    a.lib
    b.lib
    c.lib
    d.lib
    
    die lib die ich erstellt habe:
    MeineLib.lib
    die bindet a.lib, b.lib, c.lib und d.lib mit ein.
    Kompiliert perfekt.
    
    TestProgramm
    bindet MeineLib.lib ein
    bekommt Kompilierfehler, dass er a.lib nicht öffnen kann.
    

    ps: ja ich verwende visual studios 2008



  • Xenya schrieb:

    was macht das genau?
    wo soll das rein? ganz oben in dem test-programm? hab ich gemacht, hat sich nichts verändert.

    Sorgt dafür, dass der Compiler sich nicht wundert, wenn er keine Definitionen für Funktionen findet. Im Grunde nur was für faule Leute, die die entsprechenden Bibliotheken nicht auf dem üblichen Wege einbinden wollen.

    Xenya schrieb:

    Im Moment ist immer noch der Fehler aktuell, dass der Kompilier mir beim Kompilieren des Testprogramms sagt "fatal error LNK1104: Datei "....lib" kann nicht geöffnet werden". Das ist aber eine lib, die von dem Testprogramm gar nicht eingebunden wird, sondern von dem Projekt der lib die ich erstellt habe.

    ??? Jetzt bin ich verwirrt. Selbst bei DLLs wird eine *.LIB benötigt, um eine *.LIB zu erstellen, die Verweise auf Funktionen in der DLL enthält.



  • also wenn ich das "Beispiel" von oben verwenden darf um zu erklären was ich will:

    Libs die nicht von mir sind:
    a.lib
    b.lib
    c.lib
    d.lib
    
    die lib die ich erstellt habe:
    MeineLib.lib
    die bindet a.lib, b.lib, c.lib und d.lib mit ein.
    Kompiliert perfekt.
    

    Also ich stelle in MeineLib eine Funktion zur Verfügung, die andere libs benötigt. Im gesamten gesehen ist MeineLib aber eine abgeschlossene Sache.

    Nun will ich, dass andere nur MeineLib einbinden müssen um die Funktionalität zu bekommen und sich nicht mehr mit irgend welchen anderen Dingen (wie a.lib etc) beschäftigen muss.



  • Hallo Xenya ,

    sind die anderen Libs (a.lib, b.lib, ...) denn auch statische Libs?
    Wenn nicht, dann mußt du doch sowieso die externen DLLs ausliefern (und sparst also nichts ein).
    (ich glaube, das wollte dir auch "Der aus dem Westen ..." sagen, aber sein letzter Satz ist etwas unverständlich 😉



  • Th69 schrieb:

    Hallo Xenya ,

    sind die anderen Libs (a.lib, b.lib, ...) denn auch statische Libs?
    Wenn nicht, dann mußt du doch sowieso die externen DLLs ausliefern (und sparst also nichts ein).
    (ich glaube, das wollte dir auch "Der aus dem Westen ..." sagen, aber sein letzter Satz ist etwas unverständlich 😉

    Finde ich nicht.

    *.LIBs sind immer statisch - das heißt, sie werden zur Kompilierzeit in das Modul eingefügt. Es kann sein, dass eine *.LIB einen Verweis auf eine DLL enthält, sodass die DLL dynamisch zur Laufzeit geladen wird, aber die *.LIBs werden immer feste in die Anwendung gefügt.

    Wenn eine statische Bibliothek (*.LIB) in ein Modul integriert wird, kann es kaum passieren, dass andere statische Bibliotheken nicht in der zu gelinkenden Bibliothek zu finden sind, denn diese sind ja schon in der *.LIB. Es kann aller-allerhöchstens passieren, dass eine *.LIB einen nicht-statischen Verweis auf eine DLL enthält, die die Anwendung dann hinterher nicht findet ... aber selbst das geschieht zur Lauf-, nicht zur Kompilierzeit.



  • es wären eh statische libs, die ich einbinde.
    ich denke ich habe irgend was in den Einstellungen oder so falsch gemacht.

    Ich werde das ganze nun nochmals von vorne machen und Schritt für Schritt die Sachen einbinden und immer sofort von einem externen Testprogramm testen.

    Irgend wo mach ich wohl noch was grundlegend falsch, wenn ich eine lib erstelle. Hat wer nen Tipp, wie ich sinnvoll (in Visual Studios) vorgehe, um eine lib so zu gestalten (und so die Konfigurationen zu setzen), dass später keine Probleme (vor allem Linker-Probleme) auftauchen, wenn sie von einem anderen Projekt eingebunden werden (auch auf hinsicht von meinem Problem oben, von libs die in der lib eingebunden werden).
    Über google habe ich noch nichts sinnvolles gefunden, was mir half.

    Ich sehe es schon als wichtig an, dass ich dies lerne gut zu beherrschen, sonst werden Kollegen immer Probleme haben, wenn ich libs baue.



  • Xenya schrieb:

    Hat wer nen Tipp, wie ich sinnvoll (in Visual Studios) vorgehe, um eine lib so zu gestalten (und so die Konfigurationen zu setzen), dass später keine Probleme (vor allem Linker-Probleme) auftauchen, wenn sie von einem anderen Projekt eingebunden werden (auch auf hinsicht von meinem Problem oben, von libs die in der lib eingebunden werden).
    Über google habe ich noch nichts sinnvolles gefunden, was mir half.

    Das Design ist schon die halbe Miete.

    Statische *.LIBs sind dann gut, wenn du nicht vorhast, selbst was am Quellcode zu verändern oder keine Erweiterungen brauchst, damit das Programm funktioniert. Damit sparst du dir das Suchen und Einladen von DLLs, weil du immer nur diese Version gebrauchen musst.

    Eine dynamische Bibliothek ist vor allem bei häufig zu patchenden Anwendungen zu gebrauchen. Anstatt dass du einen Oschi von einer *.EXE mit einer noch gewaltigeren *.EXE überschreibst, löschst du mit vielen kleinen DLLs genau die Fehler aus, die du willst, lässt aber andere Bibliotheken und *.EXEn in Ruhe.

    Visual Studio kann dir da kaum helfen, das bist alles du. Ich würde aber Verweise auf Verweise auf DLLs vermeiden, das verwirrt nur. Sorge lieber dafür, dass deine Bibliotheken von einer Anwendung geladen werden. Bei der statischen Variante brauchst du dich nur darum zu kümmern, dass die *.LIB zur Kompilierzeit vorhanden ist, bei DLLs muss zusätzlich die miterstellte DLL zur Laufzeit zur Verfügung stehen.



  • Hallo Xenia,

    so weit ich weiss, werden lib's nicht gegeneinander gebunden. Der Linker wird ja nur zum binden der *.exe aufgerufen. Die a.lib .. d.lib sind also nicht in MeineLib.lib enthalten.

    Versuch mal folgendes:

    MeineLib.h

    #pragma comment(lib,"a")   
    #pragma comment(lib,"b")   
    #pragma comment(lib,"c")   
    #pragma comment(lib,"d")   
    #pragma comment(lib,"MeineLib")
    

    Eventuell musst Du noch den Pfad zu den einzelnen Lib's angeben

    #pragma comment(lib,"c:\\MeineLibs\\ThirdPartyLibs\\a")
    

    diesen Header includest Du dann in Deiner Testapplikation, damit werden alle benötigten Libs in die *.exe der Applikation eingebunden.

    Herzliche Grüsse
    Walter



  • weicher schrieb:

    so weit ich weiss, werden lib's nicht gegeneinander gebunden. Der Linker wird ja nur zum binden der *.exe aufgerufen. Die a.lib .. d.lib sind also nicht in MeineLib.lib enthalten.

    das heißt ich kann es gar nicht so machen, dass ich eine Funktionalität so "zusammenpacke", dass in einem anderen Projekt dann nur noch diese lib eingebunden werden muss? Ich muss also von jedem der es verwenden will verlangen, dass er die anderen libs auch mit in sein Projekt einfügt?
    Oh man, gefällt mir nicht so 😞
    Ich bin wohl zu Java verwöhnt und wollte es auch nun so konfortabel wie möglich machen, dass Funktionalitäten die von mehr Projekten benötigt wird, alle schön eigenständig sind, so dass sie ohne viel Probleme und Aufwand in allen Projekten eingebunden werden können. Dachte sowas kann ich mit libs machen.

    weicher schrieb:

    #pragma comment(lib,"c:\\MeineLibs\\ThirdPartyLibs\\a")
    

    Ja, so hat es funktioniert, dass er zumindest kompiliert.
    Aber nun kommt die Meldung, dass eine .dll dieser lib nicht gefunden wurde (wenn ich es nicht mit pragma comment mache, sondern die lib direkt in den Projekteigenschaften einbinde, kommt das gleiche).
    Anscheinend doch eine .dll (oben meinte ich ja, dass alles statische .dll - ist mir bis jetzt nicht aufgefallen, da ich nur eine .lib einbinde).

    Habe von den Projekteingenschaften und Einbindungen nun alles von dem alten Programm, wo die Funktionalität mit drin war, in meine lib kopiert aber die Fehlermeldung geht nicht weg. weiß auch wo die .dll liegt aber selbst in dem Projekt wos funktioniert hat, wird niergends darauf verlinkt.
    Alles relevante dürfte so gut wie gleich sein zwischen dem alten Projekt in der die Funktionalität funktionierte und meiner neu erstellten lib - ja der Unterschied ist im großen und ganzen nur, dass es eine statische lib ist und das andere nicht, liegts daran?
    Wie muss ich die .dll bekannt machen?

    Am liebsten würde ich die ganzen .libs die ich in meiner lib einbinde auflösen und direkt in das Projekt schreiben. Das geht aber leider nicht.

    Kann mal kurz erklären was das für libs sind:
    Mit einem externen Programm (das hier in der Firma verwendet wird), kann man xml-Schemas bauen. Zur Kommunikation über C++ erstellt es 4 Visualstudios Projekte mit der Darstellung des XML-Schemas (die Projekte die es erstellt sind statische libs).
    Diese 4 libs machen grad auch gar keinen Ärger.
    Dazu muss noch eine weitere lib eingebunden werden, das Hauptprogramm für die XML-libs. Das ist das Projekt, dass mich grad in den Wahnsinn treibt. Diese lib ist anscheinend eine .dll und die wird nicht gefunden.

    Vielleicht hilft euch die Information was, um mein Problem zu erkennen.

    Danke



  • Xenya schrieb:

    .
    Diese 4 libs machen grad auch gar keinen Ärger.
    Dazu muss noch eine weitere lib eingebunden werden, das Hauptprogramm für die XML-libs. Das ist das Projekt, dass mich grad in den Wahnsinn treibt. Diese lib ist anscheinend eine .dll und die wird nicht gefunden.

    Wie der aus dem Westen schon gesagt hat: Beim Erstellen einer DLL wird auch eine LIB erstellt. Die LIB musst du zur Kompilierzeit angeben, dafür brauchst du zu diesem Zeitpunkt keine DLL. Aber die DLL muss zur Laufzeit des Programmes vorhanden sein, sonst wird das nix.



  • Glühbirne schrieb:

    Xenya schrieb:

    .
    Diese 4 libs machen grad auch gar keinen Ärger.
    Dazu muss noch eine weitere lib eingebunden werden, das Hauptprogramm für die XML-libs. Das ist das Projekt, dass mich grad in den Wahnsinn treibt. Diese lib ist anscheinend eine .dll und die wird nicht gefunden.

    Wie der aus dem Westen schon gesagt hat: Beim Erstellen einer DLL wird auch eine LIB erstellt. Die LIB musst du zur Kompilierzeit angeben, dafür brauchst du zu diesem Zeitpunkt keine DLL. Aber die DLL muss zur Laufzeit des Programmes vorhanden sein, sonst wird das nix.

    Ja das klingt logisch.

    Als Systemvariable liegt der Ordner der .dll unter der Variable Path aber nicht vor (habe auch keine Adminrechte, dass ich ihn hinzufügen könnte).
    Das heißt, irgend wo in den Projekteinstellungen des alten Projektes muss festgelegt sein, wo er die .dll finden kann - sonst würde dieses Programm ja auch nicht gehen. Finde die Einstellung aber nicht.

    Ich habe die .dll-Datei einfach mal in einen Ordner geworfen, der in der Path-Variable vorhanden war. Dann ging es auch - zumindest bis er einmal ein Objekt erstellen wollte, dass dort implementiert ist. Dann kommt ein Laufzeitfehler, wegen einer Zugriffsverletzung beim Lesen an Position 0x00000000.



  • Xenya schrieb:

    Ich habe die .dll-Datei einfach mal in einen Ordner geworfen, der in der Path-Variable vorhanden war. Dann ging es auch - zumindest bis er einmal ein Objekt erstellen wollte, dass dort implementiert ist. Dann kommt ein Laufzeitfehler, wegen einer Zugriffsverletzung beim Lesen an Position 0x00000000.

    Hört sich eher so an, als ob ein Fehler in der DLL ist. Wenn er startet, ist das ein gutes Zeichen, das zeigt, dass die *.LIB eingebunden und die DLL gefunden wird.

    Du solltest die DLL npch einmal debuggen.



  • Habe mittlerweile herausgefunden, wie die dll beim anderen Code geladen wird. Der code wird von einer Entwicklungsumgebung aufgerufen. In diesen Ordner haben die einfach die dll reingeworfen. Da das Programm auch in dem Ordner wo es ausgeführt wird nach dll-Dateien sucht, findet er sie.

    Dass er versucht auf den Speicher 0 zuzugreifen liegt nicht an der .dll würd ich sagen. Vom anderen code aus geht es mit dieser dll ja wunderbar, ohne abzustürzen.

    Genaueres zu dem Problem:
    Bin mit dem Debugger durch. Er ruft eine Methode in einer der statischen Bibliothken auf. Dort versucht er ein Objekt einer Klasse die wohl in der .dll implementiert ist auf dem Stack zu erstellen. Der Debugger springt da nicht rein (da es eine fremde .dll ist, wird der Debugger die Vorgänge dadrin nicht verfolgen können, weshalb ich nicht verfolgen kann, wo es genau knallt. er kommt auf jeden Fall nicht darüber hinweg, das Objekt zu erstellen).

    Ich weiß grad echt nicht weiter. Da löst man ein kleines Problem, freut sich weiter gekommen zu sein und schon kommt das nächste. Ich fang an C++ zu hassen 😞

    Aber bei dem Problem werdet ihr mir wohl nicht helfen können, müsstet wahrscheinlich das komplette Projekt sehen.

    Ich geh jetzt heim, vielleicht löst sich das Problem ja von allein Übernacht *hust*



  • Bei C++-DLLs musst du gut auf Kompatibilität achten. Also ob die Import-Bibliothek wirklich die richtige ist, ob gleiche CRT-Konfigurationen (C-Runtime) verwendet werden, und vor allem ob die Compiler die gleichen sind.

    C-DLLs sind hier etwas flexibler, da das ABI in C standardisiert ist.



  • Hallo Xenia,

    Ich muss also von jedem der es verwenden will verlangen, dass er die anderen libs auch mit in sein Projekt einfügt?
    Oh man, gefällt mir nicht so 😞

    Wenn Du für jede Deiner Libraries so einen Header mit den #pragma comment (lib, ...) machst ist das doch kein Problem. Wenn jemand Deine Lib benutzen will, muss er einfach den entsprechenden Header includen und alles ist erledigt.

    Ein #pragma comment (lib, ...) kann auch in verschiedenen Headern die gleiche Lib "einbinden" da beisst sich nichts, die Lib wird trotzdem nur eimal zur App gelinkt.

    Natürlich müssen die Libraries für jeden Entwickler verfügbar sein.

    Da Du #pragma comment(lib, ...) verwendest kannst Du auch in den Properties in VS unter Linker->General Additional Library Directories den Folder mit den Libs angeben, dann kannst Du den Pfad in den #pragma comment(lib, ...) weglassen.

    Herzliche Grüsse
    Walter



  • Ich habe nun das Problem gefunden.
    Waren ganz versteckte Einstellungen im Projekt.

    Vielen Dank für eure Erklärungen, Erfahrungen und Tipps.
    Ich glaub, ich habe einiges daraus gelernt und hoffe, dass ich nun besser an die Modularisierung meiner Projekte rangehen kann.

    Dass im Hauptprogramm die libs, die ich in den libs verwende auch noch in den zusätzlichen Bibliotheksverzeichnissen stehen müssen, finde ich zwar doof (weil es meist mit verbundenem Ärger für die Anwender der lib verbunden ist) aber ich werde meinen libs immer eine ReadMe beilegen, in denen steht, wass sie alles einbinden müssen.

    Nochmals vielen Dank!!!!


Anmelden zum Antworten