• 1 `rules_go` 与 `gazelle`

  • 2 `go build` 到 `bazel build`

    • 2.1 初始化 Bazel 构建

    • 2.2 编译 Go 项目

    • 2.3 测试编译结果

    • 2.4 Go 环境变量设置

  • 3 我们需要 `go build` 到 `bazel build`?

rules_gogazelle
BazelShellObjective-CC++Javash_binarycc_binarycc_importcc_libraryjava_binaryjava_importGoBazelGogo_binarygo_librarygo_testBazelGoGoBazelBUILD.bazelgo.modgo_repositoryrules_gogazelle
rules_go
  • 构建库、二进制可执行文件、测试(go_library、go_binary、go_test)
  • Vendoring
  • cgo
  • 交叉编译
  • 通过 nogo [3] 进行构建时代码分析
  • Protocol buffers
    • proto_library
    • go_proto_library
    • go_proto_compiler
  • 远程执行
rules_go
cgoC/C++Gorules_go
gazelle
gazelleGoGo
$ gazelle -go_prefix github.com/example/project

# Add or update a repository to latest version by import path
$ gazelle update-repos example.com/new/repo

# Add or update a repository to specified version/commit by import path
$ gazelle update-repos example.com/new/repo@v1.3.1

# 从 go.mod 导入存储库,修改和更新 Bazel 宏
$ gazelle update-repos -from_file=go.mod -to_macro=repositories.bzl%go_repositories

# 设为-prune=true时,gazelle 将删除 Gopkg.lock/go.mod 文件中不再具有等效存储库的 go_repository 规则
$ gazelle update-repos -prune=true -from_file=go.mod -to_macro=repositories.bzl%go_repositories
gazelle# gazelle:{key} {value}
gazelleBazelWORKSPACE
http_archive(
name = "bazel_gazelle",
sha256 = "cdb02a887a7187ea4d5a27452311a75ed8637379a1287d8eeb952138ea485f7d",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.21.1/bazel-gazelle-v0.21.1.tar.gz",
"https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.21.1/bazel-gazelle-v0.21.1.tar.gz",
],
)

load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies")

gazelle_dependencies()
GoBUILDBUILD.bazel
load("@bazel_gazelle//:def.bzl", "gazelle")

# gazelle:prefix github.com/example/project
gazelle(name = "gazelle")
gazelleGo
load("@bazel_gazelle//:def.bzl", "gazelle")

# 建议是以注释方式也保留,Go 工具方式和 Bazel 方式都可以使用
# gazelle:prefix github.com/example/project
gazelle(
    name = "gazelle",
    prefix = "github.com/example/project",
)
go.mod
# 自动添加一个外部依赖项目(非 go.mod 导入)
$ bazel run tools/cli:gazelle update-repos {repo-uri}

# 生成 BUILD.bazel 文件
$ bazel run tools/cli:gazelle
# 生成的依赖仓库下载代码自动生成到 go_repositories.bzl 文件中,然后自动生成导入代码到 WORKSPACE 文件中
$ bazel run tools/cli:gazelle -- update-repos -from_file=tools/cli/go.mod -to_macro=go_repositories.bzl%go_repositories
go buildbazel build

2.1 初始化 Bazel 构建

WORKSPACEBUILDrules_gogazelle
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

# download rules_go
http_archive(
    name = "io_bazel_rules_go",
    sha256 = "8663604808d2738dc615a2c3eb70eba54a9a982089dd09f6ffe5d0e75771bc4f",
    urls = [
        "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.23.6/rules_go-v0.23.6.tar.gz",
        "https://github.com/bazelbuild/rules_go/releases/download/v0.23.6/rules_go-v0.23.6.tar.gz",
    ],
)

# load rules_go
load("@io_bazel_rules_go//go:deps.bzl", "go_rules_dependencies", "go_register_toolchains")

go_rules_dependencies()

go_register_toolchains()

# download gazelle
http_archive(
    name = "bazel_gazelle",
    sha256 = "cdb02a887a7187ea4d5a27452311a75ed8637379a1287d8eeb952138ea485f7d",
    urls = [
        "https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.21.1/bazel-gazelle-v0.21.1.tar.gz",
        "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.21.1/bazel-gazelle-v0.21.1.tar.gz",
    ],
)

# load gazelle
load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies", "go_repository")

gazelle_dependencies()
Gotools/cliGogo.mod
.
├── BUILD
├── WORKSPACE
└── tools
    └── cli
        ├── BUILD
        ├── go.mod
        └── cmd
            └── ota_packer
                └── main.go
tools/cli/BUILDgazelle
load("@bazel_gazelle//:def.bzl", "gazelle")

# gazelle:prefix github.com/yicm/OtaPackageTool
gazelle(
    name = "gazelle",
    prefix = "github.com/yicm/OtaPackageTool",

GogazelleBUILD.bazel
# 根据 go.mod,将go_repository规则写入一个单独的宏文件并将其加载到 WORKSPACE 文件中
$ bazel run tools/cli:gazelle -- update-repos -from_file=tools/cli/go.mod -to_macro=go_repositories.bzl%go_repositories
# 生成包的 BUILD.bazel 文件
$ bazel run tools/cli:gazelle
tools/cli/cmd/ota_packerBUILD.bazel
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")

go_library(
    name = "go_default_library",
    srcs = ["main.go"],
    importpath = "github.com/yicm/OtaPackageTool/cmd/ota_packer",
    visibility = ["//visibility:private"],
)

go_binary(
    name = "ota_packer",
    embed = [":go_default_library"],
    visibility = ["//visibility:public"],
)
ota_packergo_repositories.bzlgo_repositories
go_repositories.bzl
load("@bazel_gazelle//:deps.bzl", "go_repository")

def go_repositories():
    go_repository(
        name = "co_honnef_go_tools",
        importpath = "honnef.co/go/tools",
        sum = "h1:3JgtbtFHMiCmsznwGVTUWbgGov+pVqnlf1dEJTNAXeM=",
        version = "v0.0.1-2019.2.3",
    )
    ......
WORKSPACE
......

load("//:go_repositories.bzl", "go_repositories")

# gazelle:repository_macro go_repositories.bzl%go_repositories
go_repositories()

2.2 编译 Go 项目

rules_gogazelleGoBazelGoBazel
# 构建 ota_packer 目标
$ bazel build tools/cli/cmd/ota_packer:ota_packer
# 构建项目下所有目标
$ bazel build //...

2.3 测试编译结果

$ bazel run tools/cli/cmd/ota_packer:ota_packer

2.4 Go 环境变量设置

--action_envactionsGo
--action_env=GOPROXY=https://goproxy.cn
.bazelrcbuildtestrun
build --action_env=GOPROXY=https://goproxy.cn
test  --action_env=GOPROXY=https://goproxy.cn
run   --action_env=GOPROXY=https://goproxy.cn
go buildbazel build

Bazel Go 规则集,可以让我们很方便地管理 Go 工具链和外部库,而无需依赖于本地安装的库。Bazel 地官方项目 Gazelle,可以用来生成 Go 和 Protocol Buffers 规则。借助 Gazelle,能够以最少的人工输入为 Go 项目中的大多数 Go 软件包生成 Bazel 规则。

Bazel 本身具有的构建特性包括分布式缓存和构建、增量构建,只有当我们的工程代码发生改变或某些依赖发生变化时,才会触发构建并更新缓存,从而对大型项目可以实现快速构建。且 Bazel 的沙箱特性,保证每个开发者的构建环境一致。

GoGo ModulesBazel Go Rulesgo build
go buildbazel build

参考资料

rules_gogazelle