郵件列表: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" )