在这篇简短的文章中,我们将介绍如何将 Golang 与 Bazel 构建系统结合使用。
具体来说,我们将讨论三个场景:
从头开始一个 Golang 项目;
将一个现有的 Golang 项目转换为 Bazel 构建;
以及将一个第三方 Golang 项目引入到您的 Bazel 构建系统。
让我们从将 Go 与 Bazel 结合使用的基础知识开始。
为此,我们需要从 github.com/bazelbuild/… 获取 Go 语言的官方构建规则。
StarlarkWORKSPACE
1
2
3
4
5
6
7
8
9
10
11
12
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "io_bazel_rules_go",
sha256 = "8e968b5fcea1d2d64071872b12737bbb5514524ee5f0a4f54f5920266c261acb",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.28.0/rules_go-v0.28.0.zip",
"https://github.com/bazelbuild/rules_go/releases/download/v0.28.0/rules_go-v0.28.0.zip",
],
)
load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")
go_rules_dependencies()
go_register_toolchains(version = "1.16.5")
让我们逐步了解这段代码所做的事情。
loadload
/._github.com/user/projectcom_github_user_projectio_bazel_rules_gobazel.iogithub.com
BUILDgo_binarygo_librarygo_testio_bazel_rules_goBUILD
将现有项目转换为 Bazel 构建Gazelle
为了演示,我将使用一个第三方项目 ( github.com/aler9/rtsp-… ),我目前正在为即将到来的系统设计课程修改该项目。
WORKSPACEGazelle
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "io_bazel_rules_go",
sha256 = "8e968b5fcea1d2d64071872b12737bbb5514524ee5f0a4f54f5920266c261acb",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.28.0/rules_go-v0.28.0.zip",
"https://github.com/bazelbuild/rules_go/releases/download/v0.28.0/rules_go-v0.28.0.zip",
],
)
http_archive(
name = "bazel_gazelle",
sha256 = "62ca106be173579c0a167deb23358fdfe71ffa1e4cfdddf5582af26520f1c66f",
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.23.0/bazel-gazelle-v0.23.0.tar.gz",
"https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.23.0/bazel-gazelle-v0.23.0.tar.gz",
],
)
load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")
load("@bazel_gazelle//:deps.bzl", "gazelle_dependencies")
go_rules_dependencies()
go_register_toolchains(version = "1.16.5")
gazelle_dependencies()
您会注意到,上述代码也导入了上一节中所提到的规则。
BUILD
1
2
3
load("@bazel_gazelle//:def.bzl", "gazelle")
# gazelle:prefix github.com/aler9/rtsp-simple-server
gazelle(name = "gazelle")
gazelle:prefixmain.go
1
2
3
4
import(
"os"
"github.com/aler9/rtsp-simple-server/internal/core"
)
BUILD
1
bazel run //:gazelle
BUILD
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
git status
On branch main
Your branch is up to date with 'origin/main'.
Untracked files:
(use "git add ..."to include in what will be committed)
BUILD
WORKSPACE
bazel-bin
bazel-out
bazel-test
bazel-testlogs
internal/aac/BUILD.bazel
internal/conf/BUILD.bazel
internal/confenv/BUILD.bazel
internal/confwatcher/BUILD.bazel
internal/core/BUILD.bazel
internal/externalcmd/BUILD.bazel
internal/h264/BUILD.bazel
internal/hls/BUILD.bazel
internal/logger/BUILD.bazel
internal/rlimit/BUILD.bazel
internal/rtcpsenderset/BUILD.bazel
internal/rtmp/BUILD.bazel
nothing added to commit but untracked files present (use "git add"to track)
bazel build //...to_macro
1
bazel run //:gazelle -- update-repos -from_file=go.mod -to_macro=deps.bzl%go_dependencies
deps.bzlWORKSPACErepository_macroto_macro
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
load("@bazel_gazelle//:deps.bzl", "go_repository")
def go_dependencies():
go_repository(
name = "com_github_alecthomas_template",
importpath = "github.com/alecthomas/template",
sum = "h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=",
version = "v0.0.0-20190718012654-fb15b899a751",
)
go_repository(
name = "com_github_alecthomas_units",
importpath = "github.com/alecthomas/units",
sum = "h1:UQZhZ2O0vMHr2cI+DC1Mbh0TJxzA3RcLoMsFw+aXw7E=",
version = "v0.0.0-20190924025748-f65c72e2690d",
)
go_repository(
name = "com_github_aler9_gortsplib",
importpath = "github.com/aler9/gortsplib",
sum = "h1:Bf0hzdN1jUWsb5Mzezq1pd18EIBeKXxk5clIpHZJ1Lk=",
version = "v0.0.0-20210724151831-dae5a1f04033",
)
go_repository(
...
org_golang_x_toolsdeps.bzlrtsp-simple-server
您可以在后续继续使用 Gazelle 来管理依赖项,这也是您可以将代码库引入基于 Bazel 的项目而无需实际转换它的方法:
1
bazel run //:gazelle -- update-repos github.com/some/repo
密封测试(Hermetic tests)您可能会遇到的最后一个问题是密封测试。如果您看到测试因访问被拒绝、文件未找到或操作不允许失败而失败,那是因为 Bazel 强制执行密封测试。这意味着每个测试都必须完全独立并且独立于任何其他测试。
对于单元测试,任何文件都需要作为测试的依赖项提供并通过运行文件机制访问(github.com/bazelbuild/…)。
TEST_TMPDIRos.TempDir()
密封集成和系统测试需要从一开始就仔细设计,因此转换现有的此类测试可能很棘手。遗憾的是,我在这里没有放之四海而皆准的建议。
虽然将您的测试转换为密封测试可能很烦人,但这是一项值得的努力,它将为您带来更好的测试可重复性和更低的易碎性。