Come stampare una variabile in makefile


247

Nel mio makefile, ho una variabile 'NDK_PROJECT_PATH', la mia domanda è come posso stamparlo quando viene compilato?

Ho letto Make echo file visualizzando la stringa "$ PATH" e ho provato:

@echo $(NDK_PROJECT_PATH)
@echo $(value NDK_PROJECT_PATH)

Entrambi mi danno

"build-local.mk:102: *** missing separator.  Stop."

Qualcuno sa perché non funziona per me?

Risposte:


223

Puoi stampare le variabili mentre il makefile viene letto (supponendo che GNU make abbia taggato questa domanda in modo appropriato) usando questo metodo (con una variabile chiamata "var"):

$(info $$var is [${var}])

Puoi aggiungere questo costrutto a qualsiasi ricetta per vedere quale marca passerà alla shell:

.PHONY: all
all: ; $(info $$var is [${var}])echo Hello world

Ora, ciò che accade qui è che memorizza l'intera ricetta ( $(info $$var is [${var}])echo Hello world) come singola variabile espansa ricorsivamente. Quando make decide di eseguire la ricetta (ad esempio quando le dici di compilare all), espande la variabile e quindi passa ciascuna riga risultante separatamente alla shell.

Quindi, nei dettagli dolorosi:

  • Si espande $(info $$var is [${var}])echo Hello world
  • Per fare ciò si espande prima $(info $$var is [${var}])
    • $$ diventa letterale $
    • ${var}diventa :-)(diciamo)
    • L'effetto collaterale è che $var is [:-)]appare fuori standard
    • L'espansione del $(info...)pensiero è vuota
  • Make è rimasto con echo Hello world
    • echo Hello worldPrima fai stampe su stdout per farti sapere cosa chiederà alla shell di fare
  • La shell stampa Hello worldsu stdout.

2
dovrebbe essere (punto) .PHONY anziché PHONY?
Hammadian,

172

Come da GNU Make manual e anche indicato da 'bobbogo' nella risposta qui sotto, puoi usare info / warning / error per visualizzare il testo.

$(error   text…)
$(warning text…)
$(info    text…)

Per stampare variabili,

$(error   VAR is $(VAR))
$(warning VAR is $(VAR))
$(info    VAR is $(VAR))

'errore' interrompe l' esecuzione di make , dopo aver mostrato la stringa di errore


Wow, non lo sapevo. Molto meglio dell'eco, che duplica il comando nei registri.
deepelement


44

Se vuoi semplicemente un po 'di output, vuoi usarlo $(info)da solo. Puoi farlo ovunque in un Makefile e mostrerà quando viene valutata quella linea:

$(info VAR="$(VAR)")

Produrrà VAR="<value of VAR>"ogni volta che trasformi i processi in quella linea. Questo comportamento dipende molto dalla posizione, quindi è necessario assicurarsi che l' $(info)espansione avvenga DOPO che tutto ciò che potrebbe essere modificato $(VAR)sia già avvenuto!

Un'opzione più generica è quella di creare una regola speciale per la stampa del valore di una variabile. In generale, le regole vengono eseguite dopo l'assegnazione delle variabili, quindi questo mostrerà il valore effettivamente utilizzato. (Tuttavia, è possibile che una regola cambi una variabile .) Una buona formattazione aiuterà a chiarire su cosa è impostata una variabile e la $(flavor)funzione ti dirà che tipo di variabile è qualcosa. Quindi in questa regola:

