Как использовать команды в Makefile
Я пытаюсь использовать результат ls
в других командах (например, echo, rsync):
all:
<Building, creating some .tgz files - removed for clarity>
FILES = $(shell ls)
echo $(FILES)
а я:
make
FILES = Makefile file1.tgz file2.tgz file3.tgz
make: FILES: No such file or directory
make: *** [all] Error 1
Я пробовал использовать echo $$FILES
,echo ${FILES}
и echo $(FILES)
, не повезло.
2 ответа:
С:
FILES = $(shell ls)
с отступом под
all
вот так, это команда сборки. Так что это расширяет$(shell ls)
, затем пытается выполнить командуFILES ...
.если
FILES
должен бытьmake
переменная, эти переменные должны быть назначены вне части рецепта, например:FILES = $(shell ls) all: echo $(FILES)
конечно, это значит, что
FILES
будет установлен в "выход изls
"до запуск любой из команд, которые создают .tgz файлы. (Хотя, как Каз Примечания переменная каждый раз расширяется, поэтому в конечном итоге она будет включать в себя .tgz файлы; некоторые вариантыFILES := ...
чтобы избежать этого, для повышения эффективности и/или правильности.1)если
FILES
предполагается, что это переменная оболочки, вы можете установить ее, но вам нужно сделать это в shell-ese, без пробелов и в кавычках:all: FILES="$(shell ls)"
однако каждая строка выполняется отдельной оболочкой, поэтому эта переменная не будет сохраняться до конца следующая строка, так что вы должны использовать его немедленно:
FILES="$(shell ls)"; echo $$FILES
это все немного глупо, так как оболочка будет расширяться
*
(и другие выражения оболочки glob) для вас в первую очередь, так что вы можете просто:echo *
как ваша команда оболочки.
наконец, как общее правило (не совсем применимо к этому примеру): as эсперанто заметки в комментариях, используя выходе из
ls
не является полностью надежным (некоторые детали зависят от файла имена и иногда даже версииls
; некоторые версииls
попытка санировать вывод в некоторых случаях). Таким образом, как l0b0 и idelic обратите внимание, если вы используете GNU make, вы можете использовать$(wildcard)
и$(subst ...)
чтобы сделать все внутриmake
сам (избегая каких-либо "странных символов в имени файла" вопросы). (Вsh
скрипты, включая часть рецепта makefiles, другой метод заключается в использованииfind ... -print0 | xargs -0
чтобы не споткнуться о заготовки, новые строки, управление персонажами и так далее.)
1GNU Make documentation отмечает далее, что POSIX make добавлен
::=
назначение в 2012 году. Я не нашел быстрой ссылки на документ POSIX для этого, и я не знаю, что такоеmake
вариантов поддержки::=
назначение, хотя GNU make делает это сегодня, с тем же значением, что и:=
, т. е. выполнить задание прямо сейчас с расширением.обратите внимание, что
VAR := $(shell command args...)
может также пишетсяVAR != command args...
в рядуmake
варианты, включая все современные варианты GNU и BSD, насколько я знаю. Эти другие варианты не имеют$(shell)
так что с помощьюVAR != command args...
превосходит в короче и работает в большем количестве вариантов.
также, В дополнение к ответу торек: одна вещь, которая выделяется в том, что вы используете лениво-оценка макро назначения.
если вы находитесь на GNU Make, используйте
:=
назначение вместо=
. Это назначение приводит к тому, что правая сторона немедленно расширяется и сохраняется в левой переменной.FILES := $(shell ...) # expand now; FILES is now the result of $(shell ...) FILES = $(shell ...) # expand later: FILES holds the syntax $(shell ...)
если вы используете
=
назначение, это означает, что каждое вхождение$(FILES)
будет расширять$(shell ...)
синтаксис и вызывая команда оболочки. Это сделает вашу работу работать медленнее, или даже иметь некоторые неожиданные последствия.