сделать подстановочные цели подкаталога - PullRequest
18 голосов
/ 19 декабря 2009

У меня есть каталог "lib" в главном каталоге моих приложений, который содержит произвольное количество подкаталогов, каждое из которых имеет свой собственный Makefile.

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

Я думал о чем-то вроде следующего, но это, очевидно, не работает. Обратите внимание, что у меня также есть чистые, тестовые и т. Д. Цели, поэтому%, вероятно, не очень хорошая идея.

LIBS=lib/*

all: $(LIBS)

%:
  (cd $@; $(MAKE))

Любая помощь приветствуется!

Ответы [ 3 ]

26 голосов
/ 19 декабря 2009

Следующее будет работать с GNU make:

LIBS=$(wildcard lib/*)
all: $(LIBS)
.PHONY: force
$(LIBS): force
  cd $@ && pwd

Если в lib может быть что-то иное, кроме каталогов, вы можете альтернативно использовать:

LIBS=$(shell find lib -type d)

Чтобы решить проблему с несколькими целями, вы можете создать специальные цели для каждого каталога, а затем удалить префикс для вспомогательной сборки:

LIBS=$(wildcard lib/*)
clean_LIBS=$(addprefix clean_,$(LIBS))
all: $(LIBS)
clean: $(clean_LIBS)
.PHONY: force
$(LIBS): force
  echo make -C $@
$(clean_LIBS): force
  echo make -C $(patsubst clean_%,%,$@) clean
2 голосов
/ 22 января 2013

Существует также способ перечисления подкаталогов только с командами gmake, без использования команд оболочки:

test:
  @echo $(filter %/, $(wildcard lib/*/))

В этом списке будут перечислены все подкаталоги с конечным символом '/'. Чтобы удалить его, вы можете использовать шаблон замены:

subdirs = $(filter %/, $(wildcard lib/*/))
test:
  @echo $(subdirs:%/=%)

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

FULL_DIRS =$(filter %/, $(wildcard lib/*/))
LIB_DIRS  =$(FULL_DIRS:%/=%)
DIRS_CMD  =$(foreach subdir, $(LIB_DIRS), make-rule/$(subdir))

make-rule/%:
  cd $* && $(MAKE)

all: DIRS_CMD

В основном, цель 'all' перечисляет все подкаталоги как предварительные условия. Например, если LIB_DIRS содержит lib/folder1 lib/folder2, то расширение будет выглядеть так:

all: make-rule/lib/folder1 make-rule/lib/folder2

Затем «make», чтобы выполнить правило 'all', пытается сопоставить каждую предпосылку с существующей целью. В этом случае целью является 'make-rule/%:', который использует '$*' для извлечения строки после 'make-rule/' и использует ее в качестве аргумента в рецепте. Например, первое условие должно быть сопоставлено и расширено следующим образом:

make-rule/lib/folder1:
  cd lib/folder1 && $(MAKE)
0 голосов
/ 30 октября 2015

Что делать, если вы хотите назвать другие цели, кроме всех, в неизвестном количестве подкаталогов?

В следующем файле Makefile используются макросы, поэтому создайте фиктивную цель переадресации для ряда подкаталогов, чтобы применить данную цель из командной строки к каждому из них:

# all direct directories of this dir. uses "-printf" to get rid of the "./"
DIRS=$(shell find . -maxdepth 1 -mindepth 1 -type d -not -name ".*" -printf '%P\n')
# "all" target is there by default, same logic as via the macro
all: $(DIRS)

$(DIRS):
    $(MAKE) -C $@
.PHONY: $(DIRS)

# if explcit targets where given: use them in the macro down below. each target will be delivered to each subdirectory contained in $(DIRS).
EXTRA_TARGETS=$(MAKECMDGOALS)

define RECURSIVE_MAKE_WITH_TARGET
# create new variable, with the name of the target as prefix. it holds all
# subdirectories with the target as suffix
$(1)_DIRS=$$(addprefix $(1)_,$$(DIRS))

# create new target with the variable holding all the subdirectories+suffix as
# prerequisite
$(1): $$($1_DIRS)

# use list to create target to fullfill prerequisite. the rule is to call
# recursive make into the subdir with the target
$$($(1)_DIRS):
      $$(MAKE) -C $$(patsubst $(1)_%,%,$$@) $(1)

# and make all targets .PHONY
.PHONY: $$($(1)_DIRS)
endef

# evaluate the macro for all given list of targets
$(foreach t,$(EXTRA_TARGETS),$(eval $(call RECURSIVE_MAKE_WITH_TARGET,$(t))))

Надеюсь, это поможет. Действительно полезно при работе с паралелизмом: make -j12 очищает все в дереве с помощью make-файлов, имеющих эти цели ... Как всегда: игра с make опасна, разные метауровни программирования слишком близко друг к другу, -)

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