print-% : ; $(info $* is a $(flavor $*) variable set to [$($*)]) @true
  • $*si espande allo stelo che il % modello corrisponde alla regola.
  • $($*)si espande al valore della variabile il cui nome è dato da $*.
  • Il [e ]chiaramente delineare l'espansione variabile. Puoi anche usare "e / "o simili.
  • $(flavor $*)ti dice che tipo di variabile è. NOTA: $(flavor) prende un nome variabile e non la sua espansione. Quindi, se dici make print-LDFLAGS, ottieni $(flavor LDFLAGS), che è quello che vuoi.
  • $(info text)fornisce output. Realizza stampe textsul suo stdout come effetto collaterale dell'espansione. L'espansione di $(info)però è vuota. Puoi pensarlo come @echo, ma soprattutto non usa la shell, quindi non devi preoccuparti delle regole di quotazione della shell.
  • @truec'è solo per fornire un comando per la regola. Senza questo, anche make verrà prodotto print-blah is up to date. Sento che @truerende più chiaro che è pensato per essere un non-op.

Eseguendolo, ottieni

$ make print-LDFLAGS
LDFLAGS is a recursive variable set to [-L/Users/...]

Questo non fornisce una risposta alla domanda. Per criticare o richiedere chiarimenti a un autore, lascia un commento sotto il suo post: puoi sempre commentare i tuoi post e una volta che avrai una reputazione sufficiente sarai in grado di commentare qualsiasi post . - Dalla recensione
Dragon Energy,

Grazie per la recensione Capisco di poter commentare una volta che ho abbastanza reputazione, ma cosa devo fare nel frattempo? Credo che la mia risposta offra un valore aggiunto, quindi non dovrei aggiungerla?
Jim Nasby,

1
Suggerirei di riscrivere questa come una risposta autonoma in competizione con quella su cui stai commentando, piuttosto che farla formulare come un commento fuori posto a quella risposta.
Charles Duffy,

@JimNasby Sì, quello che Charles ha suggerito. In realtà potrebbe essere d'aiuto rimuovere semplicemente quel tipo di parte "scusate non abbastanza rappresentante per commentare", in quanto è una specie di bandiera rossa. Se lo trasformi in una risposta completa (puoi modificarlo come preferisci), dovrebbe farlo abbastanza bene. Saluti.
Dragon Energy

Eccellente: questa è una risposta molto migliore ora. :)
Charles Duffy,

6

@echo $ (NDK_PROJECT_PATH) è il modo migliore per farlo. Non credo che l'errore provenga da lì. Generalmente questo errore appare quando hai sbagliato a digitare l'intenzione: penso che tu abbia spazi in cui dovresti avere una scheda.


2
Ho provato '@echo $ (NDK_PROJECT_PATH)', ricevo ancora un errore "build-local.mk:102: *** mancante separatore. Stop.". Ho solo 1 spazio dopo 'echo', non c'è spazio o scheda prima di '@echo'.
michael

Sei sicuro che l'errore provenga da questa riga? Questa linea è in una regola? Probabilmente deve essere rientrata ...

6

Tutte le versioni di makerichiedono che le righe di comando siano rientrate con una TAB (non spazio) come primo carattere della riga. Se ci mostrassi l'intera regola anziché solo le due righe in questione, potremmo dare una risposta più chiara, ma dovrebbe essere qualcosa del tipo:

myTarget: myDependencies
        @echo hi

dove il primo carattere nella seconda riga deve essere TAB.


4

Corri make -n; ti mostra il valore della variabile ..

Makefile ...

all:
        @echo $(NDK_PROJECT_PATH)

Comando:

export NDK_PROJECT_PATH=/opt/ndk/project
make -n 

Produzione:

echo /opt/ndk/project

Questo è piuttosto utile e io uso --just-printlo stesso in Invece di esecuzione
Fredrick Gauss,

3

Questo makefilegenererà il messaggio di errore "separatore mancante":

all
    @echo NDK_PROJECT_PATH=$(NDK_PROJECT_PATH)

done:
        @echo "All done"

C'è una scheda prima del @echo "All done"(sebbene la done:regola e l'azione siano in gran parte superflue), ma non prima del @echo PATH=$(PATH).

Il problema è che la linea di partenza alldovrebbe avere due punti :o uguale =a indicare che si tratta di una linea di destinazione o di una linea macro, e non ha nessuno dei due, quindi manca il separatore.

