Как обмануть Make, чтобы динамически запускать команды во вложенных папках

#makefile

Вопрос:

Я пытаюсь заставить Make запускать команды из вложенных папок, о которых он не знает в корневом файле makefile.

У меня есть следующий файл makefile в корне проекта:

 ARGS=$(filter-out $@, $(MAKECMDGOALS))

.PHONY: build
build:
    @$(MAKE) -C ${ARGS} build

%:
    @$(MAKE) -C ${ARGS}
 

У меня есть следующее в ./folder

 build:
    @echo "Mushrooms!"
.PHONY: build

badgers:
    @echo "Badgers!"
.PHONY: badger
 

Итак, когда я бегу make build folder , я получаю эхо «Грибы!», как и ожидалось. Однако, когда я бегу make folder badgers , я получаю то же самое эхо.

Я предположил, что он правильно работал при первом запуске, но, похоже, он игнорирует любые аргументы (т. Е. подкоманду, которую я хочу запустить) и просто запускает первую запись ./folder/makefile .

Кто-нибудь знает, как я могу обмануть, чтобы вызвать правильную команду из вложенной папки?

Комментарии:

1. Никогда не отключайте повторение команд (с помощью добавления @ ), пока вы не будете уверены, что файл makefile работает должным образом. А может быть, и не тогда. Подавление эха команды скрывает информацию, которая может иметь решающее значение для отладки.

Ответ №1:

Если бы вы включили повторение команд в своем файле makefile верхнего уровня, вы бы увидели, что в данном make folder badgers случае рекурсивная make команда , которая выполняется make -C folder , отсутствует make -C folder badgers . Почему? Потому что когда ${ARGS} расширяется в контексте правила соответствия чему-либо, цель есть badgers , и вы явно отфильтровываете цель из расширения!

Вы также могли быть осведомлены о том, что обе ваши make команды печатают сообщение о folder том, что они актуальны. Это говорит вам о том, что он выбирает, а не выполняет рецепт построения folder . В этом случае make build folder марка верхнего уровня запускает только рецепт для цели build , который повторно вводит «сборку» в список целей под-марки. В случае make folder badgers , он выполняет только рецепт для badgers , который не повторно вводит эту цель в субподписку, поэтому субподписка строит цель по умолчанию.

Я бы предложил что-то менее волшебное: полагайтесь на определение макроса в командной строке. Файл makefile будет выглядеть следующим образом:

 .PHONY: build

# Just for the purpose of having a default target
build:
    make -C $(subdir) "$@"

%:
    make -C $(subdir) "$@"
 

Вы бы тогда побежали make вот так:

 make subdir=folder
make subdir=folder build
make subdir=folder badgers
 

Это все еще оставляет несколько пробелов, например , что произойдет, если пользователь не укажет значение subdirs , но, как минимум, это более прочный фундамент для строительства.