使用 Makefile(make) 实现项目工作流程自动化

make 0 创建之始主要用于大型软件(C/C++ 语言等)项目的构建。 因为 make 工具可以自动确定一个大型程序中哪些部分需要重新编译,并发出适当的命令重新编译它们。 可以极大的减轻维护项目编译脚本的负担。

当前还是有许多项目使用 makeMakefile 来完成软件的 编译 & 安装, 一个良好维护的 Makefile 的项目通常使用如下的命令来完成 编译 & 安装:

./configure
make build
make install

备注

对于现代的 C/C++ 项目,建议您使用 CMake 1 作为构建系统。

make & Makefile 简介

如果需要使用 make 那么您需要创建 Makefile 告诉 make 它所需要的运行规则。

Makefile 规则

Makefile 是基于文件规则的引擎。

一个规则通常由 target 目标(文件), prerequisites 依赖文件(目标) 以及 recipe (一系列命令) 组成。

示例如下:

您可以使用: make build 来构建 demo, make run 直接运行。

备注

关于 makeMakefile 的相关知识,可以阅读 GNU make 0 文档。

为什么使用 Makefile ?

Makefile 主要有以下几个优点:

  • 基于文件的规则引擎

  • 开箱即用 & 久经考验

    几乎所有平台(除 Windows 平台)都自带了 make, 自 1977 年 2 make 在贝尔实验室开发以来,已经经受住了四十多年的考验。

  • shell 的无缝集成

    兼容任何命令行工具。 只要能在命令行中完成的,都可以在 Makefile 中完成。 Makefile 可以作为项目级别的 alias 工具。

  • 编写简单 & 容易理解

    对于熟悉 shell 脚本的开发者而言,Makefile 编写简单,代码也很容易理解。

在项目中使用 Makefile

小型项目中使用

在小型项目中,Makefile 可以作为命令行快速执行工具,它具有如下优点:

  • 可靠的重现

  • 减轻人员的记忆负担

  • 减小需要输入的文字数量

  • 命令行自动补全功能

例如:

.PHONY: format
format:
	go    fmt path/to/go/code
	cargo fmt path/to/rust/code
	black     path/to/python/code
	npm   prettier --write path/to/javascript/code
	# 调用其他语言的 自动格式化 程序

.PHONY: build-prepare
build-prepare:
	# 构建环境准备 构建过程共享

.PHONY: build-dev
build-dev: build-prepare
	@echo "start dev build ..."
	# your build command here
	@echo "dev build done"

.PHONY: build-prod
build-prod: build-prepare
	@echo "start prod build ..."
	# your build command here
	@echo "prod build done"

.PHONY: build-feature-xxx
build-feature-xxx: build-prepare
	@echo "start feature xxx build ..."
	# your build command here
	@echo "feature xxx build done"

只需要在命令行输入 make format 即可完成整个项目代码的自动格式化。

根据不同的构建需要,使用不同的 make build-xxx 即可(无需记忆复杂的构建命令)。

备注

在需要更改编译选项、设置的时候,只需一个人更改提交到版本控制系统,其他人员直接同步即可。

大型项目中使用

在大型项目中,Makefile 通常需要分成多个模块(每个模块实现相应的功能):

例如:

.
├── Makefile
└── mk
    ├── build.mk
    ├── deploy.mk
    ├── doc.mk
    ├── help.mk
    └── install.mk

1 directory, 6 files

Makefile 引入其他的模块即可,

# Makefile entry

include mk/build.mk
include mk/deploy.mk
include mk/doc.mk
include mk/help.mk
include mk/install.mk

Makefile 小技巧

DEFAULT_GOAL

设置默认目标, 例如: .DEFAULT_GOAL := help, 直接执行 make 则相当于 make help

PHONY & FORCE

对于非编译的项目,通常目标都不是真实的文件(例如: make format 格式化代码), 这时候可以使用 PHONY 和 FORCE 联合来保证目标的执行。

FORCE:

.POHNY: format
format: FORCE
	@echo "代码格式化命令"

自定义过程

对于常用的一些固定流程,我们转换成过程供我们调用,例如:

.DEFAULT_GOAL := help

FORCE:

define my_info
	@echo "\033[0;32m$(1)\033[0m"
endef

define my_warn
	@echo "\033[0;33m$(1)\033[0m"
endef

define my_error
	@echo "\033[0;31m$(1)\033[0m"
endef

define run_cmd
	@echo
	$(eval @_CMD := $(1))
	$(call my_info,"$$ $(@_CMD)")
	@$(@_CMD)
endef

.PHONY: help
help: FORCE
	$(call my_info,"提示信息")
	$(call my_warn,"警告信息")
	$(call my_error,"错误信息")
	$(call run_cmd,ls)
	$(call run_cmd,ls -a)

执行 make 结果如下:

参考资料

0(1,2)

make 文档

1

CMake

2

make wikipedia