我有一个使用Makefile构建的C ++库。直到最近,所有的源都在一个目录中,Makefile做了类似的事情
SOURCES = $(wildcard *.cpp)
工作得很好。
现在我添加了一些子目录中的一些来源,比如subdir
。我知道我可以做到这一点
SOURCES = $(wildcard *.cpp) $(wildcard subdir/*.cpp)
但我正在寻找一种方法来避免手动指定subdir
,即make wildcard
查看子目录,或以某种方式生成子目录列表并使用多个{{1}扩展它} 功能。此时,使用非递归解决方案(即仅扩展第一级)就可以了。
我没有找到任何东西 - 我最好的猜测是使用wildcard
列出子目录,但感觉就像是黑客。有没有内置的方法来做到这一点?
答案 0 :(得分:69)
这应该这样做:
SOURCES = $(wildcard *.cpp) $(wildcard */*.cpp)
如果你改变主意并想要一个递归解决方案(即任何深度),它可以完成,但它涉及一些更强大的Make函数。你知道,那些允许你做你真正不应该做的事情。
修改:
Jack Kelly指出$(wildcard **/*.cpp)
使用GNUMake 3.81可以在任何深度上工作,至少在某些平台上。 (他怎么想出来的,我不知道。)
答案 1 :(得分:19)
递归通配符可以完全在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)
文件夹名称中的尾部斜杠是必需的。这个rwildcard函数不像Make的内置通配符函数那样支持多个通配符,但是通过foreach的更多用法添加支持将是直截了当的。
答案 2 :(得分:15)
如果您不想使用递归makefile,这可能会给您一些想法:
subdirs := $(wildcard */)
sources := $(wildcard $(addsuffix *.cpp,$(subdirs)))
objects := $(patsubst %.cpp,%.o,$(sources))
$(objects) : %.o : %.cpp
答案 3 :(得分:9)
Common practice是在每个子目录中放置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
的目标中的任何内容。
答案 4 :(得分:7)
这是一份附注,并没有回答你的问题,但有一篇论文“Recursive Make Considered Harmful”。值得一读。
答案 5 :(得分:2)
如果你可以使用find
shell命令,你可以定义一个使用它的函数。
recurfind = $(shell find $(1) -name '$(2)')
SRCS := $(call recurfind,subdir1,*.c) $(call recurfind,subdir2,*.cc) $(call recurfind,subdir2,*.cu) \
...
答案 6 :(得分:2)
您可以在wildcard
中使用多个规则:
SOURCES := $(wildcard *.cpp */*.cpp)
如果您需要更多深度:
SOURCES := $(wildcard *.cpp */*.cpp */*/*.cpp */*/*/*.cpp)
不幸的是,与我们有时阅读的内容相反,makefile不支持glob(**
),它将被解释为普通通配符(**/*.cpp
匹配*/*.cpp
而不是{{1 }}。
如果您需要无限深度,请使用*/*/*.cpp
shell