使用Make编辑Go程序

342 阅读3分钟

golang除了用内置了很多 go commands 可以帮助我们完成go每个阶段的开发工作之外,我们还可以借助GUN的Make做构建。

GUN和 MAKE工具是Linux 和 Unix 系统中一种常见的自动化构建工具,通常用于管理和组织软件项目。在 Go 语言中,使用 MAKE 工具可以轻松地管理和构建项目,并自动执行诸如编译、测试、安装等复杂的操作。

MAKE 工具最大的优势在于它可以根据指定的规则来自动执行一系列的任务,从而减少了手动操作的时间和错误率。在 Go 项目中,使用 MAKE 工具可以帮助开发人员完成以下工作:

  • 编译和构建:MAKE工具可根据指定的规则自动编译和构建Go项目,生成可执行文件或库文件。
  • 测试和检查:MAKE工具可自动运行项目中的单元测试、性能测试和代码检查,以确保项目质量和可靠性。
  • 安装和部署:MAKE工具可将编译好的程序或库文件自动安装到系统中,并实现自动部署。
  • 清理和卸载:MAKE工具可清除编译过程中生成的临时文件,卸载已安装的程序或库文件。

一、安装

on Linux

yum install -y make

on mac

如果你是mac的系统,系统是自带了的,如果是linux就需要自己安装下make,命令很简单。

on windows

常规的做法,大家都是使用安装MinGW包的方法来安装Make,但是这很繁琐,我并不推荐,我推荐使用ChocoScoop来安装管理Make。

Choco方法
  1. PowerShell安装Choco
Set-ExecutionPolicy Bypass -Scope Process -Force; 
iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
  1. 管理员权限启动PowerShell,然后运行以下命令进行安装:
choco install make

# choco 安装其他有用的工具
choco install grep gawk sed touch
choco install mingw

windows下的包管理器

  1. choco
  2. scoop
  3. winget

二、简易入门

  1. 初始化工程
go mod init myproj
  1. 在根目录下创建文件main.go与Makefile
————————
| - ...
| - main.go
| - Makefile
|

Makefile内容如下

BINARY_NAME=App
run:
    go build -o bin/$(BINARY_NAME) -v
    ./bin/$(BINARY_NAME)

说明:

  • 第1行,声明了一个变量BINARY_NAME他的值是App,方便后面使用
  • 第2行,声明一个 target,其实你可以理解成一个对外的方法
  • 第3行,这就是这个target被调用时执行的脚本,这行就是build这个项目,编译后的二进制文件放在当前工程根目录下的bin目录下,名字是变量BINARY_NAME的值
  • 第4行,这一行就是直接执行当前bin目录下的二进制文件

main.go里面的源码如下:

package main
import "fmt"

func main() {
    fmt.Println("看到我了")
}

  1. 开始构建
make build #构建
# make install 
make run #运行

make run #运行结果

image.png

三、使用详解

Makefile语法分析

PROJECT="example"

default:
    echo ${PROJECT}

install:
    @govendor sync -v

test: install
    @go test ./...

.PHONY: default install test

上述文件配置  make , make installmake test 等就能完成对应的命令。

语法说明

<target> : <prerequisites> 
      <commands> 
  • target : 即自定义的想要执行的命令, 比如 install,test 等
  • prerequisites: 前置条件,即执行 target 命令之前执行的命令
  • commands : 具体的执行的命令 ([tab]是指tab键空 格)
    • 不带参数,默认执行第一个 target
    • @ 表示禁止回声,即终端不会打印真实的执行命令
    • # 表示注释
    • ${val} 表示变量,和 shell 脚本中的变量的声明和使用一致
    • 允许使用 通配符 .PHONY 伪指令,内置的关键字

GO项目中完整的Makefile

Go 中支持内置的 go 命令,可以用来执行:测试、编译、运行、语法检查等命令

Go 项目经常会执行如下命令

  • go vet 静态检查
  • go test 运行单元测试
  • go fmt 格式化
  • go build 编译
  • go run 运行 ...

适用于Go 项目的 Makefile命令

  • make default : 编译
  • make fmt: 格式化
  • make vet: 静态检查
  • make test: 运行测试
  • make install: 下载依赖库
  • make clean: 移除编译的二进制文件

对应的Makefile的文件内容如下

BINARY="example"
VERSION=1.0.0
BUILD=`date +%FT%T%z`

PACKAGES=`go list ./... | grep -v /vendor/`
VETPACKAGES=`go list ./... | grep -v /vendor/ | grep -v /examples/`
GOFILES=`find . -name "*.go" -type f -not -path "./vendor/*"`

