2012-06-18 15 views
5

Me gustaría usar $(error ...) para abortar mi proceso de fabricación si ciertas condiciones previas no se cumplen. El objetivo fails_to_work debe abortar cuando falla test -d /foobar.

BAD.mk

all: this_works fails_to_work 

this_works: 
     @echo echo works... 
     @test -d ~ || echo ~ is not a directory 
     @test -d /foobar || echo /foobar is not a directory 

fails_to_work: 
     @echo error does not work... 
     @test -d ~ || $(error ~ is not a directory) 
     @test -d /foobar || $(error /foobar is not a directory) 

$ make -f BAD.mk

echo works... 
/foobar is not a directory 
BAD.mk:9: *** ~ is not a directory. Stop. 

Como se puede ver, ni siquiera "error no funciona ..." se hace eco de la pantalla. La receta para fails_to_work falla antes de que comience. ¿Cómo puedo solucionar esto? Uno de mis casos de uso es @test -d $(MY_ENV_VAR), pero no creo que eso difiera de las rutas codificadas en el ejemplo.

ACTUALIZACIÓN (información de la versión)

$ --version hacen

GNU Make 3.81 
Copyright (C) 2006 Free Software Foundation, Inc. 
This is free software; see the source for copying conditions. 
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A 
PARTICULAR PURPOSE. 

This program built for x86_64-pc-linux-gnu 

Respuesta

5

Usted está tratando de conseguir las cosas cáscara en una receta para invocar condicionalmente cosas makefile, que no funciona como has encontrado

puedo pensar en dos opciones:

  1. basta con quitar el material $(error). Si test falla, entonces devolverá un estado de salida distinto de cero, y el proceso de Make finalizará en ese punto.

  2. Tome la prueba de la regla, y utilizan una condicionar (que a su vez invoca la funcionalidad de la cáscara), por ejemplo:

    ifeq ($(shell test -d /foobar; echo $$?),1) 
    $(error Not a directory) 
    endif 
    
+0

Gracias. Tu primera sugerencia funciona (la cual estoy adoptando así: 'if! Test -d/foobar; luego echo"/foobar no es un directorio "; exit 1; fi'), pero tu segundo no. Con un directorio válido, el error aún se golpea. –

0

¿Por qué no sólo tiene que utilizar exit 1 comando shell en vez de $(error ...)? ¿Hay alguna razón para usar este último?

try_this: 
    @test -d /foobar || { echo /foobar is not a directory; exit 1; } 

or_this: 
    @if [ ! -d /foobar ]; then echo /foobar is not a directory; exit 1; fi 

Ambos abortará el proceso make menos que se especifique -k flag.

-k --keep-going

Continuar tanto como sea posible después de un error. Si bien el objetivo que falló y los que dependen de él no pueden rehacerse, los demás requisitos previos de estos objetivos se pueden procesar de todos modos.

+0

Estaba filmando para windows cmd shell/sh portabilidad bajo la creencia errónea de que 'test -d' estaba disponible en ambos. Sin embargo, todavía estoy interesado en la forma correcta de invocar condicionalmente $ (error ...). –

5

Los comandos de shell para una receta de fabricación se almacenan de manera efectiva como una única variable expandida recursivamente. En el momento en que decide ejecutar la receta, expande la variable y luego ejecuta cada línea en su propia invocación de shell. Cualquier$(error ...) que se expanda hará abortar incluso antes de invocando el primer comando.

Tenga en cuenta que la rama no tomada de $(if ...) o $(or ...) & c. no será expandidoDe este modo, se podría hacer

.PHONY: rule-with-assert 
rule-with-assert: 
    $(if $(realpath ${should-be-file}/),$(error Assertion failure: ${should-be-file} is a folder!)) 
    ⋮ 

Tenga en cuenta que se arrastra en el /realpath.

Por supuesto, las macros ayudan a arreglar esto mucho.

assert-is-file = $(if $(realpath $1/),$(error Assertion failure: [$1] is a folder!)) 

.PHONY: rule-with-assert 
rule-with-assert: 
    $(call assert-is-file,${should-be-file}) 
    ⋮ 

Vale la pena señalar una vez más que no importa donde se coloca la $(call assert-is-file,…) en la receta. Cualquier $(error) se generará cuando la receta se expanda, antes de se ejecutan los comandos de shell.

Cuestiones relacionadas