Golang Makefile示例深入讲解使用

 更新时间:2023年01月12日 10:35:53   作者:梦想画家  
一次偶然的机会,在 github 上看到有人用 Makefile,就尝试了一下,发现真的非常合适,Makefile 本身就是用来描述依赖的,可读性非常好,而且与强大的 shell 结合在一起,基本可以实现任何想要的功能

Makefile提供有效方式实现自动化构建任务,与Java中的Maven类似。Makefile主要应用场景为使用目标(标签)运行不同任务。

需要提醒的是,make工具仅在unix环境上使用,如果是windows,需要安装Linux环境依赖(如:mingw)执行make命令。

从入门示例开始

假设我们有一个main.go程序,构建文件需要使用命令:

go build main.go

运行程序使用命令为:

go build -o main.out main.go
./main.out

下面使用单个Makefile文件(文件命名为Makefile,首字母大写,没有扩展名),内容如下:

BINARY_NAME=main.out
build:
    go build -o ${BINARY_NAME} main.go
run:
    go build -o ${BINARY_NAME} main.go
    ./${BINARY_NAME}
clean:
    go clean
    rm ${BINARY_NAME}

现在可以运行build 和 run 任务:

make build
make run

如果需要增加缺省标签,可以使用all标签:

BINARY_NAME=main.out

## 缺省任务,不要换行
all: build test
build:
    go build -o ${BINARY_NAME} main.go
test:
    go test -v main.go
run:
    go build -o ${BINARY_NAME} main.go
    ./${BINARY_NAME}
clean:
    go clean
    rm ${BINARY_NAME}

这时直接运行make命令,则执行build test两个任务。当然我们还可以定义其他复杂任务,假如项目有多个依赖,需要通过go get package-name 命令安装,我们可以定义deps目标,实现自动安装所有相关依赖,举例:

deps:
    go get github.com/gorilla/websocket

运行命令:make deps 则自动安装相关依赖。

makefile语法详解

通过上面简单示例大概了解Makefile的用途,下面介绍其基本语法,首先介绍几个术语:目标、依赖、任务以及变量。

  • 目标(Target): Targets 是Makefile中的主要组件. make命令通过目标的名称执行任务。上面示例中的 build, run, and build_and_clean称为目标,目标是具体执行具体任务的接口。
  • 依赖(Dependencies): 目标可以包括依赖任务,在运行当前目标之前执行的目标为依赖目标。举例,build_and_clean 有两个依赖: build run。 注意,依赖不要换行写,和目标在一行。
  • 任务(Recipe): Recipe是运行目标时实际执行的一条或多条命令。如果是多个命令,则每条命令需为单独一行,且每条命令前使用tab进行缩进,不是空格。
  • 变量(Variables): 大多数脚本都支持变量,Makefile也支持变量,当在不同目标中使用相同配置时,使用变量可以让脚本更通用、以维护。定义变量使用等号:variable_name=hello-world, 引用变量使用${variable_name}

变量举例:

x = foo
y = $(x) bar
x = later
all:
    echo $(y)

这里all为默认目标,执行make命令输出结果:

echo later bar
later bar

再来一个完整示例

下面我们通过稍微复杂的示例来说明Makefile的用法,go代码很简单,但需要编译不同平台的可执行文件。首先定义main.go文件:

package main
import "fmt"
func main() {
 fmt.Println("hello world")
}

要运行项目,正常需要构建并运行二进制文件:

go build main.go

如果需要指定操作系统及输出文件,下面是mac平台:

GOARCH=amd64 GOOS=darwin go build -o hello-world main.go

如果希望创建多个OS平台,需要运行多次命令:

GOARCH=amd64 GOOS=darwin go build -o hello-world-darwin main.go
GOARCH=amd64 GOOS=linux go build -o hello-world-linux main.go
GOARCH=amd64 GOOS=window go build -o hello-world-windows main.go

上面命令可以使用Makefile,在项目根目录下创建Makefile文件:

BINARY_NAME=hello-world
build:
    GOARCH=amd64 GOOS=darwin go build -o ${BINARY_NAME}-darwin main.go
    GOARCH=amd64 GOOS=linux go build -o ${BINARY_NAME}-linux main.go
    GOARCH=amd64 GOOS=window go build -o ${BINARY_NAME}-windows main.go
run:
    ./${BINARY_NAME}
build_and_run: build run
clean:
    go clean
    rm ${BINARY_NAME}-darwin
    rm ${BINARY_NAME}-linux
    rm ${BINARY_NAME}-windows

现在可以简单运行make命令:

