#makefile
#makefile
Вопрос:
В Makefile с несколькими целевыми объектами, как можно предотвратить расширение предварительных условий целевых объектов, которые не используются? Смотрите следующий пример:
thisexpands = $(warning Expanded!)
.PHONY: target1
target1: $(thisexpands)
@echo Target 1
.PHONY: target2
target2:
@echo Target 2
Вызов target2
заставляет thisexpands
расширяться, даже если он вычисляется лениво и он и target1
никогда не используются.
В моем реальном случае расширение thisexpands
при вызове target1
является проблемой, потому что это команда оболочки, которая выводит ошибки при вызове вне контекста target1 и его родительских целевых объектов (здесь не показано).
Ответ №1:
Make-файлы полностью анализируются перед выполнением первого правила. В рамках синтаксического анализа все целевые объекты и предварительные условия должны быть расширены. Вы можете найти подробную информацию о том, когда происходит расширение для разных частей makefile в Как make считывает Makefile в руководстве GNU make.
Один из способов — использовать рекурсию:
thisexpands = $(warning Expanded!)
target1: ; $(MAKE) target1-recurse T1_DEPS='$(value thisexpands)'
T1_DEPS =
target1-recurse: $(T1_DEPS)
@echo Target 1
Это не работает:
Вероятно, вы можете отложить расширение, используя вторичное расширение, что-то вроде этого:
.SECONDEXPANSION:
target1: $$(thisexpands)
Будьте очень осторожны, чтобы соответствующим образом избежать списка предварительных условий.
Комментарии:
1. К сожалению, это только откладывает расширение, на самом деле не отменяет его.
2. Вы правы. Интересно, почему это так работает. Кажется, что было бы эффективнее подождать, пока целевой объект не понадобится перед расширением. Однако это означало бы изменение DAG во время обхода дерева, что определенно не является тривиальным изменением, так что, вероятно, именно поэтому.
3.
to wait until the target is needed before expansion
Но что, если make потребуется «попробовать» какую-то промежуточную цель, которая в конце окажется «ненужной»? Если его предварительные условия будут расширены из-за внутренних компонентов алгоритма, в то время как другие нет, это было бы, по меньшей мере, нелогично.4. Также такое расширение, вероятно, было бы в порядке «обхода графика», а не в порядке «файла». И это может привести к некоторым неприятным побочным эффектам.
5. Я не уверен, что вы подразумеваете под «порядком файлов»; может быть, «порядок создания файлов»? Но в моем примере это не имеет значения, потому что я включил вторичное расширение, поэтому расширение уже происходит в конце после того, как makefile был прочитан, в некотором случайном порядке.
Ответ №2:
Нет способа полностью отменить расширение. Однако вы можете использовать условное присвоение, основанное на значении $(MAKECMDGOALS)
:
thisexpands = $(if $(filter target1,$(MAKECMDGOALS)),$(warning Expanded!))
.PHONY: target1
target1: $(thisexpands)
@echo Target 1
.PHONY: target2
target2:
@echo Target 2
Обратите внимание, что это работает, только если target1
создается явно ( make target1
), а не по умолчанию или как часть построения другого целевого объекта.