2009-05-03 12 views
114

Ho un makefile che crea e chiama un altro makefile. Dal momento che questo makefile chiama più makefile che fa il lavoro non cambia davvero. Così continua a pensare che il progetto sia costruito e aggiornato.Come si forza un makefile per ricostruire un target

dnetdev11 ~ # make 
make: `release' is up to date. 

Come faccio a forzare il makefile per ricostruire il target?

clean = $(MAKE) -f ~/xxx/xxx_compile.workspace.mak clean 


build = svn up ~/xxx              \ 
     $(clean)                \ 
     ~/cbp2mak/cbp2mak -C ~/xxx ~/xxx/xxx_compile.workspace  \ 
     $(MAKE) -f ~/xxx/xxx_compile.workspace.mak $(1)     \ 


release: 
     $(build) 

debug: 
     $(build DEBUG=1) 

clean: 
     $(clean) 

install: 
     cp ~/xxx/source/xxx_utility/release/xxx_util /usr/local/bin 
     cp ~/xxx/source/xxx_utility/release/xxxcore.so /usr/local/lib 

Nota: i nomi rimossi per proteggere gli innocenti

Edit: Final versione fissa:

clean = $(MAKE) -f xxx_compile.workspace.mak clean; 


build = svn up;           \ 
     $(clean)          \ 
     ./cbp2mak/cbp2mak -C . xxx_compile.workspace; \ 
     $(MAKE) -f xxx_compile.workspace.mak $(1); \ 


.PHONY: release debug clean install 

release: 
     $(call build,) 

debug: 
     $(call build,DEBUG=1) 

clean: 
     $(clean) 

install: 
     cp ./source/xxx_utillity/release/xxx_util /usr/bin 
     cp ./dlls/Release/xxxcore.so /usr/lib 

risposta

30

Si potrebbe dichiarare uno o più dei vostri obiettivi per essere phony.

Un target fasullo è uno che non è realmente il nome di un file; piuttosto è è solo un nome per una ricetta da eseguire quando si effettua una richiesta esplicita . Esistono due motivi per utilizzare un obiettivo fasullo: evitare un conflitto con un file con lo stesso nome e migliorare le prestazioni.

...

Un obiettivo fasullo non dovrebbe essere un prerequisito di un file vero obiettivo; se è, la sua ricetta verrà eseguita ogni volta che make va ad aggiornare il file . Fino a quando un obiettivo falso non è mai un prerequisito di una vera e propria bersaglio, la ricetta di destinazione fasullo verrà eseguito solo quando il falso bersaglio è un obiettivo specificato

+41

Questa risposta, sebbene sia "accettata" e altamente "ottimizzata", è davvero off-the-mark. In primo luogo, dice "dichiarare gli obiettivi come falsi", ma poi dice "l'obiettivo fasullo non è in realtà il nome di un file".Bene, se il tuo obiettivo è un file, allora questa è una contraddizione nella risposta. Secondo, dice "l'obiettivo fasullo non dovrebbe essere un prerequisito di un reale" - beh, e se lo fosse? La domanda originale, non ha specificato se è o non lo è. La risposta corretta è, _non_ dichiarare _your_ bersagli per essere fasulli, ma piuttosto dichiarare un bersaglio fasullo aggiuntivo, e quindi, dipendere dai bersagli che vuoi ricostruire, su quello. –

4

Se ricordo bene, 'fare' utilizza timestamp (tempo di modifica del file) per determinare se un target è aggiornato o meno. Un modo comune per forzare una ricostruzione è aggiornare tale timestamp, usando il comando 'touch'. Puoi provare a invocare il "tocco" nel tuo makefile per aggiornare il timestamp di uno dei bersagli (forse uno di quei sotto-makefile), il che potrebbe costringere Make ad eseguire quel comando.

12

Qualcun altro ha suggerito .PHONY che è sicuramente corretto. .PHONY dovrebbe essere utilizzato per qualsiasi regola per cui un confronto di data tra l'input e l'output non è valido. Dal momento che non hai alcun bersaglio del modulo output: input dovresti usare .PHONY per TUTTI!

Detto questo, probabilmente dovresti definire alcune variabili nella parte superiore del tuo makefile per i vari nomi di file e definire regole di creazione reali che hanno entrambe le sezioni di input e di output in modo da poter utilizzare i vantaggi del make, ovvero che tu sia " Compilerò solo le cose che sono necessarie per copmila!

Modifica: aggiunto esempio. Non testato, ma questo è come lo fai .PHONY

.PHONY: clean  
clean: 
    $(clean) 
+0

Beh, se potessi mostrarmi un esempio, sarebbe bello. Ti basta hackerarlo cercando di far funzionare la diga: P – Lodle

+1

La posizione del bersaglio '.PHONY' non ha importanza. Può essere ovunque nel 'Makefile'. –

+0

Modificato "prima di" su "per". Good point = p – easel

433

L'interruttore -B da fare, la cui forma è lunga --always-make, dice make di ignorare timestamp e rendere gli obiettivi specificati. Questo potrebbe vanificare lo scopo dell'uso di make, ma potrebbe essere quello di cui hai bisogno.

+67

Questa dovrebbe essere la risposta accettata ... –

+3

@MarkKCowan Sono completamente d'accordo! Questa opzione è esattamente ciò che stavo cercando, non qualche trucco alternativo come suggerisce Dave. –

+4

L'avvertenza con questo approccio è che crea solo troppe cose. Specificamente con gli autotools, l'ho visto eseguire di nuovo la configurazione .. Vorrei che una soluzione basata su LD_PRELOAD possa essere compilata !! – vrdhn

14

Un trucco che prima era documentato in un manuale Sun per make consiste nell'utilizzare una destinazione (inesistente) ".FORCE". Puoi farlo creando un file, forza.mk, che contiene:

.FORCE: 
$(FORCE_DEPS): .FORCE 

Quindi, supponendo che il makefile esistente è chiamato makefile, è possibile eseguire:

make FORCE_DEPS=release -f force.mk -f makefile release 

Dal .FORCE non esiste, tutto ciò che dipende da esso sarà superata e ricostruito.

Tutto ciò funzionerà con qualsiasi versione di make; su Linux, hai GNU Make e puoi quindi utilizzare il target .PHONY come discusso.

Vale anche la pena considerare perché make considera la versione aggiornata. Questo potrebbe essere perché hai un comando touch release tra i comandi eseguiti; potrebbe essere perché esiste un file o una directory chiamata 'release' che esiste e non ha dipendenze e quindi è aggiornata. Poi c'è il vero motivo ...

0

In realtà dipende da quale sia l'obiettivo. Se si tratta di un obiettivo fasullo (ovvero il target NON è correlato a un file) dovresti dichiararlo come .PHONY.

Se tuttavia il target non è un target fasullo ma si desidera ricostruirlo per qualche motivo (un esempio è quando si utilizza la macro di preelaborazione __TIME__), è necessario utilizzare lo schema FORCE descritto nelle risposte qui.

1

Secondo Miller Recursive Make Considered Harmful si dovrebbe evitare di chiamare $(MAKE)! Nel caso in cui mostri, è innocuo, perché questo non è proprio un makefile, solo uno script wrapper, che potrebbe essere stato scritto in Shell. Ma tu dici di continuare così a livelli di ricorsione più profondi, quindi probabilmente hai incontrato i problemi mostrati in quel saggio che apre gli occhi.

Naturalmente con GNU è complicato da evitare. E anche se sono consapevoli di questo problema, è il loro modo documentato di fare le cose.

OTOH, makepp è stato creato come soluzione per questo problema. Puoi scrivere i tuoi makefile a livello di directory, ma tutti vengono disegnati insieme in una visione completa del tuo progetto.

Ma i file di versioni precedenti sono scritti in modo ricorsivo. Quindi c'è una soluzione alternativa in cui lo $(MAKE) non fa altro che reindirizzare i subroquest al processo makepp principale. Solo se si fanno cose ridondanti o, peggio, contraddittorie tra i propri submakes, è necessario richiedere --traditional-recursive-make (che ovviamente spezza questo vantaggio di makepp). Non conosco i tuoi altri makefile, ma se sono scritti in modo pulito, con makepp le ricostruzioni necessarie dovrebbero avvenire automaticamente, senza la necessità di alcun hack suggerito qui da altri.

+0

Non risponde alla domanda: tangente al punto principale e dovrebbe essere un commento non una risposta. – flungo

+0

Forse non ero abbastanza chiaro. Con [makepp] (http://makepp.sourceforge.net/) questo intero wrapper makefile non è necessario. Conoscendo le dipendenze esatte (tutte, non solo quelle che sono elencate dopo ':'), verranno sempre ricostruite quando necessario. – Daniel

-1

Sul mio sistema Linux (Centos 6.2), c'è una differenza significativa tra dichiarare il target .PHONY e creare una falsa dipendenza su FORCE, quando la regola effettivamente crea un file che corrisponde alla destinazione. Quando il file deve essere rigenerato ogni volta, è necessario sia la falsa dipendenza FORCE sul file, sia .PHONY per la falsa dipendenza.

errata:

date > [email protected] 

destra:

FORCE 
    date > [email protected] 
FORCE: 
    .PHONY: FORCE 
3

Questa semplice tecnica consentirà al makefile di funzionare normalmente quando forzamento non è desiderata. Crea un nuovo target chiamato force alla fine del tuo makefile. L'obiettivo forza tocca un file da cui dipende la destinazione predefinita. Nell'esempio seguente, ho aggiunto touch myprogram.cpp. Ho anche aggiunto una chiamata ricorsiva a make. Questo farà sì che la destinazione predefinita venga eseguita ogni volta che si digita come forza.

yourProgram: yourProgram.cpp 
     g++ -o yourProgram yourProgram.cpp 

force: 
     touch yourProgram.cpp 
     make 
0

E 'stato già detto, ma pensato che avrei potuto aggiungere ad usare touch

Se si touch tutti i file di origine per essere compilati, il comando touch cambia i timestamp di un file per l'ora del sistema del touch il comando è stato eseguito.

Il file timstamp fonte è ciò make utilizza per "conoscere" un file è stato modificato, e ha bisogno di essere ri-compilato

Per esempio: se il progetto era un progetto C++, poi fare touch *.cpp, quindi eseguire make di nuovo, e fare dovrebbe ricompilare l'intero progetto.

2

Ho provato questo e ha funzionato per me

aggiungere queste righe al Makefile

clean: 
    rm *.o output 

new: clean 
    $(MAKE)  #use variable $(MAKE) instead of make to get recursive make calls 

salvare e ora chiamare

make new 

che verrà ricompilare tutto nuovo

Cosa è accaduto?

chiamate 'nuove' pulite 'clean' do 'rm' che rimuove tutti i file oggetto che hanno l'estensione di '.o' 'nuove' chiamate 'make'. 'fai' vedere che non ci sono file '.o' quindi va avanti e crea di nuovo tutti '.o'. poi i link linker tutti del file .o int un'uscita eseguibile

Buona fortuna

+1

Nella ricetta per 'new' uso migliore' $ (MAKE) 'di' make' –

+0

aggiornato. Grazie – hamaney

1

Se non è necessario per preservare una delle uscite che già compilato

nmake /A 

ricostruisce tutti

1

make clean elimina tutti i file oggetto già compilati.

Problemi correlati