Як роздрукувати змінну в makefile


247

У своєму makefile у мене є змінна 'NDK_PROJECT_PATH', моє запитання полягає в тому, як я можу роздрукувати її під час компіляції?

Я прочитав Зробити ехо-файл із відображенням рядка "$ PATH" і спробував:

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

Обидва дає мені

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

Хтось знає, чому це не працює для мене?

Відповіді:


223

Ви можете роздрукувати змінні під час зчитування файлу makefile (якщо припустимо, що GNU робить, коли ви відповідним чином позначено це питання), використовуючи цей метод (зі змінною, що називається "var"):

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

Ви можете додати цю конструкцію до будь-якого рецепта, щоб побачити, що буде передано оболонці:

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

Тепер, що тут відбувається, це те, що змушує зберігати весь рецепт ( $(info $$var is [${var}])echo Hello world) як єдину рекурсивно розширену змінну. Коли make вирішує запустити рецепт (наприклад, коли ви скажете йому побудувати all), він розширює змінну, а потім передає кожну отриману лінію окремо в оболонку.

Отже, до болю детально:

  • Він розширюється $(info $$var is [${var}])echo Hello world
  • Для цього його спочатку розгортають $(info $$var is [${var}])
    • $$ стає буквальним $
    • ${var}стає :-)(сказати)
    • Побічний ефект - це те, що $var is [:-)]з'являється у стандартних вихідних
    • Розширення, $(info...)хоча, порожнє
  • Зробити залишилося echo Hello world
    • echo Hello worldСпершу зробіть відбитки на stdout, щоб ви могли знати, що потрібно просити оболонку
  • Оболонка друкується Hello worldна stdout.

2
це повинно бути (крапка) .PHONY замість PHONY?
хаммадян

172

Відповідно до інструкції GNU Make, а також вказується на 'bobbogo' у відповіді нижче, ви можете використовувати інформацію / попередження / помилку для відображення тексту.

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

Щоб надрукувати змінні,

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

'помилка' зупинить виконання make після відображення рядка помилки


Нічого, не знав цього. Шлях краще, ніж відлуння, що дублює команду в журналах.
поглиблення

148

від "Містер зробити пост" https://www.cmcrossroads.com/article/printing-value-makefile-variable

Додайте таке правило у свій Makefile:

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

Потім, якщо ви хочете дізнатися значення змінної makefile, просто:

make print-VARIABLE

і воно повернеться:

VARIABLE = the_value_of_the_variable

Ви пояснили це краще, ніж автор. Пальці вгору!
f0nzie

44

Якщо ви просто хочете отримати якийсь результат, ви хочете використовувати $(info)сам. Це можна зробити в будь-якому місці Makefile, і він покаже, коли оцінюється цей рядок:

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

Виводитиметься VAR="<value of VAR>"щоразу, коли робити процеси в цій лінії. Така поведінка дуже залежить від позиції, тому ви повинні переконатися, що $(info)розширення відбудеться ПІСЛЯ всього, що могло змінити $(VAR), вже відбулося!

Більш загальний варіант - створити спеціальне правило для друку значення змінної. Взагалі, правила виконуються після призначення змінних, тому це покаже вам значення, яке фактично використовується. (Хоча правило може змінити змінну .) Хороше форматування допоможе з’ясувати, на яку зміну встановлено, а $(flavor)функція підкаже, що таке змінна. Отже, у цьому правилі:

print-% : ; $(info $* is a $(flavor $*) variable set to [$($*)]) @true
  • $*розширюється до стебла, що % узор відповідає правилу.
  • $($*)розширюється до значення змінної, ім'я якої задано по $*.
  • [І ]чітко розмежувати розширення змінної. Ви також можете використовувати "та "або подібне.
  • $(flavor $*)говорить вам, що це за змінна. ПРИМІТКА: $(flavor) приймає ім'я змінної , а не її розширення. Тож якщо ти скажеш make print-LDFLAGS, ти отримуєш $(flavor LDFLAGS), чого ти хочеш.
  • $(info text)забезпечує вихід. Робіть відбитки textна її штриху як побічний ефект розширення. Розширення, $(info)хоча, порожнє. Ви можете думати про це як @echo, але важливо, що він не використовує оболонку, тому вам не доведеться турбуватися про правила цитування оболонок.
  • @trueчи просто для того, щоб надати команду для правила. Без цього зробити також буде вихід print-blah is up to date. Я відчуваю, що @trueце стає більш зрозумілим, що це означає бути беззахисним.

Запустивши його, ви отримаєте

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

Це не дає відповіді на запитання. Щоб критикувати або вимагати роз'яснення у автора, залиште коментар під їх публікацією - ви завжди можете коментувати свої власні публікації, і як тільки у вас буде достатня репутація, ви зможете коментувати будь-яку публікацію . - З огляду
Драконова енергія

Дякуємо за відгук. Я розумію, що можу коментувати, як тільки мені достатньо репутації, але що мені робити тим часом? Я вважаю, що моя відповідь надає додаткову цінність, тому я не повинен додати її?
Джим Насбі

