Вы должны понять и , как работает расширение make, и , как работает расширение оболочки, чтобы писать более сложные рецепты в make. Это связано с тем, что рецепты make передаются в оболочку после того, как make завершает их расширение.
Make передает строки рецептов в оболочку практически дословно: существует только один специальный символ (не считая обратную косую черту / символы новой строки в конце) и это $
. Если make видит $
, он попытается расширить его как ссылку на переменную. Чтобы избежать этого, вы должны экранировать его как $$
, чтобы скрыть его от make.
Итак, давайте посмотрим на ваш make-файл:
cooly = "The subdirectory can see me!"
echo $(new_contents) ...
Если new_contents
равен "$(cooly)"
, make видит $(cooly)
как ссылку на переменную и раскрывает ее еще до того, как она вызовет оболочку. Итак, сначала make расширяет $(new_contents)
до "$(cooly)"
, затем расширяет его до ""The subdirectory can see me!""
(потому что кавычки находятся в обеих переменных, и кавычки не являются специальными для создания: они так же, как и любой другой символ, такой как a
или b
). Результатом будет:
echo ""The subdirectory can see me!""
Оболочка будет подбрасывать кавычки, поскольку они не активны, и выводить это значение (в канал).
Если new_contents
равно "\$(cooly)"
, это backsla sh ничего не значит сделать. Как и в кавычках, обратные косые черты (если они не находятся в конце строки) не являются специальными для создания. Так что make расширяется так же, как и раньше, но на этот раз команда, которую он передает оболочке, такова: обратные слеши
echo "\"The subdirectory can see me!""
не являются специальными для выполнения, но они являются специальными для оболочки. Здесь вы избежали второй кавычки, поэтому оболочка не обрабатывает ее как символ кавычки, что означает, что у вас в команде нечетное количество кавычек, поэтому вы получаете ошибку из оболочки о не завершенных кавычках.
Если new_contents
равно "$$(cooly)"
, make не раскрывает переменную, она передается в оболочку следующим образом:
echo "$(cooly)"
Однако $
равно также специально для оболочки. Помещение в двойные кавычки не мешает оболочке пытаться ее расширить. Это говорит оболочке выполнить команду cooly
и заменить вывод. Почти наверняка нет команды с именем cooly
, и поэтому вы получите сообщение об ошибке в stderr (возможно, вы этого не заметили), и оболочка ничего не заменит, потому что ничего не печатает в stdout.
Если new_contents
равен "\$$(cooly)"
, то make не будет расширяться и запустит следующую команду оболочки:
echo "\$(cooly)"
Оболочка видит backsla sh и не расширяет $
но вместо этого использует его буквально, и вы получите желаемый результат.
Вот несколько советов:
Во-первых, не включайте кавычки в ваши переменные make (если переменная не содержит всю команду оболочки) и вам нужны цитаты внутри него). Make не заботится о кавычках, а встраивание их в переменные затрудняет рассуждение о том, что увидит оболочка.
Включайте только цитаты в рецепт.
Во-вторых, помните, что Так как make не заботится о кавычках, он не имеет такого же поведения, как одиночные и двойные кавычки оболочки WRT. Вы можете использовать одинарные кавычки вокруг переменных make, чтобы уменьшить необходимость экранирования объектов из оболочки, не скрывая их от make.
Итак, я бы написал так:
new_contents = $$(cooly)
cooly = The subdirectory can see me!
all:
mkdir -p subdir
echo '$(new_contents)' | sed -e 's/^ //' > subdir/makefile
...
Кстати, это Никогда не стоит добавлять @
значений в ваш make-файл, пока он не будет полностью готов и работает. Просмотр выходных данных make print (что и отправляется в оболочку) очень помогает выяснить, верны ли ваши рецепты, и связана ли проблема с вашими make-конструкциями или shell-конструкциями.