Как я могу использовать макросы для генерации нескольких целей / правил Makefile внутри foreach?Таинственное поведение - PullRequest
28 голосов
/ 14 марта 2012

Я использую GNU make 3.81.Вот тестовый make-файл, который демонстрирует проблему:

define BOZO

a$(1): b c
    touch a$(1)

endef

$(foreach i,1 2 3,$(call BOZO,$(i)))

Идея состоит в том, чтобы использовать шаблон макроса (BOZO) для генерации правил, которые следуют предсказуемому шаблону.

Проблема: когда яЗапустите make на этом make-файле. Я получаю сообщение об ошибке:

Makefile.fake:10: *** multiple target patterns.  Stop.

(где строка 10 - строка с foreach).

Теперь я знаю, что обычно указывает на эту ошибку.Давайте посмотрим, что расширяет эта строка, используя функцию info, чтобы отправить расширение в стандартный формат.Я изменяю строку 10 следующим образом:

$(info $(foreach i,1 2 3,$(call BOZO,$(i))))

и запускаю:

$ make -n

a1: b c
    touch a1

a2: b c
    touch a2

a3: b c
    touch a3

make: *** No targets.  Stop.

Обратите внимание, что ожидается сообщение «нет целей», так как функция $ (info ...)оценивается как пустое, но вызывает make print сгенерированные правила.

Давайте тогда запустим эти правила?

$make -n > out.txt
make: *** No targets.  Stop.
$make -f out.txt a1 a2 a3
touch a1
touch a2
touch a3
$

AAARGH!Правила работают нормально.Итак ... есть ли ошибка в make или в моем понимании?

Последнее заключение, которое может помочь диагностировать: если я изменю строку foreach на:

$(foreach i,1,$(call BOZO,$(i)))

(так, чтобы foreachимеет только одну итерацию)

, а затем сделать

$make a1

Я получаю другую ошибку:

make: *** No rule to make target `a1'.  Stop.

Я не знаю ни одного способа "увидеть"расширение $(foreach ), которое делает make, за исключением $(info ), и его вывод допустим, так что я весьма озадачен.

Ответы [ 3 ]

40 голосов
/ 14 марта 2012
$(foreach i,1 2 3,$(eval $(call BOZO,$(i))))

Функция eval говорит Make анализировать структуры как синтаксис make-файла, чтобы "ввести их в действие". Я не уверен, почему Мэйк возражал против не-eval'd правил именно таким образом, но это своего рода академическое.

32 голосов
/ 14 марта 2012

Ответ Беты верный, но я хотел ответить на комментарий: «Я не уверен, почему Make возражает против правил un-eval'd».

Причина, по которой правила un-eval'd не работают, заключается в том, что make-файл в конечном счете основан на строках, а строки разбиваются ДО того, как переменные расширятся. Так что расширение переменной не может превратиться в многострочный результат: даже если расширение содержит новые строки, make обрабатывает все это как одну «строку». Когда make заканчивает расширение цикла foreach и анализирует результаты, он в основном видит это:

a1: b c touch a1 a2: b c touch a2 a3: b c touch b3

, поэтому вы получаете ошибку "несколько целевых шаблонов".

Причины eval заставляют re-интерпретировать результат расширения с самого начала как полный фрагмент синтаксиса make-файла, включая прерывание строки и т. Д., И именно поэтому там работает многострочное расширение.

1 голос
/ 11 апреля 2018

Возможно старый, но всегда актуальный. Нет необходимости делать этот макрос вообще.

Решением вашей проблемы является простое определение этого правила:

a%: b c
    touch a%

Процент действует как подстановочный знак. Смотрите больше информации здесь: https://stackoverflow.com/a/7406471/2522849

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...