1

我想构建一些 C++ 代码。我已经有一个神奇的 Makefile 可以自动计算依赖关系,但我想将目标文件保存在单独的目录中。所以结构看起来像:

  • 生成文件
  • 来源/a/
  • 来源/b/
  • 来源/c/
  • 对象/

我能够运行使用 obj/ 前缀将源转换为对象的 Makefile,但是当我想反向移植依赖计算时事情变得一团糟。

问题是几乎所有 Makefile 示例都是一步完成的,从 .cpp ( %.d: %.cpp) 创建 .d。我花了一些时间试图理解 Makefile 并通过反复试验来修复它。最后我有一个工作脚本:

DIRS := a b c
SOURCES := $(foreach dir,$(DIRS),$(wildcard source/$(dir)/*.cpp))
OBJECTS := $(patsubst %.cpp,obj/%.o,$(SOURCES))

obj/%.d: %.cpp
    @mkdir -p $(@D)
    @$(CXX) -E $(CXXFLAGS) -MM -MP -MF $@ -MQ $(@:.d=.o) -MQ $@ $<

obj/%.o: %.cpp obj/%.d
    @$(CXX) $(CXXFLAGS) -o $@ -c $<

project: $(OBJECTS)
    ...

-include $(OBJECTS:.o=.d)

但我仍然不确定为什么我需要为 cpp->d 和 cpp&d -> o 设置单独的步骤(或者也许我理解 - 但我不知道为什么大多数示例不需要这个)。

4

1 回答 1

2

假设源文件是foo.cppand bar.cpp,并且标头是foo.hand bar.h,例如foo.cpp包含foo.hand bar.h,并且bar.cpp包含bar.h

您可以拥有一个根本不涉及依赖文件的简单生成文件:

project: $(OBJECTS)
    ...

%.o: %.cpp
    ...

现在,如果您修改foo.cpp, Make 将重建foo.o(和project)。如果您修改bar.cpp,Make 将重建bar.o(和project)。如果你修改了一个标题,Make 将什么也不做,因为 Make 不知道对象以任何方式依赖于标题。

您可以为依赖文件添加规则:

project: $(OBJECTS)
    ...

%.o: %.cpp
    ...

%.d:
    ...

-include *.d

现在 Make 将构建和使用依赖文件——如果你记得告诉它的话。如果你这样做,Make 会知道当你修改foo.h它时必须重新构建foo.o,而当你修改bar.h它时必须重新构建foo.obar.o.

记住重建依赖文件是一件痛苦的事。让Make来做会更好。什么时候必须foo.d重建?好吧,当foo.cpp被修改时,当然:

project: $(OBJECTS)
    ...

%.o: %.cpp
    ...

%.d: %.cpp
    ...

-include *.d

foo.d也必须在foo.o(iefoo.hbar.h) 的任何其他先决条件已被修改时重建。我没有拼出规则中的命令(而且我无法理解%.d规则中的命令),但是一个简单的规则将构建一个foo.d如下所示的命令:

foo.o: foo.cpp foo.h bar.h

可以编写一个生成foo.d如下所示的命令:

foo.o: foo.cpp foo.h bar.h

foo.d: foo.cpp foo.h bar.h

还有更复杂的方法,但这对于今天来说已经足够了。

至于为什么许多示例 makefile 共享某个次优特性,这是因为人们在没有严格检查或理解每个特性的情况下复制彼此的 makefile。

于 2012-11-24T18:28:41.477 回答