2012-12-27 23 views
6

Qual è la migliore pratica per scrivere codice riutilizzabile in Makefile s?Procedura consigliata per scrivere codice riutilizzabile

Supponiamo che io sono un 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 

Ora voglio aggiungere nuova famiglia di compiti (task03), e ho bisogno di CopyPaste intera sezione, fare s/02/03/ per esso e aggiungerli al .PHONY sezione - è rumoroso, disgustoso e non proprio giusto.

Come posso evitarlo? Potrei ridefinire tutte le attività con i template in qualche modo per avere un buon meccanismo per aggiungere un nuovo gruppo di attività in una riga?

risposta

9

Poiché la questione è circa la scrittura di codice riutilizzabile in Makefiles, ti darò un esempio di come utilizzare le regole del modello in GNU Make (sembra come quello che stai usando dato che menzioni la destinazione .PHONY). Tuttavia, se non si sta usando qualsiasi controllo delle dipendenze di marca, può essere più semplice di fare questo con uno script di shell - qualcosa come:

#!/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 

Ma, per espandere il principio di fare, abbiamo un altro problema affrontare. Linee di forma:

task01-all: task01-clean task01 task01-run 

non dicono Fai in quale ordine di costruire i pre-requisiti - solo che tutti hanno bisogno di essere fatto prima di task01-all ottiene costruito. Invece, ogni passo da eseguire dovrebbe dipendere dal passo precedente. Qualcosa di simile a questo:

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: % 
    ./$< 

Le regole con % sono chiamate "regole" del modello, e sono un ottimo strumento per evitare di ri-scrivere la stessa regola più volte per diversi target. Un avvertimento è che Make normalmente non controlla le regole del modello per un target .PHONY; diciamo Fai di fare questo esplicitamente prefiggendo quelle regole con l'elenco di obiettivi e un secondo due punti (ad esempio, $(TASKS):).

Dal task01-run esigenze task01 al fine di lavorare, facciamo %-run obiettivi dipendono %. Inoltre, il tuo Makefile mostra che vuoi eseguire la pulizia ogni volta, quindi facciamo % dipendente da %-clean. Dal momento che lo %-clean in realtà non produce alcun output, creiamo una dipendenza "solo ordine" - Make non cercherà un time stamp o altro, verrà semplicemente eseguita la regola %-clean per prima cosa ogni volta che è necessario eseguire lo % regola. "Ordine solo" dipendenze sono posti dopo un |:

%: %.ext | %-clean 

vale la pena ricordare che uno dei più grandi punti di forza di fare è che si può risparmiare tempo evitando di ripetere il lavoro che non ha bisogno di essere ripetuto - cioè, esegue una regola solo se le dipendenze sono più recenti della destinazione.Quindi, si potrebbe lasciare fuori la dipendenza %-clean, che causerebbe far correre solo compiler $< -O2 --make se %.ext è più recente rispetto %:

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

È quindi possibile aggiungere una regola solo per eseguire tutte le %-clean obiettivi:

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

clean: $(TASKS:run=clean) 

Ultima cosa: utilizzo alcune variabili speciali nelle ricette. [email protected] indica l'obiettivo in fase di costruzione. $< indica la prima dipendenza. $* indica la "radice" di una regola del modello (ad esempio, la parte corrispondente allo %).

+0

Belle spiegazioni. Grazie! –

+0

Fornire un esempio per "|" è stato bello, grazie. –

2

Sembra che quello che sto cercando:

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=} 
Problemi correlati