EnglischFranzösischSpanisch

Ad


OnWorks-Favicon

makepp_cookbook - Online in der Cloud

Führen Sie makepp_cookbook im kostenlosen OnWorks-Hosting-Provider über Ubuntu Online, Fedora Online, Windows-Online-Emulator oder MAC OS-Online-Emulator aus

Dies ist der Befehl makepp_cookbook, der im kostenlosen OnWorks-Hosting-Provider mit einer unserer zahlreichen kostenlosen Online-Workstations wie Ubuntu Online, Fedora Online, Windows-Online-Emulator oder MAC OS-Online-Emulator ausgeführt werden kann

PROGRAMM:

NAME/FUNKTION


makepp_cookbook -- Der beste Weg, Makefiles für verschiedene Situationen einzurichten

BESCHREIBUNG


Ich habe festgestellt, dass praktisch niemand jemals eine Anleitung für ein Make-Tool liest, denn ehrlich gesagt
Niemand interessiert sich wirklich für den Herstellungsprozess selbst – wir sind nur an den Ergebnissen interessiert.
Dieses Kochbuch wurde in der Hoffnung zusammengestellt, dass die Leute bekommen, was sie brauchen
schnell aus den Beispielen heraus, ohne durch das Handbuch zu waten. Dies zeigt, wie man tippt
Fragen, während Montageanleitungen und Stolpersteine ​​im
Häufig gestellte Fragen.

Building Bibliotheken
Do U wirklich technische a Bibliothek?

Ich habe eine Reihe von großen Programmen gesehen, die aus einer großen Anzahl von Modulen bestehen, von denen jedes
die in einem eigenen Verzeichnis lebt. Normalerweise wird jedes Verzeichnis in eine eigene Bibliothek gestellt,
und dann verbindet sich das endgültige Programm mit allen Bibliotheken.

In vielen Fällen denke ich, dass es einen besseren Ansatz gibt, als eine Bibliothek zu verwenden. Bibliotheken
sind nicht wirklich die richtige Lösung, wenn jedes Modul nicht in einem anderen wiederverwendet werden kann oder wird
Programm, denn dann haben Sie alle Nachteile von Bibliotheken und keine der
Vorteile. Bibliotheken sind in folgenden Fällen nützlich:

1. Wenn Sie eine Reihe von Unterprogrammen haben, die mit mehreren verschiedenen verknüpft werden müssen
Programme, und kein Programm verwendet tatsächlich 100 % der Unterprogramme - jedes Programm verwendet a
andere Teilmenge. In diesem Fall ist es wahrscheinlich eine gute Idee, eine statische Bibliothek zu verwenden (z
.a Datei oder eine Archivdatei).

2. Wenn Sie ein Modul haben, das mit mehreren verschiedenen Programmen verknüpft werden soll, und Sie
möchte es dynamisch laden, damit nicht jedes Programm eine separate Kopie von haben muss
die Bibliothek. Dynamische Bibliotheken können Speicherplatz für ausführbare Dateien sparen und manchmal verbessern
Systemleistung, da nur eine Kopie der Bibliothek für alle geladenen
verschiedene Programme, die es verwenden.

3. Wenn Ihre Linkzeit unerschwinglich ist, verwenden Sie gemeinsam genutzte Bibliotheken für große Teile von
das Programm kann die Verbindung erheblich beschleunigen.

Die Verwendung statischer Bibliotheken hat einen wesentlichen Nachteil: Auf manchen Systemen (zB Linux) ist die Reihenfolge
in dem Sie die Bibliotheken verlinken, ist von entscheidender Bedeutung. Der Linker verarbeitet Bibliotheken
in der in der Befehlszeile angegebenen Reihenfolge. Es schnappt sich alles, was es zu brauchen glaubt
jede Bibliothek und geht dann zur nächsten Bibliothek über. Wenn eine nachfolgende Bibliothek auf a . verweist
Symbol, das noch nicht aus einer früheren Bibliothek integriert wurde, der Linker nicht
wissen, zurückzugehen und es aus der vorherigen Bibliothek zu holen. Infolgedessen kann es erforderlich sein
um die Bibliothek mehrmals in der Linker-Befehlszeile aufzulisten. (Ich habe an einem Projekt gearbeitet
wo wir die ganze Liste der Bibliotheken dreimal wiederholen mussten. Dieses Projekt hat es geschafft
Ich bevorzuge den unten vorgeschlagenen alternativen Ansatz, den der inkrementellen Verknüpfung.)

Die Verwendung dynamischer Bibliotheken hat mehrere Nachteile. Erstens kann Ihr Programm etwas sein
langsamer zu starten, wenn die Bibliothek nicht bereits von einem anderen Programm verwendet wird, weil
es muss gefunden und geladen werden. Zweitens kann es sehr mühsam sein, die ganze Dynamik zu bekommen
Bibliotheken, die an den richtigen Orten installiert sind; Sie können die ausführbare Programmdatei nicht einfach kopieren,
Sie müssen auch sicherstellen, dass Sie alle Bibliotheken kopieren. Drittens ist es auf einigen Systemen
Es ist schwierig, Code in gemeinsam genutzten Bibliotheken zu debuggen, da die Debugger dies nicht unterstützen
Sie gut.

Wenn Ihr Modul nie in einem anderen Programm verwendet wird, gibt es wenig Grund, es zu verwenden
eine Bibliothek: Sie erhalten alle Nachteile der Verwendung von Bibliotheken und keinen der Vorteile.
Die Technik, die ich bevorzuge, ist die inkrementelle Verknüpfung, sofern verfügbar.

So können Sie dies unter Linux tun:

my_module.o : $(filter_out my_module.o, $(Wildcard *.o))
ld -r -o $(Ausgabe) $(Eingaben)

Was dies tun wird, ist, eine andere zu erstellen .o Datei aufgerufen mein_modul.o, die bestehen wird aus
alle der .o Dateien in diesem Unterverzeichnis. Der Linker löst so viele der
Referenzen so gut es geht, und lässt die verbleibenden Referenzen in a
nachfolgende Verlinkungsphase. Auf der obersten Ebene, wenn Sie Ihr Programm schließlich erstellen,
anstatt zu verlinken mit libmy_module.a or libmy_module.so, du würdest einfach verlinken mit
mein_modul.o. Wenn du verlinkst .o Dateien haben Sie keine Probleme mit der Auftragsabhängigkeit im
Linker-Befehlszeile.

Letting machenpp Abbildung welche Bibliothek Module sind erforderlich

