Jak wydrukować zmienną w makefile

247

W moim makefile mam zmienną „NDK_PROJECT_PATH”, moje pytanie brzmi: jak mogę go wydrukować podczas kompilacji?

Przeczytałem polecenie Utwórz echo pliku zawierające ciąg „$ PATH” i próbowałem:

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

Oba dają mi

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

Czy ktoś wie, dlaczego to dla mnie nie działa?

Michael
źródło

Odpowiedzi:

223

Możesz wydrukować zmienne podczas odczytywania pliku makefile (zakładając, że GNU tworzy, ponieważ odpowiednio otagowałeś to pytanie), korzystając z tej metody (ze zmienną o nazwie „var”):

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

Możesz dodać ten konstrukt do dowolnego przepisu, aby zobaczyć, co marka przejdzie do powłoki:

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

Teraz dzieje się tak, że przechowuje całą recepturę ( $(info $$var is [${var}])echo Hello world) jako jedną rekurencyjnie rozszerzoną zmienną. Kiedy make decyduje się uruchomić przepis (na przykład, gdy każesz mu budować all), rozwija zmienną, a następnie przekazuje każdą wynikową linię osobno do powłoki.

A więc w bolesny sposób:

  • Rozszerza się $(info $$var is [${var}])echo Hello world
  • Aby to zrobić, najpierw się rozwija $(info $$var is [${var}])
    • $$ staje się dosłowny $
    • ${var}staje się :-)(powiedz)
    • Efekt uboczny $var is [:-)]pojawia się na standardowym wyjściu
    • Rozszerzenie $(info...)tego jest puste
  • Marka pozostaje echo Hello world
    • echo Hello worldNajpierw wykonaj odbitki na standardowym ekranie, aby dowiedzieć się, o co ma poprosić powłokę
  • Powłoka drukuje się Hello worldna standardowym wyjściu.
bobbogo
źródło
2
powinno być (kropka) .PHONY zamiast PHONY?
hammadian
172

Zgodnie z instrukcją GNU Make, a także wskazaną przez „bobbogo” w poniższej odpowiedzi, możesz użyć informacji / ostrzeżenia / błędu do wyświetlenia tekstu.

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

Aby wydrukować zmienne,

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

„error” zatrzyma wykonanie make po wyświetleniu ciągu błędu

tsenapatia
źródło
Wow, nie wiedziałem o tym. O wiele lepsze niż echo, które powiela polecenie w dziennikach.
deepelement
148

z „Mr. Make post” https://www.cmcrossroads.com/article/printing-value-makefile-variable

Dodaj następującą regułę do pliku Makefile:

print-%  : ; @echo $* = $($*)

Następnie, jeśli chcesz poznać wartość zmiennej makefile, po prostu:

make print-VARIABLE

i zwróci:

VARIABLE = the_value_of_the_variable
Anthony Earl Wong
źródło
Wyjaśniłeś to lepiej niż autor. Kciuki w górę!
f0nzie
44

Jeśli po prostu chcesz trochę danych wyjściowych, sam chcesz użyć $(info). Możesz to zrobić w dowolnym miejscu w pliku Makefile, a pokaże on, kiedy ta linia jest oceniana:

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

Wyjdzie VAR="<value of VAR>"za każdym razem, gdy procesy zostaną przetworzone w tym wierszu. To zachowanie jest bardzo zależne od pozycji, więc musisz się upewnić, że $(info)rozszerzenie nastąpi PO wszystkim, co można zmodyfikować $(VAR), już się wydarzyło!

Bardziej ogólną opcją jest utworzenie specjalnej reguły drukowania wartości zmiennej. Ogólnie mówiąc, reguły są wykonywane po przypisaniu zmiennych, więc pokaże ci to, która wartość jest faktycznie używana. (Chociaż reguła może zmienić zmienną .) Dobre formatowanie pomoże wyjaśnić, na co ustawiona jest zmienna, a $(flavor)funkcja powie ci, co to za zmienna. Więc w tej regule:

