Dal informazioni GNU manuale
Variabili e funzioni in tutte le parti di un makefile sono espansi quando lettura, tranne nelle ricette, i lati destri di definizioni di variabili utilizzando '=', e i corpi delle definizioni delle variabili usando la direttiva 'define'.
La variabile specifica di destinazione si applica solo all'interno delle ricette. All'interno
$(OBJS): | $(OBJDIR)
e
$(OBJDIR):
si sta facendo la variabile globale.
Quindi, lavorando su ciò che accade quando si esegue make Debug32
, si vede il contenuto di OBJS
come prerequisito, che porta alla prima regola sopra. $(OBJDIR)
è già stato sostituito con il valore globale e questo corrisponde al nome-obiettivo nella seconda regola che è stata anche sostituita allo stesso modo.
Tuttavia, quando arriviamo alla ricetta:
echo mkdir $(OBJDIR) - [email protected]
$(OBJDIR)
non è stato ancora sostituito, quindi diventa il valore della variabile specifici target.
una versione funzionante
.SECONDEXPANSION:
all: Debug32
# Object directory set by target
Debug32: OBJDIR = objdir32
OBJDIR = wrongdirectory
Debug32: OBJS = $(addprefix $(OBJDIR)/,obj.o)
OBJS = wrongobjs
Debug32: $$(OBJS)
echo OBJS are $(OBJS)
echo OBJDIR is $(OBJDIR)
%/obj.o: | %
touch [email protected]
OBJDIRS = objdir32 wrongdirectory anotherdirectory
$(OBJDIRS):
# mkdir $(OBJDIR)
mkdir [email protected]
La principale novità sta usando $$
in questa linea:
Debug32: $$(OBJS)
Con un solo $
, ottengo il messaggio di errore
make: *** No rule to make target `wrongobjs', needed by `Debug32'. Stop.
Tuttavia, con la $$
, ottengo
echo OBJS are objdir32/obj.o
OBJS are objdir32/obj.o
echo OBJDIR is objdir32
OBJDIR is objdir32
L'uso di espansione secondaria ha permesso l'accesso alla variabile specifico bersaglio nelle premesse.
L'altra modifica è che ho reso OBJS
una variabile specifica della destinazione (perché è). Al fine di avere una regola per costruire OBJS
qualunque sia il suo valore, ho dovuto usare una regola modello:
%/obj.o: | %
per evitare di avere una riga separata per ogni file oggetto, si potrebbe fare la seguente invece:
OBJ_BASENAMES=obj.o obj2.o obj3.o
$(addprefix %/,$(OBJ_BASENAMES)): | %
touch [email protected] # Replace with the proper recipe
la riga contenente il addprefix
espande macro per
%/obj.o %/obj2.o %/obj3.o: | %
Poi esecuzione make anotherdirectory/obj2.o
crea una directory chiamata "anotherdirectory" abete st e crea un file chiamato "obj2.o" al suo interno.
Nota tutte le possibili directory devono essere elencate in OBJDIRS
. Non c'è modo di raccogliere tutti i valori specifici delle regole di OBJDIR, quindi elencarli è la scelta migliore. L'alternativa è una regola % :
per creare qualsiasi directory, che sia in grado di corrispondere e creare qualsiasi target, che potrebbe essere rischioso. (Se si abbandona l'utilizzo di variabili specifiche della destinazione, esiste un altro modo per ottenere un elenco di directory che potrebbero essere create: utilizzare variabili con nomi prevedibili come Debug32_OBJDIR
e generare un elenco dei relativi valori utilizzando le funzioni make.)
in alternativa, una regola generica che non richiede che elenca i file oggetto:
SOURCE=$(basename $(notdir [email protected])).cpp
DIR=$(patsubst %/,%,$(dir [email protected]))
%.o: $$(SOURCE) | $$(DIR)
touch [email protected] # Replace with proper recipe
non esiste una funzione di leggere una norma nel contesto di ogni bersaglio, sostituendo a variabili specifiche bersaglio e l'acquisizione di una nuova regola per ogni obiettivo. Le regole generiche non possono essere scritte in questo modo usando variabili specifiche del target.
Questo funziona, ma sembra che devo specificare due volte la directory degli oggetti e ciascun file .o due volte, inclusa una regola di pattern per file sorgente.Sto sbagliando tutto questo? Sembra troppo difficile creare un semplice makefile generico per due o più target. – Jeff
Ho aggiunto un modo per coprire tutti i file oggetto. Mi aspetto che sia possibile senza elencarli tutti (qualcosa come '% .o: $$ (basename%). Cpp | $$ (dir $$ @)') ma non ho ancora funzionato. –
Ho aggiunto una versione più facile da usare e note su dover elencare le directory. Il metodo di Mark Galeck per la creazione di directory sembra che potrebbe essere migliore, però. –