我有一个这样的makefile:
default: exe
%.obj: %.src
# dummy compiler
@echo link $< to $@
cat $< > $@
exe: main.obj foo.obj bar.obj
# dummy linker
@echo link $^ to $@
cat $^ > $@
main.obj: main.src
foo.obj: /some/dir/1/foo.src
bar.obj: /some/dir/2/bar.src
Make无法编译foo.obj和bar.obj(以及20多个其他对象(,因为它不使用"%"。obj:%.src"规则foo.obj和foo.src的目录分别为。bar.obj和bar.src不匹配,因此规则不匹配。
有没有办法指定一个忽略文件名目录部分的规则?
更新:
为了使Makefile工作,我将编译行从模式规则复制到foo.obj和bar.obj规则(以及20多个其他对象规则(。这根本不是干净和可维护的。本质上,我需要一个模式规则,在比较时忽略源目录和对象目录。
我不知道有这样的功能(除了宏,您可以安排它们生成手动编写的makefile片段(。但是GNUMake有一个vpath
特性,它允许指定一个路径,在那里查找给定扩展名的文件,并与自动变量交互,使其接近您想要的内容。
你的Makefile可以写为:
default: exe
vpath %.src some/dir/1:some/dir/2
%.obj: %.src
# dummy compiler
@echo compiling $< to $@
cat $< > $@
exe: main.obj foo.obj bar.obj
# dummy linker
@echo linking $^ to $@
cat $^ > $@
请注意,这并不完全是您想要的:如果some/dir/1
和some/dir/2
中都有bar.src
,则将使用some/dir/1
中的一个。
您可以使用$(shell find . -name '*.src')
为所有子目录中的所有.src
文件创建一个变量。这里有一个例子:
OBJS := $(shell find . -name '*.src')
default: exe
%.obj: %.src
@echo link $< to $@
cat $< > $@
exe: $(OBJS)
@echo link $^ to $@
cat $^ > $@
执行此操作的宏方法如下:
define mymacro
$1: $2
@echo compiling $$< to $$@
cat $$< > $$@
endef
$(eval $(call mymacro,foo.obj,/some/dir/1/foo.src))
$(eval $(call mymacro,bar.obj,/some/dir/2/bar.src))
但请注意,宏会降低makefile的可维护性(因为它更难阅读,并且会引入一些缺乏经验的用户可能会绊倒的尖锐棍子(。它也适用于GNU make,但可能在其他一些make系统上失败。
我已经编写了一个使用gmtt并依赖于显式源代码启发的构建系统。核心是一个名为wildcard-rec
的wildcard
的增强版本,它支持类似于其他扩展通配符匹配器(如git(中的**
的递归下降-也许它符合您的口味和用例:
include gmtt.mk
default: exe
SOURCE_LOCATOR := $(call wildcard-rec,main.src some/dir/**/3/*.src some/**/1/foo.src some/dir/2/bar.src)
$(info Compiling these sources: $(SOURCE_LOCATOR))
OBJECTS := $(addsuffix .obj,$(basename $(notdir $(SOURCE_LOCATOR))))
$(info Building these objects: $(OBJECTS))
# Generate the source prerequisite for each object
TGT-PREREQ := $(join $(addsuffix :,$(OBJECTS)),$(SOURCE_LOCATOR))
# Introduce them as targets via eval:
$(foreach tp,$(TGT-PREREQ),$(info $(tp))$(eval $(tp)))
$(OBJECTS):
@echo compile $< to $@
exe: $(OBJECTS)
@echo link $^ to $@
测试:
Compiling these sources: main.src some/dir/foo/3/a.src some/dir/foo/3/b.src some/dir/bar/1/foo.src some/dir/2/bar.src
Building these objects: main.obj a.obj b.obj foo.obj bar.obj
main.obj:main.src
a.obj:some/dir/foo/3/a.src
b.obj:some/dir/foo/3/b.src
foo.obj:some/dir/bar/1/foo.src
bar.obj:some/dir/2/bar.src
compile main.src to main.obj
compile some/dir/foo/3/a.src to a.obj
compile some/dir/foo/3/b.src to b.obj
compile some/dir/bar/1/foo.src to foo.obj
compile some/dir/2/bar.src to bar.obj
link main.obj a.obj b.obj foo.obj bar.obj to exe