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.)
Grazie e anche a ndim. – danatel
'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_. –
@Maxim, grazie per il tuo commento. Ecco un'altra versione ancora più sicura dei thread. Puoi trovare qualche difetto anche in esso? –