制作wildcard子目录

时间:2009-12-19 13:23:26

标签: makefile wildcard target subdirectory

我的应用程序主目录中有一个“lib”目录,其中包含任意数量的子目录,每个子目录都有自己的Makefile。

我想在主目录中有一个Makefile,它调用每个子目录的Makefile。我知道如果我手动列出子目录,这是可能的,但我想自动完成。

我在考虑以下内容,但显然不起作用。请注意,我也有干净,测试等目标,所以%可能根本不是一个好主意。

LIBS=lib/*

all: $(LIBS)

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

感谢任何帮助!

3 个答案:

答案 0 :(得分:26)

以下内容适用于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

答案 1 :(得分:2)

还有一种方法可以使用gmake命令列出子目录,而无需使用任何shell命令:

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

这将列出尾随'/'的所有子目录。要删除它,您可以使用替代模式:

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

然后实际创建在每个子目录中执行makefile的规则,你可以使用一个小技巧 - 一个不存在的目录中的虚假目标。我认为在这种情况下,一个例子将说明的不仅仅是任何解释:

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)

答案 2 :(得分:0)

如果要调用的目标不同于未知数量的子目录中的所有目标,该怎么办?

以下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))))

希望这会有所帮助。在处理paralelism时真的很有帮助:make -j12在一个树中清理所有的makefile都有这些目标...一如既往:玩make是危险的,不同的元级编程太靠近了, - )