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?

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.

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


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


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/...]

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.


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.


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

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.


3

Nie trzeba modyfikować pliku Makefile.

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

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

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


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


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

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


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))

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.