print-% : ; $(info $* is a $(flavor $*) variable set to [$($*)]) @true
  • $*rozwija się do rdzenia, którego % wzór pasował do reguły.
  • $($*)rozwija się do wartości zmiennej, której nazwę podaje $*.
  • [I ]jasno wyznaczać ekspansję zmiennych. Możesz także użyć "i tym "podobnych.
  • $(flavor $*)mówi ci, jaka to zmienna. UWAGA: $(flavor) przyjmuje nazwę zmiennej , a nie jej rozwinięcie. Więc jeśli powiesz make print-LDFLAGS, dostajesz $(flavor LDFLAGS), to jest to, czego chcesz.
  • $(info text)zapewnia wydajność. Rób odbitki textna stdout jako efekt uboczny rozszerzenia. Rozszerzenie $(info)chociaż jest puste. Możesz myśleć o tym w ten sposób @echo, ale co ważne, nie używa on powłoki, więc nie musisz się martwić o reguły cytowania powłoki.
  • @truejest tylko po to, aby podać polecenie dla reguły. Bez tego marka będzie również generować print-blah is up to date. Wydaje mi się, @trueże jest bardziej jasne, że ma to być zakaz operacji.

Uruchamiasz to

$ make print-LDFLAGS
LDFLAGS is a recursive variable set to [-L/Users/...]
Jim Nasby
źródło
To nie daje odpowiedzi na pytanie. Aby skrytykować lub poprosić autora o wyjaśnienie, zostaw komentarz pod jego postem - zawsze możesz komentować własne posty, a gdy będziesz mieć odpowiednią reputację , będziesz mógł komentować każdy post . - Z recenzji
Dragon Energy,
Dzięki za recenzję. Rozumiem, że mogę komentować, gdy mam wystarczającą reputację, ale co powinienem zrobić w międzyczasie? Uważam, że moja odpowiedź stanowi dodatkową wartość, więc czy nie powinienem jej dodać?
Jim Nasby
1
Sugerowałbym przepisanie tego na samodzielną odpowiedź konkurującą z tą, którą komentujesz, zamiast sformułowania go jako nie na miejscu komentarz do tej odpowiedzi.
Charles Duffy,
@JimNasby Tak, co sugerował Charles. Właściwie może to na początek pomóc po prostu usunąć część „przykro mi, że za mało rep, aby skomentować”, ponieważ jest to rodzaj czerwonej flagi. Jeśli zmienisz go w pełną odpowiedź (możesz edytować wszystko, co lubisz), powinno być całkiem nieźle. Twoje zdrowie.
Dragon Energy
Doskonale - teraz jest to znacznie lepsza odpowiedź. :)
Charles Duffy
6

@echo $ (NDK_PROJECT_PATH) to dobry sposób na zrobienie tego. Nie sądzę, że błąd pochodzi stąd. Zasadniczo ten błąd pojawia się, gdy źle wpisałeś zamiar: Myślę, że masz spacje, w których powinieneś mieć tabulator.


źródło
2
Próbowałem „@echo $ (NDK_PROJECT_PATH)”, nadal pojawia się błąd „build-local.mk:102: *** brak separatora. Stop.”. Mam tylko 1 spację po „echu”, nie ma spacji ani tabulacji przed „@echo”.
Michael
Czy jesteś pewien, że błąd pochodzi z tego wiersza? Czy ta linia jest regułą? Prawdopodobnie musi być wcięta ...
6

Wszystkie wersje makewymagają, aby wiersze poleceń były wcięte klawiszem TAB (nie spacją) jako pierwszym znakiem w linii. Jeśli pokazałeś nam całą regułę zamiast tylko dwóch linii, o których mowa, moglibyśmy dać jaśniejszą odpowiedź, ale powinno to być coś w stylu:

myTarget: myDependencies
        @echo hi

gdzie pierwszym znakiem w drugim wierszu musi być TAB.

Szalony naukowiec
źródło
4

Uruchom make -n; pokazuje wartość zmiennej.

Makefile ...

all:
        @echo $(NDK_PROJECT_PATH)

Komenda:

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

Wynik:

echo /opt/ndk/project
ivandcl
źródło
Jest to dość przydatne, a ja używam --just-printtego samego w Zamiast egzekucji
Fredrick Gauss,
3

