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

时间:2013-06-19 14:22:17

标签: 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 -o $@ $<

$(SRCDIR)/%.pb.cc: $(PROTODIR)/%.proto
    $(PROTOC) $(PROTOOPTIONS) --cpp_out=$(SRCDIR) $<

现在,如果我致电make gui_backend,我就会

make: *** No rule to make target `build/config.pb.o', needed by `build/gui_backend'.

为什么不在这里采用$(BUILDDIR)/%.o模式?如果我通过添加规则明确陈述事项

$(BUILDDIR)/config.pb.o: $(SRCDIR)/config.pb.cc $(SRCDIR)/config.pb.h | $(BUILDDIR)
    $(CXX) $(CXXFLAGS) -c -o $@ $<
它似乎有效。但是,我想让makefile尽可能简洁。

使用-d运行make会给我以下内容(complete output here):

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'.
        [...]

我正在运行GNU Make 3.81,顺便说一句。

此外,我刚注意到,如果我手动运行make src/config.pb.cc然后make build/config.pb.o,它就可以运行。

为什么这不起作用?

2 个答案:

答案 0 :(得分:1)

你的例子对我来说是正确的。我看到的模式规则和显式规则之间的唯一区别是显式规则没有仅订单的先决条件。您运行的是什么版本的GNU make?您确定它支持仅订购的先决条件吗?如果没有,那么模式规则将不匹配,因为它试图找到一种方法来构建像|这样的目标而不能。

每当遇到这样的问题时,最简单的方法就是运行make -d。输出量很大,但它也很有启发性:找到它试图构建config.pb.o的部分,看看它正在尝试的模式以及为什么它决定放弃那个模式。

答案 1 :(得分:0)

我还在构建原型文件,正在使用以下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 $@

我可以执行

rm -rf build/lsm.pb.o lsm.pb.h lsm.pb.cpp
make build/lsm.pb.o

它正确找到依赖项。对我来说,直到我将分号添加到第一条规则的末尾,我才能使它起作用。由于某些原因,Make不喜欢使用空规则的配方。

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