我有一个目录(root_dir
),其中包含许多子目录(subdir1, subdir2, ...
)。
我希望在每个子目录中使用放置在其中的Makefile运行make
。
(显然假设每个subdir...
内部都有自己的Makefile)。
因此,基本上有两个问题:
- 如何自动获取Makefile中的目录列表?
- 如何为每个目录内的make文件运行
make
?
据我所知,要在特定目录中运行make
,需要执行以下操作:
$(MAKE) -C subdir
在单个配方中使用 for 循环执行子 make 存在诸多问题。最佳的多个子目录处理方法如下:
SUBDIRS := $(wildcard */.)
all: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $@
.PHONY: all $(SUBDIRS)
< p >(只是提醒一下,这是特定于GNU Make的;您没提到您使用的make版本有任何限制)。
< p >< em> ETA 这里是一个支持多个顶层目标的版本。TOPTARGETS := all clean
SUBDIRS := $(wildcard */.)
$(TOPTARGETS): $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $@ $(MAKECMDGOALS)
.PHONY: $(TOPTARGETS) $(SUBDIRS)
试试这个:
SUBDIRS = foo bar baz
subdirs:
for dir in $(SUBDIRS); do \
$(MAKE) -C $$dir; \
done
这可能对你有帮助:链接
编辑:你也可以这样做:
最简单的方法是:
CODE_DIR = code
.PHONY: project_code
project_code:
$(MAKE) -C $(CODE_DIR)
.PHONY规则的意思是project_code不是需要构建的文件,-C标志表示更改目录(等同于在调用make之前运行cd code)。您可以使用相同的方法调用代码Makefile中的其他目标。
例如:
clean:
$(MAKE) -C $(CODE_DIR) clean
.PHONY
是GNU特有的功能,可用于强制make
递归到每个子目录。然而,一些非GNU版本的make
不支持.PHONY
,因此一种替代方法是使用强制目标。
以下是一个最小化的示例,它将4.7 Rules without Recipes or Prerequisites
If a rule has no prerequisites or recipe, and the target of the rule is a nonexistent file, then make imagines this target to have been updated whenever its rule is run. This implies that all targets depending on this one will always have their recipe run.
An example will illustrate this:
clean: FORCE rm $(objects) FORCE:
Here the target ‘FORCE’ satisfies the special conditions, so the target clean that depends on it is forced to run its recipe. There is nothing special about the name ‘FORCE’, but that is one name commonly used this way.
As you can see, using ‘FORCE’ this way has the same results as using ‘.PHONY: clean’.
Using ‘.PHONY’ is more explicit and more efficient. However, other versions of make do not support ‘.PHONY’; thus ‘FORCE’ appears in many makefiles. See Phony Targets.
make
递归到每个子目录中,每个子目录中都包含一个Makefile
文件。如果您只运行make
,则仅处理第一个子目录(这是不确定的)。您还可以运行make subdir1 subdir2 ...
。# Register all subdirectories in the project's root directory.
SUBDIRS := $(wildcard */.)
# Recurse `make` into each subdirectory.
$(SUBDIRS): FORCE
$(MAKE) -C $@
# A target without prerequisites and a recipe, and there is no file named `FORCE`.
# `make` will always run this and any other target that depends on it.
FORCE:
以下是与顶级虚拟目标相关的另一个示例:all
和clean
。请注意,通过$(MAKECMDGOALS)
从命令行传递的all
和clean
目标分别由每个子目录的all
和clean
目标处理。
# Register all subdirectories in the project's root directory.
SUBDIRS := $(wildcard */.)
# Top-level phony targets.
all clean: $(SUBDIRS) FORCE
# Similar to:
# .PHONY: all clean
# all clean: $(SUBDIRS)
# GNU's .PHONY target is more efficient in that it explicitly declares non-files.
# Recurse `make` into each subdirectory
# Pass along targets specified at command-line (if any).
$(SUBDIRS): FORCE
$(MAKE) -C $@ $(MAKECMDGOALS)
# Force targets.
FORCE:
define FOREACH
for DIR in packages/*; do \
$(MAKE) -C $$DIR $(1); \
done
endef
.PHONY: build
build:
$(call FOREACH,build)
.PHONY: clean
clean:
$(call FOREACH,clean)
.PHONY: test
test:
$(call FOREACH,test)
在MadScientist的答案之后只是锦上添花,以使子目录中的所有单个目标从顶层可用(您需要定义SUBDIRS
变量才能使用以下代码片段 - 您可以使用MadScientist的答案):
# Make all the individual targets in the sub-directories available from the top
# level; as in, for instance, `make foo/my_program` or `make bar/clean`
$(foreach __dir__,$(SUBDIRS),$(__dir__)/%):
@$(MAKE) -C '$(@D)' '$(@F)'
make foo/my_program
或者
make bar/clean
my_target: my_subdirectory/my_prerequisite
'my_subdirectory/my_prerequisite' > 'my_target'
通过以上的例子,从顶层目录中运行 make my_target
命令将首先构建 my_subdirectory/my_prerequisite
程序,然后再构建 my_target
文件。
有一个名为prorab的库,可用于GNU make,支持在子目录中包含独立的makefile。
关于github上的一些信息: https://github.com/cppfw/prorab/blob/master/wiki/HomePage.adoc
基本上,使用prorab调用所有子目录中的makefile看起来像这样:
include prorab.mk
$(eval $(prorab-build-subdirs))
由于我不知道“MAKECMDGOALS”变量,并忽视了MadScientist具有多个顶级目标的自身实现,因此我编写了另一种实现。也许有人会觉得它有用。
SUBDIRS := $(wildcard */.)
define submake
for d in $(SUBDIRS); \
do \
$(MAKE) $(1) --directory=$$d; \
done
endef
all:
$(call submake,$@)
install:
$(call submake,$@)
.PHONY: all install $(SUBDIRS)
关于https://stackoverflow.com/posts/17845120/revisions的参考。
这是我从那篇文章中学到的内容。
顶层Makefile
# set the default goal.
# I want the default to really just dump contents of dirs
# as a stub. For instance, I don't want it to
# push code or
.DEFAULT_GOAL := deploy
TOPTARGETS := all clean
SUBDIRS := docs src
$(TOPTARGETS): $(SUBDIRS)
$(SUBDIRS):
echo "make arg is" $(MAKECMDGOALS)
$(MAKE) -C $@ $(MAKECMDGOALS)
SUBCLEAN = $(addsuffix .clean,$(SUBDIRS))
clean: $(SUBCLEAN)
$(SUBCLEAN): %.clean:
$(MAKE) -C $* clean
deploy:
echo do deploy stub
这个 Makefile
目录中的 src/
和 docs/
都有相应的 Makefile
。
这里是文档设置的示例:
# set the default goal.
.DEFAULT_GOAL := list_docs
list_docs:
ls -l
clean:
echo "docs: make clean"
-rm "*.backup"
我和其他答案有所不同,因为我不想定义每个可能的制作目标。
SUBDIRS := $(patsubst %/,%,$(wildcard */))
.PHONY: all $(MAKECMDGOALS) $(SUBDIRS)
$(MAKECMDGOALS) all: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $@ $(MAKECMDGOALS)
.PHONY
是用于那些你希望每次运行 makefile 时都构建的目标,无论它是否存在、是否过期。 - MadScientist