使用 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 当作统一入口和任务运行器:
    • makemake testmake installmake cleanmake dev 这样的目标。
    • 底层常常只是调用 CMake、Cargo、Docker,或语言特定工具。
  • 另一些人认为大量使用 .PHONY 目标是一种异味,并建议对纯命令编排使用 justtask 之类的工具。

易用性、缺点与使用限制

  • 常见抱怨包括:依赖 tab 的语法、隐式规则、空白字符怪癖、对带空格路径的处理笨拙,以及维护大型 Makefile 的困难。
  • 建议的缓解方式包括:保持单个 Makefile 小而精,将平台逻辑集中到模板中,自动生成依赖,并在并行构建时使用 -j / -l
  • 普遍共识是:make 非常适合小到中型、面向文件的构建,以及作为胶水;但对于大型、跨平台系统,它往往会变得令人痛苦,而且经常只是被包装或被替代。