Как использовать GNU make для обновления файлов во всех подкаталогах, содержащих определенный файл? - PullRequest
0 голосов
/ 04 августа 2020

В моем проекте у меня есть набор подкаталогов, содержащих файлы package.yaml, например:

A/package.yaml
B/package.yaml
C/package.yaml

Если я запустил hpack A/package.yaml, файл A/A.cabal будет (повторно ) сгенерировано. Список таких каталогов может меняться со временем, поэтому я хочу использовать GNU make, чтобы найти все непосредственные подкаталоги, содержащие файлы package.yaml, и сгенерировать соответствующие файлы .cabal с помощью hpack.

Я пробовал это на основе на другой вопрос , но он не сработал:

HPACK_FILES := $(wildcard */package.yaml)
PKG_DIRS := $(subst /,,$(dir $(HPACK_FILES)))
CABAL_FILES := $(addsuffix .cabal,$(join $(dir $(HPACK_FILES)),$(PKG_DIRS)))

test:
    @echo $(CABAL_FILES)

update-cabal: $(CABAL_FILES)

%.cabal: package.yaml
    hpack $<

Однако make update-cabal говорит, что ничего не поделаешь. make test однако выводит правильные файлы Кабала. Как я могу это исправить?

Ура!

1 Ответ

1 голос
/ 04 августа 2020

Проблема такая:

%.cabal: package.yaml

Нет файла package.yaml. Файлы имеют имена вроде A/package.yaml. Это не одно и то же.

Поскольку предварительное условие не существует, make решает, что это правило шаблона не может соответствовать, и поэтому ищет другое правило, которое могло бы создать цель. Он не находит ни одного правила, которое могло бы создать цель, поэтому make говорит, что делать нечего, потому что все выходные файлы уже существуют. наиболее удобен для входных и выходных файлов, связанных вместе именем файла с расширениями или подобными. И, в частности, ему очень трудно работать с отношениями, в которых переменная часть повторяется более одного раза (например, A/A.cabal, где A повторяется). В make нет простого способа сделать это.

Для этого вам придется использовать расширенную функцию, например, eval. Что-то вроде:

# How to build a cabal file
%.cabal:
        hpack $<

# Declare the prerequisites
$(foreach D,$(dir $(HPACK_FILES)),$(eval $D/$D.cabal: $D/package.yml))
...