Linken von Standardbibliotheken



  • Hallo wie einige sicher wissen, beschäftige ich mich seit neustem mit der Programmierung und damit CPP. Ich möchte natürlich auch verstehen, was passiert. Nachdem man programmiert hat.(compilieren und linken). Ich könnte natürlich einfach auf eine IDE klicken und fertig, aber ich möchte es wirklich verstehen. Später wenn ich große Projekte programmiere möchte ich ja nicht immer alles compilieren und linken, da dies ja unter Umständen sehr lange dauern kann, deswegen beschäftige ich mich jetzt von Anfang an mit Makefils. Ich schreibe meinen Code in VIM und schreibe das Makefile in dem ich mit compilieren und linke. Das funktioniert auch alles wunderbar. Jetzt meine Frage. Kann man auch C++ Standardbibliotheken mit linken? Beispiel wenn ich ein einfaches

    #include<iostream>
    int main(){
      cout << “Hallo Welt!\n“;
      return 0;
    }
    

    Ich möchte jetzt so compilieren und linken in meinem Makefile, dass es. definitiv bei dem anderen läuft, ohne das er Bibliotheken installieren muss, sondern alles vorhanden ist.

    Gibt es Befehle um zu schauen welche Bibliotheken in meinem programmierten Programm vorhanden sind? Kann man dIe dann auch Linken?

    Hoffe konnte erklären, was genau ich möchte.

    Gruß Betzi



  • Ich gehe jetzt mal einfach davon aus dass du GCC oder Clang als Compiler verwendest bzw. einen der sich ausreichend ähnlich verhält wie GCC oder Clang.

    Linken musst du die benötigten Bibliotheken immer. Die Frage ist nur ob du sie statisch oder dynamisch linkst.

    Die für C++ quasi immer nötige "libgcc" kannst du mit -static-libgcc statisch linken, die C++ Standard-Library mit -static-libstdc++.
    Siehe https://gcc.gnu.org/onlinedocs/gcc/Link-Options.html

    Alles was statisch gelinkt ist ist dann Teil des produzierten Binaries und muss daher nicht auf dem System vorhanden sein wo das Binary ausgeführt werden soll. Alles was dynamisch gelinkt ist muss auf dem System verfügbar sein, und zwar in mindestens der Version die zum Bauen verwendet wurde.

    Dann bleibt noch die libc. Auf *NIX Systemen ist es sehr üblich die libc dynamisch zu linken, selbst wenn man alles andere statisch linkt. Wenn du dennoch auch die libc statisch linken willst, dann brauchst du zusätzlich noch den switch -static. Damit nimmst du dir aber dann auch die Möglichkeit irgendwelche dynamischen libraries zu laden - ob jetzt durch linken mit diesen dynamischen libraries oder explizit über dlopen. Und natürlich gibt es in der libc immer wieder kritische updates. Diese bekommst du dann auch nur wenn du das Build-System updatest, dein Programm neu baust und neu auslieferst.

    Und alles weitere musst du sowieso extra angeben wenn du das Makefile selbst schreibst, da wird nichts automatisch dazugelinkt.

    Wichtig dabei auch: Per Default bekommst du eine Dependency auf die Version der libc/libgcc/libstdc++ die auf dem System drauf ist auf dem du gebaut hast. D.h. selbst wenn du ausser der libc alles statisch linkst, kann es sein dass dein Programm auf älteren Systemen nicht läuft. Die sicherste Möglichkeit das zu vermeiden ist sich eine VM bzw. einen Container zu basteln auf dem das älteste System mit der ältesten libc drauf ist das du unterstützen willst. Es wohl geht auch über diverse switches bzw. mit einem speziell für ältere libc Versionen gebauten Compiler. Aber eine VM/einen Container zu verwenden ist relativ einfach und sehr sicher. Und ermöglicht dir natürlich das gebaute Programm auch gleich auf dem alten System zu testen.



  • Ok danke, also ich habe nun folgendes

    HalloWeltMain.cpp

    #include<iostream>
    using namespace std;
    int main(){
            cout << "Hallo Welt!\n";
            return 0;
    }
    

    Main Makefile

    HalloWeltMain: HalloWeltMain.o
            g++ -o HalloWelt HalloWeltMain.o
    
    HalloWeltMain.o: HalloWeltMain.cpp
            g++ -c HalloWeltMain.cpp -static-libgcc -static-libstdc++
    
    clean: 
            rm -f *.o
            rm -f HalloWelt
    

    Ist das so korrekt?? ich meine funktionieren tut es. Er kompliert, linkt und das Programm kann ausgeführt werden, aber habe ich es korrekt geschrieben??

    WIe gesagt bin Anfänger, sorry :(.

    Würdet ihr davon abraten diese Standardbibliotheken zu linken??? gibt es ein Befehl, der über eine CPP Datei drüber geht und anzeigt, welche Bibliotheken alles genutzt werden??

    Danke und liebe Grüße

    Betzi

    PS: SOrry wenn solche einfachen Fragen euch langweilen, aber ich würde es gerne direkt jetzt am Anfang verstehen und nicht erst, wenn es unübersichtlich wird 😞


  • Mod

    Von statischem Linken ist allgemein eher abzuraten, und erst recht von statischem Linken der Standardbibliothek ist ganz dringend abzuraten. Es mag gewisse Ausnahmeszenarien geben wo das sinnvoll ist (daher ist es ja auch generell möglich), aber darauf wirst du mit deinen Anfängerprogrammen nicht stoßen.

    Von was eine bestimmte Executable abhängig ist, kannst du mit dem Linuxkommando ldd herausbekommen. Das ist natürlich nach dem Compilieren, wenn du dir angucken willst, was eine fremde Executable so alles braucht. Vor dem Linken eines selbstgeschriebenen Programms, wenn du die entsprechenden Linkerkommandos schreibst, wird davon ausgegangen, dass du selber weißt, wovon dein Programm abhängt, denn du hast es ja schließlich selber geschrieben. Die Standardbibliotheken der jeweiligen Programmiersprache sind aber bei quasi jeder Toolchain immer automatisch mit dabei und brauchen nicht extra aufgeführt zu werden.

    (Unerwartete Ausnahme: Bei C als Sprache ist traditionell die libm (für mathematische Funktionen aus math.h) nicht dabei)



  • @SeppJ sagte in Linken von Standardbibliotheken:

    Von statischem Linken ist allgemein eher abzuraten, und erst recht von statischem Linken der Standardbibliothek ist ganz dringend abzuraten.

    Hat eigentlich schonmal jemand diesbezüglich Erfahrungen mit einer C-Standardbibliothek wie musl gemacht, die explizit auch für statisches Linken entworfen wurde?

    Es ist schon reizvoll, wenn ein Programm ausschliesslich eine bestimmte CPU-Architektur und einen Linux-Kernel als Abhängigkeit hat und auf Anhieb unter jedem Linux-System läuft.

    Über ein paar Experimente mit einem musl-basierten GCC-Crosscompiler und Programmen auf Hallo-Welt-Niveau bin ich da leider nicht hinausgekommen. War aber schon nett, dass dasselbe Programm für ARM auf dem Raspi mit Glibc wie auch auf dem Router mit OpenWrt/Musl "einfach lief" (vermute auch unter Android/Bionic, jedoch nicht getestet). Hat schon seine Daseinsberechtigung - nicht nur in absoluten Ausnahmefällen ... für totale Anfänger aber nicht unbedingt zu empfehlen 😉

    @hustbaer sagte in Linken von Standardbibliotheken:

    Und natürlich gibt es in der libc immer wieder kritische updates. Diese bekommst du dann auch nur wenn du das Build-System updatest, dein Programm neu baust und neu auslieferst.

    Das Problem hat man mit allen Bibliotheken, die man statisch linkt. Allerdings hat die libc die weiteste Verbreitung ist ist daher wohl auch ein beliebtes Angriffsziel, wenn man eine Lücke mit reinkompiliert hat.



  • Ist mein Makefile denn korrekt für das statische einbinden der Standardbibliotheken?

    Das make läuft durch und Programm läuft auch, aber wird es so geschrieben, wie ich es gemacht habe?



  • @Finnegan sagte in Linken von Standardbibliotheken:

    Das Problem hat man mit allen Bibliotheken, die man statisch linkt. Allerdings hat die libc die weiteste Verbreitung ist ist daher wohl auch ein beliebtes Angriffsziel, wenn man eine Lücke mit reinkompiliert hat.

    Vollkommen richtig 🙂



  • @betzi1985 sagte in Linken von Standardbibliotheken:

    Ist mein Makefile denn korrekt für das statische einbinden der Standardbibliotheken?

    Das make läuft durch und Programm läuft auch, aber wird es so geschrieben, wie ich es gemacht habe?

    Keine Ahnung ob es korrekt ist. Und ob "es so geschrieben wird" ist auch so ne Frage... Man kann mit Makefiles alles mögliche anstellen und auch auf sehr unterschiedliche Arten. Soweit ich das mitbekommen gibt es da nicht "den" Standard.

    Was ich dir nur sagen kann ist dass Makefiles mit Hand schreiben eher nur für kleine Projekte geeignet ist. Also grundsätzlich kann man schon auch grössere Projekte mit handgeschriebenen Makefiles machen, aber dann meist so dass das handgeschriebene Makefile diverse Tools verwendet um diverse Hilfsfiles (z.B. Auflistungen von Source-Files oder gar andere Sub-Makefiles) generieren zu lassen. Das ist aber auch alles nicht schön.

    Ich würde dir eher empfehlen die Systeme wie z.B. CMake anzuschauen. Das ist zwar auch alles andere als schön, aber immer noch besser als handgeschriebene Makefiles. Vor allem unterstützt es auch modernere Build-Systeme wie Ninja.



  • @betzi1985 sagte in Linken von Standardbibliotheken:

    Ist mein Makefile denn korrekt für das statische einbinden der Standardbibliotheken?

    Das make läuft durch und Programm läuft auch, aber wird es so geschrieben, wie ich es gemacht habe?

    Nein, du gibst die Libs nicht beim Linkschritt an sondern beim Erzeugen des Objecfiles.



  • @hustbaer sagte in Linken von Standardbibliotheken:

    Ich würde dir eher empfehlen die Systeme wie z.B. CMake anzuschauen. Das ist zwar auch alles andere als schön, aber immer noch besser als handgeschriebene Makefiles. Vor allem unterstützt es auch modernere Build-Systeme wie Ninja.

    Und vor allem unterstützt CMake auch Out-of-Source-Builds. Das bedeutet, du hast deinen Source im Verzeichnis /a/b/c und kannst dann in ein völlig beliebiges Verzeichnis, also z.B. /a/b/d oder auch /e/f kompilieren. Du kannst dann ein Build-Verzeichnis für den Debug-Build machen und eines für den Release-Build. Dann brauchst du die .o-Dateien nicht ins .gitignore zu schreiben und zum Löschen löscht du einfach das komplette Build-Verzeichnis - und braucht nicht wie bei deinem "make clean" aufzupassen, nur die richtigen Dateien zu löschen. Sehr viel besser als die In-Source-Builds!


  • Mod

    @manni66 sagte in Linken von Standardbibliotheken:

    @betzi1985 sagte in Linken von Standardbibliotheken:

    Ist mein Makefile denn korrekt für das statische einbinden der Standardbibliotheken?

    Das make läuft durch und Programm läuft auch, aber wird es so geschrieben, wie ich es gemacht habe?

    Nein, du gibst die Libs nicht beim Linkschritt an sondern beim Erzeugen des Objecfiles.

    Außerdem sollte clean ein phony-Target sein. Aber ist das wirklich die Frage, wie die best-practices beim Schreiben von Makefiles sind?



  • @hustbaer sagte in Linken von Standardbibliotheken:

    Ich würde dir eher empfehlen die Systeme wie z.B. CMake anzuschauen. Das ist zwar auch alles andere als schön, aber immer noch besser als handgeschriebene Makefiles. Vor allem unterstützt es auch modernere Build-Systeme wie Ninja.

    Hey, ich schreibe das erstmal mit der Hand, weil ich verstehen möchte, wie diese Makefiles funktionieren und möchte es erstmal verstehen. Bevor mir ein Tool diese Arbeit abnehmen soll, muss ich erstmal verstehen, was denn genau passiert. CMake, schaue ich mir gerne mal an. Wie gesagt, später werde ich auch natürlich auch eine richtige IDE wie COdeBlock verwenden, aber um erstmal zu verstehen was passiert, möchte ich es gerne per Hand machen. Und erstmal mit 1,2 Dateien ist es einfach, ich will nicht erst in sowas einsteigen, wenn ich viele Dateien habe, dann ist es meistens zu Kompliziert.

    Und was meint ihr mit phony-Target?
    meint Ihr das

    .PHONY: clean
    clean:
    rm *.o



  • @betzi1985 sagte in Linken von Standardbibliotheken:

    Und was meint ihr mit phony-Target?
    meint Ihr das
    .PHONY: clean
    clean:
    rm *.o

    Ja: https://www.gnu.org/software/make/manual/html_node/Phony-Targets.html

    Bevor mir ein Tool diese Arbeit abnehmen soll, muss ich erstmal verstehen, was denn genau passiert.

    Im Prinzip ist es nur "wenn sich Datei x geändert hat, die für y gebraucht wird, dann muss y neu kompiliert werden". Eigentlich guckt make generell auf die Zeitstempel der Dateien und führt Kommandos aus, wenn irgendeine Abhängigkeit neuer ist als das Ziel. Mehr ist das nicht.

    CMake, schaue ich mir gerne mal an.

    Ist relevant, wenn du nicht manuell alle Abhängigkeiten verwalten kannst und dich vor allem nicht damit beschäftigen willst, wann du welche Parameter an den Compiler und Linker übergeben musst (die sich je nach Compilerhersteller auch noch unterscheiden können). Du nennst CMake das Rezept: target xy hängt von diesen und jenen Sourcen und Libraries ab und CMake generiert dann entsprechende Makefiles (oder Dateien für andere Buildsysteme) für dich.

    Und erstmal mit 1,2 Dateien ist es einfach, ich will nicht erst in sowas einsteigen, wenn ich viele Dateien habe, dann ist es meistens zu Kompliziert.

    Für 1-2 Dateien kannst du auch einfach auf Kommandozeile g++ -O2 -Wall -Wextra -o meine-executable source1.cpp source2.cpp eingeben (ggf. noch -l library)



  • @wob

    Ja das mit den geänderten Dateien habe ich gemerkt. Wenn ich mehrmals das Makefile hintereinander ausführe, macht er nicht mehr viel, weil die Dateien sich nicht geändert haben. Ändere ich den Zeitstempel einer Datei mit touch, compiliert er diese wieder neu.

    Also sollte ich mich als Anfänger mit 2,3 Dateien niciht mit sowas beschäftigen?? Ich weiß auch, dass man mit einem Befehl compilieren und linken kann. Habe nur irgendwo mal gelesen, damit man es richtig versteht, soll man alles einzeln per Hand durchführen, aber ok, lasse das dann erstmal



  • @betzi1985 CMake ist auch ein eingenes Monster 🙂

    Bleib erstmal dabei, wenn du am Anfang sowieso keine großen externen Libraries hast und nur eine paar Source-Dateien hast.

    Je größer dein Projekt wird, desto schwieriger wird es, das Makefile aktuell zu halten. Ist zum Beispiel sichergestellt, dass eine Header-Datei von dir für alle .cpp-Dateien, wo dieser verwendet wird, als Abhängigkeit gelistet ist? usw. usf.

    Beschäftige dich später damit, spätestens wenn deine Make-Datei nicht mehr auf eine Bildschirmseite passt.


  • Mod

    Faustregeln:

    1. Es ist ein Übungsprogramm, nur für dich, dass du in deinem Leben vielleicht nur 5-10x übersetzen wirst, und es hat weniger als 5 Dateien -> Tipp die Kommandos selber auf der Konsole. Erstens lohnt es sich nicht, ein Makefile oder anderes Script dafür zu schreiben. Zweitens lernst du so die Compiler- und Linkeraufrufe kennen. Du willst ja schließlich verstehen, was deine Makefiles machen.
    2. Es ist ein ernstes Projekt, an dem du viele Wochen lang arbeiten wirst, und es oft übersetzen wirst, aber es ist nur für dich oder wenige Personen, und es hat weniger als 15 Dateien -> Schreib dir ein Makefile, gerne auch ganz von Grund auf von Hand. So lernst du den Zusammenhang zwischen Makefiles und den Kommandos, die du sonst von Hand tippen würdest. Und du lernst umgekehrt auch wie Makefiles funktionieren, so dass du 3. und 4. besser verstehst.
    3. So wie 2., aber mit mehr als 15 Dateien, oder es kommen auch mal neue Dateien hinzu: Beschäftige dich mit den fortgeschrittenen Features von Makefiles, wie automatische Dependencies, automatische Standardregeln, und so weiter. Damit bleibt das Makefile kurz und überschaubar, so wie im vorherigen Fall.
    4. Es ist ein großes Projekt und soll auch für Leute sein, denen du im Notfall nicht persönlich helfen kannst: Beschäftige dich mit Meta-Buildtools wie den GNU Autotools oder CMake, die das Makefile für den jeweiligen Benutzer automatisch erstellen.

    Bei 3. kannst du auch überlegen, stattdessen gleich zu 4. zu gehen. Make ist ein sehr altes und gewachsenes Programm und man sehr, sehr viel darüber lernen. Aber all das Wissen nützt dir nur etwas, wenn du regelmäßig Makefiles schreibst. Was du nicht tun wirst, denn irgendwann wirst du bei 4. landen. Es besteht auch eine gewisse Gefahr, dass du so gut mit Makefiles umgehen kannst, dass du nie so recht zu 4. kommst, weil dir auch komplizierte Makefiles leicht fallen und du deswegen die Einstiegshürde zu 4. scheust.



  • @SeppJ

    Dankeschön, das ist für mich ein super Anhaltspunkt.



  • @betzi1985 sagte in Linken von Standardbibliotheken:

    Hey, ich schreibe das erstmal mit der Hand, weil ich verstehen möchte, wie diese Makefiles funktionieren und möchte es erstmal verstehen. Bevor mir ein Tool diese Arbeit abnehmen soll, muss ich erstmal verstehen, was denn genau passiert.

    Nein, musst du nicht unbedingt. Du darfst es gerne wollen, aber, bei Seiner Nudeligkeit, verstehen/wissen muss man das nicht. Und normalerweise will man es auch nicht.


Log in to reply