Da es sich um ein Unix-Programm handelt, haben die ausführbaren Dateien keine Erweiterungen.
Es ist zu beachten, dass root-config
ist ein Dienstprogramm, das die richtigen Kompilierungs- und Linking-Flags und die richtigen Bibliotheken für die Erstellung von Anwendungen gegen Root bereitstellt. Das ist nur ein Detail, das sich auf die ursprüngliche Zielgruppe dieses Dokuments bezieht.
Mach mich zum Baby
oder Du vergisst nie das erste Mal, dass du gemacht wurdest
Eine einführende Diskussion über make und wie man ein einfaches makefile schreibt
Was ist Make? Und warum sollte mich das interessieren?
Das Werkzeug namens Machen Sie ist ein Manager für Build-Abhängigkeiten. Das heißt, er kümmert sich darum, zu wissen, welche Befehle in welcher Reihenfolge ausgeführt werden müssen, um Ihr Softwareprojekt aus einer Sammlung von Quelldateien, Objektdateien, Bibliotheken, Headern usw. usw. - von denen sich einige möglicherweise kürzlich geändert haben - in eine korrekte, aktuelle Version des Programms zu verwandeln.
Eigentlich kann man Make auch für andere Dinge verwenden, aber darüber werde ich nicht sprechen.
Ein triviales Makefile
Angenommen, Sie haben ein Verzeichnis, das Folgendes enthält: tool
tool.cc
tool.o
support.cc
support.hh
und support.o
die abhängen von root
und sollen in ein Programm namens tool
und nehmen Sie an, dass Sie an den Quelldateien herumgeschraubt haben (d. h. die vorhandenen tool
ist jetzt veraltet) und möchte das Programm kompilieren.
Um dies selbst zu tun, könnten Sie
-
Prüfen Sie, ob entweder support.cc
o support.hh
ist neuer als support.o
und wenn ja, führen Sie einen Befehl wie
g++ -g -c -pthread -I/sw/include/root support.cc
-
Prüfen Sie, ob entweder support.hh
o tool.cc
sind neuer als tool.o
und wenn ja, führen Sie einen Befehl wie
g++ -g -c -pthread -I/sw/include/root tool.cc
-
Prüfen Sie, ob tool.o
ist neuer als tool
und wenn ja, führen Sie einen Befehl wie
g++ -g tool.o support.o -L/sw/lib/root -lCore -lCint -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lTree -lRint \
-lPostscript -lMatrix -lPhysics -lMathCore -lThread -lz -L/sw/lib -lfreetype -lz -Wl,-framework,CoreServices \
-Wl,-framework,ApplicationServices -pthread -Wl,-rpath,/sw/lib/root -lm -ldl
Puh! Was für eine Anstrengung! Man muss sich eine Menge merken und es gibt viele Möglichkeiten, Fehler zu machen. (BTW-- die Einzelheiten der hier gezeigten Befehlszeilen hängen von unserer Softwareumgebung ab. Diese hier funktionieren auf meinem Computer).
Sie können natürlich auch einfach alle drei Befehle jedes Mal ausführen. Das würde funktionieren, ist aber für ein umfangreiches Programm (wie DOGS, dessen Kompilierung auf meinem MacBook mehr als 15 Minuten in Anspruch nimmt) nicht gut geeignet.
Stattdessen könnten Sie eine Datei namens makefile
wie diese:
tool: tool.o support.o
g++ -g -o tool tool.o support.o -L/sw/lib/root -lCore -lCint -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lTree -lRint \
-lPostscript -lMatrix -lPhysics -lMathCore -lThread -lz -L/sw/lib -lfreetype -lz -Wl,-framework,CoreServices \
-Wl,-framework,ApplicationServices -pthread -Wl,-rpath,/sw/lib/root -lm -ldl
tool.o: tool.cc support.hh
g++ -g -c -pthread -I/sw/include/root tool.cc
support.o: support.hh support.cc
g++ -g -c -pthread -I/sw/include/root support.cc
und tippen Sie einfach make
in der Befehlszeile. Dadurch werden die drei oben beschriebenen Schritte automatisch ausgeführt.
Die Zeilen ohne Einrückungen haben hier die Form "Ziel: Abhängigkeiten" und sagen Sie Make, dass die zugehörigen Befehle (eingerückte Zeilen) ausgeführt werden sollen, wenn eine der Abhängigkeiten neuer ist als das Ziel. Das heißt, die Zeilen mit den Abhängigkeiten beschreiben die Logik dessen, was neu erstellt werden muss, um Änderungen in verschiedenen Dateien zu berücksichtigen. Wenn support.cc
Änderungen, die bedeuten, dass support.o
wiederaufgebaut werden muss, aber tool.o
kann in Ruhe gelassen werden. Wenn support.o
Änderungen tool
muss wieder aufgebaut werden.
Die Befehle, die mit jeder Abhängigkeitslinie verbunden sind, sind mit einem Tabulator (siehe unten) versehen und sollten das Ziel ändern (oder zumindest berühren, um die Änderungszeit zu aktualisieren).
Variablen, eingebaute Regeln und andere Goodies
An diesem Punkt erinnert sich unser Makefile einfach an die Arbeit, die getan werden muss, aber wir mussten immer noch jeden einzelnen benötigten Befehl in seiner Gesamtheit herausfinden und eingeben. Das muss nicht so sein: Make ist eine mächtige Sprache mit Variablen, Funktionen zur Textmanipulation und einer ganzen Reihe von eingebauten Regeln, die uns diese Arbeit sehr erleichtern können.
Variablen erstellen
Die Syntax für den Zugriff auf eine make-Variable lautet $(VAR)
.
Die Syntax für die Zuweisung an eine Make-Variable lautet: VAR = A text value of some kind
(oder VAR := A different text value but ignore this for the moment
).
Sie können Variablen in Regeln wie dieser verbesserten Version unseres Makefiles verwenden:
CPPFLAGS=-g -pthread -I/sw/include/root
LDFLAGS=-g
LDLIBS=-L/sw/lib/root -lCore -lCint -lRIO -lNet -lHist -lGraf -lGraf3d -lGpad -lTree -lRint \
-lPostscript -lMatrix -lPhysics -lMathCore -lThread -lz -L/sw/lib -lfreetype -lz \
-Wl,-framework,CoreServices -Wl,-framework,ApplicationServices -pthread -Wl,-rpath,/sw/lib/root \
-lm -ldl
tool: tool.o support.o
g++ $(LDFLAGS) -o tool tool.o support.o $(LDLIBS)
tool.o: tool.cc support.hh
g++ $(CPPFLAGS) -c tool.cc
support.o: support.hh support.cc
g++ $(CPPFLAGS) -c support.cc
die etwas besser lesbar ist, aber immer noch viel Tipparbeit erfordert
Make-Funktionen
GNU make unterstützt eine Vielzahl von Funktionen, um auf Informationen aus dem Dateisystem oder andere Befehle auf dem System zuzugreifen. In diesem Fall sind wir interessiert an $(shell ...)
das zur Ausgabe des/der Argumente(s) expandiert, und $(subst opat,npat,text)
die alle Instanzen von opat
avec npat
im Text.
Dies können wir ausnutzen:
CPPFLAGS=-g $(shell root-config --cflags)
LDFLAGS=-g $(shell root-config --ldflags)
LDLIBS=$(shell root-config --libs)
SRCS=tool.cc support.cc
OBJS=$(subst .cc,.o,$(SRCS))
tool: $(OBJS)
g++ $(LDFLAGS) -o tool $(OBJS) $(LDLIBS)
tool.o: tool.cc support.hh
g++ $(CPPFLAGS) -c tool.cc
support.o: support.hh support.cc
g++ $(CPPFLAGS) -c support.cc
was einfacher zu tippen und viel besser lesbar ist.
Beachten Sie, dass
- Wir geben immer noch ausdrücklich die Abhängigkeiten für jede Objektdatei und die endgültige ausführbare Datei an
- Wir mussten die Kompilierungsregel für beide Quelldateien explizit eingeben
Implizite und Musterregeln
Wir würden im Allgemeinen erwarten, dass alle C++-Quelldateien gleich behandelt werden, und Make bietet drei Möglichkeiten, dies anzugeben:
- Suffix-Regeln (in GNU make als veraltet angesehen, aber aus Gründen der Abwärtskompatibilität beibehalten)
- implizite Regeln
- Musterregeln
Es sind implizite Regeln eingebaut, von denen einige im Folgenden erläutert werden. Musterregeln werden in der folgenden Form angegeben
%.o: %.c
$(CC) $(CFLAGS) $(CPPFLAGS) -c $<
was bedeutet, dass Objektdateien aus C-Quelldateien erzeugt werden, indem der gezeigte Befehl ausgeführt wird, wobei die Variable "automatic" $<
expandiert zum Namen der ersten Abhängigkeit.
Eingebaute Regeln
Make hat eine ganze Reihe von eingebauten Regeln, die bedeuten, dass ein Projekt sehr oft durch ein sehr einfaches Makefile kompiliert werden kann, in der Tat.
Die in GNU make eingebaute Regel für C-Quelldateien ist die oben gezeigte. Ähnlich erzeugen wir Objektdateien aus C++-Quelldateien mit einer Regel wie $(CXX) -c $(CPPFLAGS) $(CFLAGS)
.
Einzelne Objektdateien werden mit $(LD) $(LDFLAGS) n.o $(LOADLIBES) $(LDLIBS)
aber das wird in unserem Fall nicht funktionieren, weil wir mehrere Objektdateien verknüpfen wollen.
Von eingebauten Regeln verwendete Variablen
Die eingebauten Regeln verwenden einen Satz von Standardvariablen, die es Ihnen ermöglichen, lokale Umgebungsinformationen anzugeben (z. B. wo die Root-Include-Dateien zu finden sind), ohne alle Regeln neu schreiben zu müssen. Diejenigen, die für uns am ehesten interessant sind, sind:
CC
-- den zu verwendenden C-Compiler
CXX
-- den zu verwendenden C++-Compiler
LD
-- den zu verwendenden Linker
CFLAGS
-- Kompilierungsflag für C-Quelldateien
CXXFLAGS
-- Kompilierungsflags für C++-Quelldateien
CPPFLAGS
-- Flags für den c-Präprozessor (enthalten typischerweise Dateipfade und auf der Befehlszeile definierte Symbole), die von C und C++ verwendet werden
LDFLAGS
-- Linker-Flags
LDLIBS
-- zu verknüpfende Bibliotheken
Ein grundlegendes Makefile
Indem wir die Vorteile der eingebauten Regeln nutzen, können wir unser Makefile vereinfachen:
CC=gcc
CXX=g++
RM=rm -f
CPPFLAGS=-g $(shell root-config --cflags)
LDFLAGS=-g $(shell root-config --ldflags)
LDLIBS=$(shell root-config --libs)
SRCS=tool.cc support.cc
OBJS=$(subst .cc,.o,$(SRCS))
all: tool
tool: $(OBJS)
$(CXX) $(LDFLAGS) -o tool $(OBJS) $(LDLIBS)
tool.o: tool.cc support.hh
support.o: support.hh support.cc
clean:
$(RM) $(OBJS)
distclean: clean
$(RM) tool
Wir haben auch mehrere Standardziele hinzugefügt, die spezielle Aktionen durchführen (wie das Bereinigen des Quellverzeichnisses).
Beachten Sie, dass make, wenn es ohne ein Argument aufgerufen wird, das erste in der Datei gefundene Ziel verwendet (in diesem Fall all), aber Sie können das zu erhaltende Ziel auch benennen, wodurch make clean
entfernen Sie in diesem Fall die Objektdateien.
Wir haben immer noch alle Abhängigkeiten fest kodiert.
Einige mysteriöse Verbesserungen
CC=gcc
CXX=g++
RM=rm -f
CPPFLAGS=-g $(shell root-config --cflags)
LDFLAGS=-g $(shell root-config --ldflags)
LDLIBS=$(shell root-config --libs)
SRCS=tool.cc support.cc
OBJS=$(subst .cc,.o,$(SRCS))
all: tool
tool: $(OBJS)
$(CXX) $(LDFLAGS) -o tool $(OBJS) $(LDLIBS)
depend: .depend
.depend: $(SRCS)
$(RM) ./.depend
$(CXX) $(CPPFLAGS) -MM $^>>./.depend;
clean:
$(RM) $(OBJS)
distclean: clean
$(RM) *~ .depend
include .depend
Beachten Sie, dass
- Es gibt keine Abhängigkeitslinien mehr für die Quelldateien!?!
- Es gibt eine seltsame Magie im Zusammenhang mit .depend und depend
- Wenn Sie das tun
make
entonces ls -A
sehen Sie eine Datei namens .depend
die Dinge enthält, die wie Zeilen mit Make-Abhängigkeiten aussehen
Weitere Lektüre
Bugs und historische Hinweise kennen
Die Eingabesprache für Make ist weißraumabhängig. Insbesondere, die auf die Abhängigkeiten folgenden Aktionszeilen müssen mit einem Tabulator beginnen . Aber eine Reihe von Leerzeichen kann genauso aussehen (und es gibt tatsächlich Editoren, die Tabulatoren stillschweigend in Leerzeichen umwandeln oder umgekehrt), was dazu führt, dass eine Make-Datei zwar richtig aussieht, aber trotzdem nicht funktioniert. Dies wurde schon früh als Fehler erkannt, aber ( Die Geschichte lautet ) wurde es nicht behoben, weil es bereits 10 Benutzer gab.
(Dies wurde aus einem Wiki-Beitrag kopiert, den ich für Physik-Diplomstudenten geschrieben habe).
14 Stimmen
.EXE, also ist es definitiv Windows. Wenn ich es mir recht überlege... der Pfad ist im Unix-Stil. Wahrscheinlich verwendet er Mingw-32.
3 Stimmen
Seufz. Ich nehme an, man muss die Grundlagen eines jeden Berufs erlernen, auch wenn man sie nie anwenden wird. Man muss einfach verstehen, wie die Dinge funktionieren. Die Chancen stehen allerdings gut, dass Sie immer in einer IDE wie Eclipse entwickeln werden. Sie werden hier eine Antwort auf Ihren einfachen Ein-Zeilen-Fall bekommen, und es gibt jede Menge Web-Tutorials, aber wenn Sie in die Tiefe gehen wollen, kommen Sie um das O'Reilly-Buch nicht herum (das gilt auch für die meisten SW-Themen). amazon.com/Managing-Projects-Make-Nutshell-Handbooks/dp/ Kaufen Sie ein Exemplar aus 2. Hand bei amazon, half.com, betterworldbooks eBay
3 Stimmen
Der von @Dennis gepostete Link ist nicht mehr verfügbar, aber das gleiche Material findet sich in diesem archive.org-Seite .
0 Stimmen
Ich bevorzuge die Ideen dieser Person. ( hiltmon.com/blog/2013/07/03/ ) Die Projektstruktur kann leicht an die jeweiligen Bedürfnisse angepasst werden. Und ich stimme auch zu, dass die Zeit der Entwickler für andere Dinge als automake/autoconf verwendet werden sollte. Diese Werkzeuge haben ihren Platz, aber vielleicht nicht für interne Projekte. Ich bin dabei, ein Skript zu erstellen, das eine solche Projektstruktur erzeugen wird.
0 Stimmen
@GuilhermeSalomé Danke, ich glaube, das ist die beste einfache und vollständige Anleitung.
0 Stimmen
Gute Frage. Ich werde wahrscheinlich eine Antwort schreiben wollen, wenn ich die Zeit dazu finde.