来源于 Makefile 的子目录

我有一个使用 Makefile 构建的 C + + 库。直到最近,所有源都在一个目录中,Makefile 执行类似的操作

SOURCES = $(wildcard *.cpp)

效果不错。

现在我已经添加了一些在子目录中的源代码,比如 subdir

SOURCES = $(wildcard *.cpp) $(wildcard subdir/*.cpp)

但我正在寻找一种避免手动指定 subdir的方法,即让 wildcard查看子目录,或以某种方式生成子目录列表,然后用几个 wildcard函数展开它。此时,使用非递归解决方案(即仅展开第一级)就可以了。

我没有找到任何东西-我最好的猜测是使用 find -type d来列出子目录,但它感觉像一个黑客。有没有什么内置的方法可以做到这一点?

97484 次浏览

通常的实践 是在每个子目录中放入带有源的 Makefile,然后

all: recursive
$(MAKE) -C componentX
# stuff for current dir

或者

all: recursive
cd componentX && $(MAKE)
# stuff for current dir


recursive: true

将每个 Makefile的设置放在根源目录中的 Makefile.inc中可能是明智的。recursive目标强制 make进入子目录。确保它不会在需要 recursive的目标中重新编译任何内容。

如果您不想使用递归 makefile,这可能会给您一些启发:

subdirs := $(wildcard */)
sources := $(wildcard $(addsuffix *.cpp,$(subdirs)))
objects := $(patsubst %.cpp,%.o,$(sources))


$(objects) : %.o : %.cpp

这个应该可以:

SOURCES = $(wildcard *.cpp) $(wildcard */*.cpp)

如果您改变主意,想要一个递归解决方案(即任何深度) ,这是可以做到的,但它涉及到一些更强大的 Make 函数。就是那种能让你做不该做的事的。

编辑:
Jack Kelly 指出,$(wildcard **/*.cpp)可以工作到任何深度,至少在某些平台上,使用 GNUMake 3.81。(我不知道他是怎么知道的。)

如果可以使用 find shell 命令,则可以定义一个函数来使用它。

recurfind = $(shell find $(1) -name '$(2)')
SRCS := $(call recurfind,subdir1,*.c) $(call recurfind,subdir2,*.cc) $(call recurfind,subdir2,*.cu) \
...

递归通配符可以完全在 Make 中完成,而不需要调用 shell 或 find 命令。只使用 Make 进行搜索意味着这个解决方案也可以在 Windows 上工作,而不仅仅是 * nix。

# Make does not offer a recursive wildcard function, so here's one:
rwildcard=$(wildcard $1$2) $(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2))


# How to recursively find all files with the same name in a given folder
ALL_INDEX_HTMLS := $(call rwildcard,foo/,index.html)


# How to recursively find all files that match a pattern
ALL_HTMLS := $(call rwildcard,foo/,*.html)

文件夹名称的尾部斜杠是必需的。与 Make 的内置通配符函数不同,这个 rWildcard 函数不支持多个通配符,但是多使用 foreach 可以直接添加这种支持。

你可以在 wildcard中使用几个规则:

SOURCES := $(wildcard *.cpp */*.cpp)

如果你需要更多的深度:

SOURCES := $(wildcard *.cpp */*.cpp */*/*.cpp */*/*/*.cpp)

遗憾的是,而且与我们有时读到的不同,globb (**)不受 makefile 的支持,将被解释为普通通配符(*)。

例如,**/*.cppdir/file.cpp匹配,但 file.cppdir/sub/file.cpp都不匹配。

如果你需要无限深度,使用 shell:

SOURCES := $(shell find . -name "*.cpp")