Dumme Frage: Lib die von zwei weiteren. libs abhängt, includes richtig setzen



  • Hallo!

    Eigentlich gibt es ja keine dummen Fragen, aber diese ist dumm und ich stell sie trotzdem.

    Ich habe ein Projekt (Visual Studio) das eine .LIB (ab jetzt LibA) erzeugt. Für diese Lib sind 2 (LibB und LibC) weitere Libs notwendig, das Projekt hängt also von beiden ab. In jeweils beiden Unter-Libs (LibB und LibC) verwende ich Klasse ABC. Die Header-Datei der Klasse ABC ist jeweils nur inkludiert, die entsprechende .H und .CPP-Datei ist nicht im Projekt von LibB und LibC enthalten, wird also nicht kompiliert. Wenn ich jetzt LibB und LibC benutzen möchte (in LibA), müsste doch eigentlich ein Fehler entstehen, sehe ich das richtig? Weil die H wird zwar inkludiert, die Klasse aber nicht kompiliert, right? Muss ich die Dateien der Klasse zu jedem Projekt (LibB, LibC) hinzufügen und kompilieren?

    Vielen Dank!


  • Mod

    Nein, nein und nein. Zum Compilieren reicht die Kenntnis, wie die Klassen/Funktionen aussehen, also das was in den Headern steht. Erst wenn du ein ausführbares Programm erzeugen möchtest, braucht der Linker die konkreten Objektdateien. Deine Verwirrung rührt vermutlich daher, dass du Compilieren und Linken nicht als die getrennten Vorgänge wahrnimmst die sie sind. Wenn du immer alles in einem Durchgang machst, dann entsteht der Eindruck, dass es so nicht geht.



  • Danke!

    Also heisst das, wenn ich in meine LibA die .h und .cpp kompiliere und linke ist automatisch für LibB und LibC die Definition der Klasse vorhanden? LibA verwendet ja LibB und LibC.


  • Mod

    jensen001 schrieb:

    Danke!

    Also heisst das, wenn ich in meine LibA die .h und .cpp kompiliere und linke ist automatisch für LibB und LibC die Definition der Klasse vorhanden? LibA verwendet ja LibB und LibC.

    Nein, normalerweise nicht. Die LibB und LibC werden normalerweise erst gebraucht, wenn du mit der LibA ein Programm erstellen willst. Um die LibA selber zu erstellen sind LibB und LibC in der Regel nicht nötig (es sei denn, du erstellst sie auf sehr spezielle Weise).



  • Danke!

    Ich glaube aber es gibt ein kleines Missverständnis...ich meine eher die Frage nach der Klasse ABC die in LibB und LibC eingesetzt wird. Muss die jeweils im Projekt LibB und LibC zum Buildvorgang hinzugefügt werden, also zum Projekt? Oder reicht es diese in den Buildvorgang von LibA welches LibB und LibC benutzt (statische .lib Datei).

    Vielen Dank!


  • Mod

    Du brauchst die konkreten Libs erst ganz ganz ganz am Ende wenn wirklich etwas ausführbares (die Bibs alleine sind nicht ausführbar!) erstellt wird. Außer du hast vor, den Code in den Bibs irgendwie statisch zusammenzubauen, was aber eher ungewöhnlich wäre.

    Guck dir mal an, was Linken bedeutet und was der Unterschied zum Compilieren ist.



  • Das weiß ich doch!

    Immer noch ein Missverständnis.

    Es geht hier um die Klasse ABC, deren .h-datei jeweils in LibB und LibC inkludiert wird. Muss die .h und .cpp-Datei in LibB und LibC mit in den Buildvorgang eingeschlossen werden?



  • Wenn Du die Klasse in LibB und LibC benutzt - ja. Auch eine Lib wird ja am Ende des Build-Vorgangs dem Linker übergeben, wenn Du dann die ABC.cpp - Datei nicht mitlinkst, sollte der Linker meckern - wenn wie gesagt die Klasse benutzt wird.



  • Um das mal zu verdeutlichen:
    Nehmen wir an, du hast in der main einen Aufruf der Funktion libA() und im Sourcecode von liba.lib einen Aufruf der Funktion von ABC::foo. Die Klasse ABC steckt in abc.cpp, main in main.cpp. Compiler und Linker machen dann folgendes:

    Beim erstellen von liba.lib:
    - er compiliert die ganzen libA*.cpp's zu libA*.obj's.
    - der Linker baut alles zu der .lib zusammen. Dabei werden die Aufrufe von Symbolen, die in den libA*.obj's nicht zu finden sind, als symbolische Aufrufe stehen gelassen (z.B. ABC::foo)

    Beim Erstellen der .exe:
    - compilieren der abc.cpp und main.cpp zu abc.obj und main.obj
    - Linken von abc.obj, main.obj und liba.lib, hierbei findet der Linker den Aufruf von liba() in main.obj und liba() selbst in liba.lib -> wird zusammengelötet. Der Aufruf von ABC::foo steht ja noch so in liba.lib, der Linker findet in abc.obj den Code dazu -> wird auch verknüpft.

    Ist vermutlich jetzt nicht technisch einwandfrei beschrieben, aber es bringt die idee denke ich rüber.



  • Bist Du sicher?
    Ich hätte glatt behauptet, dass der Linker LibA nicht erstellt, wenn ein Aufruf von ABC::foo() drin ist, ABC::foo() (in ABC.obj) aber nicht mitgelinkt wird?!


  • Mod

    Belli schrieb:

    Bist Du sicher?
    Ich hätte glatt behauptet, dass der Linker LibA nicht erstellt, wenn ein Aufruf von ABC::foo() drin ist, ABC::foo() (in ABC.obj) aber nicht mitgelinkt wird?!

    Probiers aus.



  • Sagen wir ich habe 2 .cpp Dateien: A.cpp und B.cpp und in A.cpp eine Funktion functionA(), die functionB() aus B.cpp aufruft:

    // A.cpp
    #include "B.h"
    
    void functionA() {
       functionB();
    }
    

    Wenn ich diese 2 Dateien jetzt zu einer lib foo.lib kompiliere, dann werden doch gar keine konkreten Adressen eingefuegt, oder? In Pseudosytnax sieht die erstellte Lib dann doch so aus:

    B.o:
    functionB() { ... }
    
    A.o:
    functionA() {
       call [Todo:InsertAdressOfFunctionBhere]
    }
    

    Dh die konkrete Adresse von functionB wurde doch noch NICHT eingefuegt in A.o, oder?

    Das wird dann erst gemacht, wenn ich die foo.lib in einem Projekt einbinde, das zu einer .exe gebaut wird, oder?


  • Mod

    Ja!

    Wie oft muss man diese Frage in diesem Thread noch beantworten? Probiert es doch aus, wenn ihr es nicht glaubt!



  • SeppJ schrieb:

    Ja!

    Wie oft muss man diese Frage in diesem Thread noch beantworten? Probiert es doch aus, wenn ihr es nicht glaubt!

    Wie soll man das ausprobieren? Die.o dissemblieren und versuchen den asm Code zu verstehen?



  • SeppJ schrieb:

    Ja!

    Wie oft muss man diese Frage in diesem Thread noch beantworten? Probiert es doch aus, wenn ihr es nicht glaubt!

    Moment. In pumuckls Posting klang das so, als wuerden nur die Adresse NICHT aufgeloest werden, wenn er das Zeug nicht findet. In meinem Beispiel findet er aber die B.o, also koennte er beim Linken in functionA() doch gleich die echte Adresse von functionB() eintragen?



  • SeppJ schrieb:

    Belli schrieb:

    Bist Du sicher?
    Ich hätte glatt behauptet, dass der Linker LibA nicht erstellt, wenn ein Aufruf von ABC::foo() drin ist, ABC::foo() (in ABC.obj) aber nicht mitgelinkt wird?!

    Probiers aus.

    Hab ich gemacht. Es ist so, wie Du und pumuckl gesagt haben:
    Wenn ich meine Lib bilde, braucht ABC.cpp nicht mitgelinkt zu werden, muss dann aber beim Erstellen der exe-Datei vorhanden sein (bzw. die ABC.obj).
    Wenn ich ABC.cpp schon in mein Lib-Projekt hineinpacke, benötige ich später beim Erstellen einer exe - Datei nur noch die Lib.lib.



  • Moment. In pumuckls Posting klang das so, als wuerden nur die Adresse NICHT aufgeloest werden, wenn er das Zeug nicht findet. In meinem Beispiel findet er aber die B.o, also koennte er beim Linken in functionA() doch gleich die echte Adresse von functionB() eintragen?

    Definiere finden !

    Normal sollte er in Project A (also das project fuer A.lib) nur die Definition (Header) der funktion finden, nicht die Implementation (die source).

    Fügst Du in Project A, die source zu (B.cpp oder so, mit als Quelle) klar dan compiliert er den code mit in die A.Lib.
    Aber spaetestens, wenn in einem Project A.lib und B.lib gleichzeitig verendest (linkst) schmeisst dir das der Linker um die Ohren (double Symbols).
    Aehnlich wenn die Implementation im header steht und nicht inlined wird ...

    Wenn Du eine Lib baust, linkt der Linker ned wirklich, sondern fasst nur die Object-Dateien zu einem Archiv(.a) zusammen.
    Erst der Linker wenn du ein binary(exe/dll binary/so) baut, ersetzt er die symbole mit den Richtigen Adressen der Implementation ....
    Und erst dann mault er dann die typischen Symbolfehler an:
    double symbols und unresolved symbols !

    Fazit:
    Deine ABC.h darf jede Lib kennen (im include Path verfuegbar) und verwenden.
    Implementiert sollte sie nur in einer Lib sein (nur eine lib sollt ABC.cpp in den Sourcen haben).
    Nebeneffekt ist, alle libs die ABC verwenden, erzwingen dann das auch die lib mit zugelinkt wird, die ABC.cpp enthaelt, sonst gibts unresolved symbols ...

    Warum man libs trennt, wenn man die nur zusammen verwenden kann ?
    macht man normal nich ^^
    Aber man koennte gestaffelte Abhanegigkeiten haben. LibB verwendet LibA.
    LibB muss mit LibA immer zusammengelinkt werden.
    Aber libA kann auch ohne LibB verwendet werden ...
    Dann wuerde das trennen Sinn machen ...

    Ciao ...



  • [quote="RHBaum"]

    Fügst Du in Project A, die source zu (B.cpp oder so, mit als Quelle) klar dan compiliert er den code mit in die A.Lib.
    Aber spaetestens, wenn in einem Project A.lib und B.lib gleichzeitig verendest (linkst) schmeisst dir das der Linker um die Ohren (double Symbols).

    Dazu hab ich noch mal folgendes gemacht:
    a.cpp:

    #include <iostream>
    
    class A
    {
    	public:
    		void melde() const;
    };
    
    void A::melde() const
    {
    	std::cout << "bin da\n";
    }
    

    mylib.cpp:

    class A
    {
    	public:
    		void melde() const;
    };
    
    int sum(int a, int b)
    {
    	A x;
    	x.melde();
    
    	return a + b;
    }
    

    test.cpp:

    int sum(int a, int b);
    
    int main()
    {
    	sum(3, 5);
    }
    

    zuerst die lib mit a.cpp gebildet, dann ließ sich test.exe mit
    cl /EHsc test.cpp mylib.lib erstellen.
    Aber auch
    cl /EHsc test.cpp a.cpp mylib.lib
    führte zum Ergebnis ...
    die doppelten Symbole scheinen nicht zu stören, so dass es aussieht, als ob es eine gute Wahl wäre, a.cpp direkt mit in die lib zu nehmen, damit die lib alleine benutzbar ist.


  • Mod

    Und dann macht liba ein kritisches Sicherheitsupdate und jeder der die mylib benutzt, muss auf ein Update von dir warten oder die mylib selber neu bauen, anstatt einfach wie üblich die Laufzeitbibliothek der liba auszutauschen.



  • Das verstehe ich nicht ...
    es macht doch keinen Unterschied, ob ich zur Benutzung von mylib.lib die Dateien mylib.lib und a.obj liefern muss, oder a.obj schon in mylib.lib eingebaut habe und dann nur mylib.lib liefern muss?
    Es scheint mir einfacher zu handlen, wenn alles benötigte in mylib.lib drin ist (vorausgesetzt natürlich, es gibt nicht doch Linkerprobleme, wenn a.obj noch in einer anderen .lib ist, glaube ich aber nach meinem og Test nicht).

    Edit:
    Ich mach nun nicht ständig mit irgendwelchen *.lib s rum, außer denen der WinAPI, aber es ist mir noch nicht untergekommen, dass ich zusätzlich zu einer *.lib noch *.obj Dateien mitlinken muss, damit die lib überhaupt benutzbar ist.
    Dabei muss es ja nicht mal um eine Klasse gehen, für einfache Funktionsimplementierungen in eigenen *.cpp s würden doch die gleichen Regeln gelten, also müsste man ständig über so was stolpern?


Log in to reply