Heredoc в Makefile?
Возможно ли это вообще и как?
Обновление: Мне нужно это, потому что я создаю файл как из динамических, так и из статических данных.
Случай использования: У меня есть тестовый каталог. Каждый файл C создает тестовый исполняемый файл. С
SRCS = $(wildcard [a-z]*.c)
Я могу добавить новые тесты по мере необходимости, и make найдет новые тесты, скомпилирует, запустит и отбросит их. Я также использую git. Я хотел бы, чтобы .gitignore
включал исполняемые файлы.
Итак. Как создать .gitignore
и включить статические данные, т.е. Файлы, которые я хочу игнорировать (*.o
и depend
), а также исполняемые файлы динамически?
Ответы
Ответ 1
Другое решение GNU Make.
Вы можете сделать это с помощью команд define
и export
следующим образом:
define GITIGNOREDS
*.o
depend
endef
SRCS = $(wildcard [a-z]*.c)
EXES = $(SRCS:.c=)
export GITIGNOREDS
.gitignore: $(SRCS)
echo $(EXES) | sed 's/ /\n/g' > [email protected]
echo "$$GITIGNOREDS" >> [email protected]
Однако вы должны быть осторожны, чтобы делать расширения (т.е. $(x)
) внутри блока define.
Ответ 2
Это зависит от того, насколько вы настроены. Лучше предположить, что это не сработает. Запишите оболочку script для запуска вместо этого документа в файле makefile.
Сбой 1
heredoc:
cat - <<!
This is the heredoc.
!
Это дает:
cat - <<!
This is the heredoc.
make: This: No such file or directory
make: *** [heredoc] Error 1
Каждая строка выполняется отдельно - oops.
Сбой 2
heredoc:
cat - <<! \
This is the heredoc.\
!
Сгенерировано:
cat: This: No such file or directory
cat: is: No such file or directory
cat: the: No such file or directory
cat: heredoc.!: No such file or directory
make: *** [heredoc] Error 1
Могут быть методы, использующие определенную версию make (например, GNU make может выполнять все команды для действия в одной подоболочке), но тогда вы должны указать свои требования к переносимости. Для обычного (скажем, POSIX-совместимого) make
, предположим, что документы не работают.
Ответ 3
GNU Makefile может выполнять следующие действия. Это уродливо, и я не буду говорить, что вы должны это делать, но я делаю это в определенных ситуациях.
.profile = \
\#!/bin/sh.exe\n\
\#\n\
\# A MinGW equivalent for .bash_profile on Linux. In MinGW/MSYS, the file\n\
\# is actually named .profile, not .bash_profile.\n\
\#\n\
\# Get the aliases and functions\n\
\#\n\
if [ -f \$${HOME}/.bashrc ]\n\
then\n\
. \$${HOME}/.bashrc\n\
fi\n\
\n\
export CVS_RSH="ssh"\n
#
.profile:
echo -e "$($(@))" | sed -e 's/^[ ]//' >$(@)
make .profile
создает файл .profile, если он не существует.
Это решение было использовано, когда приложение будет использовать GNU Makefile только в среде оболочки POSIX. Проект не является проектом с открытым исходным кодом, где проблема совместимости с платформой.
Цель заключалась в создании Makefile, который облегчает настройку и использование определенного вида рабочего пространства. Makefile объединяет в себе различные простые ресурсы, не требуя таких вещей, как другой специальный архив и т.д. Это, в некотором смысле, архив оболочки. Процедура может затем сказать такие вещи, как сбросить этот файл Makefile в папку для работы. Настройте рабочее пространство, введите make workspace
, затем выполните blah, введите make blah
и т.д.
То, что может показаться сложным, - это выяснить, что такое оболочка. Вышеприведенная работа и близко к идее указания здесь документа в Makefile. Является ли это хорошей идеей для общего использования, является целая другая проблема.
Ответ 4
Да, вы можете. Как отмечают другие, вы, вероятно, не должны, но можете. В ответе Ash есть одно решение, включающее команды определения, но это комбинация и может затруднить получение переменных до правильных значений. Другой трюк заключается в использовании .ONESHELL:
специальной цели.
Иногда вы предпочитаете, чтобы все строки в рецепте были переданы одному вызову оболочки. Как правило, есть две ситуации, когда это полезно: во-первых, это может повысить производительность в make файлах, где рецепты состоят из многих команд, избегая дополнительных процессов. Во-вторых, вы можете захотеть, чтобы в вашу команду рецепта были включены символы новой строки (например, возможно, вы используете совсем другой интерпретатор, как ваш SHELL). Если специальная цель .ONESHELL появляется в любом месте make файла, тогда все линии рецептов для каждой цели будут предоставлены одному вызову оболочки. Будут сохранены новые линии между линиями рецептов.
Несколько слов предупреждения:
- Это повлияет на то, как работают все рецепты в Makefile.
- Операторы префикса строк, такие как
-
или @
для подавления ошибок вывода или игнорирования, работают только в первой строке всех рецептов и вступают в силу для всех следующих строк.
- Некоторые старые версии или GNU Make (например, запущенные по умолчанию в системе Travis CI даже в новых контейнерах) могут игнорировать эту директиву, приводящую к странным ошибкам и ошибкам. Убедитесь, что вы знаете целевую среду.
С этой точки зрения, вот как это могло бы выглядеть для создания файла уценки:
SHELL = bash
.ONESHELL:
MYVAR = "Some Title"
file.md:
cat <<- EOF > [email protected]
$(MYVAR)
========
This stuff will all be written to the target file. Be sure
to escape dollar-signs and backslashes as Make will be scanning
this text for variable replacements before bash scans it for its
own strings.
Otherwise formatting is just as in any other bash heredoc. Note
I used the <<- operator which allows for indentation. This markdown
file will not have whitespace at the start of lines.
Here is a programmatic way to generate a markdwon list all PDF files
in the current directory:
`find -maxdepth 1 -name '*.pdf' -exec echo " + {}" \;`
EOF
Обратите внимание, что еще одна дополнительная информация заключается в том, что Make пропускает пустые строки. Если наличие пустой строки в содержании вашего heredoc важно, вам нужно сделать отступ, чтобы строка с соответствующим уровнем пробела соответствовала методу heredoc или Make, и она даже не передала его cat!
Ответ 5
Если вы используете Gnu Make, используйте "define" для создания многострочной текстовой переменной и правила для эха в файл. См. 6.8 Определение многолинейных переменных https://www.gnu.org/software/make/manual/make.html#Appending
Вот так:
define myvar
# line 1\nline 2\nline 3\n#etc\n
endef
myfile.txt:
/bin/echo -e "$(myvar)) >myfile.txt
Чтобы создать это, вы можете использовать редактор, создать файл, который хотите иметь, добавить "\n" в конец каждой строки и затем объединить их в одну строку. Вставьте это в свой файл.
Протестировано с помощью GNU Make 3.81 на linux.
Ответ 6
По просьбе Джека Келли:
SRCS = (wildcard [a-z]*.c)
EXES = $(SRCS:.c=)
GITIGNOREDS = *.o depend
.gitignore: $(SRCS)
echo $(EXES) | sed 's/ /\n/g' > [email protected]
echo $(GITIGNOREDS) | sed 's/ /\n/g' > [email protected]
Важно GITIGNOREDS
. Я предпочел бы heredoc, как
GITIGNOREDS = <<EOT
*.o
depend
EOT
но я также доволен списком файлов, разделенным пробелами, и sed script, чтобы перевести пространство в строки новой строки.
Изменить Как было предложено Райаном В. Бисселем: используйте отдельный тестовый подкаталог, который вы добавляете в gitignore. И все встает на свои места. Это просто.
Ответ 7
Похоже, что нет никакого способа сделать здесь-документ в Makefile. Однако есть возможное обходное решение. Используйте echo для отправки данных здесь-документа:
all:
echo "some text" | myScript.sh