Определение пользовательских функций GNU make

В чем проблема с функцией dep2 в примере кода ниже?

dep1 = $(eval makefile_list_$1 := $(MAKEFILE_LIST))$(eval -include $1.mk)$(eval MAKEFILE_LIST := $(makefile_list_$1))

define dep2
$(eval makefile_list_$1 := $(MAKEFILE_LIST))
$(eval -include $1.mk)
$(eval MAKEFILE_LIST := $(makefile_list_$1))
endef

$(call dep1,test)
$(call dep2,test)

.DEFAULT_TARGET: all
.PHONY: all
all:
    @echo $@

GNU make 3.81 и 3.82 выдают Makefile:10: *** missing separator. Stop., который указывает на вызов dep2, dep1 запускается без ошибок. Единственная разница между двумя вариантами - это новые строки в dep2 (и в этом весь смысл, почему я хотел бы использовать define).


person g.b.    schedule 29.06.2011    source источник


Ответы (4)


Вы забыли =:
определить dep2 =

EDIT:
Ставьте точку с запятой в конце каждой строки. Я проверил это, и это работает (в GNUMake 3.81).

define dep2
$(eval makefile_list_$1 := $(MAKEFILE_LIST));
$(eval -include $1.mk);
$(eval MAKEFILE_LIST := $(makefile_list_$1));
endef

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

person Beta    schedule 29.06.2011
comment
Нет, = необязателен (и появился только в GNU make 3.82). Добавление не имеет значения. - person g.b.; 29.06.2011
comment
@g.b.: Вы действительно пробовали это? Я так и сделал (с GNU make 3.81), и это действительно имело значение. У меня это работает, как и ожидалось, если я добавлю =. - person eriktous; 29.06.2011
comment
@eriktous: Да, я пробовал с 3.82. Более старые версии просто полностью игнорируют оператор определения, если за ним следует =, поэтому вы не получаете сообщение об ошибке. - person g.b.; 29.06.2011
comment
@g.b., @eriktous, если это правда, то мой ответ бесполезен. Я использовал 3.81 и руководствовался документацией (я редко использую define); Я убедился, что = предотвращает ошибку, но не приводит к желаемому поведению. Позвольте мне провести еще несколько экспериментов... - person Beta; 29.06.2011
comment
Точки с запятой действительно делают эту работу, однако я не смог найти ничего об их использовании, кроме рецептов в руководстве GNU make, поэтому мне немного неудобно полагаться на такое поведение, и, вероятно, в этом случае я вернусь к однострочным определениям. Почему было бы действительно интересно здесь. - person g.b.; 29.06.2011
comment
@g.b.: А, понятно. Я этого не заметил. Как странно. @Beta: Это даже работает для меня, если я добавляю только точку с запятой в первую строку или даже если я добавляю пустую строку только с точкой с запятой в качестве первой строки внутри определения. Я не могу понять ни орла, ни хвоста. - person eriktous; 30.06.2011
comment
@eriktous: О, отлично, теперь я не буду спать сегодня ночью, большое спасибо. - person Beta; 30.06.2011
comment
Единственная важная информация о точках с запятой, которую я смог найти в руководстве по make, находится в Приложении B об ошибках, генерируемых make: if the line has a semicolon as the first non-whitespace character; make interprets this to mean you left out the "target: prerequisite" section of a rule. Обратите внимание, что результатом функции eval всегда является пустая строка. - person eriktous; 30.06.2011

Я бы переместил вызовы $(eval ...) за пределы dep2. Делая это таким образом, нет необходимости в точках с запятой в dep2. Это означает удвоение знаков $ некоторых расширений, чтобы избежать преждевременного расширения. Так:

define dep2
makefile_list_$1 := $$(MAKEFILE_LIST)
-include $1.mk
MAKEFILE_LIST := $$(makefile_list_$1)
endef

$(eval $(call dep2,test))

# Quick checks for testing, to be removed from the final code...
$(info $(makefile_list_test))
$(info $(MAKEFILE_LIST))

.DEFAULT_TARGET: all
.PHONY: all
all:
    @echo $@

Я протестировал приведенный выше код, и он работает с Gnu Make 4.0. Я ожидаю, что он будет работать и с Gnu Make 3.8x. Шаблон $(eval $(call ...)) — это то, что я всегда использую для выполнения своих пользовательских функций, и я использую его уже довольно давно.

person Louis    schedule 10.12.2014

Вы можете сделать следующую строку, чтобы убить ошибку:

FOO := $(call dep2, test)

Я предполагаю, что причина в том, что ранняя версия gcc (3.8.1/2) ничего не может принимать в качестве возврата выражения.

например, $(info string) ничего не возвращает, а $(call dep2, test) возвращает 2 символа новой строки.

person Bill Zhao    schedule 07.06.2018

Многое можно улучшить в том, что вы делаете. Во-первых, вы действительно хотите связать вызовы eval с одним вызовом вверху.

Ваша конкретная проблема, однако, связана с непониманием того, что многострочная рекурсивная строка, которую использует команда make make, никогда не включает новую строку. Наиболее естественным соглашением для написания вычисляемых функций является

определить Foo Line1 Line2

конец

Вы можете посмотреть на строку, которую видит eval, и посмотреть, что она делает с помощью команды info, например. $(информация $(вызов Foo,x) $(вызов Foo,y)).

person doctor Make    schedule 10.12.2014