前言
这篇文章主要介绍如果通过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。
具体可以参考:github.com/bazelbuild/…
然后运行以下命令:
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/…
这个时候我们看下根目录下的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文件,以及如何引用其他的包等。