L'azione che fa eco al valore di una variabile deve essere associata a un target, possibilmente un target fittizio o PHONEY. E quella linea di destinazione deve avere due punti su di essa. Se aggiungi un :after allnell'esempio makefilee sostituisci gli spazi vuoti iniziali nella riga successiva con una scheda, funzionerà in modo sicuro.

Probabilmente hai un problema analogo vicino alla linea 102 dell'originale makefile. Se sono state visualizzate 5 righe non vuote e non commentate prima delle operazioni di eco che non riescono, probabilmente sarebbe possibile completare la diagnosi. Tuttavia, dal momento che la domanda è stata posta a maggio 2013, è improbabile che l'interruzione makefilesia ancora disponibile ora (agosto 2014), quindi questa risposta non può essere validata formalmente. Può essere utilizzato solo per illustrare un modo plausibile in cui si è verificato il problema.


3

Non è necessario modificare il Makefile.

$ cat printvars.mak
print-%:
        @echo '$*=$($*)'

$ cd /to/Makefile/dir
$ make -f ~/printvars.mak -f Makefile print-VARIABLE

2

Il problema è che l'eco funziona solo con un blocco di esecuzione. cioè qualsiasi cosa dopo "xx:"

Quindi qualsiasi cosa al di sopra del primo blocco di esecuzione è solo l'inizializzazione, quindi non è possibile utilizzare alcun comando di esecuzione.

Quindi crea un blocco di esecuzione


1

Questo può essere fatto in modo generico e può essere molto utile durante il debug di un makefile complesso. Seguendo la stessa tecnica descritta in un'altra risposta , è possibile inserire quanto segue in qualsiasi makefile:

# if the first command line argument is "print"
ifeq ($(firstword $(MAKECMDGOALS)),print)

  # take the rest of the arguments as variable names
  VAR_NAMES := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))

  # turn them into do-nothing targets
  $(eval $(VAR_NAMES):;@:))

  # then print them
  .PHONY: print
  print:
          @$(foreach var,$(VAR_NAMES),\
            echo '$(var) = $($(var))';)
endif

Quindi puoi semplicemente fare "make print" per scaricare il valore di qualsiasi variabile:

$ make print CXXFLAGS
CXXFLAGS = -g -Wall


0

Se non si desidera modificare il Makefile stesso, è possibile utilizzare --evalper aggiungere un nuovo target e quindi eseguire il nuovo target, ad es.

make --eval='print-tests: @echo TESTS $(TESTS) ' print-tests

È possibile inserire il carattere TAB richiesto nella riga di comando utilizzando CTRL-V, TAB

esempio Makefile dall'alto:

all: do-something

TESTS=
TESTS+='a'
TESTS+='b'
TESTS+='c'

do-something:
        @echo "doing something"
        @echo "running tests $(TESTS)"
        @exit 1

Sto cercando di eseguire la tua sceneggiatura ma sto make: *** missing separator. Stop.
riscontrando un

Ah, scusa, riparato. Due punti mancanti alla fine del target "test di stampa".
Wade,

In realtà non hai bisogno di nuove righe e tabulazioni, sarà sufficiente un punto e virgola:make --eval='print-tests: ; @echo TESTS $(TESTS)' print-tests
bobbogo

0

se usi android make (mka) @echo $(NDK_PROJECT_PATH)non funzionerà e ti darà un errore *** missing separator. Stop." usa questa risposta se stai provando a stampare variabili in android make

NDK_PROJECT_PATH := some_value
$(warning $(NDK_PROJECT_PATH))

ha funzionato per me


0

Di solito echo con un errore se volevo vedere il valore della variabile (solo se volevi vedere il valore. Arresterà l'esecuzione).

@echo $ (errore NDK_PROJECT_PATH = $ (NDK_PROJECT_PATH))

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.