1
Я б запропонував переписати це як окрему відповідь, що конкурує з тією, яку ви коментуєте, замість того, щоб це було сформульовано як невідповідний коментар до цієї відповіді.
Чарльз Даффі

@JimNasby Так, те, що запропонував Чарльз. Насправді це може допомогти почати просто видаляти цю частину "вибачте, недостатньо репліку для коментарів", оскільки це наче червоний прапор. Якщо ви перетворите її на повну відповідь (зможете редагувати все, що вам подобається), це має зробити досить непогано. Ура.
Драконова енергія

Відмінно - це набагато краща відповідь зараз. :)
Чарльз Даффі

6

@echo $ (NDK_PROJECT_PATH) - це хороший спосіб зробити це. Я не думаю, що помилка приходить звідти. Зазвичай ця помилка з’являється, коли ви помилково ввели наміри: я думаю, у вас є пробіли, де ви повинні мати вкладку.


2
Я спробував "@echo $ (NDK_PROJECT_PATH)", я все одно отримую помилку "build-local.mk:102: *** відсутній роздільник. Стоп.". У мене просто 1 пробіл після "відлуння", перед "@echo" немає місця або вкладки.
Майкл

Ви впевнені, що помилка виходить з цього рядка? Цей рядок є правилом? Мабуть, вона має бути з відступом ...

6

Усі версії makeвимагають, щоб командні рядки були відступними TAB (а не пробілом) як першим символом у рядку. Якби ви показали нам все правило, а не два питання, ми могли б дати чіткішу відповідь, але це має бути щось на кшталт:

myTarget: myDependencies
        @echo hi

де першим символом у другому рядку має бути TAB.


4

Бігати make -n; він показує вам значення змінної ..

Makefile ...

all:
        @echo $(NDK_PROJECT_PATH)

Команда:

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

Вихід:

echo /opt/ndk/project

Це дуже корисно, хоча я використовую --just-printте саме, що замість
Фредрік Гаус

3

Це makefileстворить повідомлення про помилку "відсутній роздільник":

all
    @echo NDK_PROJECT_PATH=$(NDK_PROJECT_PATH)

done:
        @echo "All done"

Перед вкладкою є @echo "All done"(хоча done:правило і дії в основному зайві), але не перед цим @echo PATH=$(PATH).

Проблема полягає в тому, що у лінії, що починається, allповинна бути або двокрапка, :або рівна, =що вказує на те, що це цільова лінія або макро-лінія, і вона не має жодної, тому роздільник відсутній.

Дія, що перегукується зі значенням змінної, має бути пов’язана з ціллю, можливо, манекеном або PHONEY-ціллю. І ця цільова лінія повинна мати двокрапку на ній. Якщо у прикладі ви додасте :після, а провідні пробіли в наступному рядку замініть на вкладку, це буде справно.allmakefile

Напевно у вас є аналогічна проблема біля рядка 102 в оригіналі makefile. Якщо ви показали 5 непорожніх рядків без коментарів перед операціями ехо, які не виходять, ймовірно, вдасться закінчити діагностику. Однак, оскільки запитання було задано в травні 2013 року, малоймовірно, що зламаний makefileвсе ще доступний зараз (серпень 2014 року), тому ця відповідь не може бути підтверджена формально. Його можна використовувати лише для ілюстрації правдоподібного способу виникнення проблеми.


3

Не потрібно змінювати Makefile.

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

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

2

Проблема полягає в тому, що відлуння працює лише під блоком виконання. тобто що-небудь після "xx:"

Отже все, що знаходиться вище першого блоку виконання, - це лише ініціалізація, тому жодна команда виконання не може використовуватися.

Тож створіть блок виконання


1

Це можна зробити загальним способом і може бути дуже корисним при налагодженні складного 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

Тоді ви можете просто зробити "зробити друк", щоб скинути значення будь-якої змінної:

$ make print CXXFLAGS
CXXFLAGS = -g -Wall


0

Якщо ви не хочете змінювати сам Makefile, ви можете використовувати --evalдля додавання нової цілі, а потім виконати нову ціль, наприклад

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

Ви можете вставити потрібний символ TAB в командний рядок, використовуючи CTRL-V, TAB

приклад Makefile зверху:

all: do-something

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

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

Я намагаюся запустити ваш сценарій, але я отримую помилкуmake: *** missing separator. Stop.
Рінальді Сегецин

Ах, вибачте, виправлено. Відсутня двокрапка на кінці цілі "тести для друку".
Вейд

Насправді вам не потрібні нові рядки та вкладки, крапкою з комою буде достатньо:make --eval='print-tests: ; @echo TESTS $(TESTS)' print-tests
bobbogo

0

якщо ви використовуєте android make (mka), @echo $(NDK_PROJECT_PATH)це не спрацює і дає помилку, *** missing separator. Stop." використовуйте цю відповідь, якщо ви намагаєтеся надрукувати змінні в android make

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

що працювало на мене


0

Я зазвичай лунаю з помилкою, якщо хотів побачити значення змінної. (Тільки якщо ви хочете побачити значення. Це зупинить виконання.)

@echo $ (помилка NDK_PROJECT_PATH = $ (NDK_PROJECT_PATH))

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.