Spowoduje makefileto wygenerowanie komunikatu o błędzie „brak separatora”:

all
    @echo NDK_PROJECT_PATH=$(NDK_PROJECT_PATH)

done:
        @echo "All done"

Przed znakiem jest zakładka @echo "All done"(choć done:zasada i działanie są w dużej mierze zbędne), ale nie przed @echo PATH=$(PATH).

Problem polega na tym, że linia początkowa allpowinna mieć dwukropek :lub znak równości, =co oznacza, że ​​jest linią docelową lub linią makro, i nie ma żadnej, więc brakuje separatora.

Akcja, która powtarza wartość zmiennej, musi być powiązana z celem, być może atrapą lub celem PHONEY. Ta linia docelowa musi mieć dwukropek. Jeśli dodać :po allna przykład makefilei zastąpić wiodące spacje na następnej linii przez kartę, to będzie działać zdrowo.

Prawdopodobnie masz analogiczny problem w pobliżu linii 102 w oryginale makefile. Jeśli pokazałeś 5 niepustych wierszy bez komentarza przed nieudanymi operacjami echa, prawdopodobnie byłoby możliwe zakończenie diagnozy. Ponieważ jednak pytanie zostało zadane w maju 2013 r., Jest mało prawdopodobne, że zepsuty makefilejest nadal dostępny (sierpień 2014 r.), Więc tej odpowiedzi nie można formalnie zweryfikować. Można go jedynie wykorzystać do zilustrowania prawdopodobnego sposobu wystąpienia problemu.

Jonathan Leffler
źródło
3

Nie trzeba modyfikować pliku Makefile.

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

$ cd /to/Makefile/dir
$ make -f ~/printvars.mak -f Makefile print-VARIABLE
Talespin_Kit
źródło
2

Problem polega na tym, że echo działa tylko pod blokiem wykonawczym. tzn. cokolwiek po „xx:”

Zatem wszystko powyżej pierwszego bloku wykonawczego jest tylko inicjalizacją, więc nie można użyć komendy wykonawczej.

Utwórz blok wykonawczy

Andy
źródło
1

Można to zrobić w sposób ogólny i może być bardzo przydatne podczas debugowania złożonego makefile. Postępując zgodnie z tą samą techniką, jak opisano w innej odpowiedzi , możesz wstawić następujące polecenie do dowolnego pliku 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

Następnie możesz po prostu wykonać polecenie „print”, aby zrzucić wartość dowolnej zmiennej:

$ make print CXXFLAGS
CXXFLAGS = -g -Wall
Ideliczny
źródło
0

Jeśli nie chcesz modyfikować samego pliku Makefile, możesz użyć, --evalaby dodać nowy cel, a następnie wykonać nowy cel, np.

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

Możesz wstawić wymagany znak TAB w wierszu poleceń, używając CTRL-V, TAB

przykład Makefile z góry:

all: do-something

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

do-something:
        @echo "doing something"
        @echo "running tests $(TESTS)"
        @exit 1
Przebrnąć
źródło
Próbuję uruchomić skrypt, ale dostaję błądmake: *** missing separator. Stop.
Rinaldi Segecin
Ach, przepraszam, naprawione. Brak dwukropka na końcu celu „testy drukowania”.
Wade
Właściwie nie potrzebujesz nowych linii i tabulatorów, wystarczy średnik:make --eval='print-tests: ; @echo TESTS $(TESTS)' print-tests
bobbogo,
0

jeśli używasz Androida make (mka) @echo $(NDK_PROJECT_PATH)nie będzie działać i wyświetli się błąd, *** missing separator. Stop." użyj tej odpowiedzi, jeśli próbujesz wydrukować zmienne w android make

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

to działało dla mnie

mjalil
źródło
0

Zwykle odbijam się z błędem, gdy chcę zobaczyć wartość zmiennej (tylko jeśli chcesz zobaczyć wartość. Zatrzyma to wykonywanie).

@echo $ (błąd NDK_PROJECT_PATH = $ (NDK_PROJECT_PATH))

Abdul Jaleel
źródło