2009-12-12 4 views
7

Il mio progetto ha bisogno di directory temporanee che vengono creati durante la compilazione utilizzando mkdir -p simile a questo:makefile con la creazione di directory adatta a parallelo (j) costruire

all: dirtree $(OBJFILES) 

dirtree: 
    @mkdir -p $(BUILD)/temp_directory 

Ma questo approccio non può essere utilizzato con il -j switch, perché il primo OBJFILES viene compilato prima che venga eseguito l'obiettivo mkdir.

Esiste un modo standard per farlo?

risposta

14

Il problema con il vostro makefile è che la creazione dei file oggetto non dipende creazione del relativo directory (solo un falso obiettivo "tutto" fa). Questo tipo di dipendenza è necessaria per l'opzione -j, e anche senza di essa il tuo makefile funziona solo per caso. Ci sono due (giusti) modi per imporre la dipendenza in questione.

directory come obiettivi separati

si è creato il target per la creazione di directory; quello di sinistra è appena messo come un prerequisito per opporsi regola del file:

$(BUILD)/temp_directory/%.o: %.c | dirtree 
     $(CC) $^ -o [email protected] 

Il simbolo pipe | significa che dirtree è un "order only prerequisite". Viene utilizzato quando "dirtree" è un prerequisito, ma le modifiche apportate al dirtree non invalidano i file oggetto e non influiscono sul risultato del comando di compilazione.

L'utilizzo del prerequisito "solo per ordine" è importante qui. Il fatto è che il target dirtree verrà rifatto a ogni invocazione Make. Ciò farebbe sì che anche tutto ciò che dipende da esso venga rifatto, quindi ricostruirà tutti i file oggetto ogni volta.

creare directory in comandi di shell

Un altro modo è quello di garantire che la directory viene creata immediatamente prima di richiamare la compilazione

$(BUILD)/temp_directory/%.o: %.c 
     @mkdir -p $(@D) 
     $(CC) $^ -o [email protected] 

nota l'utilizzo di $(@D). Questo è espanso come "la directory per il file di destinazione". Quindi può essere usato uniformemente in molti posti e anche con l'aiuto di una variabile.

[email protected] -p $(@D) 
$(BUILD)/temp_directory/%.o: %.c 
     $(Mkdir) 
     $(CC) $^ -o [email protected] 
$(INSTALL_DIR)/%: src_dir/% 
     $(Mkdir) 
     cp -p $^ [email protected] 

Entrambi i modi garantiscono che la directory si crea prima che i comandi di compilazione vengono richiamati.In entrambi i casi è necessario scrivere del testo (| dirtree o $(Mkdir)) per ogni regola che ne ha bisogno. Entrambi i modi sono compatibili con -j, ma la seconda soluzione richiede che mkdir -p sia thread-safe (poiché due comandi di questo tipo potrebbero tentare di creare la stessa directory e uno di essi non funzionerebbe).

Mentre la maggior parte dei sistemi la implementano in modo tale che mkdir -p è più o meno thread safe, su alcuni sistemi (as in some Solaris systems, for example), sono meno thread-safe rispetto agli altri. Tuttavia, anche in GNU, la toolchain mkdir -p potrebbe non riuscire se invocano contemporaneamente la stessa chiamata alla libreria mkdir(2).

Se si desidera essere molto sicuro, si può lavorare anche in questo. Quale potrebbe essere il problema? Che due script mkdir -p provano a creare la stessa directory e si scontrano da qualche parte all'interno della libreria C. Quindi, uno di questi mkdir -s avrà esito positivo e l'altro avrà esito negativo. Tuttavia, se il mkdir richiamato ha avuto esito negativo, potrebbe trattarsi di errore relativo al thread non correlato alla sicurezza solo se la directory è stata creata da un numero simultaneo mkdir. Quindi basterebbe controllare solo che la directory di destinazione viene creato dopo mkdir invocazione:

[email protected] -p $(@D) || test -d $(@D) 

(Questa soluzione ha anche un problema con modalità: mkdir potrebbe non riuscire quando esiste directory, ma non è conforme alle umask, quindi potresti voler controllare anche quello, ma è troppo suppongo.)

+0

Grazie e anche a ndim. – danatel

+4

'mkdir -p' non è' -j' compatibile. Due processi che eseguono la gara 'mkdir -p/a/b/c' e uno fallisce con EEXIST. Non ci sono mitiche serrature _ interne del filesystem_. –

+0

@Maxim, grazie per il tuo commento. Ecco un'altra versione ancora più sicura dei thread. Puoi trovare qualche difetto anche in esso? –

2

È possibile avere le regole per la creazione dei file oggetto chiamare mkdir -p come prima azione.

4

Non sono sicuro di comprendere appieno la tua domanda. Tuttavia, posso dire questo: se la tua build si rompe quando aggiungi il parallelismo, allora è un'indicazione che non hai definito correttamente le dipendenze. Chiediti: "Le directory devono esistere prima che i file oggetto vengano generati?" Se la risposta è "sì", le directory devono essere elencate come prerequisiti dei file oggetto. In altre parole:

${OBJFILES}: dirtree 

E sì, che è più o meno il modo standard di fare questo :)

+0

Questo non funziona per me. Un oggetto ha due prerequisiti: file dirt e .c. Make può iniziare con la creazione del file .c prima (l'ordine non è definito). Quindi ho dovuto aggiungere la dipendenza da dirtree alla regola .obj da .c. La nuova build funziona bene ma quando cambio un solo file .c vengono ricostruiti tutti i file .c. – danatel

+0

Aspetta, stai dicendo che make sta * generando * i file .c e che dopo che sono stati creati, i file .o sono compilati? –

+0

Scusate se vi confondete, l'inglese è tutt'altro che perfetto. Volevo dire che make * process * .c (input .c output .o). – danatel

Problemi correlati