GNU make:从不同路径编译的通用规则



我有一个这样的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/1some/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-recwildcard的增强版本,它支持类似于其他扩展通配符匹配器(如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

最新更新