Afraid of Makefiles? Don't be!

Matthias Endler

害怕 Makefile?别怕!

原文由 Matthias Endler 发布,订阅该博客

衣服和 Makefile 有什么关系?在这篇文章中一探究竟!
衣服和 Makefile 有什么关系?在这篇文章中一探究竟!
来源: 插图由 Anindyanfitri 提供 - Freepik.com

过去几年里,我有幸与许多优秀的软件工程师共事。让我印象深刻的一点是,他们中很多人对 Makefiles 几乎一无所知,也不了解它有什么用。

当需要自动化构建流程时,他们常常会自己写 shell 脚本。在项目目录里,常见的就是那些叫 build.shrun.shdoall.sh 的脚本。

这些脚本总是在反复实现同样的基础功能:

  • 解析输入参数和环境变量。
  • 手动管理各个构建步骤之间的依赖。
  • 错误处理(……也许会做)。

在这个过程中,他们也总在犯同样的基础错误:

而这些,正是 Makefile 被发明出来要解决的问题。

Makefile 很可怕!

如果你觉得 make 很可怕,你想到的可能是那些为 大型 软件项目准备的复杂构建系统。其实完全不必如此。来听听 make 的作者 Stuart Feldman 本人是怎么说的:

一开始是个相当复杂的依赖分析器的构想,后来被精简为简单得多的东西,就在那个周末变成了 Make。使用那些还很不成熟的工具本就是当时文化的一部分。Makefile 是文本文件,而不是经过神秘编码的二进制文件,因为这就是 Unix 的哲学:可打印、可调试、可理解的东西。

The Art of Unix Programming (2003)

Make 仅用一个周末就被创造出来,用一种简单的方式解决了一个反复出现的问题。

Makefile 很简单!

出门之前,我得先穿好衣服。我每次都遵循同样的简单顺序:内裤、裤子、衬衫、套头衫、袜子、鞋子、外套。你很可能也有自己的穿衣顺序,虽然可能和我的不一样。

其中有些步骤是相互依赖的。
Make 正好擅长处理依赖关系。
我们来试着把我的穿衣流程写成一个 Makefile

dress: trousers shoes jacket
	@echo "All done. Let's go outside!"

jacket: pullover
	@echo "Putting on jacket."

pullover: shirt
	@echo "Putting on pullover."

shirt:
	@echo "Putting on shirt."

trousers: underpants
	@echo "Putting on trousers."

underpants:
	@echo "Putting on underpants."

shoes: socks
	@echo "Putting on shoes."

socks: pullover
	@echo "Putting on socks."

如果我们执行这个 Makefile,就会得到如下输出:

$ make dress
Putting on underpants.
Putting on trousers.
Putting on shirt.
Putting on pullover.
Putting on socks.
Putting on shoes.
Putting on jacket.
All done. Let's go outside!

刚才发生了什么?

注意到这些步骤的顺序是正确的吗?只要把步骤之间的依赖关系清楚地写下来,make 就能帮我们按正确的顺序执行。

每个构建步骤都遵循如下结构:

target: [dependencies]
	<shell command to execute>
	<shell command to execute>
	...
  • Makefile 中的第一个 target 会在我们执行 make 时默认被执行。

  • 各个 target 的先后顺序并不重要。

  • Shell 命令必须用制表符(Tab)缩进。

  • 在命令前加上 @ 符号可以抑制该命令本身的输出。

  • 如果 target 并不是你想要生成的文件,请在该构建步骤末尾加上 .PHONY <target>。常见的伪目标有:clean、install、run……否则,如果有人创建了一个名为 install 的目录,make 就会静默失败,因为构建目标已存在。

    .PHONY: install
    install:
    	npm install

恭喜!你已经掌握了关于 make 需要了解的 90% 内容。

下一步

真正的 Makefiles 还能做得更多!它们会只构建发生变更的文件,而不是每次都全量重建。它们还会尽可能并行地执行。不过,还是请尽量保持简单。

本文章由 muse-spark-1.2-contributor 进行翻译

评论