使用 bazel 編譯 go 項目
【導讀】本文介紹如果通過 bazel 來構建和管理 go 的項目。
前言
這篇文章主要介紹如果通過 bazel 來構建和管理 go 的項目。這裏是一個最簡單的實例。
bazel 是什麼
bazel 是一個可以快速構建和測試任意規模軟件的工具,能夠用來編譯 Java,C++,Go,TS,iOS,Android 等大部分的語言。
1. 創建工作空間
在使用 bazel 的時候,需要先創建一個 WORKSPACE 文件在你的項目根目錄,表示這是 bazel 的工作空間,後續所有的配置都是基於這個目錄來的。
那我們就先創建一個目錄,然後添加一個這樣的文件。
然後創建一個 WORKSPACE 文件 添加以下內容:
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(
name = "io_bazel_rules_go",
urls = [
"https://storage.googleapis.com/bazel-mirror/github.com/bazelbuild/rules_go/releases/download/0.19.0/rules_go-0.19.0.tar.gz",
"https://github.com/bazelbuild/rules_go/releases/download/0.19.0/rules_go-0.19.0.tar.gz",
],
sha256 = "9fb16af4d4836c8222142e54c9efa0bb5fc562ffc893ce2abeac3e25daead144",
)
load("@io_bazel_rules_go//go:deps.bzl", "go_rules_dependencies", "go_register_toolchains")
go_rules_dependencies()
go_register_toolchains()
這裏面的內容不需要手寫啊,你去 https://github.com/bazelbuild/rules_go/releases 複製過來就好了。
2. 走一個 hello go
配置了上面的東西之後,我們在項目目錄下創建一個 main.go 的文件,內容如下:
package main;
import (
"fmt"
)
func main() {
fmt.Println("hello go!");
}
然後創建一個 BUILD.bazel 文件,添加一下內容:
load("@io_bazel_rules_go//go:def.bzl", "go_binary")
go_binary(
name = "go_default_library",
srcs = ["main.go"],
importpath = "test",
visibility = ["//visibility:private"],
)
完成上面的工作之後,看下目前的目錄結構:
非常簡單,只有 3 個文件,然後我們看下怎麼用 bazel 來運行這個 go 程序。
在項目的根目錄下執行一下命令:
如果你是第一次跑的話可能會需要一點時間,當然你還可能報錯,報錯的原因一般都是網絡問題,然後你懂得。
然後我們看到了 hello go 的輸出了,而且我們沒有配置 gopath 什麼的,是不是很方便?
3. 使用 gazelle 自動生成 BUILD.bazel 文件
上面看到了,我們需要手寫 BUILD.bazel?那如果大項目包很多的話,不是要寫到吐血?下面就來說下,怎麼用 gazelle 這個工具來自動給每個包生成一個 BUILD.bazel 的文件。
爲了演示,我們需要重新創建 2 個包。
在項目根目錄下新建一個文件,叫做 p1 吧。
然後進到 p1 目錄, 添加一個文件 p1.go。
內容如下:
package p1;
import (
"fmt"
)
func TestP1() {
fmt.Println("from p1")
}
p2 也是一樣,就不貼上來了。
之後的目錄結構如下:
下面我們需要添加 gazelle 這個工具到我們的 WORKSPACE 文件中。
修改跟目錄下的 BUILD.bazel 文件內容如下:
load("@bazel_gazelle//:def.bzl", "gazelle")
# gazelle:prefix bazel-go
gazelle(name = "gazelle")
劃重點
:
# gazelle:prefix bazel-go
這行註釋必須要的啊,gazelle:prefix 後面跟你的項目名稱,這裏我寫的就是 bazel-go。
具體可以參考:
然後運行以下命令:
bazel run //:gazelle
然後輸出應該像下面這樣,就是正確的。
看下現在的 p1,p2 目錄下:
發現已經給我們生成了對應的文件,打開一個看下內容:
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = ["p1.go"],
importpath = "bazel-go/p1",
visibility = ["//visibility:public"],
)
這裏的參數可以參考:github.com/bazelbuild/…[3]
這個時候我們看下根目錄下的 BUILD.bazel 文件的內容:
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")
load("@bazel_gazelle//:def.bzl", "gazelle")
# gazelle:prefix bazel-go
gazelle(name = "gazelle")
go_library(
name = "go_default_library",
srcs = ["main.go"],
importpath = "bazel-go",
visibility = ["//visibility:private"],
deps = ["//p2:go_default_library"],
)
go_binary(
name = "bazel-go",
embed = [":go_default_library"],
visibility = ["//visibility:public"],
)
發現跟上面的有點不一樣了,自動添加了一些聲明。
4. 使用上面生成的包
在上面我們定義了兩個包,那怎麼 import 進來使用呢?
這裏我們再 main.go 這裏來導入 p2 這個包,並且執行下里面的函數。
看下 main.go 的代碼:
package main;
import (
"fmt"
p2 "bazel-go/p2"
)
func main() {
p2.TestP2()
fmt.Println("hello go!");
}
p2 "bazel-go/p2"
這裏我們導入了 p2 這個包,並且用 p2 代替。爲什麼後面是 "bazel-go/p2" 呢?看下 p2 的 BUILD.bazel 文件裏面的聲明,有個 importpath,對的,我們用這個值就行了。
p2.TestP2()
這句是調用了 p2 這個包裏面的 TestP2() 這個函數。然後我們在根目錄運行以下命令:
bazel run //:bazel-go
看下結果:
可以看到,正確輸出了函數中打印的字符串。
總結
到這裏,我們基本上講解了如何使用 bazel 搭建一個 go 項目,使用 bazel 初始化項目,使用 gazelle 自動生成 BUILD 文件,以及如何引用其他的包等。
轉自:
juejin.cn/post/6844903892757528590
Go 開發大全
參與維護一個非常全面的 Go 開源技術資源庫。日常分享 Go, 雲原生、k8s、Docker 和微服務方面的技術文章和行業動態。
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/WKQ5wckl_idqo-f4JyHxfg