Makefile 模式规则取决于另一个模式规则

Makefile 模式规则取决于另一个模式规则,makefile,gnu-make,Makefile,Gnu Make,考虑我的makefile的以下片段: gui_backend: $(BUILDDIR)/gui_backend $(BUILDDIR)/gui_backend: $(BUILDDIR)/gui_backend.o $(BUILDDIR)/config.pb.o $(CXX) $(LDFLAGS) -o $@ $^ $(BUILDDIR)/%.o: $(SRCDIR)/%.cc $(SRCDIR)/%.h | $(BUILDDIR) $(CXX) $(CXXFLAGS) -c

考虑我的makefile的以下片段:

gui_backend: $(BUILDDIR)/gui_backend

$(BUILDDIR)/gui_backend: $(BUILDDIR)/gui_backend.o $(BUILDDIR)/config.pb.o
    $(CXX) $(LDFLAGS) -o $@ $^

$(BUILDDIR)/%.o: $(SRCDIR)/%.cc $(SRCDIR)/%.h | $(BUILDDIR)
    $(CXX) $(CXXFLAGS) -c -o $@ $<

$(SRCDIR)/%.pb.cc: $(PROTODIR)/%.proto
    $(PROTOC) $(PROTOOPTIONS) --cpp_out=$(SRCDIR) $<
为什么不在这里选择
$(BUILDDIR)/%.o
模式?如果我通过添加规则来明确说明问题

$(BUILDDIR)/config.pb.o: $(SRCDIR)/config.pb.cc $(SRCDIR)/config.pb.h | $(BUILDDIR)
    $(CXX) $(CXXFLAGS) -c -o $@ $<
顺便说一句,我正在运行GNU Make 3.81

另外,我刚刚注意到,如果我运行
makesrc/config.pb.cc
,然后手动运行
makebuild/config.pb.o
,它就会工作


为什么这样不行?

我觉得你的例子很正确。我看到的模式规则和显式规则之间的唯一区别是显式规则没有仅顺序的先决条件。您正在运行哪个版本的GNU make?您确定它只支持订单前提条件吗?如果不匹配,则模式规则将不匹配,因为它试图找到一种方法来构建像
|
这样的目标,但无法


无论何时遇到这样的问题,最简单的方法就是运行
make-d
。输出内容非常丰富,但也很有启发性:找到它试图构建
config.pb.o
的部分,看看它在尝试什么模式,以及为什么它决定放弃这个模式。

我也在构建原型文件,我在使用这些Makefile目标:

%.pb.cpp: %.proto
    protoc --cpp_out=. $<
    mv $(@:cpp=cc) $@

%.pb.h: %.pb.cpp ;

build/%.o: %.cpp
    @mkdir -p $(@D)
    $(CXX) $(CXXFLAGS) $(NON_PROFILE_CXXFLAGS) -MD -MF $(@:%.o=%.d) -MT $@ -c $< -o $@
它正确地找到了依赖项。对我来说,直到我在第一条规则的末尾添加了分号,我才能够让它起作用。出于某种原因,Make不喜欢模式规则的空配方


这是一个六年前的问题,但希望这个答案能帮助像我这样最终来到这里的其他人。

谢谢你的快速回复,我已经相应地编辑了这个问题。虽然-,但是不能从make-d的输出中做出任何东西。-您已经在-d输出中留下了更有趣的部分:您想看一下接近结尾的地方,在那里它决定不知道如何更新对象文件。在它这样做之前,将有行描述它未能找到的内容,这样它就无法使用该模式规则。这也可能是GNU make 3.81中的一个bug。我已经添加了完整的make-d输出。我还注意到,如果我手动运行
make src/config.pb.cc
make build/config.pb.o
(一旦
src/config.pb.cc
存在,
src/config.pb.cc
就可以工作了。我要澄清的是,
src/config.pb.cc
一开始就不存在,但是
src/config.pb.h
$(PROTODIR)/config.proto>怎么办?当你
生成build/config.pb.o
时,它什么也不生成?当您
创建src/config.pb.cc
时会怎么样?您确定
PROTODIR
变量吗?我的意思是,它就是你所认为的,并且原型文件实际上就在那里,
src/config.pb.cc
src/config.pb.h
都不存在。它们都是通过调用$(PROTOC)生成的。是的,
PROTODIR
设置正确。如果我运行
make src/config.pb.cc
,它将正确调用
protoc
,并从
config.proto
文件生成两个文件。
Considering target file `build/config.pb.o'.
       File `build/config.pb.o' does not exist.
       Looking for an implicit rule for `build/config.pb.o'.
       Trying pattern rule with stem `config.pb'.
       Trying implicit prerequisite `src/config.pb.cc'.
       Trying pattern rule with stem `config.pb'.
       Trying implicit prerequisite `build/config.pb.c'.
       Trying pattern rule with stem `config.pb'.
       Trying implicit prerequisite `build/config.pb.cc'.
       Trying pattern rule with stem `config.pb'.
       [...]
       Trying implicit prerequisite `build/SCCS/s.config.pb.o'.
       Trying pattern rule with stem `config.pb'.
       Trying implicit prerequisite `src/config.pb.cc'.
       Looking for a rule with intermediate file `src/config.pb.cc'.
        Avoiding implicit rule recursion.
        Trying pattern rule with stem `config'.
        Trying implicit prerequisite `src/proto/config.proto'.
        [...]
%.pb.cpp: %.proto
    protoc --cpp_out=. $<
    mv $(@:cpp=cc) $@

%.pb.h: %.pb.cpp ;

build/%.o: %.cpp
    @mkdir -p $(@D)
    $(CXX) $(CXXFLAGS) $(NON_PROFILE_CXXFLAGS) -MD -MF $(@:%.o=%.d) -MT $@ -c $< -o $@
rm -rf build/lsm.pb.o lsm.pb.h lsm.pb.cpp
make build/lsm.pb.o