2010-08-27 12 views
12

Es difícil de creer, pero me parece que la expresión común de Makefile "> $ @" es incorrecta. En particular, un objetivo cuya regla tiene un comando que falla pero utiliza esta redirección fallará la primera vez, pero no las veces subsiguientes. Esto se debe a que, aunque el comando falla, la redirección "tiene éxito" en el sentido de crear un objetivo actualizado (aunque de longitud cero).

Me parece que lo correcto es redirigir a un temporal y, con éxito, renombrar este temporal al objetivo.

Aquí es ejemplo y Makefile:

bad-target: 
     command-that-will-fail > [email protected] 

good-target: 
     command-that-will-fail > [email protected] || (rm [email protected]; false) 
     mv [email protected] [email protected] 

clean: 
     rm -f bad-target good-target 

Y aquí es una secuencia de comandos que ilustran el problema y su solución:

$ make clean 
rm -f bad-target good-target 

$ make bad-target 
command-that-will-fail > bad-target 
/bin/sh: command-that-will-fail: not found 
make: *** [bad-target] Error 127 

$ make bad-target 
make: `bad-target' is up to date. 

$ make good-target 
command-that-will-fail > good-target.tmp || (rm good-target.tmp; false) 
/bin/sh: command-that-will-fail: not found 
make: *** [good-target] Error 1 

$ make good-target 
command-that-will-fail > good-target.tmp || (rm good-target.tmp; false) 
/bin/sh: command-that-will-fail: not found 
make: *** [good-target] Error 1 

Respuesta

0

Sí, esto es definitivamente algo a tener en cuenta.

Pero algunas veces está bien con la falla del comando y no quiere volver a intentarlo, porque el error solo se repetirá.

En ese caso, dejar un resultado vacío es correcto. Simplemente no hagas que el procesamiento posterior cuente que hay contenido significativo en ese archivo.

15

Si está utilizando GNU make, también puede agregar el .DELETE_ON_ERROR objetivo especial a su archivo MAKE. Esto hará que hacer para borrar el archivo de salida si se produce un error durante la ejecución de los comandos para ese archivo:

all: foo.o 

foo.o: 
     echo bogus! > [email protected] 
     exit 1 

.DELETE_ON_ERROR: 

He aquí un ejemplo de este archivo MAKE en acción:

$ gmake 
echo bogus! > foo.o 
exit 1 
gmake: *** [foo.o] Error 1 
gmake: *** Deleting file `foo.o' 

Esto es más fácil uso que su versión, ya que no necesita modificar todas las reglas en el archivo MAKE.

+0

¡Bien, gracias! .DELETE_ON_ERROR es útil. –

+1

¿Hay alguna manera de obtener el comportamiento DELETE_ON_ERROR solo para reglas específicas? – Will

1

Quizás esta es una solución obvia, pero muchos comandos comunes proporcionan una bandera -o o similar. Así que en lugar de redirección de la salida, se debe utilizar la regla:

target: target.dep 
    some_command target.dep -o [email protected] 

Si el comando falla, no se creará el archivo de salida. No he tenido muchas ocasiones para usar la redirección de salida en archivos make.

Cuestiones relacionadas