我有一个目录(root_dir
),其中包含许多子目录(subdir1, subdir2, ...
)。
我想在make
中的每个目录中运行root_dir
,并使用放置在其中的Makefile。
(显然假设每个subdir...
都有自己的Makefile。)
所以基本上有两个问题:
我知道为了在特定目录中运行make,我应该注意以下事项:
$(MAKE) -C subdir
答案 0 :(得分:66)
在单个配方中的for循环中执行sub-make会有各种问题。执行多个子目录的最佳方法是这样的:
SUBDIRS := $(wildcard */.)
all: $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $@
.PHONY: all $(SUBDIRS)
(只是要指出这是GNU make具体的;你没有提到对你正在使用的make版本的任何限制。)
ETA 这是一个支持多个顶级目标的版本。
TOPTARGETS := all clean
SUBDIRS := $(wildcard */.)
$(TOPTARGETS): $(SUBDIRS)
$(SUBDIRS):
$(MAKE) -C $@ $(MAKECMDGOALS)
.PHONY: $(TOPTARGETS) $(SUBDIRS)
答案 1 :(得分:4)
试试这个:
SUBDIRS = foo bar baz
subdirs:
for dir in $(SUBDIRS); do \
$(MAKE) -C $$dir; \
done
这可能会对您有所帮助link
编辑:你也可以这样做:
最简单的方法是:
CODE_DIR = code
.PHONY: project_code
project_code:
$(MAKE) -C $(CODE_DIR)
.PHONY规则意味着project_code不是需要的文件 内置,-C标志表示目录中的更改(相当于 在调用make之前运行cd代码。您可以使用相同的方法 用于调用代码Makefile中的其他目标。
例如:
clean:
$(MAKE) -C $(CODE_DIR) clean
答案 2 :(得分:1)
GNU make有一个名为 prorab 的库,它支持在子目录中包含独立的makefile。
关于github的一些信息:https://github.com/igagis/prorab/blob/master/wiki/HomePage.md
基本上,使用 prorab 调用子目录中的所有makefile都是这样的:
include prorab.mk
$(eval $(prorab-build-subdirs))
答案 3 :(得分:1)
在MadScientist回答之后,只需要锦上添花……为了使子目录中的所有单个目标都可以从顶层使用(您需要定义SUBDIRS
变量才能使用以下代码段):
# 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
文件。
答案 4 :(得分:1)
这是MadScientist's answer的另一种方法。 .PHONY
是GNU特定的功能,可用于强制make
递归到每个子目录中。但是,make
的某些非GNU版本不支持.PHONY
,因此可以选择force target。
4.7没有配方或先决条件的规则
如果规则没有先决条件或配方,并且没有规则的目标 是一个不存在的文件,则使该目标成为 每当运行其规则时更新。这意味着所有目标 取决于这一点,总是可以运行他们的配方。
一个例子将说明这一点:
clean: FORCE rm $(objects) FORCE:
目标“ FORCE”满足特殊条件,因此 依赖于它的目标清除将被强制运行其配方。有 “ FORCE”这个名字没什么特别的,但这通常是一个名字 用这种方式。
如您所见,以这种方式使用“ FORCE”具有与使用相同的结果 ‘.PHONY:干净’。
使用“ .PHONY”更为明确和有效。但是,其他 make版本不支持“ .PHONY”;因此,“ FORCE”出现在许多 生成文件。参见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
。请注意,从命令行通过all
传递的clean
和$(MAKECMDGOALS)
目标分别由每个子目录的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:
答案 5 :(得分:1)
您还可以在Makefile中定义一个函数(当然,您当然也需要在每个子目录中另外一个makefile)。这是外壳相关的,但可能有用:
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)
答案 6 :(得分:0)
由于我不了解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)