2009-06-10 22 views
8

Trovo che sto scrivendo un sacco di Makefile che potrebbero essere ripuliti con l'uso di n. - liste di tuple. Ma non riesco a trovare alcun modo per farlo correttamente (e in modo pulito). Finora sono stato in grado di inventare solo $ (shell ...) e tr, sed, o comunque standard non Makefile.Iterare gli elenchi nei Makefile?

Per esempio, mi piacerebbe fare questo:

XYZs = \ 
    dog.c pull_tail bark \ 
    duck.c chase  quack \ 
    cow.c tip  moo 

all: 
    @- $(foreach X Y Z,$(XYZs), \ 
     $(CC) $X -o bully/$Y ; \ 
     ln bully/$Y sounds/$Z ; \ 
    ) 

C'è un buon modo per iterare n liste -tuple in Makefiles? Grazie!

risposta

10

I makefile sono essenzialmente di natura dichiarativa, quindi non credo che si provveda a fornire ciò che si desidera. Tuttavia, sembra che tu voglia associare alcuni valori stringa con target specifici, quindi forse la caratteristica Target specific variable values di GNU sarà di interesse. Questo è un estratto dal manuale:

C'è un'altra caratteristica speciale di variabili specifiche bersaglio: quando si definisce una variabile specifica-bersaglio, che il valore variabile è anche in vigore per tutte le dipendenze di questo target (a meno che tali dipendenze non lo sostituiscano con con il proprio valore variabile specifico di destinazione ). Così, per esempio, una dichiarazione come questo:

prog : CFLAGS = -g

prog : prog.o foo.o bar.o

imposterà CFLAGS--g nel script di comandi per prog, ma sarà anche impostare CFLAGS--g nel comando script che creano prog.o, foo.o, e bar.o e qualsiasi script di comando che creano le loro dipendenze.

Se non lo hai già letto, il manuale di GNU rende il manuale è dannatamente buono.

Edit: di fare quello che hai chiesto nel tuo commento:

dog: ANIMAL=dog.c BULLY=pull_tail SOUND=bark 

uso:

dog: ANIMAL=dog.c 
dog: BULLY=pull_tail 
dog: SOUND=bark 
+0

Cool, e potrebbe essere a metà strada lì! C'è sintassi per fare questo? cane: ANIMALE = dog.c BULLY = pull_tail SOUND = corteccia – Dylan

+0

+1, molto bello. –

+2

Il problema non è che make è dichiarativo, è che non fornisce una sintassi dichiarativa per questo schema frequentemente richiesto! – reinierpost

0

Lo stai facendo a ritroso.

Stai cercando di trattare come se fosse una sceneggiatura. Non è, invece è un insieme di regole su come creare X dato Y. Quindi il motore di make calcola cosa deve succedere per ottenere quel risultato.

Per l'esempio fornito, si dovrebbe davvero usare uno script per le fasi di generazione. Forse chiamandolo dal make, ma lascia che sia la roba del CC.

+4

Questa è una limitazione nel make che non ha motivo di essere lì in primo luogo, e può essere comunque lavorata con $ (foreach). – reinierpost

2

Nessuno di ciò che conosco, ma è perché stai cercando di forzare a far funzionare un linguaggio imperativo, quando non è quello che è.

In GNU Make probabilmente che ci si vuole fare qualcosa di simile:

pull_tail : SOUND=bark 
pull_tail : dog.c 
     $(CC) $< -o $^ 
     ln [email protected] $(SOUND) 

chase : SOUND=quack 
chase : duck.c 
     $(CC) $< -o $^ 
     ln [email protected] $(SOUND) 

... 

O meglio ancora, ridefinire la regola predefinita per i file .c per gestire il collegamento per voi, ma la strana struttura dei vostri nomi (i nomi dei programmi non hanno una relazione lessicale con i nomi delle fonti) lo rendono difficile.

Se ciò che si vuole essere in grado di ricostruire in fretta senza un sacco di editing mano, probabilmente avrete bisogno di scrivere uno script per rigenerare il makefile framgment dai dati e utilizzare la funzione include di GNU make ...

5

Vorrei controllare il manuale GNU Make su foreach. ecco alcuni snips casuali che ho usato in un progetto diverso ... l'esempio è incompleto, ma forse ti darà qualche idea? Potrei pulire questo più tardi se ho più tempo ...

REMAKE_PROGS:= dog duck cow 

XYZs = \ 
    dog.c pull_tail bark \ 
    duck.c chase  quack \ 
    cow.c tip  moo 

$(foreach src, $(XYZs), $(eval $MAKE $(src)) 

$(REMAKE_PROGS): 
     @echo "\n# === [email protected] linking\n" 
     $(call compile,[email protected],$([email protected]),$(CXX),$(MPICXX),$(LDFLAGS) $(LIBS) $(SYSLIBS) $(OTHER_LIB) $(EXTRA_LD_FLAGS)) 
     @echo "\n# --- [email protected] compiled\n" 

define compile 
    @mkdir -p $(dir $(1)) 
    $(if ${ANNOUNCE},@echo "\n# +++ ${MAKECMDGOALS} compiling\n" $(eval ANNOUNCE=)) 
    $(call compiler,$(1),NOMPI,$(3),$(4)) 
    $(eval MY_FLAGS=$(FLAGS_$(1)) $(5)) 
    $(if $(filter %xlf %xlf90,$(COMPILER_$(1))),$(eval MY_FLAGS:=$(MY_FLAGS:-D%=-WF,-D%))) 
    $(strip $(COMPILER_$(1)) $(2) $(MY_FLAGS) -o $(1)) 
endef 
+0

Non sto usando foreach-call-make, ma foreach-eval-call, che è altrettanto brutto. Vedi http://www.gnu.org/software/automake/manual/make/Eval-Function.html#Eval-Function – reinierpost

0

È possibile utilizzare le regole predefinite per una serie di file con la stessa estensione in per la compilazione ogni file c a un o. Ovviamente non sei limitato ad alcuna estensione di file speciale. Per la compilazione di una serie di .c file che si possa fare in questo modo:

OBJS = foo.o bar.o baz.o 
OUT = myprog 

all: $(OBJS) 
     $(SILENT) echo "LD [email protected]" 
     $(SILENT) $(CPP) -o $(OUT) $^ $(LDFLAGS) 

%.o: %.c 
     $(SILENT) echo "CC $<" 
     $(SILENT) $(CC) $(CCOPTS) -o [email protected] -c $< 
+0

Il problema inizia quando è necessario utilizzare uno "il valore corrente $ (OBJ)" all'interno del regola del modello. GNU make non fornisce la sintassi dichiarativa per questo, e $ (foreach) è una brutta soluzione (ma perfettamente funzionale). – reinierpost

6

Grazie per i suggerimenti - dopo un po 'di hacking Penso che questo sia più quello che speravo:

XYZs = \ 
    dog.c:pull_tail:bark \ 
    duck.c:chase:quack \ 
    cow.c:tip:moo 

all: 
    @- $(foreach XYZ,$(XYZs), \ 
     $(eval X = $(word 1,$(subst :, ,$(XYZ)))) \ 
     $(eval Y = $(word 2,$(subst :, ,$(XYZ)))) \ 
     $(eval Z = $(word 3,$(subst :, ,$(XYZ)))) \ 
     \ 
     $(CC) $X -o bully/$Y ; \ 
     ln bully/$Y sounds/$Z ; \ 
    ) 

Può chiunque fare meglio?

Problemi correlati