2016-06-21 99 views
6

L'ultima versione di make ha un'opzione --output-sync che può fare la STDOUT di ciascun target atomica in modo che le dichiarazioni provenienti da più obiettivi non sono intercalati quando si utilizza make --jobs=NGNU make 3,81 - come fare '--output-sync = target'

Sfortunatamente, devo usare make v 3.81 perché è quello che viene fornito con il nostro SDK.

Per determinare se ho bisogno --output-sync, ho aggiunto un po 'di dichiarazioni da guardia' in giro i miei obiettivi

all: $(patsubst %.cpp, %.o, $(wildcard *.cpp)) 


%.o: %.cpp 
    @echo BEFORE 
    @echo MAKEFLAGS=$(MAKEFLAGS) 
    qcc.exe $(CC_FLAGS) [email protected] $< 
    @echo AFTER 

L'uscita è stata molto interleaved.

AFTER 
BEFOREAFTER 
AFTER 
AFTER 

Esiste un modo per emulare la funzionalità --output-sync?

Comprendo che la velocità di costruzione può essere compromessa se, ad esempio, esiste un modo per bloccare la pre-ricetta del mutex STDOUT e rilasciarla dopo la ricetta.

Sto bene modificando ognuno dei nostri obiettivi se è quello che serve.

+1

Non utilizzare l'opzione '-j'? Questo eviterà l'interleaving, ed è banale da fare senza modificare il makefile, ed è approssimativamente equivalente a qualsiasi cosa tu abbia intenzione di fare, solo più facile. La funzione è solo in GNU Make 4.2? GNU Make 4.2.1 risolve il problema riscontrato con 4.2? –

+0

@JonathanLeffler Devo usare '-j' per ottenere build parallele. Aggiornerò il post riguardante la versione 'make'. – Adrian

risposta

0

Si potrebbe registrare tutte le uscite di una ricetta in un file temporaneo e cat-toglierlo alla fine:

%.o: %.cpp 
    @d=$$(mktemp) && \ 
    echo BEFORE >> $$d 2>&1 && \ 
    echo MAKEFLAGS=$(MAKEFLAGS) >> $$d 2>&1 && \ 
    qcc.exe $(CC_FLAGS) [email protected] $< >> $$d 2>&1 && \ 
    echo AFTER >> $$d 2>&1 && \ 
    cat $$d && \ 
    rm $$d 

Questo non prevenire completamente interleaving perché diversi cat comandi possono essere eseguiti in parallelo se avete diverse CPU, ma dovrebbe ridurre significativamente la probabilità. Se vuoi davvero evitare l'interleaving, dovrai aggiungere un spin-lock attorno ai comandi cat. Sotto un sistema operativo GNU/Linux si potrebbe avere uno sguardo a flock, per esempio:

%.o: %.cpp 
    @d=$$(mktemp) && \ 
    echo BEFORE >> $$d 2>&1 && \ 
    echo MAKEFLAGS=$(MAKEFLAGS) >> $$d 2>&1 && \ 
    qcc.exe $(CC_FLAGS) [email protected] $< >> $$d 2>&1 && \ 
    echo AFTER >> $$d 2>&1 && \ 
    flock /tmp/my-lock-file cat $$d && \ 
    rm $$d 

Spiegazioni:

  • ho trasformato la vostra ricetta in un unico guscio di invocazione (ogni riga in una ricetta make viene eseguito in una shell diversa) in modo tale che la variabile di shell d sia disponibile in tutti i comandi nell'elenco.
  • I comandi sono concatenati usando l'operatore &&: se uno fallisce, l'intero elenco fallisce con lo stesso stato di uscita e make lo dirà.
  • Invece di mettere tutti i comandi sulla stessa riga, che diventa rapidamente illeggibile, ho aggiunto \ prima della fine delle righe ma l'ultima. Più leggibile ma ancora interpretato come una singola riga di make.
  • Il primo comando nell'elenco (mktemp) crea atomicamente un file temporaneo univoco. Utilizzare qualsiasi equivalente disponibile nel proprio ambiente. Si noti il ​​doppio $ in d=$$(mktemp). È necessario passare la prima espansione di make e diventare d=$(mktemp) quando si passa alla shell. Lo stesso quando si fa riferimento all'espansione della shell della variabile di shell d: $$d viene prima espanso da marca come $d prima di essere passato alla shell.
  • I reindirizzamenti delle uscite dei comandi (>> $d 2>&1 dopo la prima espansione di make) reindirizzano le uscite standard al file temporaneo in modalità append (>> $d) e rendono al descrittore di errore standard una copia del descrittore di output standard (2>&1) con l'effetto di aggiungere anche gli errori standard allo stesso file temporaneo.
+0

Per evitare di offuscare le ricette, creerei uno script che si occupi di serializzare l'output e utilizzi lo script in un makefile come ['SHELL'] (https://www.gnu.org/software/make/manual/ html_node/scelta-the-Shell.html). Anche in alcuni casi, potrebbe essere utile ['.ONESHELL'] (https://www.gnu.org/software/make/manual/html_node/One-Shell.html). – Kuchara

+0

Non posso credere che questa domanda sia così popolare dato che 'gnu make 3.81' è davvero vecchio! Sono così tanti sviluppatori che lo usano ancora? – Adrian

+1

@Adrian Sì, è nel sistema cluster che sto utilizzando e non posso fare nulla al riguardo. – mxmlnkn