Tengo una forma muy cómoda de compilar mi proyecto a través de unas pocas líneas de comandos bash. Pero ahora necesito compilarlo a través de Makefile. Teniendo en cuenta que cada comando se ejecuta en su propio shell, mi pregunta es ¿cuál es la mejor manera de ejecutar el comando bash de varias líneas, dependientes entre sí, en un archivo MAKE? Por ejemplo, así:
for i in `find`
do
all="$all $i"
done
gcc $all
Además, ¿alguien puede explicar por qué incluso el comando de una sola línea bash -c 'a=3; echo $a > file'
funciona correctamente en la terminal, pero crea un archivo vacío en el caso del archivo MAKE?
Respuestas:
Puede utilizar la barra invertida para la continuación de la línea. Sin embargo, tenga en cuenta que el shell recibe todo el comando concatenado en una sola línea, por lo que también debe terminar algunas de las líneas con un punto y coma:
Pero si solo desea tomar la lista completa devuelta por la
find
invocación y pasarlagcc
, en realidad no necesita un comando de varias líneas:O, utilizando un
$(command)
enfoque más convencional de shell ($
aunque observe el escape):fuente
Como se indica en la pregunta, cada subcomando se ejecuta en su propio shell . Esto hace que escribir scripts de shell no triviales sea un poco complicado, ¡ pero es posible! La solución es consolidar su script en lo que se considerará un único subcomando (una sola línea).
Consejos para escribir scripts de shell dentro de archivos MAKE:
$
reemplazando con$$
;
entre comandos\
set -e
para que coincida con la disposición de make para abortar en caso de falla del subcomando()
o{}
para enfatizar la cohesión de una secuencia de líneas múltiples, que esta no es una secuencia de comandos típica de makefileAquí hay un ejemplo inspirado en el OP:
fuente
SHELL := /bin/bash
en su archivo MAKE habilitar funciones específicas de BASH, como la sustitución de procesos .{
es crucial para evitar la interpretación de{set
un comando desconocido.{}
y()
hace una gran diferencia si a veces desea copiar el script y ejecutarlo directamente desde un indicador de shell. Puede causar estragos en su instancia de shell declarando variables, y especialmente modificando el estado conset
, dentro de{}
.()
evita que el script modifique su entorno, lo que probablemente sea el preferido. Ejemplo ( esto va a terminar su sesión de shell ):{ set -e ; } ; false
.command ; ## my comment \` (the comment is between
:; `y` \ `). Esto parece funcionar bien, excepto que si ejecuta el comando manualmente (copiando y pegando), el historial de comandos incluirá el comentario de una manera que rompe el comando (si intenta reutilizarlo). [Nota: El resaltado de sintaxis está roto para este comentario debido al uso de la barra invertida dentro de la tilde.]¿Qué hay de malo en invocar los comandos?
Y para su segunda pregunta, debe escapar
$
usando en su$$
lugar, es decirbash -c '... echo $$a ...'
.EDITAR: Su ejemplo podría reescribirse en un script de una sola línea como este:
fuente
Por supuesto, la forma correcta de escribir un Makefile es documentar qué destinos dependen de qué fuentes. En el caso trivial, la solución propuesta
foo
dependerá de sí misma, pero, por supuesto,make
es lo suficientemente inteligente como para eliminar una dependencia circular. Pero si agrega un archivo temporal a su directorio, "mágicamente" se convertirá en parte de la cadena de dependencias. Es mejor crear una lista explícita de dependencias de una vez por todas, quizás a través de un script.GNU make sabe cómo ejecutarse
gcc
para producir un ejecutable a partir de un conjunto de archivos.c
y.h
, por lo que quizás todo lo que realmente necesite seafuente
La directiva ONESHELL permite escribir varias recetas de línea para ejecutarlas en la misma invocación de shell.
Sin embargo, hay un inconveniente: los caracteres de prefijo especiales ('@', '-' y '+') se interpretan de manera diferente.
https://www.gnu.org/software/make/manual/html_node/One-Shell.html
fuente