make run
make build

也可以运行组合命令:

make build_and_run

最后还可以运行清理命令:

make clean

这些命令非常方便,有助于开发过程流水线。开发团队成员可以使用相同命令,减少操作不一致造成错误,提升构建效率。

下面扩展上面的示例,增加一些自动化任务,包括测试、覆盖率测试、代码检查以及管理依赖。具体内容如下:

BINARY_NAME=hello-world
build:
    GOARCH=amd64 GOOS=darwin go build -o ${BINARY_NAME}-darwin main.go
    GOARCH=amd64 GOOS=linux go build -o ${BINARY_NAME}-linux main.go
    GOARCH=amd64 GOOS=window go build -o ${BINARY_NAME}-windows main.go
run:
    ./${BINARY_NAME}
build_and_run: build run
clean:
    go clean
    rm ${BINARY_NAME}-darwin
    rm ${BINARY_NAME}-linux
    rm ${BINARY_NAME}-windows
test:
    go test ./...
test_coverage:
    go test ./... -coverprofile=coverage.out
dep:
    go mod download
vet:
    go vet
lint:
    golangci-lint run --enable-all

现在可以简单执行下列任务:

make test
make test_coverage
make dep
make vet
make lint

注意:我们使用了外部包golangci-lint,需要使用 go mod ,确保在go.mod文件中增加相应依赖。

总结

Golang是开发大型项目的流行语言。较大的项目会有多人协作,并且需要持续的自动化构建。通过自动化开发、测试和发布等任务来简化构建过程,会带来更快、更可靠、更简单的开发体验。

到此这篇关于Golang Makefile示例深入讲解使用的文章就介绍到这了,更多相关Go Makefile内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • golang validator库参数校验实用技巧干货

    golang validator库参数校验实用技巧干货

    这篇文章主要为大家介绍了validator库参数校验实用技巧干货,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步早日升职加薪
    2022-04-04
  • Go使用sync.Pool提高性能的代码示例

    Go使用sync.Pool提高性能的代码示例

    在高性能应用程序中,频繁的内存分配和回收是性能瓶颈的常见原因之一,Go 语言提供了 sync.Pool 类型,它可以用来存储和重用临时对象,本文将详细介绍如何在 Go 中使用 sync.Pool,并通过实际代码示例来展示其对性能的提升效果,需要的朋友可以参考下
    2024-04-04
  • go如何删除字符串中的部分字符

    go如何删除字符串中的部分字符

    这篇文章主要介绍了go删除字符串中的部分字符操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-04-04
  • golang 实现时间滑动窗口的示例代码

    golang 实现时间滑动窗口的示例代码

    滑动时间窗口就是把一段时间片分为多个样本窗口,可以通过更细粒度对数据进行统计,这篇文章主要介绍了golang 实现时间滑动窗口,需要的朋友可以参考下
    2022-10-10
  • Go语言中的反射原理解析与应用

    Go语言中的反射原理解析与应用

    反射(Reflection)是计算机科学中的一个重要概念,它允许程序在运行时检查变量和值,获取它们的类型信息,并且能够修改它们,本文将结合实际案例,详细介绍Go语言中反射的基本概念、关键函数以及使用场景,需要的朋友可以参考下
    2024-10-10
  • 基于Go语言实现类似tree命令的小程序

    基于Go语言实现类似tree命令的小程序

    tree 命令是一个小型的跨平台命令行程序,用于递归地以树状格式列出或显示目录的内容。本文将通过Go语言实现类似tree命令的小程序,需要的可以参考一下
    2022-10-10
  • Go 实现基于Token 的登录流程深度分析

    Go 实现基于Token 的登录流程深度分析

    Token 认证机制的核心思想是,服务端在用户登录时生成一个 Token,客户端在后续的请求中携带这个 Token,服务端通过验证 Token 的有效性来确认用户的身份,本文将带你深入探索基于 Token 的登录流程,这是一种更为灵活且适用于现代应用架构的认证方式
    2024-03-03
  • 详解Go中Set的实现方式

    详解Go中Set的实现方式

    这篇文章主要介绍了详解Go中Set的实现方式,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-09-09
  • GO语言类型查询类型断言示例解析

    GO语言类型查询类型断言示例解析

    这篇文章主要为大家介绍了GO语言类型判断及类型断言,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步早日升职加薪
    2022-04-04
  • go的defer和闭包示例说明(非内部实现)

    go的defer和闭包示例说明(非内部实现)

    这篇文章主要为大家介绍了go的defer和闭包示例说明(非内部实现),有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-08-08

最新评论