良好的Makefile实践
1. 背景
这篇文章的主要目的是记录一些可以在Makefile中使用的技巧,以便可以为Makefile本身中的每个目标添加文档,并且可以将其作为make目标查看(例如make help)。
在项目中拥有可靠的文档是一件很了不起的事情,而且如果它们不会过时,那就更好了。通常在顶级Readme.md或类似文件中记录每个Make目标。尽管这是迈出的重要第一步,但更新Makefile而不是更新文档是很常见的,因此使它们变得毫无用处。
2. 目标
最终目标是能够根据Makefile中的注释运行以下内容。
# make
Usage:
make
Targets:
help Display this help
deps Check dependencies
clean Cleanup the project folders
build Build the project
watch Watch file changes and build
对于具有很多目标的复杂Makefile,我们也可以将它们组合在一起。
# make
Usage:
make
Dependencies
deps Check dependencies
Cleanup
clean Cleanup the project folders
Building
build Build the project
watch Watch file changes and build
Helpers
help Display this help
让我们继续看看它是如何实现的
要求:
make
和awk
是唯一的要求。在macOS(BSD)和Linux(GNU)版本上均能工作。
实现:
如上面的示例所示,我们可以针对两种不同的情况实现它们。
- 简单的makefile
对于目标文件很少的Makefile,我们可以列出所有目标文件而没有任何分组。
首先,添加一个帮助目标。
help: ## Display this help
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n\nTargets:\n"} /^[a-zA-Z_-]+:.*?##/ { printf " \033[36m%-10s\033[0m %s\n", $$1, $$2 }' $(MAKEFILE_LIST)
然后,使用上述帮助目标中指定的语法添加注释。在此示例中,我们将使用##作为可打印注释的标签。
deps: ## Check dependencies
$(info Checking and getting dependencies)
clean: ## Cleanup the project folders
$(info Cleaning up things)
build: clean deps ## Build the project
$(info Building the project)
watch: clean deps ## Watch file changes and build
$(info Watching and building the project)
(可选)将默认目标添加为help,最好在Makefile的顶部
.DEFAULT_GOAL:=help
(可选)调整目标和通过make help输出的注释之间的宽度。
在上述帮助目标中,将数字10替换为您喜欢的字符宽度。
完整的例子:
.DEFAULT_GOAL:=help
SHELL:=/bin/bash
.PHONY: help deps clean build watch
help: ## Display this help
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n\nTargets:\n"} /^[a-zA-Z_-]+:.*?##/ { printf " \033[36m%-10s\033[0m %s\n", $$1, $$2 }' $(MAKEFILE_LIST)
deps: ## Check dependencies
$(info Checking and getting dependencies)
clean: ## Cleanup the project folders
$(info Cleaning up things)
build: clean deps ## Build the project
$(info Building the project)
watch: clean deps ## Watch file changes and build
$(info Watching and building the project)
- 分组的Makefile
添加分组与上面的分组非常相似。我们再添加一种注释格式,以区分分组注释和目标注释,并稍微调整帮助目标以适应更改。
添加帮助目标(确保正确复制/转换制表符)
help: ## Display this help
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
使用上述帮助目标中指定的语法添加注释。在此示例中,我们将使用##作为可打印注释的标记,并使用## @作为分组注释 的标记
##@ Dependencies
deps: ## Check dependencies
$(info Checking and getting dependencies)
##@ Cleanup
clean: ## Cleanup the project folders
$(info Cleaning up things)
##@ Building
build: clean deps ## Build the project
$(info Building the project)
watch: clean deps ## Watch file changes and build
$(info Watching and building the project)
(可选)提供默认目标,并调整目标和打印输出的注释之间的字符宽度,如上面“简单Makefile”部分中所述
完整的例子:
.DEFAULT_GOAL:=help
SHELL:=/bin/bash
##@ Dependencies
.PHONY: deps
deps: ## Check dependencies
$(info Checking and getting dependencies)
##@ Cleanup
.PHONY: clean
clean: ## Cleanup the project folders
$(info Cleaning up things)
##@ Building
.PHONY: build watch
build: clean deps ## Build the project
$(info Building the project)
watch: clean deps ## Watch file changes and build
$(info Watching and building the project)
##@ Helpers
.PHONY: help
help: ## Display this help
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m\033[0m\n"} /^[a-zA-Z_-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
参考:
make help - Well documented Makefiles
Gist by prwhite
Client9 - Self documenting makefiles
Marmelab - Self documented makefiles