我的应用程序主目录中有一个名为“lib”的文件夹,其中包含任意数量的子文件夹,每个子文件夹都有自己的Makefile。
我希望在主目录中有一个单独的Makefile,它调用每个子目录的Makefile。如果我手动列出子目录,我知道这是可能的,但我希望自动完成。
我考虑了以下的方法,但显然它不起作用。注意,我还有清理、测试等目标,因此%可能根本不是一个好主意。
LIBS=lib/*
all: $(LIBS)
%:
(cd $@; $(MAKE))
非常感谢您的帮助!
我的应用程序主目录中有一个名为“lib”的文件夹,其中包含任意数量的子文件夹,每个子文件夹都有自己的Makefile。
我希望在主目录中有一个单独的Makefile,它调用每个子目录的Makefile。如果我手动列出子目录,我知道这是可能的,但我希望自动完成。
我考虑了以下的方法,但显然它不起作用。注意,我还有清理、测试等目标,因此%可能根本不是一个好主意。
LIBS=lib/*
all: $(LIBS)
%:
(cd $@; $(MAKE))
非常感谢您的帮助!
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
还有一种通过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
然后,为了执行规则'all'
,'make'会尝试将每个前提与现有目标进行匹配。在这种情况下,目标是'make-rule/%:'
,它使用'$*'
提取在'make-rule/'
之后的字符串,并将其用作配方的参数。例如,第一个前提将被匹配和扩展如下:
make-rule/lib/folder1:
cd lib/folder1 && $(MAKE)
all: DIRS_CMD
应该改为 all: $DIRS_CMD
,因为当前的迭代没有正确扩展。我得到了类似于 make: *** No rule to make target 'DIRS_CMD', needed by 'all'. Stop.
的东西。 - jnt30# 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))))
$(clean_LIBS)
定义为虚拟目标呢?例如.PHONY: $(LIBS) $(clean_LIBS)
,这样的话我认为你就不需要使用force
了。 - dma_k