邮件列表:bazel-go-discuss
Slack:#go on Bazel Slack,#bazel on Go Slack
该规则正处于开发测试阶段。他们支持:
他们目前不支持或支持有限:
Go 规则在以下主机平台上经过测试并受支持:
用户已报告在其他几个平台上取得了成功,但这些规则仅在上面列出的平台上进行了测试。
注意:从 v0.38.0 版本开始,rules_go 需要 Bazel ≥ 5.4.0 才能工作。
master
分支仅保证与最新版本的 Bazel 配合使用。
要使用 Bazel 构建 Go 代码,您将需要:
patch
、 cat
和PATH
中的一些其他 Unix 工具。您通常不需要安装 Go 工具链。 Bazel 将下载一个。
有关特定于 Windows 的设置说明,请参阅在 Windows 上使用 Rules_go。需要安装和配置几个附加工具。
如果您使用 Bazel 的新外部依赖管理系统 Bzlmod,请参阅专用的 Go with Bzlmod 指南。
在存储库顶部创建一个名为WORKSPACE
的文件,然后添加下面的代码片段(或添加到现有的WORKSPACE
中)。这告诉 Bazel 获取rules_go 及其依赖项。 Bazel 将下载最新支持的 Go 工具链并注册使用。
load ( "@bazel_tools//tools/build_defs/repo:http.bzl" , "http_archive" )
http_archive (
name = "io_bazel_rules_go" ,
integrity = "sha256-M6zErg9wUC20uJPJ/B3Xqb+ZjCPn/yxFF3QdQEmpdvg=" ,
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.48.0/rules_go-v0.48.0.zip" ,
"https://github.com/bazelbuild/rules_go/releases/download/v0.48.0/rules_go-v0.48.0.zip" ,
],
)
load ( "@io_bazel_rules_go//go:deps.bzl" , "go_register_toolchains" , "go_rules_dependencies" )
go_rules_dependencies ()
go_register_toolchains ( version = "1.23.1" )
您可以通过使用 git_repository 而不是 http_archive 并指向最近的提交来在master
上使用rules_go。
在项目的根目录中添加名为BUILD.bazel
的文件。您需要在每个包含 Go 代码的目录中都有一个构建文件,但在根目录中也需要一个构建文件,即使您的项目那里没有 Go 代码。对于“Hello, world”二进制文件,该文件应如下所示:
load ( "@io_bazel_rules_go//go:def.bzl" , "go_binary" )
go_binary (
name = "hello" ,
srcs = [ "hello.go" ],
)
您可以使用bazel build //:hello
构建此目标。
如果您的项目可以使用go build
构建,那么您可以使用瞪羚自动生成和更新构建文件。
将bazel_gazelle
存储库及其依赖项添加到您的WORKSPACE
。它应该看起来像这样:
load ( "@bazel_tools//tools/build_defs/repo:http.bzl" , "http_archive" ) http_archive ( name = "io_bazel_rules_go" , integrity = "sha256-M6zErg9wUC20uJPJ/B3Xqb+ZjCPn/yxFF3QdQEmpdvg=" , urls = [ "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.48.0/rules_go-v0.48.0.zip" , "https://github.com/bazelbuild/rules_go/releases/download/v0.48.0/rules_go-v0.48.0.zip" , ], ) http_archive ( name = "bazel_gazelle" , integrity = "sha256-12v3pg/YsFBEQJDfooN6Tq+YKeEWVhjuNdzspcvfWNU=" , urls = [ "https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.37.0/bazel-gazelle-v0.37.0.tar.gz" , "https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.37.0/bazel-gazelle-v0.37.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.23.1" ) gazelle_dependencies ()
将以下代码添加到项目根目录中的BUILD.bazel
文件中。将prefix
后的字符串替换为与您的项目匹配的导入路径前缀。如果您有go.mod
文件,它应该与您的模块路径相同。
load ( "@bazel_gazelle//:def.bzl" , "gazelle" )
# gazelle:prefix github.com/example/project
gazelle ( name = "gazelle" )
这声明了一个gazelle
二进制规则,您可以使用以下命令运行该规则:
bazel run //:gazelle
这将为项目中的每个包生成一个BUILD.bazel
文件,其中包含 go_library、go_binary 和 go_test 目标。您可以在将来运行相同的命令,以使用新的源文件、依赖项和选项更新现有的构建文件。
如果您的项目不遵循go build
约定或者您不喜欢使用瞪羚,则可以手动编写构建文件。
在包含 Go 代码的每个目录中,创建一个名为BUILD.bazel
的文件,在文件顶部添加一条用于您使用的规则的load
语句。
load ( "@io_bazel_rules_go//go:def.bzl" , "go_binary" , "go_library" , "go_test" )
对于每个库,添加如下所示的 go_library 规则。源文件列在srcs
属性中。标准库外部导入的包使用引用相应 go_library 规则的 Bazel 标签在deps
属性中列出。库的导入路径必须使用importpath
属性指定。
go_library (
name = "foo_library" ,
srcs = [
"a.go" ,
"b.go" ,
],
importpath = "github.com/example/project/foo" ,
deps = [
"//tools" ,
"@org_golang_x_utils//stuff" ,
],
visibility = [ "//visibility:public" ],
)
对于测试,请添加如下所示的 go_test 规则。正在测试的库应列在embed
属性中。
go_test (
name = "foo_test" ,
srcs = [
"a_test.go" ,
"b_test.go" ,
],
embed = [ ":foo_lib" ],
deps = [
"//testtools" ,
"@org_golang_x_utils//morestuff" ,
],
)
对于二进制文件,添加如下所示的 go_binary 规则。
go_binary (
name = "foo" ,
srcs = [ "main.go" ],
)
对于每个 Go 存储库,将 go_repository 规则添加到WORKSPACE
如下所示。该规则来自 Gazelle 存储库,因此您需要加载它。瞪羚 update-repos 可以从 go.mod 或 Gopkg.lock 文件自动生成或更新这些规则。
load ( "@bazel_tools//tools/build_defs/repo:http.bzl" , "http_archive" )
# Download the Go rules.
http_archive (
name = "io_bazel_rules_go" ,
integrity = "sha256-M6zErg9wUC20uJPJ/B3Xqb+ZjCPn/yxFF3QdQEmpdvg=" ,
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.48.0/rules_go-v0.48.0.zip" ,
"https://github.com/bazelbuild/rules_go/releases/download/v0.48.0/rules_go-v0.48.0.zip" ,
],
)
# Download Gazelle.
http_archive (
name = "bazel_gazelle" ,
integrity = "sha256-12v3pg/YsFBEQJDfooN6Tq+YKeEWVhjuNdzspcvfWNU=" ,
urls = [
"https://mirror.bazel.build/github.com/bazelbuild/bazel-gazelle/releases/download/v0.37.0/bazel-gazelle-v0.37.0.tar.gz" ,
"https://github.com/bazelbuild/bazel-gazelle/releases/download/v0.37.0/bazel-gazelle-v0.37.0.tar.gz" ,
],
)
# Load macros and repository rules.
load ( "@io_bazel_rules_go//go:deps.bzl" , "go_register_toolchains" , "go_rules_dependencies" )
load ( "@bazel_gazelle//:deps.bzl" , "gazelle_dependencies" , "go_repository" )
# Declare Go direct dependencies.
go_repository (
name = "org_golang_x_net" ,
importpath = "golang.org/x/net" ,
sum = "h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=" ,
version = "v0.23.0" ,
)
# Declare indirect dependencies and register toolchains.
go_rules_dependencies ()
go_register_toolchains ( version = "1.23.1" )
gazelle_dependencies ()
要从协议缓冲区生成代码,您需要将对com_google_protobuf
的依赖项添加到您的WORKSPACE
。
load ( "@bazel_tools//tools/build_defs/repo:http.bzl" , "http_archive" )
http_archive (
name = "com_google_protobuf" ,
sha256 = "535fbf566d372ccf3a097c374b26896fa044bf4232aef9cab37bd1cc1ba4e850" ,
strip_prefix = "protobuf-3.15.0" ,
urls = [
"https://mirror.bazel.build/github.com/protocolbuffers/protobuf/archive/v3.15.0.tar.gz" ,
"https://github.com/protocolbuffers/protobuf/archive/v3.15.0.tar.gz" ,
],
)
load ( "@com_google_protobuf//:protobuf_deps.bzl" , "protobuf_deps" )
protobuf_deps ()
您需要为执行平台(Bazel 运行操作的平台)注册一个 C/C++ 工具链来构建协议。
proto_library 规则由rules_proto
存储库提供。 protoc-gen-go
是 Go proto 编译器插件,由com_github_golang_protobuf
存储库提供。两者都是由 go_rules_dependency 声明的。除非您特别想使用不同的版本,否则不需要声明显式依赖项。有关使用不同版本的说明,请参阅覆盖依赖项。
默认情况下,gRPC 依赖项未声明(太多)。您可以使用 go_repository 在 WORKSPACE 中声明它们。您可能想使用 gazelle update-repos 从go.mod
导入它们。
有关更多信息,请参阅 Proto 依赖项、gRPC 依赖项。另请参阅避免冲突。
注册所有依赖项后,您可以声明 proto_library 和 go_proto_library 规则以从 .proto 文件生成和编译 Go 代码。
load ( "@rules_proto//proto:defs.bzl" , "proto_library" )
load ( "@io_bazel_rules_go//proto:def.bzl" , "go_proto_library" )
proto_library (
name = "foo_proto" ,
srcs = [ "foo.proto" ],
deps = [ "//bar:bar_proto" ],
visibility = [ "//visibility:public" ],
)
go_proto_library (
name = "foo_go_proto" ,
importpath = "github.com/example/protos/foo_proto" ,
protos = [ ":foo_proto" ],
visibility = [ "//visibility:public" ],
)
go_proto_library
目标可以像普通的go_library
一样导入和依赖。
请注意,rules_go 的最新版本支持 APIv1 ( github.com/golang/protobuf
) 和 APIv2 ( google.golang.org/protobuf
)。默认情况下,代码是使用github.com/golang/protobuf/cmd/protoc-gen-gen
生成的,以便与两个接口兼容。客户端代码可以使用运行时库或两者都导入。
去
协议缓冲区
依赖关系和测试
是的,但不是直接的。
Rules_go 根据 go_binary 和其他规则描述的目标直接调用 Go 编译器和链接器。 Bazel 和rules_go 一起扮演与go
命令相同的角色,因此没有必要在Bazel 工作区中使用go
命令。
也就是说,遵循go
命令所需的约定通常仍然是一个好主意(例如,每个目录一个包,包路径与目录路径匹配)。与 Bazel 不兼容的工具仍然可以工作,并且您的项目可以被非 Bazel 项目依赖。
如果您需要使用go
命令执行 Bazel 未涵盖的任务(例如向go.mod
添加新的依赖项),您可以使用以下 Bazel 调用来运行 Bazel 配置的 Go SDK 的go
二进制文件:
bazel run @io_bazel_rules_go//go -- < args >
与直接运行go
相比,更喜欢这样做,因为它可以确保 Go 的版本与rules_go 使用的版本相同。
是的,但不是直接的。 Bazel 会忽略go.mod
文件,并且所有包依赖项都必须通过 go_library 和其他规则描述的目标中的deps
属性来表达。
您可以使用 go_repository(由瞪羚提供的工作区规则)下载特定版本的 Go 模块作为外部存储库。这也将使用瞪羚生成构建文件。
您可以使用 gelelle update-repos 从go.mod
文件导入 go_repository 规则。
这用于在importpath
属性可用之前保持可以使用go build
构建的库中的导入路径一致。
为了正确编译和链接,rules_go 必须知道每个库的 Go 导入路径(可以导入包的字符串)。现在,这是使用importpath
属性显式设置的。在该属性存在之前,导入路径是通过连接特殊go_prefix
规则中的字符串以及库的包和标签名称来推断的。例如,如果go_prefix
是github.com/example/project
,对于库//foo/bar:bar
,rules_go 会将导入路径推断为github.com/example/project/foo/bar/bar
。最后的口吃与go build
不兼容,因此如果标签名称是go_default_library
,导入路径将不包含它。因此,对于库//foo/bar:go_default_library
,导入路径将为github.com/example/project/foo/bar
。
由于go_prefix
已被删除并且importpath
属性成为强制性的(请参阅#721),因此go_default_library
名称不再有任何用途。我们可能决定将来停止使用它(参见#265)。
您可以通过在命令行上设置--platforms
标志来交叉编译。例如:
$ bazel build --platforms=@io_bazel_rules_go//go/toolchain:linux_amd64 //cmd
默认情况下,交叉编译时禁用cgo。要与 cgo 交叉编译,请向目标平台添加_cgo
后缀。您必须向 Bazel 注册交叉编译 C/C++ 工具链才能使其工作。
$ bazel build --platforms=@io_bazel_rules_go//go/toolchain:linux_amd64_cgo //cmd
带有构建标签或文件名后缀的特定于平台的源代码会在编译时自动过滤。您可以使用select
表达式有选择地包含特定于平台的依赖项(Gazelle 自动执行此操作)。
go_library (
name = "foo" ,
srcs = [
"foo_linux.go" ,
"foo_windows.go" ,
],
deps = select ({
"@io_bazel_rules_go//go/platform:linux_amd64" : [
"//bar_linux" ,
],
"@io_bazel_rules_go//go/platform:windows_amd64" : [
"//bar_windows" ,
],
"//conditions:default" : [],
}),
)
要为目标平台构建特定的 go_binary 目标或使用特定的 golang SDK 版本,请使用 go_cross_binary 规则。这对于在单个构建中为不同平台生成多个二进制文件非常有用。
要为目标平台构建特定的 go_test 目标,请在该规则上设置goos
和goarch
属性。
您可以等效地通过//command_line_option:platforms
上的 Bazel 配置转换来依赖 go_binary 或 go_test 规则(在rules_go 0.23.0 之前,这种方法存在问题)。
Bazel 在沙箱中执行测试,这意味着测试不会自动访问文件。您必须包含使用data
属性的测试文件。例如,如果您想包含testdata
目录中的所有内容:
go_test (
name = "foo_test" ,
srcs = [ "foo_test.go" ],
data = glob ([ "testdata/**" ]),
importpath = "github.com/example/project/foo" ,
)
默认情况下,测试在定义它们的构建文件的目录中运行。请注意,这遵循 Go 测试约定,而不是其他语言遵循的 Bazel 约定,这些约定在存储库根目录中运行。这意味着您可以使用相对路径访问测试文件。您可以使用rundir
属性更改测试目录。请参阅 go_test。
如果你有一个testdata
目录,Gazelle 会自动添加一个类似于上面的data
属性,除非它包含可构建的 .go 文件或构建文件,在这种情况下, testdata
被视为普通包。
请注意,在 Windows 上,数据文件不能直接用于测试,因为测试数据文件依赖于符号链接,并且默认情况下,Windows 不允许非特权用户创建符号链接。您可以使用 github.com/bazelbuild/rules_go/go/tools/bazel 库来访问数据文件。
go_binary
写入其可执行文件的位置在不同的rules_go 版本中并不稳定,不应依赖。父目录的名称中包含一些配置数据。当在不同配置中构建相同的二进制文件时,这可以防止 Bazel 的缓存中毒。二进制基本名称也可能与平台相关:在 Windows 上,我们添加 .exe 扩展名。
要依赖go_test
规则中的可执行文件,请在data
属性中引用可执行文件(以使其可见),然后展开args
中的位置。真实位置将传递给命令行上的测试。例如:
go_binary (
name = "cmd" ,
srcs = [ "cmd.go" ],
)
go_test (
name = "cmd_test" ,
srcs = [ "cmd_test.go" ],
args = [ "$(location :cmd)" ],
data = [ ":cmd" ],
)
有关访问二进制文件的测试的完整示例,请参阅 //tests/core/cross。
或者,您可以将 go_binary 的out
属性设置为特定的文件名。请注意,设置out
后,更改配置时不会缓存二进制文件。
go_binary (
name = "cmd" ,
srcs = [ "cmd.go" ],
out = "cmd" ,
)
go_test (
name = "cmd_test" ,
srcs = [ "cmd_test.go" ],
data = [ ":cmd" ],
)
请参阅原型文档中的避免冲突。
不支持此操作。当将 go_proto_library 与@io_bazel_rules_go//proto:go_grpc
编译器一起使用时,会在@org_golang_google_grpc//:go_default_library
上添加隐式依赖项。如果您从//vendor/google.golang.org/grpc:go_default_library
或其他任何地方链接同一包的另一个副本,则可能会在编译或运行时遇到冲突。
如果您使用启用了原始规则生成的 Gazelle, google.golang.org/grpc
的导入将自动解析为@org_golang_google_grpc//:go_default_library
以避免冲突。在这种情况下,应忽略供应商的 gRPC。
如果您特别需要使用供应商的 gRPC 包,最好完全避免使用go_proto_library
。您可以签入预先生成的 .pb.go 文件并使用go_library
规则构建它们。当原始规则生成被禁用时,Gazelle 将生成这些规则(将# gazelle:proto disable_global
添加到根构建文件中)。
有关覆盖 go_rules_dependency 中声明的存储库的说明,请参阅覆盖依赖项。
参考:
为了在 Travis CI 上运行 Bazel 测试,您需要在before_install
脚本中安装 Bazel。请参阅上面链接的配置文件。
您需要使用多个标志来运行 Bazel,以防止它在测试环境中消耗大量内存。
--host_jvm_args=-Xmx500m --host_jvm_args=-Xms500m
:设置最大和初始 JVM 堆大小。保持不变意味着 JVM 不会花费时间来增加堆。堆大小的选择有些随意;其他配置文件建议限制高达 2500m。值越高意味着构建速度越快,但 OOM 终止的风险也越高。--bazelrc=.test-bazelrc
:使用特定于 Travis CI 的 Bazel 配置文件。您可以将大部分剩余选项放在这里。build --spawn_strategy=standalone --genrule_strategy=standalone
:禁用构建的沙箱。 Travis 容器内的沙箱可能会失败,因为不允许mount
系统调用。test --test_strategy=standalone
:也禁用测试的沙箱。--local_resources=1536,1.5,0.5
:设置 Bazel 对可用 RAM(以 MB 为单位)、可用计算核心和可用 I/O 核心的限制。较高的值意味着更快的构建,但更高的争用和 OOM 终止的风险。--noshow_progress
:抑制输出中的进度消息以保持更清晰的日志。--verbose_failures
:获取更详细的失败消息。--test_output=errors
:在 Travis 日志中显示测试 stderr。通常,测试输出是写入日志文件,Travis 不会保存或报告。 Travis 上的下载相对较慢(网络竞争激烈),因此您需要最大限度地减少构建中的网络 I/O 量。下载 Bazel 和 Go SDK 是其中很大一部分。为了避免下载 Go SDK,您可以在.travis.yml
文件中请求预装 Go 版本的容器,然后在 Travis 特定的WORKSPACE
文件中调用go_register_toolchains(go_version = "host")
。
您可能会想将 Bazel 的缓存放入 Travis 缓存中。虽然这可以显着加快构建速度,但 Travis 将其缓存存储在 Amazon 上,并且传输需要很长时间。在实践中,干净的构建似乎更快。
Rules_go 仅支持 Go SDK 的官方版本。但是,您仍然可以通过将"1.16beta1"
等version
传递给 go_register_toolchains 来测试 beta 和 RC 版本。另请参阅 go_download_sdk。
load ( "@io_bazel_rules_go//go:deps.bzl" , "go_register_toolchains" , "go_rules_dependencies" )
go_rules_dependencies ()
go_register_toolchains ( version = "1.17beta1" )