Come forzare un makefile a ricostruire un obiettivo


184

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 l'innocente

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

Lodle, dal momento che questa è una domanda frequentemente visitata, vorresti modificare la domanda per renderla più moderna? (Sembra che .PHONYnon sia stato il tuo unico problema e non dovresti davvero modificare la soluzione nella domanda, o almeno non più.)
Keith M

Risposte:


23

Potresti dichiarare falso uno o più dei tuoi obiettivi .

Un target falso è uno che non è proprio 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 target falso: evitare un conflitto con un file con lo stesso nome e migliorare le prestazioni.

...

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


68
Questa risposta, mentre è "accettata" e altamente "votata" è davvero fuori dal comune. Innanzitutto, dice "dichiara i target come falsi", ma poi dice "target fasullo non è proprio il nome di un file". Bene, se il tuo obiettivo è un file, questa è una contraddizione nella risposta. Secondo, dice "il bersaglio falso non dovrebbe essere un prerequisito di un vero" - beh, e se lo fosse? La domanda originale, non ha specificato se lo è o non lo è. La risposta corretta, è, non dichiarare i tuoi bersagli come falsi, ma piuttosto dichiarare un bersaglio falso aggiuntivo e, quindi, dipendere da quelli che vuoi ricostruire.
Mark Galeck,

2
@MarkGaleck. Quando la risposta afferma che "Un target falso è uno che non è proprio il nome di un file", sta citando direttamente dal manuale di gcc make. È perfettamente corretto.
drlolly,

"Target" è un termine Make che si riferisce al testo a sinistra dei due punti :, non solo al risultato finale che si desidera creare (ad es. Il file binario). Nella domanda, release, debug, clean, e installsono gli obiettivi fare, non xxx_utilo xxxcore.soo qualsiasi altra cosa.
Keith M

728

Il -Bpassaggio da fare, la cui forma lunga è --always-make, dice makedi ignorare i timestamp e fare gli obiettivi specificati. Questo potrebbe vanificare lo scopo di usare make, ma potrebbe essere quello di cui hai bisogno.


4
@MarkKCowan Sono completamente d'accordo! Questa opzione è esattamente quello che stavo cercando, non una soluzione alternativa come suggerisce Dave.
Maarten Bamelis,

8
L'avvertenza con questo approccio è che costruisce solo troppe cose. In particolare con gli autotools, l'ho visto eseguire nuovamente la configurazione .. Vorrei che fosse possibile costruire una soluzione basata su LD_PRELOAD !!
vrdhn,

sì, e può anche riscrivere i file che non volevi! come le librerie di sistema globali che compaiono nelle dipendenze e che vengono ricostruite e sovrascritte ...
Julio Guerra

18

Un trucco usato per essere documentato in un manuale Sun makeè l'uso di un bersaglio (inesistente) ". FORZA". Puoi farlo creando un file, force.mk, che contiene:

.FORCE:
$(FORCE_DEPS): .FORCE

Quindi, supponendo che venga chiamato il tuo makefile esistente makefile, puoi eseguire:

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

Poiché .FORCEnon 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é makeconsidera il rilascio aggiornato. Ciò potrebbe essere dovuto al fatto che hai un touch releasecomando 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 ...


14

Qualcun altro ha suggerito .PHONY che è decisamente corretto. .PHONY dovrebbe essere usato per qualsiasi regola per la quale un confronto delle date tra input e output non è valido. Dal momento che non hai obiettivi 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 con sezioni di input e output in modo da poter utilizzare i vantaggi di make, vale a dire che dovrai effettivamente compilare cose che sono necessarie per copmile!

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

.PHONY: clean    
clean:
    $(clean)

1
Bene, se potessi mostrarmi un esempio sarebbe bello. Atm, sto solo cercando di far funzionare la diga: P
Lodle,

1
La posizione del .PHONYbersaglio non ha importanza. Può essere ovunque nel Makefile.
Adrian W,

5

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.


5

Questa semplice tecnica consentirà al makefile di funzionare normalmente quando non si desidera forzare. Crea un nuovo target chiamato force alla fine del tuo makefile . Il target forzato toccherà un file da cui dipende il target predefinito. Nell'esempio seguente, ho aggiunto touch myprogram.cpp . Ho anche aggiunto una chiamata ricorsiva da 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

Non dovresti mai usare makeall'interno di un Makefile. Usa $(MAKE)invece.
Benjamin Crawford Ctrl-Alt-Tut

3

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

Quello che è successo?

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

2) "nuove" chiamate "make". 'make' vede che non ci sono file '.o', quindi crea nuovamente '.o'. quindi il linker collega tutto il file .o in un output eseguibile

In bocca al lupo


1
In ricetta per newun uso migliore $(MAKE)dimake
Basile Starynkevitch il

1

Secondo Millers ricorsivo considerato dannoso dovresti evitare di chiamare $(MAKE)! 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 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 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.


Non ha risposto alla domanda: tangente al punto principale e dovrebbe essere un commento, non una risposta.
flungo,

Forse non ero abbastanza chiaro. Con makepp non è necessario l'intero makefile del wrapper. Conoscendo le dipendenze esatte (tutte, non solo quelle elencate dopo :), si ricostruirà sempre quando necessario.
Daniel,

1

Se non è necessario conservare nessuno degli output già compilati correttamente

nmake /A 

ricostruisce tutto


0

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 ricostruirlo per qualche motivo (un esempio è quando si utilizza la macro di preelaborazione __TIME__), è necessario utilizzare lo schema FORCE descritto nelle risposte qui.



0

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

Se touchtutti i file di origine da compilare, il touchcomando modifica i timestamp di un file sull'ora di sistema in cui è touchstato eseguito il comando.

Il timstamp del file di origine è ciò che viene makeutilizzato per "sapere" che un file è stato modificato e deve essere ricompilato

Ad esempio: se il progetto era un progetto c ++ touch *.cpp, quindi esegui, quindi esegui di makenuovo e make dovrebbe ricompilare l'intero progetto.


0

Come ha sottolineato Abernier, esiste una soluzione raccomandata nel manuale di GNU make, che utilizza un obiettivo "falso" per forzare la ricostruzione di un obiettivo:

clean: FORCE
        rm $(objects)
FORCE: ; 

Questo funzionerà pulito, indipendentemente da qualsiasi altra dipendenza.

Ho aggiunto il punto e virgola alla soluzione dal manuale, altrimenti è richiesta una riga vuota.


-1

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

sbagliato:

date > $@

giusto:

FORCE
    date > $@
FORCE:
    .PHONY: FORCE

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.