具有复杂相互依赖关系的 Makefile 和大型项目

Makefiles and large projects with complex interdependencies

我正在尝试为具有如下结构的大型项目设计一个构建系统:

├── deploy
├── docs
├── libs
│   ├── lib1
│   └── lib2
├── scripts
└── tools
    ├── prog1
    └── prog2

我的问题是库和程序可能以经常更改的顺序相互依赖。我在 Internet 上查找了信息,但得到的信息不一。有人说我应该只使用 makefiles 而其他人说递归 makefiles 是邪恶的。

除此之外,我不知道如何使用 makefile 管理依赖关系(如果 lib2 需要 lib1 来构建,如何告诉 make 先构建 lib1)。有人告诉我,使用变量 VPATH 很容易实现,但我已经阅读了文档,我认为这与此无关。

所以我的问题是:

我不认为递归 makefile 是邪恶的阵营——虽然递归 makefile 确实效率不高(它们没有最大化并发性等),但它通常可以忽略不计。另一方面,使用递归 makefile 使您的项目更具可扩展性——移入和移出模块、与其他组共享等更简单。

在你的情况下,如果 lib2 依赖于 lib1,你可以这样做:

 lib2: lib1
    make -C libs/lib2

现在 make 将在 lib2 之前构建 lib1(即使您指定了 -j)。

现在如果你有交叉依赖(lib1 中的某些东西依赖于 lib2 中的东西,而 lib2 又依赖于 lib1 中的其他东西),那么你可能想要考虑重组你的目录以避免交叉依赖,或使用单个 makefile(如果您在这种情况下尝试使用递归 makefile,则会暴露出很多尖锐的棍子)。

我属于不要撒谎阵营。 这里, 细粒度的依赖是你的朋友。 不要认为你需要表达 prog1 依赖于 lib2。你真正想对 make 说的是:

"To link prog1 you need all the .o files, and all the appropriate .a files."

如果你能表达这个, 它将为您的构建改进许多非常重要的参数:

  1. 并行构建工作正常
    • prog1.o文件可以和prog1的文件同时编译 lib2.a
    • 如果您 运行 将测试作为构建的一部分,则这一点更为重要 (你这样做了,不是吗?)
  2. 无所事事的时间非常接近于零
    • 没有比发布构建更糟糕的了, 几分钟后你会得到一个 构建已经是最新的(WinCE,我在看你)
  3. 工作被正确剔除
    • 换句话说,你可以依赖你的依赖, 永远不必做 make clean 因为你不信任他们

毕竟, 这些目标实际上是使用 make 的全部意义所在。 如果弄错了,您还不如使用批处理文件。 (顺便说一句,在递归 make 系统中让它们正确是非常棘手的。)

当然, 在 make 中清楚地表达这一点确实需要一些努力, 但你确实说过你有一个大型项目。