2012-12-13 10 views
10

Ecco una versione ridotta del mio Makefile:dipendenze Makefile non funzionano per obiettivo fasullo

.PHONY: all 

all: src/server.coffee 
    mkdir -p bin 
    ./node_modules/.bin/coffee -c -o bin src/server.coffee 

Voglio correre make e hanno solo lo ricompilare quando src/server.coffee è cambiato. Tuttavia, ricompila ogni volta che corro make:

$ make 
mkdir -p bin 
./node_modules/.bin/coffee -c -o bin src/server.coffee 
$ make 
mkdir -p bin 
./node_modules/.bin/coffee -c -o bin src/server.coffee 

Se cambio il mio Makefile non usare un obiettivo fasullo, funziona come previsto. Nuovo Makefile:

bin/server.js: src/server.coffee 
    mkdir -p bin 
    ./node_modules/.bin/coffee -c -o bin src/server.coffee 

Risultato:

$ make 
mkdir -p bin 
./node_modules/.bin/coffee -c -o bin src/server.coffee 
$ make 
make: `bin/server.js' is up to date. 

Perché non si è rispettare i miei dipendenze con un obiettivo fasullo? Il motivo per cui lo chiedo è perché in realtà, non sto semplicemente compilando un singolo file in un singolo altro file, quindi non voglio dover tenere traccia dei nomi di tutti i file di output da utilizzare come target.

risposta

8

Piuttosto che un obiettivo fasullo (che come @cmotley sottolinea, sta lavorando esattamente come dovrebbe) quello che si potrebbe usare quando si vuole evitare lavoro extra è un "empty target":

Il bersaglio è un vuoto variante del bersaglio fasullo; è usato per contenere le ricette per un'azione che si richiede esplicitamente di volta in volta. A differenza di un obiettivo fasullo, questo file di destinazione può esistere davvero; ma il contenuto del file non ha importanza e di solito è vuoto.

Lo scopo del file di destinazione vuoto è di registrare, con il suo tempo di ultima modifica, quando la ricetta della regola è stata eseguita l'ultima volta. Lo fa perché uno dei comandi nella ricetta è un comando touch per aggiornare il file di destinazione.

Tuttavia, in questo caso non c'è davvero alcun bisogno di aggiungere un file di output vuoto in più - hai già l'uscita della compilation CoffeeScript! Questo si adatta al più tipico pattern Makefile, come hai già dimostrato nella tua domanda. Che cosa si potrebbe fare è refactoring a questo approccio:

.PHONY: all 
all: bin/server.js 

bin/server.js: src/server.coffee 
    mkdir -p bin 
    ./node_modules/.bin/coffee -c -o bin src/server.coffee 

Ora avete due cose: una bella convenzionale "tutti" di destinazione che è correttamente falso, ma non lo farà lavoro extra. Lei è anche in una posizione migliore per rendere questo più generico in modo da poter facilmente aggiungere più file:

.PHONY: all 
all: bin/server.js bin/other1.js bin/other2.js 

bin/%.js: src/%.coffee 
    mkdir -p bin 
    ./node_modules/.bin/coffee -c -o bin $< 
+3

Giusto per essere chiari, un ** target vuoto ** deve essere un file ed è davvero usato solo per il suo timestamp? Esiste un altro tipo di '.PHONY' che consente a una regola di destinazione di avere un corpo di una ricetta (con comandi eseguiti) * e * eseguiti solo quando le dipendenze hanno bisogno di essere aggiornate? Sembra piuttosto spezzato, dato che avere '.PHONY' fa cose diverse a seconda che abbia o meno un corpo di ricette. – jozxyqk

4

È necessario un file di destinazione da confrontare con il tempo di modifica del file server.coffee. Dal momento che non hai un obiettivo concreto make non puoi sapere se l'uscita è più recente della dipendenza o meno, quindi verrà sempre creato all.

+0

Ah, grazie. Non mi rendevo conto che è così che computare quali file dovevano essere ricompilati. Molto utile –

9

Secondo la documentazione fa:

The prerequisites of the special target .PHONY are considered 
to be phony targets. When it is time to consider such a target, 
make will run its recipe unconditionally, regardless of whether 
a file with that name exists or what its last-modification time is. 

http://www.gnu.org/software/make/manual/html_node/Special-Targets.html

Fai gestisce la ricetta di obiettivi fasulli incondizionatamente - prerequisiti non contano.

+0

Ok, è abbastanza semplice. Sei a conoscenza di una buona soluzione per raggiungere l'obiettivo di non dover dichiarare esplicitamente i file di output che dipendono da un insieme di file sorgente? –

+0

È possibile dichiarare alcune variabili per tenere traccia dei file di origine e dei file oggetto. Ad esempio, SRC = $ (carattere jolly ./src/*.c) e OBJECTS = $ (patsubst% .c,% .o, $ (SRC)). Quindi $ (OGGETTI) potrebbe essere un prerequisito per il tuo obiettivo. Penso che sia quello che stai cercando di fare. – cmotley

1

Mentre gli altri menzionati, fare esamina il timestamp del file da capire se le dipendenze sono cambiate.

Se si desidera "emulare" una destinazione fasulla con dipendenze, sarà necessario creare un file reale con quel nome e utilizzare il comando touch (su sistemi Unix).

Avevo bisogno di una soluzione per pulire solo la directory se i makefile sono stati modificati (cioè i flag del compilatore sono stati modificati, quindi i file oggetto devono essere ricompilati).

Ecco quello che ho usato (e corre prima di ogni compilazione) con un file denominato makefile_clean:

makefile_clean: makefile 
    @rm '*.o' 
    @sudo touch makefile_clean 

Il comando touch aggiorna il timestamp dell'ultima modifica al tempo corrente.

Problemi correlati