Die Sache mit den Bibliotheken



  • Hallo ihr Lieben,

    ich sinniere gerade über die Möglichkeiten eine Bibliothek zu verwenden.

    Zum Einen gibt es den Unterschied, dass ich einfach mittels #include etwas einfügen kann, wie ich es z.B. von Boost kenne. Was mich dann nur wundert: Wo liegt das dann? Ich finde z.B. in dem Verzeichnis /usr/lib ein paar Dateien libbosst_[..] .
    Ich nehme an, dass der Verzeichnisname lib für Library, also Bibliothek steht.

    Zum Anderen gibt es die GSL, die ich auch einfach mittels #include<gsl/...> einbinden kann, allerdings finde ich die ganzen header Dateien auch in /usr/include/gsl , während ich ich /usr/include nichts zu boost finde. 😕

    Dann geht das ganze weiter, dass ich bei boost keine Tags im Makefile setzen muss, während ich bei der GSL beim Linken -lm -lgsl -lgslcblas mitgeben muss, während der erste Buchstabe l (kleines L) für Library, also wieder Bibliothek, steht. Wieso muss ich das bei Boost nicht machen?

    Und schließlich gibt es noch den Unterschied, dass ich ganze Verzeichnisse angeben muss, wo die Bibliothek liegen soll. Ich nehme an, dass dieser Fall daher kommt, dass ich eine Bibliothek nicht über den Paketmanager von Linux installiert habe und der Compiler sie deshalb nicht dort findet, wo er standardmäßig mittels #include<..> sucht.

    Ich schätze, dass Teile der Antwort den Unterschied zwischen einer Shared und einer Static Library bezeichnen, doch finde ich die unterschiedliche Anwendung noch etwas ominös.

    Viele Grüße,
    -- Klaus.





  • Wenn du libs aus dem Packetmanager hollst sind diese im Ordner:

    /usr/include
    /usr/lib
    

    Wenn du libs von fremden Quellen installierst sind diese im Ordner:

    /usr/local/include
    /usr/local/lib
    

    Das macht aber keinen unterschied, weil beide Ordner durchsucht werden.

    Boost brauch nur für wenige Libs gelinkt werden:
    http://www.boost.org/doc/libs/1_55_0/more/getting_started/unix-variants.html#header-only-libraries

    Dabei deine Fragen nichts mit C++ zu tun haben.



  • exploit126 schrieb:

    Dabei deine Fragen nichts mit C++ zu tun haben.

    Okay Yoda. 🙂

    Dann soll ein Moderator doch bitte diesen Thread in den richtigen Bereich verschieben.

    Aber meine Frage mit den Tags ist nach wie vor offen, z.B. wie für die GSL hier zum Linken angegeben

    -lgsl -lgslcblas -lm
    

    Sind das Überreste aus C oder warum muss das beim Linken nochmal explizit angeben, während es z.B. bei Boost genügt einfach die nötigen Header Dateien einzubinden.

    Gruß,
    -- Klaus.



  • Klaus82 schrieb:

    -lgsl -lgslcblas -lm
    

    Sind das Überreste aus C oder warum muss das beim Linken nochmal explizit angeben, während es z.B. bei Boost genügt einfach die nötigen Header Dateien einzubinden.

    Gruß,
    -- Klaus.

    boost ist größtenteils headeronly, d.h. die Headerdateien reichen.
    GSL braucht neben den Deklerationen auch die Definitionen im Sourcecode, weswegen du die vorkompilierten Sourcecodedateien brauchst.


  • Mod

    Das -lm ist aber tatsächlich ein Überrest aus C und in C++ nicht nötig.



  • SeppJ schrieb:

    Das -lm ist aber tatsächlich ein Überrest aus C und in C++ nicht nötig.

    Das hatte noch nie was mit C zu tun, das ist ein Überrest aus historischen GCC-Designentscheidungen für ihren C-Compiler.


  • Mod

    überrest schrieb:

    Das hatte noch nie was mit C zu tun, das ist ein Überrest aus historischen GCC-Designentscheidungen für ihren C-Compiler.

    Nein. Das kommt zwar nicht aus dem C-Sprachstandard, aber war schon so lange bevor der GCC entstanden ist. Also aus Tradition 🙂



  • Also ich verstehe es noch nicht so recht:

    Ich stelle mir das z.B. so vor, dass ich bei einer static library den Quellcode quasi in mein Programm kopiere, welches dann kompiliert wird. D.h. ich benötige lediglich die header Dateien, dass der Kompiler weiß woher er die Quellcodeschnipsel kriegt?

    Bei einer shared library werden eher die vorkompilierten Funktionen an dieser Stelle des Quellcodes aufgerufen. D.h. ich benötige keine header Dateien mehr, weil mich der genaue Quellcode der implementierten Funktionen eh nicht interessiert - bestenfalls die Deklaration für das Interface.

    Dafür muss der Kompiler wissen, dass er die Funktionen aufrufen soll? Also die als Bibliothek zusammengefassten Funktionen? D.h. wenn ich beim Linken -lgsl angebe, dann wird die Bibliothek, also das Paket libgsl (oder so ähnlich) durchsucht nach den vorkompilierten Funktionen?

    Gruß,
    -- Klaus.


  • Mod

    Klaus82 schrieb:

    Ich stelle mir das z.B. so vor, dass ich bei einer static library den Quellcode quasi in mein Programm kopiere, welches dann kompiliert wird.

    Nein, hier ist schon falsch. Die Bibliotheken sind schon fertig übersetzt. In den Headern stehen nur Deklarationen. Ob das dann statisch oder dynamisch gelinkt wird, tut dabei nichts zur Sache.

    Beispiel: Quellcode der Bibliothek libfoo:
    foo.cpp

    int foo(int i)
    {
      return 2*i;
    }
    

    Das wird spätestens beim Installieren der Bibliothek (traditionell bei Open Source Software) oder auch vorher vom Hersteller (traditionell bei Closed Source Software) oder von jemand anderem (typisches Vorgehen bei Linuxdistributionen) übersetzt. Da kommt dann eine statische Bibliothek wie (ich nutze hier typische Linuxnamenskonvention) lifoo.a und/oder eine dynamische Bibliothek wie libfoo.so heraus. In beiden Fällen steht in der Bibliotheksdatei übersetzter Quellcode von der Funktion drin, also das was du erhalten würdest, wenn du den Code selber übersetzen würdest (aber nicht linken, das geht ja noch nicht). Beispielsweise mit gcc:

    g++ foo.cpp -c -o foo.o
    

    Und dann passend zusammen geschnürt für das Bibliotheksdateiformat (welches übrigens nicht sehr anspruchsvoll ist).

    Damit man die Funktione korrekt benutzen kann, muss der Compiler wissen, wie sie aufzurufen ist. Das muss er wissen, damit er kontrollieren kann, ob du die Funktion im Quellcode richtig benutzt hast (z.B. ob du foo auch wirklich mit nur einem Argument benutzt und das auch ein int (oder kompatibles) ist) und um den korrekten Code für den Aufruf zu erzeugen. Dazu reicht die Signatur der Funktion, die er aus der Deklaration bekommt:
    foo.h

    #ifndef FOO_H
    #define FOO_H
    
    int foo(int);
    
    #endif
    

    Wenn er dann dein Programm übersetzt hat, dann steht an der Stelle wo foo() aufgerufen wird auch nur das: Dass da eine Funktion namens int foo(int) aufgerufen werden soll. Der Linker nimmt dann (entweder statisch oder dynamisch) deinen Programmcode und den Programmcode aus der Bilbiothek und setzt das zu einem Gesamtprogramm zusammen. Das heißt (in der Regel) nicht, dass er den Code der Funktion foo inline am Ort des Aufrufs einsetzt, sondern dass er die übersetzten Funktionen alle in eine Datei schreibt (die Executable) und an die Stelle der Aufrufe schreibt, wohin in der Datei an der Stelle gesprungen werden soll.

    Bei Bibliotheken die nur Header haben (vieles von Boost, aber auch die STL aus der C++-Standardbibliothek) ist hingegen tatsächlich aller Code in den Headern. Oder es ist gar kein Code, weil es nur ein paar typedefs oder ähnliches sind (zum Beispiel cstddef). Dazu muss der Code natürlich inline sein, um doppelte Definitionen zu verhindern. Dies kommt meistens vor bei Templates, die auch automatisch inline sind. Da fällt auch gleich auf, dass es sich bei der STL und großen Teilen von Boost gerade eben um Sammlungen von Templates handelt, deswegen sind die auch Header only. Warum Templates (fast) immer inline sein müssen hat technische Gründe, wie aus Templates Code erzeugt wird.


Anmelden zum Antworten