2013-10-10 18 views
9

Ho il seguente makefile semplificato e sto provando a impostare percorsi diversi in base a target diversi. Sfortunatamente, non sto ottenendo i risultati che mi aspetto. Questo è con make versione 3.81.Perché questa variabile specifica del target makefile non si espande come previsto?

.SECONDEXPANSION: 
all: Debug32 

# Object directory set by target 
Debug32: OBJDIR = objdir32 
#OBJDIR = wrongdirectory 

# ObjDir is empty here. :(
OBJS = $(addprefix $(OBJDIR)/,DirUtil.o) 

$(OBJDIR)/%.o : %.cpp 
      echo Compile: [email protected] 

Debug32: $(OBJS) 

$(OBJS): | $(OBJDIR) 

$(OBJDIR): 
      echo mkdir $(OBJDIR) - [email protected] 

I risultati sono i seguenti con nessuna impostazione di OBJDIR:

echo Compile: /DirUtil.o 

Se io commento dalla riga "OBJDIR = wrongdirectory", vado a prendere i seguenti risultati, che sono fonte di confusione in quanto vedo entrambi i valori della variabile in cui penso che dovrei vedere una sola:

echo mkdir objdir32 - wrongdirectory - 
echo Compile: wrongdirectory/DirUtil.o 

sto assumendo che le variabili non vengono espanse quando penso che dovrebbero, ma non riesco a capire come modificare questo beh Avior.

risposta

11

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.

+0

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

+0

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. –

+0

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ò. –

3

un buon modo per gestire

%/obj.o: | % 
    touch [email protected] 

OBJDIRS = objdir32 wrongdirectory anotherdirectory 
$(OBJDIRS): 
    mkdir [email protected] 

è:

%/.: 
    mkdir -p [email protected] 

.SECONDEXPANSION: 

poi si può solo scrivere, per ogni bersaglio che possono avere bisogno di una directory

target: prerequisites | $$(@D)/. 
    normal recipe for target