73

我有一个目录 ( root_dir),其中包含许多子目录 ( subdir1, subdir2, ...)。

我想make在每个目录中运行root_dir,使用放置在其中的 Makefile。(显然假设每个人subdir...都有自己的Makefile)。

所以基本上有两个问题:

  1. 如何(自动)获取 Makefile 中的目录列表?
  2. 如何为makemake文件中的每个目录运行?

据我所知,为了make在特定目录中运行,我需要执行以下操作:

$(MAKE) -C subdir
4

8 回答 8

122

在单个配方的 for 循环中进行子制作存在各种问题。做多个子目录的最好方法是这样的:

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)
于 2013-07-24T21:27:15.907 回答
10

试试这个 :

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 代码)。您可以使用相同的方法在代码 Makefile 中调用其他目标。

例如:

clean:
   $(MAKE) -C $(CODE_DIR) clean

来源

于 2013-07-24T12:56:53.243 回答
7

这是MadScientist 答案的另一种方法。.PHONY是 GNU 特定的功能,可用于强制make递归到每个子目录。但是,一些非 GNU 版本make不支持.PHONY,因此替代方案是force target

4.7 没有配方或先决条件的规则

如果一个规则没有先决条件或配方,并且该规则的目标是一个不存在的文件,那么 make 会认为该目标在其规则运行时已被更新。这意味着所有依赖于此目标的目标都将始终运行其配方。

一个例子将说明这一点:

clean: FORCE
        rm $(objects)
FORCE:

这里目标“FORCE”满足特殊条件,因此依赖于它的目标清理被迫运行其配方。“FORCE”这个名字没有什么特别之处,但这是一个常用的名字。

如您所见,以这种方式使用 'FORCE' 与使用 '.PHONY: clean' 的结果相同。

使用“.PHONY”更明确、更有效。但是,其他版本的 make 不支持 '.PHONY';因此'FORCE' 出现在许多makefile 中。请参阅虚假目标。

以下是递归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:

这是另一个顶级虚假目标的示例:allclean. 请注意,从命令行 via 传递的all和目标分别由每个子目录的和目标处理。clean$(MAKECMDGOALS)allclean

# 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:
于 2019-12-30T22:23:43.810 回答
4

您还可以在 Makefile 中定义一个函数(当然您也需要在每个子目录中添加一个附加的 makefile)。这是依赖于 shell 的,但可能很有用:

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)
于 2020-06-09T13:02:07.027 回答
2

由于我不知道 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)
于 2019-03-26T14:03:35.110 回答
2

在 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文件。

于 2019-12-21T22:16:16.957 回答
1

GNU make有一个名为prorab的库,它支持在子目录中包含独立的 makefile。

github上的一些信息:https ://github.com/cppfw/prorab/blob/master/wiki/HomePage.adoc

基本上,通过prorab调用子目录中的所有 makefile 看起来像这样:

include prorab.mk

$(eval $(prorab-build-subdirs))
于 2016-08-20T18:15:03.227 回答
0

参考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

这个目录的src/docs/通用的Makefile,都有一个对应的Makefile.

这是文档设置的示例:

# set the default goal.
.DEFAULT_GOAL := list_docs



list_docs:
    ls -l


clean:
    echo "docs: make clean"
    -rm "*.backup"

于 2022-01-14T19:16:10.123 回答