Go 项目使用 Makefile

2022-05-17 11:48:17 浏览数 (1)

01

介绍

Go 提供一个名为go的命令,该命令可自动下载、构建、安装和测试 Go 包和命令。

Go 提供go命令,官方的目的是为了不需要编写 Makefile,而是能够仅使用 Go 源代码本身中的信息来构建 Go 代码。

但是,我们在 Go 项目中也不需要完全摒弃使用 make 和 Makefile,可以使用 Makefile 的“伪目标”,简化使用 go 命令的复杂性,规范团队使用 go 命令的方式,提升个人或团队的生产力。

02

make 和 Makefile

make 命令行工具可以自动判断是否需要重新编译程序,实际上 make 不仅限于程序,我们可以使用它来描述任何任务,只要其他文件发生更改,某些文件就必须从其他文件自动更新。

在使用 make 命令行工具之前,我们需要编写一个名为 Makefile 的文件,该文件描述程序中文件之前的关系,并提供用于更新每个文件的命令。也就是说 Makefile 决定 make 做什么。

关于 Makefile 的介绍,感兴趣的读者朋友,可以查阅相关资料深入学习,本文仅介绍 Makefile 的规则(格式),如下所示:

代码语言:javascript复制
target ... : prerequisites ...
<Tab>command
    ...
    ...

代码语言:javascript复制
target ... : prerequisites ...;command

阅读上面示例代码,target 是目标文件,多个目标文件之间使用空格分隔,一般只有一个目标文件,也可以是“伪目标”(某个操作的名字);prerequisites 是先决条件;command 是“命令”,可以在 prerequisites 后面,使用分号分隔,也可以另起一行,但是必须以<Tab>开头,如果想要使用其他键,可以使用内置变量 .RECIPEPREFIX 声明。

target 目标是必须的,不可省略。prerequisites 和 command 是可选的,但是二者必须存在其一。

03

Go 项目使用 Makefile

在 Go 项目中使用 Makefile,一般我们只会使用“伪目标”,我们使用 go build 构建可执行文件为例,介绍 Go 项目怎么使用 Makefile。

示例代码:

代码语言:javascript复制
build:
  go build -o blog

阅读上面示例代码,我们编写一个简单的 Makefile,定义一个“伪目标” build,命令是 go build -o blog,构建名为 blog 的可执行文件。

使用 make 命令行工具,运行“伪目标”build。

代码语言:javascript复制
make build

运行 make build,终端打印出 Makefile 中“伪目标” build 的命令。

代码语言:javascript复制
go build -o blog

如果我们不想打印出执行的命令,可以在命令前面加上 @ 符号。

在实际项目开发时,我们可能需要构建多个操作系统的可执行文件,我们再编写一个 Makefile,新增三个“伪目标”,分别是windows、linux 和 darwin。

示例代码:

代码语言:javascript复制
APP=blog

build:
        @go build -o ${APP}
windows:
        @GOOS=windows go build -o ${APP}-windows
linux:
        @GOOS=linux go build -o ${APP}-linux
darwin:
        @GOOS=darwin go build -o ${APP}-darwin

阅读上面示例代码,我们定义一个自定义变量 APP,在命令行中使用 $(APP) 调用变量,并且 GOOS 指定操作系统,使用@开头,不再打印执行命令。

运行 make windowsmake linuxmake darwin,分别构建 windows、linux 和 drawin 操作系统的可执行文件。

运行结果如下:

代码语言:javascript复制
.
├── Makefile
├── blog
├── blog-darwin
├── blog-linux
├── blog-windows
├── go.mod
└── main.go

需要注意的是,如果有文件名和“伪目标”同名,那么该“伪目标”无法使用 make 命令执行指定的 command。因为 make 发现与“伪目标”同名的文件已存在,将不会再重新构建,所以就不会运行指定的 command,为了避免出现该问题,可以使用内置目标名.PHONY声明这些“伪目标”名是“伪目标”,而不是与“伪目标”同名的文件。

完整 Makefile 文件:

代码语言:javascript复制
APP=blog

.PHONY: help all build windows linux darwin

help:
        @echo "usage: make <option>"
        @echo "options and effects:"
        @echo "    help   : Show help"
        @echo "    all    : Build multiple binary of this project"
        @echo "    build  : Build the binary of this project for current platform"
        @echo "    windows: Build the windows binary of this project"
        @echo "    linux  : Build the linux binary of this project"
        @echo "    darwin : Build the darwin binary of this project"
all:build windows linux darwin
build:
        @go build -o ${APP}
windows:
        @GOOS=windows go build -o ${APP}-windows
linux:
        @GOOS=linux go build -o ${APP}-linux
darwin:
        @GOOS=darwin go build -o ${APP}-darwin

阅读上面示例代码,我们可以看到 Makefile 中第二个“伪目标” all,该目标只有 4 个先决条件,没有任何命令。执行 make all 命令,可以批量执行多个“伪目标”。该命令等同于以下命令:

代码语言:javascript复制
make build
make windows
make linux
make darwin

细心的读者朋友们阅读到此处,心中可能会有一个疑问,想要知道 Makefile 中包含哪些“目标”,必须查看 Makefile 文件吗?

不必如此,我们可以在 Makefile 中编写一个“伪目标” help,用于描述 Makefile 中的“伪目标”列表和使用示例等。

Make 命令运行时,如果不指定“目标”,默认执行 Makefile 文件的第一个“目标”。一般将 help 作为 Makefile 的第一个“伪目标”,我们可以执行 makemake help 命令,输出使用方法。

04

总结

本文我们介绍 make 和 Makefile 的使用方法,并且通过 go 命令中的 go build 介绍 Go 项目怎么使用 Makefile,大家可以举一反三,编写自己的 Go 项目 Makefile。

参考资料:

  1. https://en.wikipedia.org/wiki/Make_(software)
  2. https://www.gnu.org/software/make/manual/make.html#Introduction
  3. https://www.gnu.org/software/make/manual/make.html#Phony-Targets
  4. https://go.dev/doc/articles/go_command
  5. https://tutorialedge.net/golang/makefiles-for-go-developers/

0 人点赞