español - Probar si un archivo existe en el destino de makefile, y salir si no está presente
makefile linux c (5)
Cada línea de comando en make se ejecuta en su propio sub-shell. Por lo tanto, ejecutar exit
solo sale de ese sub-shell, no el archivo make en su totalidad. De forma predeterminada, la ejecución de la ejecución se detendrá si cualquier sub-shell devuelve un estado de salida sin éxito (por convención, 0 significa éxito, por lo que cualquier otra cosa detendrá la ejecución). El método más simple sería utilizar el estado de salida del comando de test
:
all: foo
foo:
test -s /opt/local/bin/gsort
Imprimir un mensaje de diagnóstico complica un poco las cosas porque los comandos como echo
devolverán un estado de salida de 0, lo que make
que todo esté bien. Para solucionar esto, debe ejecutar un comando después de él que le dará al sub-shell un estado de salida distinto de cero:
all: foo
foo:
test -s /opt/local/bin/gsort || { echo "GNU sort does not exist! Exiting..."; exit 1; }
o incluso simplemente
all: foo
foo:
test -s /opt/local/bin/gsort || { echo "GNU sort does not exist! Exiting..."; false; }
¿Hay alguna manera de salir con una condición de error si no existe un archivo? Actualmente estoy haciendo algo como esto:
all: foo
foo:
test -s /opt/local/bin/gsort || echo "GNU sort does not exist! Exiting..." && exit
Ejecutar make
ejecuta el objetivo all
, que ejecuta foo
.
La expectativa es que si la test -s
condicional falla, entonces se ejecutan las sentencias echo/exit
.
Sin embargo, incluso si existe /usr/bin/gsort
, obtengo el resultado de la instrucción echo
pero el comando exit
no se ejecuta. Esto es lo contrario de lo que espero lograr.
¿Cuál es la forma correcta de hacer algo como lo anterior?
Me doy cuenta de que esto es un poco viejo en este momento, pero no es necesario que uses una subshell para probar si existe un archivo en Make.
También depende de cómo quieras / esperes que se ejecute.
Usando la función de comodín, así:
all: foo
foo:
ifeq (,$(wildcard /opt/local/bin/gsort))
$(error GNU Sort does not exist!)
endif
Es una buena manera de hacerlo. Tenga en cuenta que la cláusula ifeq no tiene sangría porque se evalúa antes que el objetivo en sí.
Si desea que esto suceda sin condiciones para cada objetivo, simplemente puede moverlo fuera de un objetivo:
ifeq (,$(wildcard /opt/local/bin/gsort))
$(error GNU Sort does not exist!)
endif
Simplemente haz:
all: /opt/local/bin/gsort
y si falta /opt/local/bin/gsort
, aparecerá un mensaje de error "no hay regla para hacer que el objetivo` / opt / local / bin / gsort ''".
Pero si también quieres una buena explicación, hazlo:
/opt/local/bin/gsort:
echo "GNU sort does not exist! Exiting..."
false
En GNU / Make si el destino no está declarado .PHONEY
y no tiene ninguna dependencia, se invocará la regla si no existe un archivo que coincida con ese objetivo.
El código anterior activará el comando false
solo cuando /opt/local/bin/gsort
no existe, devolverá un valor distinto de 0 y la marca fallará.
Ya que está verificando si existe el archivo ejecutable gsort
, puede usar which
o el comando de shell para eso, por ejemplo:
all: foo
:
foo:
which gsort || exit 1
# or
type gsort || exit 1
No necesita un mensaje de error, ya que se imprimirá automáticamente:
/ bin / sh: línea 0: tipo:
gsort
: no encontrado
que es obvio
Alternativamente, use test
o [
(ver: help test
/ help [
para sintaxis), por ejemplo,
test -x /opt/local/bin/gsort || { echo Error msg; exit 1; }
que comprueba si el archivo dado existe y es ejecutable, de lo contrario muestra el mensaje y sale. Los paréntesis son importantes para anular la precedencia normal de los operadores (de izquierda a derecha) agrupando los comandos (consulte la sección Compound Commands
en man bash
para obtener más información).
Otra forma es usar los objetivos de la regla para verificar si el archivo existe y agregar como dependencia a all
, por ejemplo,
all: /opt/local/bin/gsort
@echo Success.
/opt/local/bin/gsort:
@echo "GNU sort does not exist! Exiting..."
exit 1
Resultado:
$ make
GNU sort does not exist! Exiting...
exit 1
make: *** [/opt/local/bin/gsort] Error 1
solo exit
devuelve el estado del último comando ejecutado. En este caso, devuelve cero, lo que significa que todo está bien.
Esto es, porque ||
y &&
tienen la misma prioridad , y el shell interpreta el comando como si estuviera escrito
( test ... || echo ... ) && exit
Si desea señalar una falla, debe salir con un valor que no sea cero, por ejemplo, la exit 1
. Y si desea hacer eco y salir, simplemente ponga los comandos en secuencia separados por ;
all: foo
foo:
test -s /opt/local/bin/gsort || { echo "GNU sort does not exist! Exiting..."; exit 1; }