在我的工作目录中,有一个makefile
,一个空的obj
文件夹和一个包含src
的{{1}}文件夹。我有一个简单的规则,该规则接受一个目标文件,用 src 替换所有内容,直到第一个斜杠,然后用 .c 替换结尾的 .o 。
示例:obj / foo.o-> src / foo.c
在 MadScientist 的帮助下(归功于他),我获得了以下模式规则(请不要提出更简单的规则->我知道它们的存在,但仅此规则说明了我的问题):
foo.c
一旦我运行了上面的makefile,就会得到一个循环依赖:
OBJFILES=obj/foo.o
all: $(OBJFILES)
@echo "all executed"
Y = $(shell echo $1 | sed -e 's,^[^\/]*,src,' -e 's,\.o$$,.c,')
.SECONDEXPANSION:
%.o: $$(call Y,$$@)
@echo "OBJECTS executed for $@ - [$^]"
src/foo.c:
@echo "Congrats"
迅速找到原因:xxxx@null:~/Desktop/experiment$ make
make: Circular src.o <- src dependency dropped.
OBJECTS executed for obj/foo.o - [src/foo.c]
all executed
创建了隐式规则Make
,这触发了我的模式规则。由于Makefile: Makefile.o
不包含斜杠,因此Makefile.o
的值为sed
。 src
再次应用隐式规则Make
,该规则最终导致循环依赖。可以在make输出中看到:
src:src.o
如果我们现在以这种方式重新定义make --print-data-base | grep src
make: Circular src.o <- src dependency dropped.
OBJECTS executed for obj/foo.o - [src/foo.c]
Y = $(shell echo $1 | sed -e 's,^[^\/]*,src,' -e 's,\.o$$,.c,')
# src (device 64769, inode 14031369): No files, no impossibilities so far.
Makefile.o: src
src: src.o
# Implicit/static pattern stem: 'src'
src.o:
# Implicit/static pattern stem: 'src'
# @ := src.o
# * := src
# < := src.o
obj/foo.o: src/foo.c
# + := src/foo.c
# < := src/foo.c
# ^ := src/foo.c
# ? := src/foo.c
src/foo.c:
:Y
,则不会发生循环依赖,因为Y = $(patsubst obj/%.o,src/%.c,$1)
甚至没有尝试应用隐式规则make
>
Makefile:Makefile.o
make --print-data-base | grep src
OBJECTS executed for obj/foo.o - [src/foo.c]
Y = $(patsubst obj/%.o,src/%.c,$1)
# src (device 64769, inode 14031369): No files, no impossibilities so far.
obj/foo.o: src/foo.c
# + := src/foo.c
# < := src/foo.c
# ^ := src/foo.c
# ? := src/foo.c
src/foo.c:
何时创建隐式规则make
? Makefile: Makefile.o
的两个不同定义之间有什么区别?
答案 0 :(得分:2)
第一件事是,如果要使用二级扩展,则有责任确保结果正确。在模式规则中,这意味着您的扩展必须处理%
的所有不同值。从根本上说,这里的问题是,您没有正确处理不包含斜杠的%
的值,但是目标%.o
将适用于所有目标,而不仅仅是子目录中的目标。您需要修复sed
调用。一种选择是:
Y = $(shell echo $1 | sed -e 's,^[^\/]*/,src/,' -e 's,\.o$$,.c,')
通过添加斜杠表示替换将不匹配简单的文件名。但是,.o
仍被.c
取代。
您看到此行为的原因是因为make tries to remake makefiles。因此,它想建立一个目标Makefile
。有一个内置的模式规则,该规则知道如何从具有相同名称的目标文件构建可执行文件:% : %.o
Makefile
与%
匹配,因此请尝试构建{{1} }。它会看到您的模式规则Makefile.o
并尝试应用它,在第二个扩展中,它如上所述将%.o
转换为Makefile.o
。
因此,除了上述内容外,您还可以考虑其他事项:
如果您使用的make版本足够新(并且您定义了所有自己的规则),则可以通过添加以下内容来禁用所有内置规则:
src
这是个好主意,因为它可以通过删除所有内置规则来使make运行更快。
第二,您可以将模式更改为更具体,以便仅匹配目标文件,如下所示:
MAKEFLAGS += -r
现在,此模式规则将仅匹配该子目录中的obj/%.o: $$(call Y,$$@)
...
个文件。