2013-01-15 10 views
18

C'è un modo per uscire con una condizione di errore se un file non esiste? Attualmente sto facendo qualcosa di simile:Verificare se un file esiste nella destinazione makefile e chiudere se non presente

all: foo 

foo: 
    test -s /opt/local/bin/gsort || echo "GNU sort does not exist! Exiting..." && exit 

Esecuzione make corre il all bersaglio, che corre foo.

L'aspettativa è che se il condizionale test -s non riesce, vengono eseguite le istruzioni echo/exit.

Tuttavia, anche se /usr/bin/gsort esiste, ottengo il risultato della dichiarazione echo ma il comando exit non funziona. Questo è l'opposto di quello che spero di ottenere.

Qual è il modo corretto di fare qualcosa come sopra?

+0

Se provo questo sulla riga di comando, avendo il lato destro del '' || tra parentesi, per ottenere un guscio di sub, lo fa funzionare come previsto. Non ho idea se sia lo stesso in un makefile. Senza la parentesi, l'"uscita" verrà eseguita anche se il test è positivo. – HonkyTonk

risposta

15

exit restituisce da solo lo stato dell'ultimo comando eseguito. In questo caso, restituisce zero, il che significa che tutto è ok.

Questo è, perché || e && hanno equal precedence, e la shell interpreta il comando come se fosse scritto

(test ... || echo ...) && exit 

Se vuoi segnalare il fallimento è necessario uscire con un valore diverso da zero, per esempio exit 1. E se si vuole eco e uscita, basta mettere i comandi in sequenza separati da ;

all: foo 

foo: 
    test -s /opt/local/bin/gsort || { echo "GNU sort does not exist! Exiting..."; exit 1; } 
5

Ogni riga di comando nel make corre nel proprio sub-shell. Quindi, eseguendo exit, si esce da quella sub-shell, non dal makefile nel suo complesso. Per impostazione predefinita, l'esecuzione di make si interromperà se qualsiasi sub-shell restituisce uno stato di uscita non riuscito (per convenzione, 0 significa successo, quindi qualsiasi altra cosa interromperà l'esecuzione). Il metodo più semplice sarebbe solo di utilizzare lo stato di uscita del comando test:

all: foo 

foo: 
    test -s /opt/local/bin/gsort 

Stampa di un messaggio di diagnostica complica le cose un po 'perché i comandi come echo torneranno uno stato di uscita pari a 0, causando make pensare tutto va bene. Per ovviare a questo, è necessario eseguire un comando dopo che darà il sub-shell uno status diverso da zero uscita:

all: foo 

foo: 
    test -s /opt/local/bin/gsort || { echo "GNU sort does not exist! Exiting..."; exit 1; } 

o anche solo

all: foo 

foo: 
    test -s /opt/local/bin/gsort || { echo "GNU sort does not exist! Exiting..."; false; } 
24

Mi rendo conto che è un po ' vecchio a questo punto, ma non è necessario nemmeno usare una subshell per verificare se esiste un file in Make.

Dipende anche da come si desidera/si aspetta che funzioni.

Utilizzando la funzione di jolly, in questo modo:

all: foo 
foo: 
ifeq (,$(wildcard /opt/local/bin/gsort)) 
    $(error GNU Sort does not exist!) 
endif 

è un buon modo per farlo. Si noti qui che la clausola ifeq non è rientrata perché viene valutata prima del target stesso.

Se si vuole che questo accada incondizionatamente per ogni destinazione, si può semplicemente spostarlo al di fuori di un obiettivo:

ifeq (,$(wildcard /opt/local/bin/gsort)) 
$(error GNU Sort does not exist!) 
endif 
1

Semplicemente fare:

all: /opt/local/bin/gsort 

e se /opt/local/bin/gsort manca, sarà ottieni un messaggio di errore "no rule to make target/opt/local/bin/gsort" ".

Ma se volete anche qualche bella spiegazione con esso fare:

/opt/local/bin/gsort: 
    echo "GNU sort does not exist! Exiting..." 
    false 

In GNU/Verificare se l'obiettivo non è dichiarato .PHONEY e non ha dipendenze, la regola verrà invocata se un file la corrispondenza con quell'obiettivo non esiste.

Il codice sopra attiverà il comando false solo quando non esiste, restituirà un valore diverso da 0 e l'esecuzione non avrà esito positivo.

+0

C'è un modo per fare ciò in modo che continui a controllare ogni file mancante e poi restituisca falso? In questo modo, se a qualcuno mancano molti file, verranno visualizzati tutti, anziché uno alla volta. – thepiercingarrow

1

Dal momento che si sta controllando se esiste gsort file eseguibile, è possibile utilizzare which o type comando della shell per questo, ad esempio:

all: foo 
    : 

foo: 
    which gsort || exit 1 
    # or 
    type gsort || exit 1 

Non è necessario un messaggio di errore, dal momento che sarà automaticamente stampa :

/bin/sh: linea 0: tipo: gsort: non trovato

che è ovvio.


alternativa utilizzare test o [ (vedi: help test/help [ per la sintassi), ad esempio

test -x /opt/local/bin/gsort || { echo Error msg; exit 1; } 

che verifica se il file specificato esiste ed è eseguibile, altrimenti mostra il messaggio ed esce. Le parentesi sono importanti per ignorare la normale precedenza degli operatori (da sinistra a destra) raggruppando i comandi (vedere la sezione Compound Commands in man bash per ulteriori informazioni).


Un altro modo è quello di utilizzare gli obiettivi della regola per verificare se esiste il file e aggiungere come dipendenza all, per esempio

all: /opt/local/bin/gsort 
    @echo Success. 

/opt/local/bin/gsort: 
    @echo "GNU sort does not exist! Exiting..." 
    exit 1 

Risultato:

$ make 
GNU sort does not exist! Exiting... 
exit 1 
make: *** [/opt/local/bin/gsort] Error 1 
Problemi correlati