Я предполагаю, что вы используете GNU make. Ваша проблема связана с тем, как GNU make обрабатывают шаблонные (неявные) правила. Из введения в раздел Алгоритм поиска неявных правил из GNU make manual :
Вот процедура make, используемая для поиска неявного правила для
цель т. Эта процедура выполняется для каждого правила двойного двоеточия с
нет рецепта, для каждой цели обычных правил, ни одно из которых не имеет
рецепт, и для каждой предпосылки, которая не является целью какого-либо правила.
Это также рекурсивно следует для предварительных условий, которые приходят из
неявные правила, в поисках цепочки правил.
Итак, ваше шаблонное правило не учитывается для целей file1.out
и file2.out
, поскольку они являются целями обычных правил с рецептом .
Решение: вы можете перечислить цели *.out
в переменной и использовать ее, чтобы объявить, что все они зависят от source.txt
:
OUTFILES := $(wildcard *.out)
$(OUTFILES): source.txt
file1.out:
cat source.txt | grep "hello,world" > file1.out
file2.out:
cat source.txt > file2.out
Если цели могут находиться в подкаталогах, вы можете использовать функцию shell
make для вызова find
вместо использования функции wildcard
make:
OUTFILES := $(shell find . -type f -name '*.out')
Примечания:
Это будет работать только для существующих *.out
файлов. Make не может придумать список целевых файлов, если они еще не существуют (и, следовательно, их можно найти по make), и если вы сами не предоставили список в make-файле.
Ваш рецепт cat source.txt | grep "hello,world" > file1.out
потерпит неудачу с ненулевым статусом выхода, если файл source.txt
не содержит строку hello,world
. И если это произойдет, make завершит работу с сообщением об ошибке. Вы можете избежать этого с помощью:
cat source.txt | grep "hello,world" > file1.out || true
Автоматические переменные могут быть очень полезны. Если source.txt
является единственной предпосылкой ваших целей, вы можете упростить все это с помощью таких рецептов, как:
file1.out:
cat "$<" | grep "hello,world" > "$@" || true
file2.out:
cat "$<" > "$@"
($@
расширяется как цель правила, а $<
расширяется как первая предпосылка). Это позволяет избежать опечаток и делает рецепты более общими. Иногда вы можете даже иметь один и тот же рецепт для нескольких целей:
file1.out file3.out:
cat "$<" | grep "hello,world" > "$@" || true