Как я могу использовать макросы для создания нескольких целей/правил Makefile внутри foreach? Таинственное поведение
Я использую GNU make 3.81. Вот тестовый файл, который демонстрирует проблему:
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 для печати сгенерированных правил.
Запустите эти правила, тогда мы будем?
$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 имеет только одну итерацию)
а затем do
$make a1
Я получаю другую ошибку:
make: *** No rule to make target `a1'. Stop.
Я не знаю, как "видеть" расширение $(foreach )
, которое делает вид, кроме $(info )
, и его вывод легален, поэтому я довольно сильно озадачен.
Ответы
Ответ 1
$(foreach i,1 2 3,$(eval $(call BOZO,$(i))))
функция eval сообщает Make для синтаксического анализа структур как синтаксиса makefile, "принять" их. Я не знаю, почему Make возражал против правил un-eval'd именно таким образом, но такого рода академические.
Ответ 2
Бета-ответ правильный, но я хотел бы обратиться к комментарию: "Я не уверен, почему Make Objected to un un-eval'd rules".
Причина, по которой правила un-eval'd не работают, заключается в том, что make файл, в конечном счете, основан на линии, и строки прерываются до того, как переменные расширены. Так что просто невозможно развернуть переменную, чтобы она превратилась в многострочный результат: даже если расширение содержит символы новой строки, все это рассматривает как одну "линию". Когда make заканчивает расширение цикла foreach
и анализирует результаты, он в основном видит это:
a1: b c touch a1 a2: b c touch a2 a3: b c touch b3
поэтому вы получаете ошибку "множественные целевые шаблоны".
Причины eval позволяют повторно интерпретировать результат расширения с самого начала как полный фрагмент синтаксиса makefile, включая прерывание строк и т.д., и почему здесь работает многострочное расширение.
Ответ 3
после использования функции eval все же я столкнулся с проблемой остановки множества шаблонов. Я рекурсивно строю цель с помощью foreach, но я столкнулся с этой проблемой с несколькими задачами. при запуске make файла на 32-битной платформе окна (которые корректно работают для Linux-машины)
define BOZO
$(CWD)/$(1).o:$(CWD).$(1).def
endef
$(foreach target,$(basename $(list)),$(eval $(call BOZO,$(target))))
$(CWD)/%.def: a.out
@echo building [email protected]
a.out %.def
Что-то вроде этого. Можете ли вы предложить для этого...!
Ответ 4
Может быть, старый, но всегда актуальный. Нет необходимости делать этот макрос вообще.
Решение вашей проблемы - просто определить это правило:
a%: b c
touch a%
Процент действует как подстановочный знак. Смотрите больше информации здесь: fooobar.com/info/146566/...