default:
    @go build -o ${BINARY} -tags=jsoniter

list:
    @echo ${PACKAGES}
    @echo ${VETPACKAGES}
    @echo ${GOFILES}

fmt:
    @gofmt -s -w ${GOFILES}

fmt-check:
    @diff=?(gofmt -s -d $(GOFILES)); \
    if [ -n "$$diff" ]; then \
        echo "Please run 'make fmt' and commit the result:"; \
        echo "$${diff}"; \
        exit 1; \
    fi;

install:
    @govendor sync -v

test:
    @go test -cpu=1,2,4 -v -tags integration ./...

vet:
    @go vet $(VETPACKAGES)

docker:
    @docker build -t wuxiaoxiaoshen/example:latest .

clean:
    @if [ -f ${BINARY} ] ; then rm ${BINARY} ; fi

.PHONY: default fmt fmt-check install test vet docker clean

配合CICD使用的Makefile

language: go
go:
  - "1.11"
  - "1.11.x"
env:
  - GO111MODULE=on
notifications:
  email:
    recipients:
      - wuxiaoshen@shu.edu.cn
    on_success: change # default: change
    on_failure: always # default: always

before_install:
  - go test -cpu=1,2,4 -v -tags integration ./...
  - go vet $(go list ./... | grep -v /vendor/)

script:
  - make fmt
  - make fmt-check
  - make vet
  - make list  
  - go test -race  ./... -coverprofile=coverage.txt -covermode=atomic

Makefile函数

word函数

作用:取字符串text中第n个单词(从1开始),如果n比text中的单词数要大,那么返回空字符串。

$(word <n>,<text> )

如:
$(word 1,$(MAKEFILE_LIST))

words函数

作用:统计text中字符串中的单词个数。

$(words <text> )

如:
$(words $(MAKEFILE_LIST))

firstword函数

作用:返回text中字符串中的第一个单词。

$firstword <text> )

 如
$(firstword $(MAKEFILE_LIST))

4.lastword函数

作用:返回text中字符串中的最后一个单词。

$(lastword <text>)$(lastword $(MAKEFILE_LIST))

abspath

将相对路径转为绝对路径

$(abspath NAME...)
# NAME... 一个或多个文件的路径

# 获取当前Makefile文件所在的路径 
MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) 
CURRENT_DIR := $(dir $(MAKEFILE_PATH)) 
 
# 使用当前路径 
$(info Current directory is $(CURRENT_DIR)) 
  • $(lastword $(MAKEFILE_LIST)):获取当前Makefile文件的名称。
  • $(abspath):将相对路径转换为绝对路径。
  • 使用$(dir)函数从路径中提取目录部分。
  • 使用$(info)函数输出当前路径。
  • 注意$(MAKEFILE_PATH)$(CURRENT_DIR)都是Makefile变量,可以在Makefile中的任何地方使用。

origin

函数的作用是告诉你变量是哪里来的,其出生状况如何,他并不改变变量。函数语法:

$(origin )  

为变量的名字,而不是引用,所以一般没有"$"字符在前。

  • 普通变量
@echo $(origin V)
$ make  
 输出:undefined

  • 环境变量
 @echo $(origin USER)
 
$ make  
输出:environment  
其中 USER 这个变量为系统定义的当前用户,使用 env 命令可以看到。

  • 如果变量是个默认定义,那么返回 "default"
如下面的 Makefile 代码:  
all:  
@echo $(origin CC)

--
运行输出:  
$ make  
default
  • 如果一个变量被定义在 Makefile 文件中,那么返回 "file"
V := 1  
all:  
@echo $(origin V)

--
运行输出:  
$ make  
file
  • 如果变量来自命令行,那么返回 "command line"
all:  
@echo $(origin MyVar)

--
运行方法:  
$ make MyVar="Are you ok?"  
command line
  • 如果变量被 override 被重新定义过,那么返回 "override"
override SHELL = /bin/sh
all:
@echo $(origin SHELL)

---
运行输出:
$ make
override

上面,SHELL 原本是个环境变量,但在 Makefile 里被 override 指示符重定义过。

如果变量是自动化变量(如 @,@,< 等),那么返回 "automatic"

all:  
@echo $(origin @)

--
运行输出:  
$ make  
automatic

shell函数

shell函数也不像其它的函数。顾名思义,它的参数应该就是操作系统Shell的命令。

contents := $(shell cat foo)  
files := $(shell echo *.c)