Selbst wenn Sie eine echte Bibliothek haben, von der ein bestimmtes Programm nur wenige Dateien benötigt
(und nicht jedes einzelne Modul), kann makepp herausfinden, welche Module es sind
aus der Bibliothek benötigt und nur die im Build enthalten. Dies kann die Kompilierung sparen
Zeit, wenn Sie die Bibliothek zusammen mit einem Programm entwickeln, weil Sie sich nicht darum kümmern
kompilieren Sie Bibliotheksmodule, die für das jeweilige Programm, an dem Sie arbeiten, nicht benötigt werden.

Wenn Ihre Bibliothek die Konvention strikt einhält, dass alle Funktionen oder Klassen in
eine Datei xyz.h sind vollständig in einer Quelldatei implementiert, die zu kompiliert wird xyzo (dh du
unterteilen Sie die Implementierung nicht in xyz1.o und xyz2.o), dann können Sie die
"$(infer_objects)"-Funktion, um makepp anzuweisen, nur die relevanten Module aus dem
Bücherei. Dies kann für Bibliotheken mit sogar Dutzenden von Include-Dateien überraschend gut funktionieren.
Grundsätzlich untersucht "$(infer_objects)" die Liste der .h Dateien, die enthalten sind, und sieht aus
für entsprechendes .o Dateien. Wenn Sie schnell eine Bibliothek und ein Programm entwickeln
Zusammen kann dies Kompilierungszeit sparen, da Sie sich nie die Mühe machen, Module von . zu kompilieren
die Bibliothek, die das Programm nicht verwendet.

Hier ist ein Beispiel dafür, wie ich es verwende:

