2009-06-10 14 views
8

Ich finde, ich schreibe viele Makefiles, die mit Hilfe von n-Tupel-Listen aufgeräumt werden konnten. Aber ich kann keinen Weg finden, dies richtig (und sauber) zu machen. Bisher konnte ich nur mit $ (shell ...) und tr, sed, oder andere nicht Makefile-Standards kommen.Iterieren über Listen in Makefiles?

Zum Beispiel, würde Ich mag, dies zu tun:

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 ; \ 
    ) 

Gibt es einen guten Weg, n tupel Listen in Makefiles wiederholen? Vielen Dank!

Antwort

10

Makefiles sind im Wesentlichen deklarativer Natur, also glaube ich nicht, dass sich selbst das liefert, was Sie wollen. Allerdings scheinen Sie einige String-Werte mit bestimmten Zielen assoziieren zu wollen, so dass vielleicht die Target specific variable values-Funktion von GNU make von Interesse sein wird. Dies ist ein Auszug aus dem Handbuch:

Es gibt eine weitere Besonderheit zielspezifische Variablen: Wenn Sie eine zielspezifische Variable definieren, dass Variablenwert ist auch in der Tat für alle Abhängigkeiten von Dieses Ziel (es sei denn, diese Abhängigkeiten überschreiben es mit ihrem eigenen zielspezifischen Variablenwert). So zum Beispiel eine Anweisung wie folgt:

prog : CFLAGS = -g

prog : prog.o foo.o bar.o

gesetzt CFLAGS--g im Befehl Skript für prog, aber es wird auch festgelegt CFLAGS--g im Kommando Skripte, die prog.o, foo.o, und bar.o erstellen, und alle Befehlsskripte , die ihre Abhängigkeiten erstellen.

Wenn Sie es nicht schon gelesen haben, ist das GNU-Handbuch ziemlich verdammt gut.

Edit: zu tun, was Sie in Ihrem Kommentar gefragt:

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

Verwendung:

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

Cool, und es könnte auf halbem Weg sein! Gibt es dafür eine Syntax? Hund: ANIMAL = Hund.c BULLY = pull_tail SOUND = Rinde – Dylan

+0

+1, sehr schön. –

+2

Das Problem ist nicht, dass make deklarativ ist, sondern dass es keine deklarative Syntax für dieses häufig benötigte Muster bietet! – reinierpost

0

Sie es rückwärts zu tun.

Sie versuchen zu behandeln, wie es ein Skript ist. Es ist nicht, stattdessen ist es eine Reihe von Regeln, wie man X mit Y erzeugt. Dann ermittelt die make-Engine, was passieren muss, um dieses Ergebnis zu erhalten.

Für das gegebene Beispiel sollten Sie wirklich ein Skript für die Generierungsschritte verwenden. Vielleicht von make aus, aber lass das CC-Zeug machen.

+4

Dies ist eine Einschränkung in Make, die keinen Grund hat, an erster Stelle zu sein, und kann sowieso mit $ (foreach) umgehen. – reinierpost

2

Keine, von denen ich weiß, aber das ist, weil Sie versuchen, machen zu zwingen, zu arbeiten und eine imperative Sprache, wenn das nicht ist, was es ist.

In GNU machen Sie wahrscheinlich so etwas wie tun wollen würde:

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) 

... 

Oder noch besser, neu definieren die Standardregel für .c-Dateien die Verknüpfung für Sie, aber die seltsame Struktur Ihrer Namen zu handhaben (Die Programmnamen haben keine lexikalische Beziehung zu den Quellennamen) macht das schwierig. machen

Wenn das, was Sie diese in der Lage sein wollen, ohne viel Hand Bearbeitung schnell wieder aufbauen, wollen Sie wahrscheinlich ein Skript zu schreiben, das Makefile framgment von Daten zu regenerieren und die include Merkmal der GNU verwenden ...

5

Ich würde die GNU Make Handbuch auf foreach überprüfen. Hier sind einige zufällige Schnitte, die ich in einem anderen Projekt verwendet habe ... das Beispiel ist unvollständig, aber vielleicht gibt es dir ein paar Ideen? Ich könnte dies später aufzuräumen, wenn ich mehr Zeit habe ...

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

Ich benutze nicht foreach-call-make, sondern foreach-eval-call, was genauso hässlich ist. Siehe http://www.gnu.org/software/automake/manual/make/Eval-Function.html#Eval-Function – reinierpost

0

Sie können Standardregeln für eine Reihe von Dateien mit dieser Endung verwenden, wie in für jede c-Datei in eine o kompilieren. Natürlich sind Sie nicht auf spezielle Dateierweiterungen beschränkt. Für eine Reihe von .c Dateien kompilieren können Sie es wie folgt tun:

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

Das Problem beginnt, wenn Sie einen "den aktuellen $ (OBJ) Wert" innerhalb der verwenden müssen Musterregel. GNU make bietet dafür keine deklarative Syntax, und $ (foreach) ist eine hässliche (aber perfekt funktionierende) Problemumgehung. – reinierpost

6

Danke für die Hinweise - nach einiger Hacking Ich denke, das mehr ist, was ich hatte gehofft, für:

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 ; \ 
    ) 

Kann jemand Machs besser?