具有复杂相互依赖关系的 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 是邪恶的阵营——虽然递归 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."
如果你能表达这个,
它将为您的构建改进许多非常重要的参数:
- 并行构建工作正常
prog1
的.o
文件可以和prog1
的文件同时编译
lib2.a
- 如果您 运行 将测试作为构建的一部分,则这一点更为重要
(你这样做了,不是吗?)
- 无所事事的时间非常接近于零
- 没有比发布构建更糟糕的了,
几分钟后你会得到一个
构建已经是最新的(WinCE,我在看你)
- 工作被正确剔除
- 换句话说,你可以依赖你的依赖,
永远不必做 make clean 因为你不信任他们
毕竟,
这些目标实际上是使用 make 的全部意义所在。
如果弄错了,您还不如使用批处理文件。
(顺便说一句,在递归 make 系统中让它们正确是非常棘手的。)
当然,
在 make 中清楚地表达这一点确实需要一些努力,
但你确实说过你有一个大型项目。
我正在尝试为具有如下结构的大型项目设计一个构建系统:
├── deploy
├── docs
├── libs
│ ├── lib1
│ └── lib2
├── scripts
└── tools
├── prog1
└── prog2
我的问题是库和程序可能以经常更改的顺序相互依赖。我在 Internet 上查找了信息,但得到的信息不一。有人说我应该只使用 makefiles 而其他人说递归 makefiles 是邪恶的。
除此之外,我不知道如何使用 makefile 管理依赖关系(如果 lib2
需要 lib1
来构建,如何告诉 make 先构建 lib1
)。有人告诉我,使用变量 VPATH
很容易实现,但我已经阅读了文档,我认为这与此无关。
所以我的问题是:
- 在这种情况下我真的应该避免使用 makefile 吗?如果是这样,有哪些替代方案?
- 如果我应该使用 makefile,我该如何自动有效地管理依赖关系?
我不认为递归 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."
如果你能表达这个, 它将为您的构建改进许多非常重要的参数:
- 并行构建工作正常
prog1
的.o
文件可以和prog1
的文件同时编译lib2.a
- 如果您 运行 将测试作为构建的一部分,则这一点更为重要 (你这样做了,不是吗?)
- 无所事事的时间非常接近于零
- 没有比发布构建更糟糕的了, 几分钟后你会得到一个 构建已经是最新的(WinCE,我在看你)
- 工作被正确剔除
- 换句话说,你可以依赖你的依赖, 永远不必做 make clean 因为你不信任他们
毕竟, 这些目标实际上是使用 make 的全部意义所在。 如果弄错了,您还不如使用批处理文件。 (顺便说一句,在递归 make 系统中让它们正确是非常棘手的。)
当然, 在 make 中清楚地表达这一点确实需要一些努力, 但你确实说过你有一个大型项目。