mein_programm: $(infer_objects *.o, $(LIB1)/*.o $(LIB2)/*.o)
$(CXX) $(Eingänge) -o $(Ausgabe) $(SYSTEM_LIBRARIES)

Die Funktion "$(infer_objects )" gibt ihr erstes Argument zurück (nachdem Wildcard
Erweiterung darauf) und durchsucht auch die Liste der Dateien in ihrem zweiten Argument, nach
Dateien, deren Name der gleiche ist wie der Name von any .h Dateien, die von einer Datei in ihrer ersten eingeschlossen sind
Streit. Wenn solche Dateien gefunden werden, werden diese der Liste hinzugefügt.

Building a statisch Bibliothek

Wenn Sie sicher sind, dass Sie tatsächlich eine Bibliothek benötigen und die inkrementelle Verknüpfung nicht verfügbar ist, oder
ist nicht das, was Sie tun möchten, es gibt mehrere Möglichkeiten, dies zu tun. Hier zunächst ein Beispiel
wo alle Dateien explizit aufgelistet sind:

LIBRARY_FILES = abcde

libmine.a: $(LIBRARY_FILES).o
&rm -f $(Ausgabe)
$(AR) cr $(Ausgabe) $(Eingänge)
ranlib $(output) # Je nach Betriebssystem möglicherweise nicht erforderlich.

&rm ist der eingebaute "rm"-Befehl von makepp. Wenn Sie es gewohnt sind, Makefiles zu schreiben, sind Sie vielleicht
ein wenig überrascht von diesem Befehl; Sie sind vielleicht eher an so etwas gewöhnt:

libmine.a: $(LIBRARY_FILES).o
$(AR) ru $@ $? # Nicht empfohlen!!!!!!!
ranlib $(Ausgabe)

wo $? (auch bekannt als "$(changed_inputs)") ist eine automatische Variable, die alle Dateien bedeutet
die sich seit der letzten Erstellung der Bibliothek geändert haben, und $@ ist ungefähr gleich
als "$(Ausgabe)".

Dieser Ansatz wird aus mehreren Gründen nicht empfohlen:

· Angenommen, Sie entfernen eine Quelldatei aus dem aktuellen Verzeichnis. Es ist noch in der
Bibliothek, weil Sie die Bibliothek nicht von Grund auf neu erstellt haben. Als Ergebnis alles
dass Links zu dieser Bibliothek veraltet sein werden .o Datei, und das kann Ihre vermasseln
baut. (Ich war einmal gründlich verwirrt, als ich versuchte, toten Code zu entfernen
aus einem Projekt: Ich habe immer wieder Dateien gelöscht und es ist immer noch verlinkt, also dachte ich, der Code wäre
tot. Als jedoch jemand anderes das Projekt von Grund auf neu erstellte, wurden keine verknüpft
mehr! Das Problem war, dass die alten .o Dateien waren noch im Archiv.)

Abhängig von Ihren Optionen für "ar" und Ihrer Implementierung von "ar" (z. B. wenn Sie
Verwenden Sie die Option "q" anstelle von "r"), können Sie am Ende mehrere Versionen der
gleich .o innerhalb der .a Datei. Wenn die verschiedenen Versionen unterschiedliche Globals definieren, wird die
Linker kann versuchen, beide einzubinden. Dies ist wahrscheinlich eine schlechte Sache.

Aus diesem Grund entfernen wir zuerst die Bibliotheksdatei und erstellen sie von Grund auf neu. Dieser Wille
dauert etwas länger, als nur Module in einer Bibliothek zu aktualisieren, aber nicht viel länger; An
eines modernen Computers, der Zeitaufwand der ar Programm ist winzig im Vergleich
zu dem, was der C-Compiler in einem typischen Build aufnimmt, also ist es einfach nicht wert, sich Sorgen zu machen
etwa.

· Eine der Möglichkeiten, wie makepp versucht, korrekte Builds zu garantieren, besteht darin, dass es
automatisch neu erstellen, wenn sich die Befehlszeile zum Erstellen eines bestimmten Ziels geändert hat. Aber
mit dem $? Variable kann zu Problemen führen, da jedes Mal, wenn die Bibliothek aktualisiert wird,
der build-Befehl ist anders. (Sie können dies unterdrücken mit
":build_check ignore_action"; Einzelheiten finden Sie unter makepp_build_check.)

· Das Aktualisieren des Archivs, anstatt es neu aufzubauen, macht es für makepp unmöglich,
Legen Sie die Datei richtig in einen Build-Cache (siehe makepp_build_cache für Details).

Manchmal kann es schwierig sein, alle Dateien aufzulisten, besonders wenn ein
Projekt durchläuft eine rasante Entwicklung und die Liste der Dateien ändert sich ständig. Es
Es kann einfacher sein, die Bibliothek mit Platzhaltern zu erstellen, wie folgt:

libmine.a: $(only_targets *.o)
&rm $(Ausgabe)
$(AR) cr $(Ausgabe) $(Eingänge)

Damit sind alle .o Dateien im aktuellen Verzeichnis in die Bibliothek. Die Wildcard
passt zu jedem .o Datei, die existiert oder erstellt werden kann, so dass sie funktioniert, auch wenn die Dateien dies nicht tun
noch existieren.

Die Funktion "only_targets" dient zum Ausschließen .o Dateien, die keine Entsprechung haben
Quelldateien nicht mehr. Angenommen, Sie haben eine Datei namens xyz.c die du immer in deine steckst
Bücherei. Dies bedeutet, dass es eine xyzo Datei herumliegen. Jetzt löschst du xyz.c
weil es veraltet ist, aber du vergisst zu löschen xyzo. Ohne die "only_targets"
Funktion, xyzo würde noch in die Liste der aufgenommen werden .o Dateien in der Bibliothek enthalten.

Building a dynamisch Bibliothek

Der Prozess der Erstellung dynamischer Bibliotheken ist vollständig systemabhängig. ich würde sehr
empfehlen die Verwendung von libtool, um eine dynamische Bibliothek zu erstellen (siehe
<http://www.gnu.org/software/libtool/>), also musst du nicht herausfinden, wie es geht
Ihre Plattform und damit Ihr Makefile auch dann funktioniert, wenn Sie zu a wechseln
anderes Betriebssystem. Weitere Informationen finden Sie in der libtool-Dokumentation. Hier ist ein Beispiel-Makefile:

LIBTOOL := Bibliothekstool

libflick.la : $(only_targets *.lo)
$(LIBTOOL) --mode=link $(CC) $(Eingänge) -o $(Ausgabe)

%.lo : %.c
$(LIBTOOL) --mode=kompilieren $(CC) $(CFLAGS) $(INCLUDES) -c $(Eingabe) -o $(Ausgabe)

Building on mehrere anders Maschinen or Netzwerke
Eines der nervigsten Probleme mit Makefiles ist, dass sie fast nie funktionieren, wenn Sie
zu einem anderen Gerät oder einem anderen Netzwerk wechseln. Wenn Ihre Makefiles arbeiten müssen
jede mögliche Maschine auf dem Planeten, dann brauchst du wahrscheinlich eine Art Konfiguration
Skript. Wenn Sie jedoch nur an wenigen verschiedenen Maschinen arbeiten müssen, gibt es mehrere Möglichkeiten
Sie können dieses Problem angehen:

Verwenden Sie die a anders das Datei in alle Umgebungen

Am Anfang jedes Makefiles können Sie eine Zeile wie diese einfügen:

enthalten system_defs.mk

Die Datei system_defs.mk würde sich normalerweise für jeden an einem anderen Ort befinden
Umgebung. Wenn Sie möchten, dass Ihre Build-Verzeichnisse auf allen Maschinen identisch sind, setzen Sie
system_defs.mk in einem Verzeichnis über den Build-Verzeichnissen oder geben Sie einen Include-Pfad an
zu makepp mit der Befehlszeilenoption "-I".

Dies ist normalerweise etwas schmerzhaft, aber es funktioniert gut, wenn es eine große Anzahl von gibt
Unterschiede.

Verwenden Sie die if Aussagen

Dies ist der hässlichste Weg, aber es wird normalerweise funktionieren.

ifsys i386
CC := gcc
sonst ifsys sun4u
CC := cc
sonst ifsys hpux11
CC = c89
Endif

Wenn Sie nur ein paar Programme oder Bibliotheken finden oder Dateien in verschiedene
Orten gibt es vielleicht bessere Möglichkeiten (siehe unten).

find_programm, first_verfügbar, findfile

Diese Funktionen können verschiedene Verzeichnisse in Ihrem System durchsuchen, um die
entsprechenden Dateien. Das ist natürlich nicht so mächtig wie ein Konfigurationsskript, aber ich finde es
sinnvoll. Ich mache zum Beispiel folgendes:

CXX ;= $(find_program g++ c++ pg++ cxx CC aCC)
# Wählen Sie den ersten C++-Compiler, der in PATH verfügbar ist.
# (Wenn Sie CXX überhaupt nicht definieren, ist dies
# ist die Art und Weise, wie es definiert ist.)
TCL_INCLUDE ;= -I$(dir_noslash $(findfile tcl.h, \
/usr/local/stow/tcl-8.4.5-nothread/include \
/usr/include/tcl8.4 /usr/include/tcl \
/net/na1/tcl8.4a3/include /net/na1/tcl8.4a3/include))
# $(findfile ) sucht nach tcl.h in jedem der angegebenen
# Verzeichnisse und gibt den vollständigen Pfad zurück. Das ist dann
# in eine Kompilierungsoption umgewandelt, indem die
# Dateiname (verlässt das Verzeichnis) und Präfix mit -I.
%.o : %.cpp
$(CXX) $(CXXFLAGS) $(TCL_INCLUDE) $(Eingabe) -o $(Ausgabe)

TCL_LIB ;= $((erste_verfügbar
/usr/local/stow/tcl-8.4.5-nothread/lib/libtcl8.4.so
/usr/lib/libtcl8.4.so /usr/lib/libtcl.so
/net/na1/tcl8.4a3/lib/libtcl8.4.a
/net/na1/tcl8.4a3/lib/libtcl8.4.sl))
# Finden Sie heraus, wo sich die Tcl-Bibliothek befindet. Das ist dann explizit
# im Link-Befehl aufgeführt:
mein_programm : *.o
$(CXX) $(CXXFLAGS) $(Eingänge) -o $(Ausgabe) $(TCL_LIB)

Nehmen haben Vorteile für of Perls Config Information

Die oben genannten Techniken reichen möglicherweise nicht aus, wenn Sie zusätzliche Informationen über . benötigen
Ihrem System, beispielsweise ob ein Long-Double vorhanden ist oder wie die Byte-Reihenfolge ist. Jedoch,
Perl hat diese Dinge bereits berechnet, also können Sie einfach seine Antworten verwenden.

Das Autoconfigure-Skript von Perl stellt alle seine Konfigurationsinformationen über
der %Config-Hash. Es gibt keine Syntax, um direkt in makepp auf einen Perl-Hash zuzugreifen, aber Sie können
Drop in Perl und setze skalare Variablen, die direkt von makepp aus zugänglich sind:

perl_begin
# Werte aus dem Konfigurations-Hash holen.
Konfig verwenden;
$CC = $Config{'cc'}; # C-Compiler, der von Perl verwendet wurde;
$byteorder_flags = "-DBYTEORDER=$Config{'byteorder'}";
$longdouble_defined = $Config{'d_longdbl'} eq 'define';
$CFLAGS_for_shared_libs = $Config{'cccdlflags'};
$LDFLAGS_for_shared_libs = $Config{'ccdlflags'};
perl_end

Sobald Sie die 'use Config' ausgeführt haben, können Sie auch die Anweisung "$(perl )" verwenden, wie z
Dies:

SHARED_LIB_EXTENSION := $(perl $Config{'dlext'})

Geben Sie "perldoc Config" ein, um zu sehen, welche Informationen über den %Config-Hash verfügbar sind.

Die Konfiguration von Perl ist ein guter Ort, um Informationen über Integer-Typen, Byte
order und andere Dinge, die normalerweise ein separates Konfigurationsskript erfordern, um sie zu finden. Einige
seine Informationen, die sich auf das Vorhandensein von Dingen im Dateisystem beziehen, sind möglicherweise nicht
gültig. Zum Beispiel bezieht sich $Config{'cc'} auf den C-Compiler, mit dem Perl erstellt wurde,
Dies ist möglicherweise nicht derselbe C-Compiler, den Sie verwenden möchten. Tatsächlich existiert es vielleicht gar nicht
auf Ihrem System, da Sie Perl wahrscheinlich über ein Binärpaket installiert haben.

Tips für Verwendung von Platzhalter
Abstimmung alle Dateien ausgeschlossen a sicher Teilmenge

Die Platzhalter von Makepp haben derzeit keine Möglichkeit, alle Dateien abzugleichen ausgeschlossen eine gewisse
einstellen, aber Sie können dies mit einer Kombination von Funktionen tun.

Angenommen, Sie haben für jedes Modul in einer Bibliothek ein Testprogramm, haben es aber nicht
die Testprogramme in die Bibliothek aufnehmen möchten. Wenn alle Testprogramme mit beginnen
Test, dann kannst du sie wie folgt ausschließen:

libproduktion.a: $(filter_out test*, $(wildcard *.o))

Die Funktionen "$(filter )" und "$(filter_out )" sind ein sehr mächtiger Satz von Filtern
alle Arten von Schnitt- und Differenzoperationen. Zum Beispiel,

SUBDIRS ;= $(filter_out *test* *$(ARCH)*, $(shell find . -type d -print))
# Gibt alle Unterverzeichnisse zurück, die kein . haben
# "test" oder $(ARCH) darin.

$(filter $(patsubst test_dir/test_%.o, %.o, $(Platzhalter test_dir/*.o)), \
$(Platzhalter *.o))
# Gibt eine Liste von .o-Dateien im aktuellen . zurück
# Verzeichnis, für das es ein entsprechendes gibt
# Datei test_*.o im Unterverzeichnis test_dir.
$(filter_out $(patsubst man/man3/%.3, %.o, $(wildcard man/man3/*.3)), \
$(Platzhalter *.o))
# Gibt eine Liste von .o-Dateien im aktuellen . zurück
# Verzeichnis, für das es keine Handbuchseite gibt
# mit demselben Dateinamen im Unterverzeichnis man/man3.

Die richtigen "$(only_targets )" Funktion zu beseitigen abgestanden .o Dateien

Angenommen, Sie erstellen ein Programm oder eine Bibliothek mit einem Build-Befehl wie diesem:

Programm: *.o
$(CC) $(Eingänge) -o $(Ausgabe)

Angenommen, Sie löschen jetzt eine Quelldatei. Wenn Sie vergessen, das entsprechende zu löschen .o Datei,
es wird immer noch eingebunden, obwohl es keine Möglichkeit mehr gibt, es zu bauen. In dem
in Zukunft wird makepp diese Situation wahrscheinlich automatisch erkennen und ausschließen
die Wildcard-Liste, aber derzeit müssen Sie ihr mitteilen, dass sie manuell ausgeschlossen werden soll:

Programm: $(only_targets *.o)
$(CC) $(Eingänge) -o $(Ausgänge)

Makepp kennt keine Möglichkeit, das Abgestandene zu bauen .o Datei nicht mehr, da die Quelldatei ist
weg, also wird die Funktion "$(only_targets )" es aus der Abhängigkeitsliste ausschließen.

Tips für mehrere Verzeichnisse
Einer der Hauptgründe für das Schreiben von makepp war die Vereinfachung des Umgangs mit mehreren
Verzeichnisse. Makepp kann Build-Befehle aus mehreren Makefiles kombinieren, also kann es
richtig mit einer Regel in einem Makefile umgehen, das von einer Datei abhängt, die von a . erstellt wurde
anderes Makefile.

Was zu do in Ort of rekursive um

Makepp unterstützt rekursives Make aus Gründen der Abwärtskompatibilität, wird jedoch dringend empfohlen
That You nicht benutze es. Wenn Sie nicht wissen, was es ist, gut.

Siehe "Besseres System für hierarchische Builds" in Makepp für Details, warum Sie dies nicht möchten
verwenden Sie rekursives Make, oder suchen Sie im Internet nach "rekursivem Make, das als schädlich angesehen wird".

Anstatt ein rekursives Make durchzuführen, um das "all" -Ziel in jedem Makefile zu erstellen, ist es
normalerweise ist es einfacher, makepp herausfinden zu lassen, welche Ziele tatsächlich erstellt werden müssen.
Außerdem, wenn Sie alle Ihre .o und Bibliotheksdateien im selben Verzeichnis wie die
Makefiles, dann wird makepp automatisch herausfinden, welche Makefiles auch benötigt werden - die
Das einzige, was Sie brauchen, ist die Liste der benötigten Dateien auf der obersten Ebene
für den letzten Verknüpfungsschritt. Siehe die Beispiele unten.

Eins Makefile für jeder Verzeichnis: mit implizit Laden

Die gängigste Methode zur Handhabung mehrerer Verzeichnisse besteht darin, in jedem Verzeichnis ein Makefile abzulegen
die beschreibt, wie alles in oder aus diesem Verzeichnis erstellt wird. Wenn du stellst .o Dateien in
das gleiche Verzeichnis wie die Quelldateien, dann implizites Laden (siehe "Implizites Laden" in
makepp_build_algorithm) findet automatisch alle Makefiles. Wenn du deine .o
Dateien in einem anderen Verzeichnis (zB in einem architekturabhängigen Unterverzeichnis), dann können Sie
müssen wahrscheinlich alle relevanten Makefiles mit der Anweisung "load_makefile" laden.

Hier ist ein Beispiel für ein Makefile der obersten Ebene für eine Verzeichnishierarchie, die implizites Laden verwendet
um ein Programm zu erstellen, das aus vielen gemeinsam genutzten Bibliotheken besteht (siehe aber "Brauchen Sie wirklich eine?
Bibliothek?" in makepp_cookbook, weil ein Programm aus einem Haufen gemeinsam genutzter Bibliotheken gemacht wird
ist nicht unbedingt eine gute Idee):

# Makefile der obersten Ebene:
Programm : main.o **/*.la # Link in Shared Libraries aus allen Unterverzeichnissen.
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) $(Eingänge) -o $(Ausgabe) $(LIBS)

