Я пытаюсь понять, почему в некоторых Makefile есть предварительные условия %.txt
, а в других — *.txt
.
Я создал такую структуру папок.
$ tree .
.
├── hi1.txt
├── hi2.txt
├── hi3.txt
└── Makefile
Сначала я попробовал это.
foo.txt: *.txt
echo $^
И он делает то, что я ожидаю.
$ make
echo hi1.txt hi2.txt hi3.txt
hi1.txt hi2.txt hi3.txt
Но потом я увидел, что некоторые Makefiles используют его %.txt
как подстановочный знак. Так что я попробовал это следующим.
foo.txt: %.txt
echo $^
Однако это приводит к ошибке.
$ make
make: *** No rule to make target '%.txt', needed by 'foo.txt'. Stop.
Может ли кто-нибудь объяснить, почему это происходит?
GNU Make 4.3
решение1
В make
знак процента используется для сопоставления с образцом, и для этого требуется один в целевом объекте, а также (по крайней мере) один в предварительных условиях:
%.o: %.c
$(CC) $(CFLAGS) -c -o $@ $<
С помощью этого make-файла мы указываем, что для сборки чего-либо, имя файла которого заканчивается на .o
, вам нужен файл с тем же префиксом, но заканчивающийся на , .c
а не на.o
Чтобы иметь возможность построить эти правила, вам, очевидно, нужно иметь возможность ссылаться на цель, а также на предпосылки; вот где появляются переменные $@
и . означает «цель этого правила», а означает «первое перечисленное предварительное условие этого правила». Если вам нужно построить команду, которая использует$<
$@
$<
всепредварительных условий (например, для компоновки исполняемого файла), то вы можете использовать переменную $^
:
%: %.o lib.o
$(CC) $(LDFLAGS) -o $@ $^
Если вы объедините два приведенных выше примера фрагментов makefile в один makefile и у вас есть файл 'lib.c' с некоторым общим кодом, который вы хотите использовать в нескольких программах на языке C в том же каталоге, то вы можете добавить любой случайный .c
файл, скажем foo.c
, , и скомпилировать его в программу foo
, которая также будет связана с кодом в lib.c
, без необходимости внесения каких-либо изменений в ваш makefile.
Обратите внимание, что также возможны шаблоны с одной и той же целью, если предварительные условия различны; например, будет работать следующее:
%.o: %.c
$(CC).....
%.o: %.cpp
$(CXX).....
то есть, он будет работать так, как и ожидалось, пока у вас нет исходных файлов C++ в этом каталоге, которые случайно имеют то же имя (без расширения), что и исходный файл C. Если это так, версия C++ будет проигнорирована, и вместо нее будет скомпилирован исходный файл C (потому что правило C указано первым в makefile)
Для получения более подробной информации см.соответствующий разделв руководстве GNU make.