Перебирать списки в Makefiles? - PullRequest
11 голосов
/ 11 июня 2009

Я нахожу, что пишу много Makefile-ов, которые можно очистить с помощью списков n -tuple. Но я не могу найти способ сделать это правильно (и чисто). До сих пор я только смог придумать, используя $ (shell ...) и tr , sed или другие не-Makefile стандарты.

Например, я хотел бы сделать это:

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

Есть ли хороший способ для итерации списков кортежей n в Makefiles? Спасибо!

Ответы [ 6 ]

12 голосов
/ 11 июня 2009

Makefiles по сути своей декларативны, поэтому я не думаю, что make сам по себе обеспечивает то, что вы хотите. Тем не менее, вы, похоже, хотите связать некоторые строковые значения с конкретными целями, поэтому, возможно, будет интересна особенность Target специфических переменных GNU make. Вот выдержка из руководства:

Есть еще одна особенность целевые переменные: когда вы определить целевую переменную, это значение переменной также действует для всех зависимостей этой цели (если эти зависимости не перекрывают его с их собственной целевой значение переменной). Так, например, утверждение как это:

prog : CFLAGS = -g

prog : prog.o foo.o bar.o

установит CFLAGS в -g в команде скрипт для prog, но он также будет установите CFLAGS в -g в команде скрипты, которые создают prog.o, foo.o, и bar.o, и любые командные сценарии которые создают свои зависимости.

Если вы еще не прочитали его, руководство по сборке GNU чертовски хорошо.

Редактировать: Чтобы сделать то, о чем вы спрашивали в своем комментарии:

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

использование:

dog: ANIMAL=dog.c 
dog: BULLY=pull_tail 
dog: SOUND=bark
8 голосов
/ 11 июня 2009

Я бы проверил руководство по GNU Make на foreach . Вот несколько случайных фрагментов, которые я использовал в другом проекте ... пример неполный, но, может быть, он даст вам некоторые идеи? Я могу почистить это позже, если у меня будет больше времени ...

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# === $@ linking\n"
        $(call compile,$@,$(OBJS_$@),$(CXX),$(MPICXX),$(LDFLAGS) $(LIBS) $(SYSLIBS) $(OTHER_LIB) $(EXTRA_LD_FLAGS))
        @echo "\n# --- $@ 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
7 голосов
/ 11 июня 2009

Спасибо за подсказки - после некоторого взлома я думаю, что это больше, чем я надеялся:

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

Кто-нибудь может сделать лучше?

2 голосов
/ 11 июня 2009

Ничего из того, что я знаю, но это потому, что вы пытаетесь заставить заставить работать и императивный язык, когда это не то, чем он является.

В GNU make вы, вероятно, захотите сделать что-то вроде:

pull_tail : SOUND=bark
pull_tail : dog.c 
        $(CC) $< -o $^
        ln $@ $(SOUND)

chase : SOUND=quack
chase : duck.c 
        $(CC) $< -o $^
        ln $@ $(SOUND)

...

Или, что еще лучше, переопределите правило по умолчанию для файлов .c, чтобы обрабатывать ссылки для вас, но странная структура ваших имен (имена программ не имеют лексической связи с именами источников) усложняет задачу.

Если вы хотите, чтобы это можно было быстро перестроить без большого количества ручного редактирования, вы, вероятно, захотите написать скрипт для регенерации фрагмента make-файла из данных и использовать функцию include GNU make ...

0 голосов
/ 11 июня 2009

Вы можете использовать правила по умолчанию для набора файлов с тем же расширением, что и для компиляции каждого c файла в o. Конечно, вы не ограничены никакими специальными расширениями файлов. Для компиляции набора .c файлов вы можете сделать это так:

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

all: $(OBJS)
        $(SILENT) echo "LD $@"
        $(SILENT) $(CPP) -o $(OUT) $^ $(LDFLAGS)

%.o: %.c
        $(SILENT) echo "CC $<"
        $(SILENT) $(CC) $(CCOPTS) -o $@ -c $<
0 голосов
/ 11 июня 2009

Вы делаете это задом наперед.

Вы пытаетесь относиться к make как к сценарию. Это не так, а свод правил о том, как создать X с учетом Y. Тогда механизм make выясняет, что должно произойти, чтобы получить этот результат.

В приведенном примере вы действительно должны использовать скрипт для шагов генерации. Возможно, это вызывается из make, но пусть make обрабатывает CC.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...