makefile: % шаблон в пререквизите $(переменная)
У меня что-то вроде этого работает:
target1.PREREQUISITES = file11 file12 file13
target2.PREREQUISITES = file21 file22 file23
$(myDir)target1.sfx : $(target1.PREREQUISITES)
<same recipe here>
$(myDir)target2.sfx : $(target2.PREREQUISITES)
<same recipe here>
и это то, что я хочу сделать, но это не работает:
target1.PREREQUISITES = file11 file12 file13
target2.PREREQUISITES = file21 file22 file23
$(myDir)%.sfx : $(%.PREREQUISITES)
<commun recipe here>
Всегда говорится, что делать нечего, потому что цель актуальна.
У меня такое ощущение, что проблема может заключаться в том, что делается на каждом этапе сборки, я имею в виду, что делается в первую очередь% или $. Должно ли это работать просто отлично?
3 ответа
Спасибо user657267 за ваш ответ, он работает и дал мне хорошее преимущество. Для тех, кто не слишком знаком с, обратите внимание на двойной знак доллара. Однако я включаю свой ответ здесь, потому что он все еще использует %
знак, который был частью моего первоначального вопроса и работает так же, как ваш. Я использую следующее решение.
.SECONDEXPANSION:
$(mydir)%.sfx: $$(%.PREREQUISITES)
echo $^
Я только заметил и осознаю, что при использовании вторичного расширения make не сообщает вам, что у отсутствующей предпосылки нет правила, вместо этого он отображает вводящее в заблуждение сообщение о том, что правила для создания цели нет.
Для этого вам понадобится что-то вроде вторичного расширения, иначе расширение переменной в предварительных условиях происходит до замены шаблона, и вы не определили переменную с именем %.PREREQUISITES
,
.SECONDEXPANSION:
$(mydir)%.sfx: $$($$*.PREREQUISITES)
echo $^
Второе расширение, предложенное пользователем 657267, работает хорошо. GNU make также поддерживает своего рода механизм цикла, который вы можете использовать для создания нескольких правил с очень похожими формами:
target1.PREREQUISITES = file11 file12 file13
target2.PREREQUISITES = file21 file22 file23
TARGETS = target1 target2
# $(1) is a parameter to substitute. The $$ will expand as $.
define MY_rule
$$(myDir)$(1).sfx : $$($(1).PREREQUISITES)
<same recipe here>
endef
$(foreach target,$(TARGETS),$(eval $(call MY_rule,$(target))))
foreach
перебирает все слова в$(TARGETS)
и назначает текущее слово$(target)
,call
выполняет расширениеMY_rule
где он заменяет$(1)
с текущим значением$(target)
а также$$
с$
,eval
инстанцирует результатcall
расширение как обычное правило.
Результат первой итерации foreach
Например, будет:
$(eval $(call MY_rule,target1))
call
будет оценивать как:
$(myDir)target1.sfx : $(target1.PREREQUISITES)
<same recipe here>
а также eval
будет создавать его как правило. Важно: не забывайте, что call
выполняет первое расширение. Итак, если ваш <same recipe here>
содержит $
символы, не забудьте удвоить их, если их расширение call
Это хорошо. Если ваш рецепт использует переменные оболочки, даже возможно, что вы в конечном итоге с такими вещами, как $$$$var
,
Этот механизм немного более мощный и общий, чем второе расширение. Он даже работает с более чем одним параметром для замены и с вложенными циклами:
target1.PREREQUISITES = file11 file12 file13
target2.PREREQUISITES = file21 file22 file23
TARGETS = target1 target2
DIRS = myDir
# $(1): target
# $(2): directory
define MY_rule
$(2)$(1).sfx : $$($(1).PREREQUISITES)
<same recipe here>
endef
$(foreach target,$(TARGETS),$(foreach dir,$(DIRS),$(eval $(call MY_rule,$(target),$(dir)))))
И вы даже можете вставить foreach-eval-call
внутри define-endef
:
target1.PREREQUISITES = file11 file12 file13
target2.PREREQUISITES = file21 file22 file23
TARGETS = target1 target2
DIRS = myDir
# $(1): target
# $(2): directory
define MY_rule_1
$(2)$(1).sfx : $$($(1).PREREQUISITES)
<same recipe here>
endef
# $(1): directory
define MY_rule_2
$$(foreach target,$$(TARGETS),$$(eval $$(call MY_rule_1,$$(target),$(1))))
endef
$(foreach dir,$(DIRS),$(eval $(call MY_rule_2,$(dir))))