Makefile: правила для нескольких каталогов и файлов, различающихся по строковому шаблону - PullRequest
0 голосов
/ 16 марта 2020

У меня есть правило Makefile в проекте RStudio, которое создает различные промежуточные и выходные файлы данных. Некоторые из ключевых правил выглядят так:

outdir/<location>/outdata_<location>.file: script.R datadir/<location>/indata_<location>.file
    $(EXEC) $< <location>

, где location различает каталоги, а также имена файлов как целей, так и предварительных требований, и одновременно передается в качестве аргумента to script.R.

Наглядно показано, например, как структурированы каталоги предварительных условий:

datadir
|- location1
|  |- indata_location1.file 
|  |- ...
|
|- location2
|  |- indata_location2.file 
|  |- ...
|
|- location3

Каждый из этих каталогов имеет разные уровни файлов данных, следовательно, решение организовать их по месту нахождения. Кроме того, с течением времени добавляется больше местоположений проекта, следовательно, необходимость в неявных правилах сводит к минимуму необходимость постоянного манипулирования с Makefile.

Я пробовал использовать правила шаблонов, как описано в документации GNU Make, но там говорится заполнитель шаблона может появляться только один раз в цели или в предварительных условиях. Я пытался использовать манипуляции со строками и функции foreach, но не смог решить ее, так как мой опыт работы с GNU Make ограничен.

Я видел похожие вопросы SO по нескольким каталогам, но ни один из них не касался использования дифференцирующей строки в качестве аргумента в рецепте.

Любая помощь будет оценена.

1 Ответ

1 голос
/ 17 марта 2020

Вы хотите использовать несколько очень похожих правил, и дисперсия слишком сложна для правила шаблона. Это похоже на работу для «консервированного рецепта» .

Мы пишем шаблон:

define data-rule
outdir/$(1)/outdata_$(1).file: script.R datadir/$(1)/indata_$(1).file
    $(EXEC) $$< $(1)
endef

(точный синтаксис зависит от версии Make, поэтому вам может понадобиться '=' в конце строки "define".)

Теперь мы можем сгенерировать текст правила location1 с помощью call:

$(call data-rule,location1)

и Make должен интерпретировать этот текст как фактический код makefile с помощью eval:

$(eval $(call data-rule,location1))

Как только мы убедимся, что это работает, мы можем сгенерировать правила по одному один:

$(eval $(call data-rule,location1))
$(eval $(call data-rule,location2))
$(eval $(call data-rule,location3))

или используйте foreach:

LOCATIONS := location1 location2 location3
$(foreach loc,$(LOCATIONS),$(eval $(call data-rule,$(loc))))

Наконец, вы можете захотеть цель, которая создает все эти файлы:

all-locations: outdir/location1/outdata_location1.file outdir/location2/outdata_location2.file outdir/location3/outdata_location3.file

Вы также можете автоматизировать эту конструкцию:

$(foreach loc,$(LOCATIONS),$(eval all-locations: outdir/$(loc)/outdata_$(loc).file))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...