# 3.19 请入门 Makefile

项目地址：<https://github.com/EDDYCJY/go-gin-example>

## 知识点

* 写一个 Makefile

## 本文目标

含一定复杂度的软件工程，基本上都是先编译 A，再依赖 B，再编译 C...，最后才执行构建。如果每次都人为编排，又或是每新来一个同事就问你项目 D 怎么构建、重新构建需要注意什么...等等情况，岂不是要崩溃？

我们常常会在开源项目中发现 Makefile，你是否有过疑问？

本章节会简单介绍 Makefile 的使用方式，最后建议深入学习。

## 怎么解决

对于构建编排，Docker 有 Dockerfile ，在 Unix 中有神器 [Make](https://en.wikipedia.org/wiki/Make_%28software%29) ....

## Make

### 是什么

Make 是一个构建自动化工具，会在当前目录下寻找 Makefile 或 makefile 文件。如果存在，会依据 Makefile 的**构建规则**去完成构建

当然了，实际上 Makefile 内都是你根据 make 语法规则，自己编写的特定 Shell 命令等

它是一个工具，规则也很简单。在支持的范围内，编译 A， 依赖 B，再编译 C，完全没问题

### 规则

Makefile 由多条规则组成，每条规则都以一个 target（目标）开头，后跟一个 : 冒号，冒号后是这一个目标的 prerequisites（前置条件）

紧接着新的一行，必须以一个 tab 作为开头，后面跟随 command（命令），也就是你希望这一个 target 所执行的构建命令

```
[target] ... : [prerequisites] ...
<tab>[command]
    ...
    ...
```

* target：一个目标代表一条规则，可以是一个或多个文件名。也可以是某个操作的名字（标签），称为**伪目标（phony）**
* prerequisites：前置条件，这一项是**可选参数**。通常是多个文件名、伪目标。它的作用是 target 是否需要重新构建的标准，如果前置条件不存在或有过更新（文件的最后一次修改时间）则认为 target 需要重新构建
* command：构建这一个 target 的具体命令集

### 简单的例子

本文将以 [go-gin-example](https://github.com/EDDYCJY/go-gin-example) 去编写 Makefile 文件，请跨入 make 的大门

#### 分析

在编写 Makefile 前，需要先分析构建先后顺序、依赖项，需要解决的问题等

#### 编写

```
.PHONY: build clean tool lint help

all: build

build:
    go build -v .

tool:
    go tool vet . |& grep -v vendor; true
    gofmt -w .

lint:
    golint ./...

clean:
    rm -rf go-gin-example
    go clean -i .

help:
    @echo "make: compile packages and dependencies"
    @echo "make tool: run specified go tool"
    @echo "make lint: golint ./..."
    @echo "make clean: remove object files and cached files"
```

1、在上述文件中，使用了 `.PHONY`，其作用是声明 build / clean / tool / lint / help 为**伪目标**，声明为伪目标会怎么样呢？

* 声明为伪目标后：在执行对应的命令时，make 就不会去检查是否存在 build / clean / tool / lint / help 其对应的文件，而是每次都会运行标签对应的命令
* 若不声明：恰好存在对应的文件，则 make 将会认为 xx 文件已存在，没有重新构建的必要了

2、这块比较简单，在命令行执行即可看见效果，实现了以下功能：

1. make: make 就是 make all
2. make build: 编译当前项目的包和依赖项
3. make tool: 运行指定的 Go 工具集
4. make lint: golint 一下
5. make clean: 删除对象文件和缓存文件
6. make help: help

#### 为什么会打印执行的命令

如果你实际操作过，可能会有疑问。明明只是执行命令，为什么会打印到标准输出上了？

**原因**

make 默认会打印每条命令，再执行。这个行为被定义为**回声**

**解决**

可以在对应命令前加上 @，可指定该命令不被打印到标准输出上

```
build:
    @go build -v .
```

那么还有其他的特殊符号吗？有的，请课后去了解下 +、- 的用途 🤩

## 小结

这是一篇比较简洁的文章，希望可以让您对 Makefile 有一个基本了解。

## 参考

### 本系列示例代码

* [go-gin-example](https://github.com/EDDYCJY/go-gin-example)

## 关于

### 修改记录

* 第一版：2018年02月16日发布文章
* 第二版：2019年10月01日修改文章

## ？

如果有任何疑问或错误，欢迎在 [issues](https://github.com/EDDYCJY/blog) 进行提问或给予修正意见，如果喜欢或对你有所帮助，欢迎 Star，对作者是一种鼓励和推进。

### 我的公众号

![image](https://image.eddycjy.com/8d0b0c3a11e74efd5fdfd7910257e70b.jpg)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://eddycjy.gitbook.io/golang/di-3-ke-gin/makefile.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
