У меня есть очень удобный способ скомпилировать проект с помощью нескольких строк команд bash. Но теперь мне нужно скомпилировать его через make-файл. Учитывая, что каждая команда запускается в собственной оболочке, мой вопрос: как лучше всего запустить многострочную команду bash, зависящую друг от друга, в make-файле? Например, вот так:
for i in `find`
do
all="$all $i"
done
gcc $all
Кроме того, может кто-нибудь объяснить, почему даже однострочная команда bash -c 'a=3; echo $a > file'
работает правильно в терминале, но создает пустой файл в случае файла makefile?
Ответы:
Для продолжения строки можно использовать обратную косую черту. Однако обратите внимание, что оболочка получает всю команду, объединенную в одну строку, поэтому вам также необходимо завершить некоторые строки точкой с запятой:
Но если вы просто хотите взять весь список, возвращенный
find
вызовом, и передать егоgcc
, вам на самом деле не обязательно нужна многострочная команда:Или, используя более традиционный
$(command)
подход к оболочке (обратите внимание на$
экранирование):источник
Как указано в вопросе, каждая подкоманда запускается в собственной оболочке . Это делает написание нетривиальных сценариев оболочки немного беспорядочным - но это возможно! Решение состоит в том, чтобы объединить ваш скрипт в одну подкоманду (одну строку), которую make будет рассматривать.
Советы по написанию сценариев оболочки в make-файлах:
$
заменив его на$$
;
между командами\
set -e
чтобы соответствовать положению make для прерывания при сбое подкоманды()
или{}
подчеркнуть связность многострочной последовательности - это не типичная последовательность команд make-файла.Вот пример, вдохновленный OP:
источник
SHELL := /bin/bash
включить в свой make-файл специфические для BASH функции, такие как подстановка процесса .{
важен для предотвращения интерпретации{set
как неизвестной команды.{}
и()
имеет большое значение, если вы иногда хотите скопировать сценарий и запустить его прямо из приглашения оболочки. Вы можете нанести ущерб своему экземпляру оболочки, объявив переменные и особенно изменив состояние с помощьюset
внутри{}
.()
предотвращает изменение сценарием вашей среды, что, вероятно, предпочтительнее. Пример ( это конец вашей оболочки сессии ):{ set -e ; } ; false
.command ; ## my comment \` (the comment is between
:; `и` \ `). Кажется, это работает нормально, за исключением того, что если вы запустите команду вручную (путем копирования и вставки), история команд будет включать комментарий таким образом, что команда прервется (если вы попытаетесь использовать его повторно). [Примечание: выделение синтаксиса для этого комментария нарушено из-за использования обратной косой черты внутри обратного апострофа.]Что плохого в простом вызове команд?
И для вашего второго вопроса вам нужно избежать
$
, используя$$
вместо этого, то естьbash -c '... echo $$a ...'
.РЕДАКТИРОВАТЬ: ваш пример можно переписать в однострочный скрипт следующим образом:
источник
Конечно, правильный способ написать Makefile - это фактически задокументировать, какие цели зависят от источников. В тривиальном случае предлагаемое решение будет
foo
зависеть от самого себя, но, конечно,make
достаточно умен, чтобы отказаться от циклической зависимости. Но если вы добавите временный файл в свой каталог, он «волшебным образом» станет частью цепочки зависимостей. Лучше раз и навсегда создать явный список зависимостей, возможно, с помощью скрипта.GNU Make знает , как работать ,
gcc
чтобы получить исполняемый из набора из.c
и.h
файлов, так что, может быть , все , что вам действительно нужно , чтобы количествоисточник
Директива ONESHELL позволяет писать несколько строковых рецептов, которые будут выполняться при одном вызове оболочки.
Однако есть недостаток: специальные символы префикса ('@', '-' и '+') интерпретируются по-разному.
https://www.gnu.org/software/make/manual/html_node/One-Shell.html
источник