2009-06-10 15 views
8

Mi chiedo se c'è un modo per implementare trap in GNU make, simile a quello integrato in BASH?Come posso intercettare errori e interruzioni in GNU make?

Se l'utente preme CTRL-C o se lo stesso make non riesce (uscita non zero), mi piacerebbe chiamare un particolare target o macro.

+0

+1 per la domanda interessante, anche se quello che stai facendo sembra una cattiva idea. – finnw

risposta

2

No. La gestione del segnale di GNU make lascia già molto a desiderare. Dal suo gestore di segnale, chiama funzioni come printf che non possono essere chiamate da un gestore di segnale sicuro. Ho visto questo causare problemi, ad esempio le regole .DELETE_ON_ERROR non vengono sempre eseguite se stderr viene reindirizzato su stdout.

Ad esempio, su un CentOS 7.4 scatola:

  1. Creare la seguente Makefile:

    .DELETE_ON_ERROR: 
    
    foo: 
         touch [email protected] 
         sleep 10 
    
  2. aperto in vim ed eseguire :make,

  3. Mentre si dorme, hit Ctrl - C

Vim/effettuare stampe

Press ENTER or type command to continue 
touch foo 
sleep 10 
^C 
shell returned 130 

Interrupt: Press ENTER or type command to continue 

Effettuare le è stato inviato un segnale di interrupt, ma foo esiste ancora.

+0

Avete alcuni esempi in cui il '.DELETE_ON_ERROR' non funziona? È un bug nell'implementazione make? –

+0

@HakanBaba Dettagli aggiunti. – andrewdotn

1

No. Per quanto ne so non esiste tale funzionalità.

1

produce codici di ritorno. Per quanto posso ricordare ora, restituisce 0 per il successo, 2 per il fallimento (si prega di consultare la documentazione). Quindi, sarebbe sufficiente per te racchiudere make all'interno di uno script di shell, ad esempio?

+1

Posso farlo, ma cercando di evitarlo se possibile, è autonomo e sto * cercando * di mantenerlo in quel modo. – Cyrus

2

Make non lo supporta, ma utilizzando i trucchi BASH è possibile ottenere qualcosa di simile.

default: complete 

complete: do_mount 
     echo "Do something here..." 

do_mount: 
     mkdir -p "$(MOUNTPOINT)" 
     (while ps -p $$PPID >/dev/null ; do \ 
       sleep 1 ; \ 
     done ; \ 
     unmount "$(MOUNTPOINT)" \ 
     ) & 
     mount "$(MOUNTSOURCE)" "$(MOUNTPOINT)" -o bind 

Il "smontare" verrà eseguito dopo il completamento del "fare". Solitamente si tratta di una soluzione soddisfacente se si sta tentando di eseguire operazioni di pulizia che potrebbero verificarsi durante la compilazione, ma normalmente non vengono ripulite all'uscita "make".

5

A questo punto, GNU make non ha supporto nativo.

C'è una soluzione affidabile per quanto:

.PHONY: internal-target external-target 

external-target: 
    bash -c "trap 'trap - SIGINT SIGTERM ERR; <DO CLEANUP HERE>; exit 1' SIGINT SIGTERM ERR; $(MAKE) internal-target" 

internal-target: 
    echo "doing stuff here" 

Questa cattura interruzioni, cessazioni e gli eventuali codici di uscita diverso da zero.

Nota il $(MAKE) in modo che la riga di comando si sovrascriva e le opzioni vengono passate a submake.

Su trappola:

  • gestore di trap chiaro (con -)
  • fare la pulizia
  • uscita con diverso da zero stato di uscita, in modo da costruire strumenti di automazione segnalare la generazione non riuscita.

DELETE_ON_ERROR non funziona per le directory, quindi questa è la chiave per la pulizia dopo mktemp -d, ad esempio

Sostituire <DO CLEANUP HERE> con valida CMD.

+0

Oltre alla citazione nidificata nella tua eco, che ovviamente è illegale, questo non sembra funzionare, almeno per quello che voglio realizzare. Come si dovrebbe usarlo? Supponiamo che il mio makefile avesse un solo bersaglio con un sonno e un tocco, come l'esempio @andrewdotn (ignora .DELETE_ON_ERROR), come lo modificheresti per usare questa soluzione alternativa? – Davide

+0

Si prega di vedere le modifiche. echo "fare cose qui" sarebbe il sonno/tocco. DO CLEANUP QUI sarebbe qualcosa di simile, echo hai premuto ctrl-c – kevinf

3

Una versione semplificata di risposta di @ kevinf che sembra abbastanza buono per i casi di base:

run: 
    bash -c "trap 'docker-compose down' EXIT; docker-compose up --build" 

(Questo esempio è per un motivo: docker-compose up fa dire

Quando il comando uscite, tutte i contenitori sono fermi

ma non lo è rm come docker run --rm, quindi è ancora possibile vederli con docker ps -a.)

+0

Vedo ancora 'ricetta per target 'run' fallita ... make: *** [run] Interrupt' quando provo questo, e il make target non eseguire il comando 'docker-compose down'. (Ho il caso d'uso esatto descritto in questa risposta.) – ely

Problemi correlati