Как правильно удалить данные для Makefile?
Я динамически генерирую config.mk
с помощью bash script, который будет использоваться Makefile. Файл сконструирован с помощью:
cat > config.mk <<CFG
SOMEVAR := $value_from_bash1
ANOTHER := $value_from_bash2
CFG
Как обеспечить, чтобы сгенерированный файл действительно содержал содержимое $value_from_bash*
, а не что-то расширенное/интерпретируемое? Вероятно, мне нужно избежать $
до $$
и \
до \\
, но есть ли другие символы, которые нужно экранировать? Возможно, есть специальное литеральное задание, о котором я не слышал?
Кажется, что пространства тоже неприятны:
$ ls -1
a b
a
$ cat Makefile
f := a b
default_target:
echo "$(firstword $(wildcard ${f}))"
$ make
a
Если я использую f := a\ b
, он работает (использование кавычек вроде f := 'a b'
тоже не работает, makefile просто рассматривает его как обычный символ)
Ответы
Ответ 1
Хорошо, оказалось, что Makefile не нуждается в небольшом экранировании для себя, но команды, которые выполняются интерпретатором оболочки, должны быть экранированы.
Символами, которые имеют особое значение в Makefile и которые должны быть экранированы, являются:
- sharp (
#
, комментарий) становится \#
- доллар (
$
, начало переменной) становится $$
Новые строки не могут быть вставлены в переменную, но чтобы не сломать остальную часть Makefile, добавьте ее с обратной косой чертой, чтобы игнорировать разрыв строки.
Слишком плохо сам обратный слэш не может быть экранирован (\\
по-прежнему будет \\
, а не \
, как вы могли бы ожидать). Это делает невозможным поставить буквальную косую черту в конце строки, поскольку она либо будет использовать новую строку, либо хэш следующего комментария. Пространство можно поместить в конец строки, но оно также будет помещено в самую переменную.
Сам рецепт интерпретируется как команда оболочки без какого-либо фантастического экранирования, поэтому вы должны сами избегать данных, просто представьте, что вы пишете shellscript и вставляете переменные из других файлов. Стратегия здесь заключалась бы в переносе переменных между одинарными кавычками и побеге только '
с помощью '\''
(закройте строку, вставьте литерал '
и запустите новую строку). Пример: mornin' all
становится 'morning'\'' all'
, что эквивалентно "morning' all"
.
Проблема с первым словом + подстановочным знаком вызвана тем фактом, что имена файлов с пробелами в них рассматриваются как отдельные имена файлов с помощью firstword
. Кроме того, wildcard
расширяет возможности с помощью \
, поэтому x\ y
соответствует как одно слово, x y
, а не два слова.
Ответ 2
- Я не вижу, как этот make файл может работать, как вы говорите. Правило шаблона не может быть значением по умолчанию.
- Вам не хватает `$` в `$ (wildcard...)`, поэтому я думаю, что вы не опубликовали то, что вы действительно тестируете.
- Вам также следует избегать новых строк.
Ответ 3
Кажется, что полный ответ на этот вопрос найден нигде в Интернете, поэтому я, наконец, сел и понял это для случая Windows.
В частности, "случай Windows" относится к именам файлов, которые действительны в Windows, а это означает, что они не содержат символы \
, /
, *
, ?
, "
, ^
, <
, >
, |
. Это также означает, что \
и /
считаются действительными разделителями каталогов для целей Make.
Пример очистит его лучше, чем я могу объяснить. В основном, если вы пытаетесь сопоставить этот путь к файлу:
Child\a$b {'}(a.o#[email protected],&+=~`),[].c
Затем вы должны написать эти правила:
all: Child\\a$$b\\\ \\\ {'}(a.o\#[email protected],&+=~`),[].o
%.o: %.c
$(CC) '$(subst ','"'"',$(subst \,,$(subst \\,/,$+)))'
Посмотрите на него в течение долгого времени, и это начнет делать какой-то отдаленный смысл.
Это работает в моей среде MSYS2, поэтому я предполагаю, что это правильно.