2012-12-27 21 views
6

Was ist eine bewährte Methode zum Schreiben von wiederverwendbarem Code in Makefile s?Best Practice zum Schreiben von wiederverwendbarem Code

Angenommen, ich habe ein Makefile:

.PHONY: all task01-all task01-clean task01-run task02-all task02-clean task02-run 

all: task01-all task02-all 

############################################################################### 
task01-all: task01-clean task01 task01-run 

task01-clean: 
    rm task01 task01.{exi,o} -f 

task01: 
    compiler task01.ext -O2 --make 

task01-run: 
    ./task01 

############################################################################### 
task02-all: task02-clean task02 task02-run 

task02-clean: 
    rm task02 task02.{exi,o} -f 

task02: 
    compiler task02.ext -O2 --make 

task02-run: 
    ./task02 

Jetzt habe ich neue Familie von Aufgaben (task03) hinzufügen möchten, und ich brauche ganzen Abschnitt Copypaste, machen s/02/03/ für sie und fügen Sie sie in .PHONY Abschnitt - es ist Laut, eklig und einfach nicht richtig.

Wie kann ich das vermeiden? Könnte ich alle Aufgaben mit Vorlagen irgendwie neu definieren, um einen schönen Mechanismus zum Hinzufügen neuer Aufgabengruppen in einer Zeile zu haben?

Antwort

9

Da die Frage ist, wiederverwendbaren Code in Makefiles zu schreiben, werde ich ein Beispiel geben, wie Musterregeln in GNU verwenden Stellen (es sieht aus wie das ist, was Sie verwenden, da Sie das Ziel .PHONY erwähnen). Wenn Sie jedoch sind nicht alle Make der Abhängigkeitsprüfung verwendet wird, kann es einfacher sein, dieses Skript mit einem Shell zu tun - so etwas wie:

#!/bin/sh 
TASKS="task01 task02 task03" 

for i in $TASKS; do 
    rm $i $i.ext $i.o -f; 
    compiler $i.ext -O2 --make; 
    ./$i; 
done 

Aber, um das Prinzip zu erweitern zu machen, haben wir ein anderes Problem anpacken. Zeilen der Form:

task01-all: task01-clean task01 task01-run 

nicht sagen, in welcher Reihenfolge Machen Sie die Voraussetzungen zu bauen - nur, dass sie alles getan werden müssen, bevor task01-all gebaut wird. Stattdessen sollte jeder auszuführende Schritt vom vorherigen Schritt abhängen. Etwas wie folgt aus:

TASKS=task01-run task02-run task03-run 

.PHONY: all $(TASKS) $(TASKS:run=clean) 

all: $(TASKS) 

$(TASKS:run=clean): %-clean: 
    rm $* $*.ext $*.o -f 

%: %.ext | %-clean 
    compiler $< -O2 --make 

$(TASKS): %-run: % 
    ./$< 

Die Regeln mit % werden „Musterregeln“ genannt, und sie sind ein großartiges Werkzeug, das Neuschreiben die gleiche Regel mehrmals für unterschiedliche Ziele zu vermeiden. Eine Einschränkung ist, dass Make normalerweise keine Musterregeln für ein .PHONY Ziel überprüft; Wir weisen Make an, dies ausdrücklich zu tun, indem wir diesen Regeln die Liste der Ziele und einen zweiten Doppelpunkt voranstellen (z. B. $(TASKS):).

Da task01-run benötigt task01 um zu arbeiten, machen wir %-run Ziele sind abhängig von %. Außerdem zeigt Ihr Makefile, dass Sie jedes Mal sauber laufen wollen, also machen wir % abhängig von %-clean. Da %-clean tatsächlich keine Ausgabe erzeugt, machen wir dies zu einer "Nur-Reihenfolge" -Abhängigkeit - Make wird nicht nach einem Zeitstempel oder irgendetwas suchen, es wird nur die %-clean Regel zuerst ausgeführt, wenn es die % ausführen muss Regel. „Order nur“ Abhängigkeiten werden nach einem platziert |:

%: %.ext | %-clean 

Es ist erwähnenswert, dass eine der größten Stärken der Marke ist, dass es an der Zeit durch nicht wiederkehrende Arbeit sparen können, die wiederholt zu werden, braucht nicht zu - das heißt, es Führt nur eine Regel aus, wenn die Abhängigkeiten neuer als das Ziel sind.So könnte man die Abhängigkeit von %-clean wegzulassen, die nur machen würde dazu führen, laufen compiler $< -O2 --make wenn %.ext neuer ist als %:

%: %.ext 
    compiler $< -O2 --make 

Sie dann eine Regel hinzufügen konnte nur all die %-clean Ziele auszuführen:

.PHONY: all $(TASKS) $(TASKS:run=clean) clean 

clean: $(TASKS:run=clean) 

Letzte Sache: Ich verwende einige spezielle Variablen in den Rezepten. [email protected] steht für das zu erstellende Ziel. $< steht für die erste Abhängigkeit. $* steht für den "Stamm" einer Musterregel (d. H. Der Teil, der durch die % abgeglichen wird).

+0

Schöne Erklärungen. Vielen Dank! –

+0

Ein Beispiel für "|" War nett, danke. –

2

Sieht aus wie das, was ich suche:

ALLS=task01-all task02-all 
BUILDS=${ALLS:-all=-build} 
CLEANS=${ALLS:-all=-clean} 
RUNS=${ALLS:-all=-run} 

.PHONY: all $(ALLS) $(CLEANS) $(BUILDS) $(RUNS) 

all: $(ALLS) 

############################################################################### 
$(ALLS): $(CLEANS) $(BUILDS) $(RUNS) 

$(CLEANS): 
     rm ${@:-clean=} ${@:-clean=}.{ext,o} -f 

$(BUILDS): 
     compiler ${@:-build=}.ext -O2 --make 

$(RUNS): 
     ./${@:-run=} 
Verwandte Themen