Как распечатать переменную в make-файле


247

В моем make-файле у меня есть переменная 'NDK_PROJECT_PATH', мой вопрос, как я могу распечатать его, когда он компилируется?

Я прочитал Make file echo с отображением строки "$ PATH" и попытался:

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

Оба дает мне

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

Кто-нибудь знает, почему это не работает для меня?

Ответы:


223

Вы можете распечатать переменные, когда читается make-файл (при условии, что GNU make, поскольку вы соответствующим образом пометили этот вопрос), используя этот метод (с переменной с именем «var»):

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

Вы можете добавить эту конструкцию в любой рецепт, чтобы увидеть, что make перейдет в оболочку:

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

Теперь, что здесь происходит, это то, что make хранит весь recipe ( $(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на стандартный вывод.

2
это должно быть (точка) .PHONY вместо PHONY?
хаммадиан

172

Согласно руководству GNU Make, которое также указано 'bobbogo' в ответе ниже, вы можете использовать info / warning / error для отображения текста.

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

Чтобы напечатать переменные,

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

'error' остановит выполнение make после отображения строки ошибки


Вау, не знал этого. Способ лучше, чем эхо, которое дублирует команду в логах.
17

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это просто, чтобы предоставить команду для правила. Без этого make также выдаст print-blah is up to date. Я чувствую, @trueделает это более ясным, что это должно быть неоперативным.

Запустив его, вы получите

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

Это не дает ответа на вопрос. Чтобы критиковать или запрашивать разъяснения у автора, оставьте комментарий под его постом - вы всегда можете комментировать свои собственные посты, и, когда у вас будет достаточно репутации, вы сможете комментировать любой пост . - Из Обзора
Энергия Дракона

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

1
Я бы предложил переписать этот текст как отдельный ответ, конкурирующий с тем, который вы комментируете, вместо того, чтобы формулировать его как неуместный комментарий к этому ответу.
Чарльз Даффи

@JimNasby Да, что предложил Чарльз. На самом деле это может помочь в качестве начала просто убрать часть типа "извините, недостаточно реп. Комментировать", так как это своего рода красный флаг. Если вы превратите его в полный ответ (можете отредактировать все, что захотите), это должно получиться довольно неплохо. Приветствия.
Dragon Energy

Отлично - теперь это гораздо лучший ответ. :)
Чарльз Даффи

6

@echo $ (NDK_PROJECT_PATH) - хороший способ сделать это. Я не думаю, что ошибка происходит оттуда. Обычно эта ошибка появляется, когда вы неправильно набрали намерение: я думаю, у вас есть пробелы, в которых вы должны иметь вкладку.


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

Вы уверены, что ошибка исходит из этой строки? Эта строка в правиле? Наверное, она должна быть с отступом ...

6

Все версии makeтребуют, чтобы командные строки имели отступ с табуляции (не пробел) в качестве первого символа в строке. Если бы вы показали нам все правило вместо двух рассматриваемых строк, мы могли бы дать более четкий ответ, но это должно быть что-то вроде:

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-целью. И эта целевая линия должна иметь двоеточие. Если вы добавите :после allв примереmakefile и замените начальные пробелы в следующей строке на вкладку, это будет работать разумно.

У вас, вероятно, есть аналогичная проблема около линии 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

Проблема в том, что эхо работает только под блоком исполнения. т.е. что-нибудь после "хх:"

Таким образом, все, что находится выше первого блока выполнения, является просто инициализацией, поэтому никакая команда выполнения не может быть использована.

Так что создайте исполнительный блок


1

Это может быть сделано общим способом и может быть очень полезно при отладке сложного make-файла. Следуя той же методике, которая описана в другом ответе , вы можете вставить следующее в любой make-файл:

# 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», чтобы вывести значение любой переменной:

$ make print CXXFLAGS
CXXFLAGS = -g -Wall

1

Вы можете создать правило vars в вашем файле make, например:

dispvar = echo $(1)=$($(1)) ; echo

.PHONY: vars
vars:
    @$(call dispvar,SOMEVAR1)
    @$(call dispvar,SOMEVAR2)

Здесь есть несколько более надежных способов вывести все переменные: gnu make: перечислить значения всех переменных (или «макросов») в конкретном прогоне .


0

Если вы не хотите изменять сам Makefile, вы можете использовать --evalдля добавления новой цели, а затем выполнить новую цель, например

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

Вы можете вставить необходимый символ табуляции в командной строке, используя 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.
Ринальди Сегецин

Ах, извините, исправлено. Отсутствует двоеточие в конце цели «print-tests».
Уэйд

На самом деле вам не нужны переводы строк и табуляции, достаточно точки с запятой: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.