Я столкнулся с трудностью при определении общих правил для нерекурсивной системы make.
Фон
Для дальнейшего чтения, вместо того, чтобы воспроизводить слишком много существующего материала, см. " title="Ранее SO вопрос / обсуждение нерекурсивных подходов make">этот более ранний вопрос, который довольно хорошо освещает тему и ранее помог мне при построении этой системы.
Для системы make, которую я создаю, я хочу определить зависимости между компонентами системы, например. компонент A зависит от компонента B, а затем оставьте систему make, чтобы гарантировать, что любые продукты процесса сборки B будут построены до того, как они потребуются на этапах сборки для A. Это немного расточительно из-за детализации (могут быть построены некоторые ненужные промежуточные продукты). ), но для моего варианта использования он обеспечивает удобный баланс между простотой использования и производительностью сборки.
Трудность, с которой приходится сталкиваться системе, заключается в том, что порядок загрузки make-файла нельзя контролировать - на самом деле, это не должно иметь значения. Однако из-за этого компонент, определенный в ранее загруженном make-файле, может зависеть от компонента, определенного в еще не прочитанном make-файле.
Чтобы разрешить применение общих шаблонов ко всем make-файлам, определяющим компоненты, каждый компонент использует такие переменные, как: $(component_name)_SRC
. Это распространенное решение для нерекурсивных (но рекурсивно включенных) систем make.
Для получения информации о различных типах переменных GNU make см. руководство. Подводя итог: просто расширенные переменные (SEV) расширяются по мере чтения make-файла, демонстрируя поведение, подобное императивному языку программирования; рекурсивно расширяемые переменные (REV) расширяются во время второй фазы make после того, как все make-файлы были прочитаны.
Проблема
Конкретная проблема возникает при попытке превратить список зависимых компонентов в список файлов, которые эти компоненты представляют.
Я сократил свой код до этого исполняемого примера, который упускает из виду многие детали реальной системы. Я думаю, что это достаточно просто, чтобы продемонстрировать проблему, не теряя ее существа.
правила.мк:
$(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
еще не существует.
Расширение после того, как все make-файлы были прочитаны, — это проблема, которую должны решить REV, и ранее я пытался определить $(c)_dependencies_src
как REV, но это тоже не работает, потому что $(c)
затем расширяется во время замены, а не во время определения, поэтому больше не имеет правильного значения.
Если кому-то интересно, почему я не использую переменные, специфичные для цели, я обеспокоен тем, что применение переменной ко всем предварительным условиям цели, описанным в руководстве, вызовет нежелательное взаимодействие между правилами для разных компонентов.
Я хотел бы знать:
- Есть ли решение этой конкретной проблемы? (т.е. есть ли простой способ заставить эту строку достичь того, чего я хочу?)
- Есть ли более типичный способ построения такой системы make? (т. е. один экземпляр make, загружающий компоненты из нескольких make-файлов и определяющий зависимости между этими компонентами.)
- Если есть несколько решений, каковы компромиссы между ними?
Последний комментарий: когда я написал свой вопрос, я начал понимать, что может быть возможное решение с использованием eval для построения определения REV, однако, поскольку я не мог найти эту проблему, описанную где-либо еще на SO, я подумал, что стоит в любом случае задавайте вопрос ради будущих искателей, плюс я хотел бы услышать мысли более опытных пользователей об этом или любых других подходах.
:=
вместо=
при настройке$(c)_dependencies_src
? Если бы вы использовали здесь=
, это решило бы вашу проблему. - person MadScientist   schedule 01.01.2017c := foo
, затем включение файлов правил, затем назначениеc := bar
и включение файлов правил. Я бы сделал это так:targets += foo
, затемfoo_c := foo
,foo_src := foo.x
и т. д., затемtargets += bar
,bar_c := bar
,bar_src := bar.x
и т. д. Это позволяет избежать установки одинаковых имен переменных и гарантировать их использование до их сброса. - person MadScientist   schedule 01.01.2017