GNU делает подстановочную функцию не обнаруживает созданные файлы времени выполнения

Резюме:
Я использую GNU Make (3.81) в unix-подобной системе, и я столкнулся с проблемой, когда функция $(wildcard, pattern) не может найти файл, сгенерированный ранее (по-видимому?), Ранее выполненный рецепт, тогда как другие программы (например, ls) могут проверить свое существование. Я хотел бы знать, почему функция wildcard ничего не возвращает, когда она расширена (до пустой строки) и как я могу заставить ее найти сгенерированный файл.

Тестовый пример:
Следующий тестовый пример иллюстрирует проблему.
Содержимое Makefile:

.PHONY: build clean

test:
    @echo "Creating test file 'test'."
    @echo "this is a test file" > test

build: test
    @echo "Directory contents:"
    @ls
    @echo "Test file contents:"
    @cat test
    @echo "Wildcard output:"
    @echo $(wildcard test)

clean:
    @rm -f test

Запуск make файла дважды (затем очистка) показывает, что только при втором запуске он обнаруживает созданный файл.
Выход:

Creating test file 'test'.
Directory contents:
makefile  test
Test file contents:
this is a test file
Wildcard output:

Directory contents:
makefile  test
Test file contents:
this is a test file
Wildcard output:
test

Воспроизведение:
Сохраните make файл в пустом каталоге, затем запустите команду make make make make make make make clean.

Исследование:
Порядок, в котором обрабатываются предпосылки для цели, не зависит от порядка, в котором они отображаются в списке после двоеточия, поэтому должны быть введены явные взаимозависимые зависимости если вы хотите определить порядок их обработки.

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

Из моего знания того, как make анализирует make файл, подстановочная функция внутри рецепта не должна расширяться до его обработки. Тем не менее, я отчетливо вижу разницу между выходом встроенной функции make и выходом общих утилит, доступ к которым осуществляется через оболочку, поэтому эта презумпция, вероятно, неверна, но я не нашел никаких хороших объяснений того, что должно было происходят здесь, даже в GNU не делают руководство.

N.B. Цель этого вопроса - просто понять понимание работы подстановочной функции, имеющей отношение к этой проблеме; есть практический случай использования, из которого я перегонял эту политую версию, но меня больше интересует этот случай.

Ответ 1

GNU make расширяет все команды для цели перед выполнением любого из них. В этом контексте "expand" означает "заменить все ссылки на переменные своими значениями (рекурсивно) и оценить любые ссылки на функции". $(wildcard), конечно, является ссылкой на функцию. Поскольку разложение происходит до того, как какая-либо из команд будет выполнена, конечно, файл test не может быть найден - он еще не создан. Во второй раз, когда вы запускаете сборку, test уже существует, поэтому $(wildcard) может найти его.

Относительно вашего заявления о том, что порядок, в котором обрабатываются предварительные условия: технически GNU make не дает никаких гарантий относительно порядка, но практически говоря, prereqs обрабатываются слева направо и, несмотря на попытки пуристов изменить это (для единственного цель завинчивания с людьми, которые не имеют полностью определенных зависимостей), вероятность того, что GNU make действительно изменит, детали реализации исчезающе малы. Однако вы можете реально положиться на этот заказ в серийной сборке. Если вы запускаете сборку параллельно, все становится немного сложнее: GNU make все еще обрабатывает prereqs в порядке слева направо, но он больше не ждет завершения до начала следующего, так что они могут появиться для обработки в случайном или "любом" порядке, с учетом взаимных зависимостей, поэтому рекомендуется указать эти зависимости.