使用 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