Das ist so ziemlich alles, was Sie im Makefile der obersten Ebene benötigen. In jedem Unterverzeichnis haben Sie
würde wohl sowas machen:

# Makefile in jedem Unterverzeichnis:
include standard_defs.mk # Sucht ., .., ../ .., usw. bis es
# findet die angegebene Include-Datei.
# hier einige Variablendefinitionen überschreiben
SPECIAL_FLAGS := -do_something_different

Jedes Makefile kann wahrscheinlich ziemlich gleich sein, wenn die Befehle zum Erstellen der Ziele
sind recht ähnlich.

Schließlich würden Sie Folgendes in die standard_defs.mk Datei (die wahrscheinlich
sich im obersten Verzeichnis befinden):

# Gemeinsame Variableneinstellungen und Erstellungsregeln für alle Verzeichnisse.
CFLAGS := -g -O2
INCLUDE_DIR := $(find_upwards beinhaltet)
# Sucht ., .., ../ .., etc. für eine Datei oder
# Verzeichnis mit dem Namen enthält, also wenn Sie setzen
# alle deine Include-Dateien drin, das wird
# finde sie.
ENTHÄLT := -I$(INCLUDE_DIR)

%.lo : %.c
$(LIBTOOL) --mode=kompilieren $(CC) $(CFLAGS) $(INCLUDES) -c $(Eingabe) -o $(Ausgabe)

