Я столкнулся с трудностью в определении общих правил для нерекурсивной системы make.Определить рекурсивно расширенную переменную, используя переменную, имя которой вычисляется из просто расширенной переменной
фон
Для дальнейшего чтения, а не мне воспроизвести слишком много существующего материала, см this earlier question, который покрывает землю довольно хорошо, и ранее помогли мне при создании этой системы.
Для создания системы, которую я создаю, я хочу определить зависимости между компонентами системы - например. компонент A зависит от компонента B - и затем оставить систему make, чтобы гарантировать, что любые продукты процесса сборки B будут построены до того, как они понадобятся для выполнения шагов сборки для A. Это немного расточительно из-за зернистости (могут быть созданы некоторые ненужные промежуточные продукты), но для моего случая использования он удовлетворяет удобной балансовой точке между простотой использования и производительностью.
Сложность, с которой система должна иметь дело, заключается в том, что порядок загрузки файлов не может контролироваться - действительно, не имеет значения. Однако из-за этого компонент, определенный в раннем загруженном файле makefile, может зависеть от компонента, определенного в файле незавершенного чтения.
Чтобы разрешить общие шаблоны применяться ко всем определяющим компонент файлам, каждый компонент использует такие переменные, как: $(component_name)_SRC
. Это общее решение для нерекурсивных (но рекурсивно включенных) систем make.
Для получения информации о различных видах переменных GNU make см. the manual. В итоге: просто расширенные переменные (SEV) расширяются по мере чтения make-файла, демонстрируя поведение, подобное языку обязательного программирования; рекурсивно расширенные переменные (REV) расширяются во второй фазе make, после того, как все make-файлы были прочитаны.
Проблема
Конкретная проблема возникает при попытке превратить список зависел навесные детали в список файлов, эти компоненты представляют.
Я перегнал свой код на этот запущенный пример, который не содержит много деталей реальной системы. Я думаю, что это достаточно просто, чтобы продемонстрировать проблему, не теряя при этом ее сути.
rules.mk:
$(c)_src := $(src)
$(c)_dependencies := $(dependencies)
### This is the interesting line:
$(c)_dependencies_src := $(foreach dep, $($(c)_dependencies), $($(dep)_src))
$(c) : $($(c)_src) $($(c)_dependencies_src)
@echo $^
Makefile:
.PHONY: foo_a.txt foo_b.txt bar_a.txt hoge_a.txt
### Bar
c := bar
src := bar_a.txt
dependencies :=
include rules.mk
### Foo
c := foo
src := foo_a.txt foo_b.txt
dependencies := bar hoge
include rules.mk
### Hoge
c := hoge
src := hoge_a.txt
dependencies := bar
include rules.mk
Они будут работать, чтобы дать:
$ make foo
foo_a.txt foo_b.txt bar_a.txt
$
hoge_a.txt не включаются в выходной, потому что на время, которое foo_dependencies
определяется как SEV, hoge_src
еще не существует.
Расширение после того, как все профайлы были прочитаны, проблема должна быть в состоянии решить, и я попытался определить $(c)_dependencies_src
как REV, но это не сработает, потому что $(c)
затем расширяется при времени замены, а не в определении время, поэтому оно больше не содержит правильное значение.
В случае, если кто-то задается вопросом, почему я не использую переменные, специфичные для конкретной цели, я обеспокоен тем, что применение переменной ко всем предварительным требованиям цели, описанной в руководстве, приведет к нежелательному взаимодействию между правилами для разных компонентов ,
Я хотел бы знать:
- Есть ли решение этой конкретной проблемы? (т. е. есть ли простой способ сделать эту линию достижением того, что я хочу?)
- Существует ли более типичный способ создания такой системы? (т. е. один экземпляр make, загружая компоненты из нескольких make-файлов и определяя зависимости между этими компонентами.)
- Если существует несколько решений, каковы компромиссы между ними?
Последний комментарий: Поскольку я написал свой вопрос, я начал понимать, что может быть возможно решение с использованием eval для построения определения REV, однако, поскольку я не мог найти эту проблему в любом месте еще на SO Я думал, что стоит задать вопрос в любом случае ради будущих искателей, плюс я хотел бы услышать мысли более опытных пользователей об этом или любых других подходах.
Почему вы используете ': =' вместо просто '=' при установке '$ (c) _dependencies_src'? Если вы использовали '=' здесь, это решило бы вашу проблему. – MadScientist
Лично я никогда бы не создал систему, в которой использовались «глобальные» переменные, такие как присвоение 'c: = foo', включая файлы правил, а затем назначение' c: = bar' и включая файлы правил. Я бы сделал это следующим образом: 'target + = foo', затем' foo_c: = foo', 'foo_src: = foo.x' и т. Д., Тогда' target + = bar', 'bar_c: = bar',' bar_src : = bar.x' и т. д. Это позволяет избежать наличия одинаковых имен переменных и обеспечения их использования до их сброса. – MadScientist
Вы пробовали это с приведенным мной примером? Это, по крайней мере, не работает для меня, как я сказал: «... REVs должны быть в состоянии решить, и я ранее пытался определить $ (c) _dependencies_src как REV ...» –