使用 Make——少写一些 Makefile
程序员们再次讨论久经考验的 `make` 构建系统,指出它的隐式规则和极简 Makefile 能被延展到多远——从小型 C 项目到容器编排和 dotfile 管理。许多人称赞 `make` 无处不在、依赖跟踪简单,并且能作为 CMake 或 Ninja 之类新工具的前端;而另一些人则认为它晦涩的语法、隐藏规则和扩展性问题,让现代生成器或任务运行器(如 CMake、Meson、Ninja、just、Task)更高效。除了构建系统的争论外,评论者还顺带批评了文章采用的 manpage 风格布局,认为它在手机上或放大后可读性和可访问性都较差。
类 manpage 的呈现方式与可读性
- 一些读者喜欢复古的“manpage”美学;也有人觉得它很难阅读,尤其是在手机上或高倍率缩放时。
- 抱怨主要集中在等宽、不可重排的文本和较小的字号;有人指出这很讽刺,因为真正的 man page 会根据终端宽度重新排版。
- 也有人提出可访问性方面的担忧(视力问题、屏幕阅读器)。另一些人则认为个人网站可以把风格放在功能之上。
Make 的最小化使用与隐式规则
- 评论者强调,文章中的许多示例其实还能进一步简化,只需依赖内建规则:
- 如果
foo.c存在,make foo就能在没有 Makefile 的情况下工作。 - 像
foo: foo.o bar.o baz.o这样的链接规则,通常可以省略显式的编译命令,只使用LDFLAGS/LDLIBS。
- 如果
- 建议使用自动变量(
$@、$^、$<)来避免重复写文件列表,不过也有人不喜欢这些为了可读性而显得“魔法化”的符号。
通配、对象列表与通用 Makefile
- 一派人主张使用 wildcard/通配来发现源文件,这样就不必手工列出文件,并且可以编写可在许多项目和平台上复用的通用 Makefile。
- 另一些人警告说通配存在以下问题:
- 更难推理(意外匹配、安全/可靠性问题)。
- 在非常大的目录树或递归扫描时可能较慢。
- 对细粒度标志和将整洁的源码树映射到树外构建目录也有问题。
- 还提到了已成熟的多架构模式,其中为了清晰和控制,更倾向于显式路径。
Make vs CMake、Meson、Ninja、Autotools、脚本
- 对“2023 年还用 make”存在强烈分歧:
- 批评者称它过时、冗长,并且在小型项目之外很脆弱;他们更偏好 CMake/Meson 或用 Python/Node 手写构建,理由是更好的易用性、依赖发现和 IDE 集成。
- 支持者则强调 make 的无处不在、极小的依赖足迹(对引导系统很有利)、可移植性,以及数十年的稳定性。
- Ninja 被认为通过放弃 make 的某些昂贵特性,在超大规模构建中更快,但也有人认为对于典型项目,解析开销可以忽略不计。
- Autotools 被提到功能强大但很重;CMake 被视为事实上的跨平台生成器,尽管它本身也很复杂,而且调试很痛苦。
- 还有人认为现代工具只是重新学习了 make 的经验,只是慢慢堆积出类似的复杂度。
Make 作为任务运行器 / 项目前端
- 许多人主要把 make 当作统一入口和任务运行器:
- 像
make、make test、make install、make clean、make dev这样的目标。 - 底层常常只是调用 CMake、Cargo、Docker,或语言特定工具。
- 像
- 另一些人认为大量使用
.PHONY目标是一种异味,并建议对纯命令编排使用just或task之类的工具。
易用性、缺点与使用限制
- 常见抱怨包括:依赖 tab 的语法、隐式规则、空白字符怪癖、对带空格路径的处理笨拙,以及维护大型 Makefile 的困难。
- 建议的缓解方式包括:保持单个 Makefile 小而精,将平台逻辑集中到模板中,自动生成依赖,并在并行构建时使用
-j/-l。 - 普遍共识是:make 非常适合小到中型、面向文件的构建,以及作为胶水;但对于大型、跨平台系统,它往往会变得令人痛苦,而且经常只是被包装或被替代。