lib$(relative_to ., ..).la: $(only_targets *.lo)
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) -o $(Ausgabe) $(Eingänge)
# $(relative_to ., ..) gibt den Namen des Stroms zurück
# Unterverzeichnis relativ zur oberen Ebene
# Unterverzeichnis. Wenn dieses Makefile also xyz/Makefile ist,
# diese Regel erstellt xyz/libxyz.la.

# Veröffentlichen Sie öffentliche Include-Dateien im Include-Verzeichnis der obersten Ebene:
$(INCLUDE_DIR)/public_%.h : public_%.h
:build_check symlnk
&ln -fr $(Eingabe) $(Ausgabe)

Eins Makefile für jeder Verzeichnis: explizit Laden

Wenn Sie alle Ihre .o Dateien in ein architekturabhängiges Unterverzeichnis, dann
Das obige Beispiel sollte in etwa so geändert werden:

# Makefile der obersten Ebene:
MAKEFILES := $(Wildcard **/Makeppfile) # Liste aller Unterverzeichnisse zu
# Makefiles abrufen von.

load_makefile $(MAKEFILES) # Lade sie alle ein.

include standard_defs.mk # Kompilierungsbefehl für main.o abrufen.

Programm : $(ARCH)/main.o */**/$(ARCH)/*.la
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) $(Eingänge) -o $(Ausgabe) $(LIBS)
# */**/$(ARCH) schließt das Unterverzeichnis aus
# $(ARCH), wo wir nicht bauen wollen
# eine gemeinsam genutzte Bibliothek.

Jedes Makefile wäre genau das gleiche wie zuvor:

# Makefile in jedem Unterverzeichnis:
schließen Sie standard_defs.mk ein
# ... Variablenüberschreibungen hier

Und schließlich standard_defs.mk würde etwa folgendes enthalten:

# Gemeinsame Variableneinstellungen und Erstellungsregeln für alle Verzeichnisse.
ARCH ;= $(Shell-Uname -s)-$(Shell-Uname -m)-$(Shell-Uname -r)
# Manchmal verwenden Leute nur $(shell uname -m), aber
# dies wird für FreeBSD und Linux gleich sein
# ein x86. Das -r ist unter Linux nicht wirklich nützlich,
# ist aber für andere Betriebssysteme wichtig: Binärdateien für
# SunOS 5.8 läuft normalerweise nicht auf SunOS 5.7.
&mkdir -p $(ARCH) # Stellen Sie sicher, dass das Ausgabeverzeichnis existiert.
CFLAGS := -g -O2
INCLUDE_DIR := $(find_upwards beinhaltet)
# Sucht ., .., ../ .., etc. für eine Datei oder
# Verzeichnis mit dem Namen enthält, also wenn Sie setzen
# alle deine Include-Dateien drin, das wird
# finde sie.
ENTHÄLT := -I$(INCLUDE_DIR)

$(ARCH)/%.lo : %.c
$(LIBTOOL) --mode=kompilieren $(CC) $(CFLAGS) $(INCLUDES) -c $(Eingabe) -o $(Ausgabe)

$(ARCH)/ lib$(relative_to ., ..).la: $(only_targets *.lo)
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) -o $(Ausgabe) $(Eingänge)
# $(relative_to ., ..) gibt den Namen des Stroms zurück
# Unterverzeichnis relativ zur oberen Ebene
# Unterverzeichnis. Wenn dieses Makefile also xyz/Makefile ist,
# diese Regel erstellt xyz/$(ARCH)/libxyz.la.

# Kopieren Sie öffentliche Include-Dateien in das Include-Verzeichnis der obersten Ebene:
$(INCLUDE_DIR)/public_%.h : public_%.h
&cp $(Eingabe) $(Ausgabe)

Automatisch Herstellung Makefiles

Wenn Ihre Makefiles alle sehr ähnlich sind (wie im obigen Beispiel), können Sie Makepp
um sie automatisch zu erstellen, wenn sie nicht existieren. Fügen Sie einfach Folgendes zu Ihrer obersten Ebene hinzu
Makefile:

