2012-08-30 8 views
15

Sto eseguendo il seguente tipo di tubazione:dire 'fare' a ignorare le dipendenze quando l'obiettivo superiore è stato creato

digestA: hugefileB hugefileC 
    cat $^ > [email protected] 
    rm $^ 

hugefileB: 
    touch [email protected] 

hugefileC: 
    touch [email protected] 

Gli obiettivi hugefileB e hugefileC sono molto grandi e prendere un lungo tempo di calcolare (e ha bisogno del potere di Make). Ma una volta creato digestA, non è necessario mantenere le sue dipendenze: elimina tali dipendenze per liberare spazio su disco.

Ora, se invoco 'make' ancora una volta, hugefileB e hugefileC sarà ricostruito, mentre Digesta è già ok.

C'è un modo per dire 'make' per evitare di ri-associare le dipendenze?

NOTA: non voglio creare le due dipendenze all'interno delle regole per 'digestA'.

+2

Si desidera ricostruire 'digestA' solo quando non esiste già, giusto? – Beta

+0

@Beta "Si desidera ricostruire digestA solo quando non esiste già": sì – Pierre

risposta

22

Uso "intermediate files" di GNU Make:

file intermedi sono rifatto utilizzando le loro regole, proprio come tutti gli altri file. Ma i file intermedi vengono trattati in modo diverso in due modi.

La prima differenza è cosa succede se il file intermedio non esiste. Se un file ordinario b non esiste e considera un obiettivo che dipende da b, invariabilmente crea b, quindi aggiorna il target da b. Ma se b è un file intermedio, quindi make può lasciare abbastanza bene da solo. Non disturberà l'aggiornamento di b, o il target finale, a meno che qualche prerequisito di b non sia nuovo rispetto a quell'obiettivo o ci sia qualche altra ragione per aggiornare quel target.

La seconda differenza è che se make crea b per aggiornare qualcos'altro, cancella b in seguito dopo che non è più necessario. Pertanto, un file intermedio che non esisteva prima di fare anche non esiste dopo il make. crea report cancellandoti stampando un comando rm -f che mostra il file che sta eliminando.

In genere, un file non può essere intermedio se viene menzionato nel makefile come obiettivo o prerequisito.Tuttavia, è possibile contrassegnare esplicitamente un file come intermedio elencandolo come prerequisito del target speciale .INTERMEDIATE. Questo ha effetto anche se il file è menzionato esplicitamente in qualche altro modo.

È possibile impedire la cancellazione automatica di un file intermedio contrassegnandolo come file secondario. Per fare ciò, elencarlo come prerequisito del target speciale .SECONDARY. Quando un file è secondario, make non crea il file semplicemente perché non esiste già, ma make non elimina automaticamente il file. Contrassegnare un file come secondario lo segna anche come intermedio.

Quindi, aggiungendo la seguente riga al Makefile dovrebbe essere sufficiente:

.INTERMEDIATE : hugefileB hugefileC 

Invocare fare per la prima volta:

$ make 
touch hugefileB 
touch hugefileC 
cat hugefileB hugefileC > digestA 
rm hugefileB hugefileC 

E la prossima volta:

$ make 
make: `digestA' is up to date. 
+0

molte grazie. È molto utile La tua soluzione è stata citata qui: http://plindenbaum.blogspot.com/2012/08/next-generation-sequencing-gnu-make-and.html – Pierre

+0

Hai qualche idea sul perché .secondary non è il comportamento predefinito per tutti gli obiettivi? –

+0

@Pierre, prego. Grazie per la citazione! –

1

Si consiglia di creare file di pseudo-cache creati dagli obiettivi hugefileB e hugeFileC.

Quindi avere digestA dipende da quei file di cache, perché si sa che non cambieranno di nuovo fino a quando non si invocano manualmente gli obiettivi costosi.

0

Il modo corretto è quello di non eliminare i file, in quanto rimuove le informazioni che make utilizza per determinare se ricostruire i file.

Ricreare come vuoti non aiuta perché make assumerà quindi che i file vuoti siano completamente compilati.

Se esiste un modo per unire i digest, è possibile crearne uno da ciascuno dei file di grandi dimensioni, che viene quindi conservato e l'enorme file rimosso automaticamente poiché si tratta di un intermedio.

caratteristica
2

Se si contrassegnano hugefileB e hugefileC come intermediate files, si otterrà il comportamento desiderato:

digestA: hugefileB hugefileC 
     cat $^ > [email protected] 

hugefileB: 
     touch [email protected] 

hugefileC: 
     touch [email protected] 

.INTERMEDIATE: hugefileB hugefileC 

Ad esempio:

$ gmake 
touch hugefileB 
touch hugefileC 
cat hugefileB hugefileC > digestA 
rm hugefileB hugefileC 
$ gmake 
gmake: `digestA' is up to date. 
$ rm -f digestA 
$ gmake 
touch hugefileB 
touch hugefileC 
cat hugefileB hugefileC > digestA 
rm hugefileB hugefileC 

Si noti che non è necessario il comando esplicito rm $^ più - gmake elimina automaticamente file intermedi alla fine della build.