2017-07-20 3 views
1

Ich sah Flussdiagramm zu verstehen, wie Makefiles wirklich funktionieren, aber ich bin immer noch zu 100% zu kämpfen, um zu verstehen, was vor sich geht.Das Verständnis von Makefiles

Ich habe eine main.cpp-Datei, die auf eine Funktion aufruft, die in function.h und function.cpp definiert ist. Dann habe ich das Makefile gegeben:

main: main.cpp function.o 
    g++ main.cpp function.o -o main 

mainAssembly: main.cpp 
    g++ -S main.cpp 

function.o: function.cpp 
    g++ -c function.cpp 

clean: 
    rm -f *.o *.S main 

linkerError: main.cpp function.o 
    g++ main.cpp function.o -o main 

Was ist los? Was ich soweit verstehe ist, dass wir function.cpp kompilieren, was sich in eine Objektdatei verwandelt? Warum ist das notwendig?

Ich weiß nicht, was der mainAssembly Teil wirklich tut. Ich habe versucht, die g ++ - Flags zu lesen, aber ich habe immer noch Schwierigkeiten zu verstehen, was das ist. Besteht das nur darin, main.cpp mit den Headern zu kompilieren? Sollten wir main nicht auch in eine Objektdatei konvertieren?

Ich denke, main einfach ist Haupt genannt alles zusammen in eine exe Verknüpfung? Und ich bin völlig verloren auf was clean und linkerError versuchen, zu tun. Kann mir jemand helfen zu verstehen, was vor sich geht?

Antwort

2

Das Flussdiagramm mehr verwirrt, als es erklärt, wie es unnötig kompliziert erscheint. Jeder Schritt ist eigentlich ganz einfach isoliert, und es hat keinen Sinn, sie alle in einem Diagramm zu stauen.

Denken Sie daran, eine Makefile erstellt einfach eine Abhängigkeitskette, eine Reihenfolge der Operationen, die es zu folgen versucht, wobei die Datei auf der linken Seite von den Dateien auf der rechten Seite abhängt.

Hier ist Ihr erster Teil, in dem function.o ist das Produkt vonfunction.cpp:

function.o: function.cpp 
    g++ -c function.cpp 

Wenn function.cpp ändert, dann wird die .o Datei neu erstellt werden muß. Dies ist vielleicht unvollständig, wenn function.h vorhanden ist, wie es function.cpp#include könnte, so dass die korrekte Definition ist wahrscheinlich:

function.o: function.cpp function.h 
    g++ -c function.cpp 

Nun, wenn Sie sich fragen, warum Sie eine einzelne .cpp in einer einzigen Datei .o bauen würde, sollten Programme in einem viel größeren Maßstab. Sie möchten nicht jede Quelldatei jedes Mal neu kompilieren, wenn Sie etwas ändern, sondern nur die Dinge kompilieren, die direkt von Ihren Änderungen betroffen sind. Die Bearbeitung von function.cpp sollte sich nur auf function.o und nicht auf main.o auswirken, da dies nichts miteinander zu tun hat. Die Änderung function.h könnte sich jedoch auf main.o wegen einer Referenz in main.cpp auswirken. Es hängt davon ab, wie Dinge mit #include referenziert werden.

Dieser Teil ist ein wenig seltsam:

mainAssembly: main.cpp 
    g++ -S main.cpp 

Das ist nur den Code kompilierte Assembly für main.cpp Dumps aus. Dies ist ein optionaler Schritt und ist nicht notwendig, um die endgültige ausführbare Datei zu erstellen.

Dieser Teil Schinken-fistedly baut die aus zwei Teilen:

main: main.cpp function.o 
    g++ main.cpp function.o -o main 

Ich sage das, weil normalerweise Sie alle .cpp Dateien .o kompilieren würde und verknüpfen Sie dann die .o-Dateien zusammen mit Ihrer libstdc++ Bibliothek und jede Andere Shared Libraries verwenden Sie mit einem Tool wie ld, dem Linker. Der letzte Schritt bei einer typischen Kompilierung ist das Verknüpfen, um eine binäre ausführbare Datei oder Bibliothek zu erstellen, obwohl g++ dies stillschweigend für Sie ausführt, wenn Sie wie hier angesprochen werden.

Ich denke, es gibt viel bessere Beispiele als das, was Sie hier haben. Diese Datei ist nur voller Verwirrung.

+1

Vielen Dank! Kannst du nochmal erklären, was du gemeint hast, als du function.o neu definiert hast? Wollen Sie sagen, dass wir vielleicht function.h einbinden müssen, falls function.cpp es in seinen Code aufnimmt? Wie würde eine bessere Compilation genau aussehen? –

+0

[Diese Antwort auf Makefiles] (https://stackoverflow.com/questions/1484817/how-do-i-make-a-simple-makefile-for-gcc-on-linux) sieht viel konventioneller aus. Jede '.h' Datei, die Sie * gemacht haben *, könnte als eine Abhängigkeit aufgelistet werden. Sie können das im '$ (HEADERS)' Teil dieses Beispiels sehen. – tadman

+0

Lies 'x: y z' als" die Erstellung der Datei x hängt von den Dateien y und z ab ". Später haben Sie vielleicht etwas wie "a: x z", wo das heißt "creating a hängt von x und z ab", was bedeutet, dass es auch indirekt von "y" abhängt, weil "x" das tut. Das ist, wo dieses Flussdiagramm wirklich batty wird, wenn diese Abhängigkeiten akkumulieren. Es ist wie "Sandwich: Brot Thunfisch Senf" und dann später "Mittagessen: Sandwich Salat", wo Ihr Mittagessen endet indirekt abhängig von Brot, Thunfisch und Senf. – tadman