Domanda

Ho un makefile che crea e poi chiama un altro makefile. Dal momento che questo makefile chiama più makefile che fa il lavoro, non cambia davvero. Quindi continua a pensare che il progetto sia stato costruito e aggiornato.

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

Come posso forzare il makefile a 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: nomi rimossi per proteggere gli innocenti

Modifica: versione fissa finale:

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
È stato utile?

Soluzione

Potresti dichiarare uno o più dei tuoi target come falso.

  

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

     

...

     

Un target fasullo non dovrebbe essere un prerequisito di un vero file target; Se   lo è, la sua ricetta verrà eseguita ogni volta che andrà ad aggiornarla   file. Finché un bersaglio falso non è mai un prerequisito di un reale   bersaglio, la ricetta del bersaglio falso verrà eseguita solo quando il falso   target è un obiettivo specificato

Altri suggerimenti

L'opzione -B da fare, la cui forma lunga è --sempre-make , dice a make di ignorare i timestamp e rendere il valore specificato obiettivi. Questo potrebbe vanificare lo scopo di usare make, ma potrebbe essere quello che ti serve.

Un trucco che era documentato in un manuale Sun per make è usare un target (inesistente) '.FORCE'. Puoi farlo creando un file, force.mk, che contiene:

.FORCE:
$(FORCE_DEPS): .FORCE

Quindi, supponendo che il tuo makefile esistente sia chiamato makefile , potresti eseguire:

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

Poiché .FORCE non esiste, tutto ciò che dipende da esso sarà obsoleto e ricostruito.

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

Vale anche la pena considerare perché make considera il rilascio aggiornato. Ciò potrebbe essere dovuto al fatto che 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 è aggiornato. Quindi c'è il vero motivo ...

Qualcun altro ha suggerito .PHONY che è decisamente corretto. .PHONY dovrebbe essere usato per qualsiasi regola per la quale un confronto di date tra input e output non è valido. Dato che non hai obiettivi nel formato 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 con sezioni di input e output in modo da poter utilizzare i vantaggi di make, ovvero che in realtà compilare solo le cose necessarie per copmile!

Modifica: esempio aggiunto. Non testato, ma è così che fai .PHONY

.PHONY: clean    
clean:
    $(clean)

Se ricordo bene, 'make' usa i timestamp (ora di modifica del file) per determinare se un target è aggiornato. Un modo comune per forzare una ricostruzione è quello di aggiornare quel timestamp, usando il comando 'touch'. Potresti provare a invocare 'touch' nel tuo makefile per aggiornare il timestamp di uno dei target (forse uno di quei sub-makefile), che potrebbe costringere Make ad eseguire quel comando.

Questa semplice tecnica consentirà al makefile di funzionare normalmente quando non si desidera forzare. Crea un nuovo target chiamato force alla fine del makefile . La destinazione forza toccherà un file da cui dipende la destinazione predefinita. Nell'esempio seguente, ho aggiunto touch myprogram.cpp . Ho anche aggiunto una chiamata ricorsiva per effettuare . Ciò causerà il raggiungimento del target predefinito ogni volta che si digita make force .

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

force:
       touch yourProgram.cpp
       make

Ho provato questo e ha funzionato per me

aggiungi queste righe a Makefile

clean:
    rm *.o output

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

salva e ora chiama

make new 

e ricompilerà di nuovo tutto

Che cosa è successo?

1) 'nuove' chiamate pulite. 'clean' do 'rm' che rimuove tutti i file oggetto con estensione '.o'.

2) 'new' chiama 'make'. 'make' vede che non ci sono file '.o', quindi crea nuovamente '.o'. quindi il linker collega tutti i file .o in un output eseguibile

Buona fortuna

Secondo il Ricorsivo considerato dannoso di Miller dovresti evitare di chiamare $ (FARE) ! Nel caso che mostri, è innocuo, perché questo non è davvero un makefile, solo uno script wrapper, che potrebbe anche essere stato scritto in Shell. Ma dici di continuare così a livelli di ricorsione più profondi, quindi probabilmente hai riscontrato i problemi mostrati in quel saggio di apertura degli occhi.

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

OTOH, makepp è stata creata 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 makefile legacy sono scritti in modo ricorsivo. Quindi c'è una soluzione alternativa in cui $ (MAKE) non fa altro che canalizzare i sottorequisiti al processo di makepp principale. Solo se fai cose ridondanti o, peggio, contraddittorie tra le tue sottomissioni, devi richiedere --traditional-recursive-make (che ovviamente rompe 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 eventuali hack suggeriti qui da altri.

Se non hai bisogno di conservare nessuno degli output che hai già compilato con successo

nmake /A 

ricostruisce tutto

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

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

È già stato menzionato, ma ho pensato di aggiungere l'utilizzo di touch

Se tocchi tutti i file di origine da compilare, il comando touch modifica i timestamp di un file nell'ora di sistema in cui touch il comando è stato eseguito.

Il timstamp del file sorgente è ciò che make usa per " conoscere " un file è stato modificato e deve essere ricompilato

Ad esempio: se il progetto era un progetto c ++, quindi fare toccare * .cpp , quindi eseguire nuovamente make e make dovrebbe ricompilare l'intero progetto.

make clean elimina tutti i file oggetto già compilati.

Sul mio sistema Linux (Centos 6.2), esiste una differenza significativa tra la dichiarazione del target .PHONY e la creazione di una dipendenza falsa su FORCE, quando la regola crea effettivamente un file corrispondente al target. Quando il file deve essere rigenerato ogni volta, richiede entrambi la falsa dipendenza FORCE sul file e .PHONY per la falsa dipendenza.

sbagliato:

date > $@

giusto:

FORCE
    date > $@
FORCE:
    .PHONY: FORCE
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top