SUBDIRS := $(filter_out unerwünschtes_dir1 unerwünschtes_dir2, $(wildcard */**))
$(foreach)/Makeppfile: : foreach $(SUBDIRS)
&echo "standard_defs.mk einschließen" -o $(Ausgabe)
&echo "_include zusätzliche_defs.mk" -o >>$(Ausgabe)
# Wenn die Datei zusätzliche_defs.mk existiert, dann
# es wird aufgenommen, aber wenn es nicht existiert,
# die _include-Anweisung wird ignoriert.

Jetzt werden die Makefiles selbst automatisch erstellt.

Eins Makefile einzige at Top Grad des

Wenn alle Ihre Makefiles identisch sind, fragen Sie sich vielleicht: Warum sollte ich jeweils ein Makefile haben?
Niveau? Warum nicht das alles in das Top-Level-Makefile packen?

Ja, das ist möglich. Der Hauptnachteil ist, dass die Angabe schwieriger wird
verschiedene Build-Optionen für jedes Unterverzeichnis. Ein zweiter Nachteil ist, dass Ihr
makefile wird wahrscheinlich etwas schwieriger zu lesen sein.

Hier ist ein Beispiel dafür:

# Makefile der obersten Ebene für die Verzeichnishierarchie. Erstellt das Programm
# aus einer Reihe von Shared Libraries als Beispiel. (Siehe Vorbehalte oben
# warum Sie inkrementelles Linking oder etwas anderes verwenden möchten
#-Ansatz statt gemeinsam genutzter Bibliotheken.)
makepp_percent_subdirs := 1 # Erlaube %, mehrere Verzeichnisse abzugleichen.
SUBDIRS := $(filter_out *CVS* other-unwanted_dirs $(Wildcard **))
CFLAGS := -g -O2
INKLUSIVE := -Iinklusive

%.lo: %.c
$(LIBTOOL) --mode=kompilieren $(CC) $(INCLUDES) $(CFLAGS) -c $(Eingabe) -o $(Ausgabe)

$(foreach)/ lib$(notdir $(foreach)).la: $(foreach)/*.lo : foreach $(SUBDIRS)
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) -o $(Ausgabe) $(Eingänge)
# Regel zum Erstellen aller Bibliotheken.

Programm : main.o **/*.la
$(LIBTOOL) --mode=link $(CC) $(CFLAGS) -o $(Ausgabe) $(Eingänge)

beinhaltet/$(notdir $(foreach)) : $(foreach) : foreach **/public_*.h
&cp $(Eingabe) $(Ausgabe)
# Beispielregel zum öffentlichen Kopieren
# zugängliche .h-Dateien an der richtigen Stelle.

A reinigen Ziel

Herkömmliche Makefiles enthalten ein sauberes Ziel, das es ermöglicht, alles zu entfernen, was war
gebaut. Es gibt drei Gründe, warum Sie dies nicht mit makepp tun sollten:

1. Makepp unternimmt große Anstrengungen, um einen korrekten Build zu gewährleisten. Also das verzweifelte "Ich nicht
wissen, was los ist", gehört damit der Vergangenheit an, dass Sie bei Null anfangen wollen.

2. Menschen versuchen manchmal, Zeit zu sparen, indem sie zwei widersprüchliche Dinge gleichzeitig tun:
"alles sauber machen". Dies kann das intelligente Wildcard-System von makepp verwirren, denn es wird
Informieren Sie sich zuerst über die Fakten, bevor Sie etwas unternehmen. Dann kommt die saubere Aktion, die tut
Makepp nicht sagen, was es tut (tatsächlich kann es nicht, weil es etwas rückgängig macht - die
im Gegensatz zu dem, wofür ein Build-Tool gedacht ist). Dann kommt "alle", aber die aktuellen Dateien,
die dort, sind auf mysteriöse Weise verschwunden.

3. Es gibt den Befehl "makeppclean", der dasselbe und effizienter macht.

Trotzdem behalten wir diesen historischen Abschnitt bei, da er Ihnen etwas über die
Funktionsweise von makepp: Ein falsches Ziel namens "clean" ist nur ein Name für eine Reihe von Befehlen, die
Entfernen Sie alle Dateien, die aus dem Make-Prozess resultieren. Normalerweise sieht ein sauberes Ziel aus
etwas wie das:

$(gefälschte Reinigung):
&rm -fm $(Platzhalter *.o .makepp_log)
# -m und .makepp_log entfernt den ganzen Müll von Makepp.

Anstatt die Dateien, die Sie löschen möchten, explizit aufzulisten, können Sie makepp auch anweisen,
Entfernen Sie alles, was es zu bauen weiß, wie folgt:

$(gefälschte Reinigung):
&rm -fm .makepp_log $(only_targets *)

Dies hat den Vorteil, dass, wenn eine Ihrer Quelldateien aus anderen Dateien erstellt werden kann,
sie werden auch gelöscht; auf der anderen Seite altbacken .o Dateien (Dateien, die früher
buildable, dessen Quelldatei jedoch inzwischen entfernt wurde) werden nicht gelöscht.

Wenn Sie einen Build haben, der Makefiles in mehreren verschiedenen Verzeichnissen enthält, ist Ihr Top-
Level-Makefile kann auf das "saubere" Ziel (oder jedes andere falsche Ziel) in einer anderen Weise verweisen
Makefile:

# Makefile der obersten Ebene
UNTERVERZEICHNIS := sub1 sub2

# Build-Regeln hier

# Aufräumen nach dem Build:
$(gefälschte Reinigung): $(SUBDIRS)/sauber
&rm -fm .makepp_log $(only_targets *)

Alternativ können Sie Ihr "sauberes" Ziel nur in das Makefile der obersten Ebene einfügen und es haben
Verarbeiten Sie alle Verzeichnisse wie folgt:

$(gefälschte Reinigung):
&rm -fm $(only_targets **/*)

Die richtigen Qt's mok Präprozessor
Dieses Beispiel zeigt ein Makefile für ein Dienstprogramm, das die Qt-GUI-Bibliothek von Nokia verwendet (siehe
<http://qt.nokia.com>). Das einzige, was daran etwas ungewöhnlich ist, ist, dass du
muss einen Präprozessor namens "moc" für die meisten ".h"-Dateien ausführen, die Widget-Definitionen enthalten.
aber Sie möchten "moc" nicht für ".h"-Dateien ausführen, die das Makro "Q_OBJECT" nicht verwenden.

Automatisch Festlegung welche Dateien technische mok Dateien

Sie können natürlich einfach alle ".h"-Dateien auflisten, auf denen "moc" ausgeführt werden muss.
Wenn Sie jedoch schnell neue Widgets entwickeln, kann dies etwas lästig sein
Aktualisieren Sie die Liste im Makefile ständig. Sie können die Notwendigkeit umgehen, die Moc aufzulisten
Module explizit mit etwa so:

MOC := $(QTDIR)/bin/moc
MODULE := welche Module auch immer Sie in Ihrem Programm haben
MOC_MODULES := $(patsubst %.h, moc_%, $(&grep -l /Q_OBJECT/ *.h))
# Durchsucht alle .h-Dateien nach dem Q_OBJECT-Makro.

mein_programm: $(MODULES).o $(MOC_MODULES).o
$(CXX) $(Eingänge) -o $(Ausgabe)

moc_%.cxx: %.h # Erstellt die moc-Dateien aus den .h-Dateien.
$(MOC) $(Eingabe) -o $(Ausgabe)

%.o: %.cxx
$(CXX) $(CXXFLAGS) -c $(Eingabe) -o $(Ausgabe)

Dieser Ansatz scannt jeden Ihrer .h Dateien jedes Mal, wenn makepp ausgeführt wird, auf der Suche nach dem
Makro "Q_OBJECT". Das klingt teuer, wird aber wahrscheinlich nicht lange dauern. (Die .h
Dateien müssen beim Kompilieren sowieso alle von der Festplatte geladen werden, also werden sie
zwischengespeichert werden.)

#einschließen .moc Datei

Ein anderer Ansatz besteht darin, die Ausgabe des Präprozessors "moc" in Ihr Widget zu "#include"
Implementierungsdatei. Das bedeutet, dass Sie daran denken müssen, das "#include" zu schreiben, aber es hat
der Vorteil, dass weniger Module zu kompilieren sind und die Kompilierung daher schneller geht.
(Bei den meisten C++-Kompilierungen wird die meiste Zeit damit verbracht, die Header-Dateien zu lesen, und
die Ausgabe des Präprozessors muss fast so viele Dateien enthalten wie Ihr Widget
sowieso.) Zum Beispiel:

// mein_widget.h
Klasse MyWidget : öffentliches QWidget {
Q_OBJEKT
// ...
}

// mein_widget.cpp

#include "my_widget.h"
#include "my_widget.moc" // my_widget.moc ist die Ausgabe von der
// moc-Präprozessor.
// Andere Implementierungsdinge hier.
MyWidget::MyWidget(QWidget * parent, const char * name) :
QWidget(Elternteil, Name)
{
// ...
}

Jetzt müssen Sie eine Regel in Ihrem Makefile haben, um alle ".moc" -Dateien zu erstellen, wie folgt:

MOC := $(QTDIR)/bin/moc
# Regel zum Erstellen von .moc-Dateien:
%.moc: %.h
$(MOC) $(Eingabe) -o $(Ausgabe)

Makepp ist schlau genug, um zu erkennen, dass es "my_widget.moc" erstellen muss, wenn dies nicht der Fall ist
bereits vorhanden oder veraltet ist.

Diesen zweiten Ansatz verwende ich normalerweise, weil er die Kompilierung beschleunigt.

Ersatzteile für veraltet um Redewendungen
MAKECMDGOALS

Manchmal haben Benutzer Regeln in ihrem Makefile, die davon abhängen, welches Ziel sie erstellen.
über die spezielle Variable "MAKECMDGOALS". Zum Beispiel sieht man manchmal Dinge wie
Dies:

ifneq ($(Filterproduktion, $(MAKECMDGOALS)),)
CFLAGS := -O2
sonst
CFLAGS := -g
Endif

Mit Makepp funktioniert das problemlos. Ich empfehle jedoch, "MAKECMDGOALS" nicht für solche zu verwenden
Fällen (und auch das Handbuch von GNU make). Sie sind besser dran, Ihre optimierten und
Debug-kompiliert .o Dateien in separaten Verzeichnissen speichern oder ihnen unterschiedliche Präfixe geben oder
Suffixe oder die Verwendung von Repositorys, um sie getrennt zu halten.

Wahrscheinlich möchten Sie auf "MAKECMDGOALS" nur dann wirklich verweisen, wenn es
das Laden deiner Makefiles dauert lange, und das brauchst du nicht für dein "sauberes" Ziel
(aber Sie brauchen kein sauberes Ziel). Zum Beispiel,

ifneq ($(MAKECMDGOALS),sauber)
load_makefile $(Platzhalter **/Makeppfile)
sonst
no_implicit_load . # Verhindern Sie das automatische Laden anderer Makefiles.
Endif

$(gefälschte Reinigung):
&rm -f $(Platzhalter **/*.o)

Rekursive um zu bauen in anders Verzeichnisse

Siehe "Tipps für mehrere Verzeichnisse" in makepp_cookbook.

Rekursive um zu Übernehmen Wert of a Variable

Einige Makefiles rufen sich selbst mit einem anderen Wert einer Variablen wieder auf, z. B. das Debug
Ziel im folgenden Makefile-Fragment

.PHONY: alle debuggen

optimiert:
$(MAKE) Programm CFLAGS=-O2

debuggen:
$(MAKE) Programm CFLAGS=-g

Programm: ao bo
$(CC) $(CFLAGS) $^ -o $@

%.o : %.c
$(CC) $(CFLAGS) -c $< -o $@

Wenn der Benutzer "make debug" eingibt, wird das Programm im Standardmodus mit aktiviertem Debug erstellt
statt mit Optimierung.

Ein besserer Weg, dies zu tun, besteht darin, zwei verschiedene Programme mit zwei verschiedenen Sätzen von zu erstellen
Objektdateien, wie folgt:

CFLAGS := -O2
DEBUG_FLAGS := -g
MODULE := ab

Programm: $(MODULES).o
$(CC) $(CFLAGS) $(Eingänge) -o $(Ausgabe)

debug/Programm: debug/$(MODULES).o
$(CC) $(DEBUG_FLAGS) $(Eingänge) -o $(Ausgabe)

%.o : %.c
$(CC) $(CFLAGS) -c $(Eingabe) -o $(Ausgabe)

debug/%.o : %.c
$(CC) $(DEBUG_FLAGS) -c $(Eingabe) -o $(Ausgabe)

$(falscher Debug): Debug/Programm

Der Vorteil auf diese Weise ist (a) dass Sie nicht alles neu aufbauen müssen, wenn Sie
von Debug auf optimiert und wieder zurück wechseln; (B)

Das Obige kann mit Repositories etwas prägnanter geschrieben werden. Folgende
makefile ist genau äquivalent:

Repository-Debug=. # Lässt das Debug-Unterverzeichnis wie eine Kopie von . aussehen
# das aktuelle Unterverzeichnis.
load_makefile debuggen CFLAGS=-g
# CFLAGS überschreiben, wenn es im Debug-Unterverzeichnis aufgerufen wird
CFLAGS := -O2 # Wert von CFLAGS bei Aufruf in diesem Unterverzeichnis

Programm: ao bo
$(CC) $(CFLAGS) $^ -o $@

%.o : %.c
$(CC) $(CFLAGS) -c $< -o $@

$(falscher Debug): Debug/Programm
# Wenn der Benutzer "makepp debug" eingibt, erstellt
# Debug/Programm statt Programm.

Weitere Anwendungsbereiche Tipps
Ultraschall do I bauen dank One Teil anders nur Einmal?

Makepp erschwert dies, da das Ergebnis im Hinblick auf die Regeln inkonsistent ist.
Es gibt jedoch Situationen, in denen Sie dies möglicherweise benötigen, z. B. um nur ein Modul mit zu kompilieren
umfangreiche Debugging-Informationen. Sie können dies in zwei Schritten erreichen, indem Sie zuerst die
Abhängigkeit separat und dann aus der Linkphase ausschließen:

makepp DEBUG=3 buggy.o # Build mit anderer Option.
makepp --dont-build=buggy.o buggy # Verwenden Sie es, trotz "falscher" Build-Option.

Ultraschall do I um sicher my Ausgabe Verzeichnisse existieren?

Sie können eine Regel zum Erstellen des Ausgabeverzeichnisses angeben und dann sicherstellen, dass jede Datei, die
geht in das Ausgabeverzeichnis hängt davon ab. Aber normalerweise ist es einfacher, so etwas zu tun wie
Dies:

# Der klassische Weg
dummy := $(Shell-Test -d $(OUTPUT_DIRECTORY) || mkdir -p $(OUTPUT_DIRECTORY))
# Dies ist normalerweise einfacher, als alle Dateien abhängig zu machen
# $(OUTPUT_DIRECTORY) und eine Regel dafür zu haben.
# Beachten Sie, dass Sie := anstelle von = verwenden müssen, um es zu erzwingen
# sofort ausführen.
# Ein alternativer Ansatz: Verwendung von Perl-Code, lokale OUTPUT_DIRECTORY-Variable
perl_begin
-d $OUTPUT_DIRECTORY oder mkdir $OUTPUT_DIRECTORY;
perl_end
# Der moderne Weg, tut nichts für bestehende Verzeichnisse
&mkdir -p $(OUTPUT_DIRECTORY)

Eine dieser Anweisungen sollte ganz oben in Ihrem Makefile stehen, damit sie ausgeführt werden
vor allem, was möglicherweise das Verzeichnis benötigen könnte.

Ultraschall do I Stärke a Befehl zu ausführen on alles, bauen?

Am einfachsten ist es, den Regelmechanismus gar nicht zu verwenden, sondern einfach auszuführen, wie
Dies:

Dummy := $(Shell-Datum > last_build_timestamp)

Oder legen Sie es in einen Perl-Block, wie folgt:

perl_begin
system("Befehl zum Ausführen");
perl_end

Dieser Ansatz hat den Nachteil, dass er auch dann ausgeführt wird, wenn ein nicht verwandtes Ziel
ausgeführt werden.

Ein zweiter Ansatz besteht darin, die Datei als falsches Ziel zu deklarieren, selbst wenn es sich um eine echte Datei handelt.
Dies zwingt makepp, den Befehl jedes Mal neu auszuführen, um ihn zu erstellen, aber nur, wenn es
erscheint in der Abhängigkeitsliste einer Regel.

Ultraschall do I verkürzen angezeigt bauen Befehle?

Oft gibt es so viele Optionen zum Kompilieren von Befehlen, dass das, was auf dem
Bildschirm ist nicht lesbar. Sie können die Anzeige ändern, indem Sie die Anzeige des unterdrücken
gesamten Befehl, und drucken Sie dann den interessanten Teil des Befehls explizit aus. Es ist
einfach, nur den relevanten Teil des Befehls auszudrucken, indem Sie "$(filter_out )" verwenden, wie
Dies:

ALLE_CFLAGS = $(CFLAGS) $(INCLUDES) $(ADDL_CXX_FLAGS) $(DEBUG_FLAGS)

%.o : %.c
@&echo $(notdir $(CC)) ... \
$(filter_out -I* $(ADDL_CXX_FLAGS), $(ALL_CFLAGS)) \
-c $(Eingabe)
@$(CC) $(ALL_CFLAGS) -c $(Eingabe) -o $(Ausgabe)

(Das "@" vor dem Befehl unterdrückt das Ausdrucken des Befehls.)

Auf diese Weise können Sie die meisten interessanten Optionen sehen, aber nicht alle anzeigen
include-Verzeichnisse (von denen es oft sehr viele gibt!). Wenn das Teil Sie interessiert
in in Ihrem Befehl zusammenhängend ist, können Sie auch die Funktion "Drucken" verwenden (die ein
newline, damit Sie nicht mehrere davon haben möchten):

Ziel:
@... $(interessanten Teil drucken) ...

Ultraschall do I verkaufen a Datei in Abhängigkeiten?

Bei einigen obskuren Dateiformaten lohnt es sich nicht, einen Scanner zu implementieren. In einem Projekt
wir haben xml-dateien, sagen wir foobar.xml welches die Abhängigkeiten für . enthält foobar.out:


ein
B
C


Wir haben uns entschieden, dieses einfache Layout beizubehalten, damit wir XML nicht parsen müssen. Mit dem
Builtin &sed, so machen wir es mit drei einfachen Ersetzungen für die drei Arten von
Linien:

%.d: %.xml
&seds! !$(Stamm).out: \\! || S! (.+) !$$1 \\! || S! !# Leer!' \
$(Eingabe) -o $(Ausgabe)

foobar.d einschließen

Beim Versuch, dies einzuschließen, wird zuerst "foobar.d" erzeugt:

foobar.out: \
ein \
B \
C \
# Leer

Leere (nur ein Kommentar oder wirklich leere) Zeile vermeidet es, sich um das Ende kümmern zu müssen
umgekehrter Schrägstrich. Eine Alternative zum Erstellen einer mehrzeiligen Liste ist:

%.d: %.xml
&seds! !$(Stamm).out: \$$((! || s! !))! || s!<.+?>!!g' \
$(Eingabe) -o $(Ausgabe)

foobar.d einschließen

Dies ergibt ein Äquivalent:

foobar.out: $((
a
b
c
))

Wenn Sie komplexere Umschreibungen durchführen müssen, definieren Sie eine Funktion innerhalb des Makefiles oder in a
Modul, das Sie einschließen. Wenn Sie beispielsweise $_ nicht definieren, werden Eingabezeilen übersprungen:

sub myfilter {
Rückgabe undef $_ if /
mein $stamm = f_stamm;
S! !$stem.out: \$((! || s! !))! || s!<.+?>!!g;
}

%.d: %.xml
&seds! !$(Stamm).out: \$$((! || s! !))! || s!<.+?>!!g' \
$(Eingabe) -o $(Ausgabe)

foobar.d einschließen

Verwenden Sie makepp_cookbook online mit den Diensten von onworks.net


Kostenlose Server & Workstations

Laden Sie Windows- und Linux-Apps herunter

Linux-Befehle

Ad