plz初窥门径

·

2 min read

因为工作的原因,在前司时,我就对bazel产生了深厚的兴趣,奈何各种原因没有在工作落地,甚至来不及在团队内普及monorepo的概念,但一直记挂于心,也应了那句话:念念不忘,必有回响。

bazel到底是什么呢?

Bazel 是一个支持多语言构建的构建系统

我为何对bazel如此上心呢,根据官网的宣传,主要有两点:

仅重新构建必要的代码。使用 Bazel' 先进的本地和分布式缓存、优化的依赖项分析和并行执行功能,实现快速增量构建。

快速构建,一直是我非常在意的一个特性,还有一点就是跨语言、跨平台

使用 Java、C++、Go、Android、iOS 以及其他许多语言和平台进行构建和测试。Bazel 在 Windows、macOS 和 Linux 上运行。

这一点,跨语言这一点我也是后来才领悟到的,毕竟如果你经常跨编程语言开发,学会一套bazel的构建规则即可,这一点还真是挺妙的。

不过接下来我要聊的是please, 跟bazel可以说非常类似,不同的是,这个please是使用go开发的,因为我的主力编程语言是go,偶然发现了这please,觉得还挺有趣,就用它来做示例吧。

我的示例来源于please官网的Getting started with Go,我们先来看一下plz-demo的目标结构

├── .plzconfig
├── pleasew
├── src
│   ├── BUILD
│   ├── greetings
│   │   ├── BUILD
│   │   ├── greetings.go
│   │   └── greetings_test.go
│   └── main.go
└── third_party
    └── go
        └── BUILD

是的,你没看错,没有go.mod,当我运行plz run //src:main ,plz会根据BUILD的配置完成依赖分析、下载、缓存,有一说一,速度还是挺快的。

我用常规方式下go-demo的代码目标结构

├── go.mod
├── go.sum
├── greetings
│   ├── greetings.go
│   └── greetings_test.go
└── main.go

直观来看,go.mod这类方式肯定最简单,最舒服,跟go的生态适配性也更好,一个可能不太恰当的比方:go.mod之于plz/blazel,好比gc与自己管理依赖的区别。

话不多说,我们先来看下plz-demo/src/BUILD长啥样

go_binary(
  name = "main",
  srcs = ["main.go"],
  deps = ["//src/greetings:greetings"],
)

还是很容易看懂的,最终生成的

  • 二进制name: 在plz-out/bin/src路径下

  • -main文件

  • 第三方依赖

再来看third_parth/go下的BUILD(third_parth文件夹名字只是一个约定,不强制),不理解第一行PUBLIC的意义所在?

package(default_visibility = ["PUBLIC"])
​
go_module(
    name = "assert",
    module = "github.com/go-playground/assert",
    version = "v1.2.1",
)

也挺清晰的,声明了第三依赖github.com/go-playground/assert的,功能上与go.mod类似,事实上assert这个第三方依赖是在greetings_test.go中使用到的。第一次跑plz test //src/...

//src/greetings:greetings_test 1 test run in 0s; 1 passed [cached]
1 test target and 1 test run; 1 passed.
Total time: 260ms real, 0s compute.

第二次

//src/greetings:greetings_test 1 test run in 0s; 1 passed [cached]
1 test target and 1 test run; 1 passed.
Total time: 70ms real, 0s compute.

缓存果然很强大

对比go-demo跑test:

❯ go test -v ./...
?     example_module  [no test files]
=== RUN   TestGreeting
--- PASS: TestGreeting (0.00s)
PASS
ok    example_module/greetings  0.212s

嗯,可见差别并不明显

再来看src/greetings/BUILD

go_library(
    name = "greetings",
    srcs = ["greetings.go"],
    visibility = ["//src/..."],
)
​
go_test(
    name = "greetings_test",
    srcs = ["greetings_test.go"],
    deps = [
        ":greetings",
        "//third_party/go:assert",
    ],
    external = True,
)

虽然写的挺多,但还是容易理解的,不太明白这里external = True为何意,一般而言,test代码其它地方也用不到。

最后还看一下根目录下的.plzconfig

; Please config file
; Leaving this file as is is enough to use plz to build your project.
; Please will stay on whatever version you currently have until you run
; 'plz update', when it will download the latest available version.
;
; Or you can uncomment the following to pin everyone to a particular version;
; when you change it all users will automatically get updated.
; [please]
; version = 16.28.0
​
[go]
;gotool = ...
;goroot - ...
importpath = example_module
​
[build]
;path = $(dirname $(which go)):/usr/local/bin:/usr/bin:/bin
path =/Users/yourname/.gvm/gos/go1.17/bin:/usr/local/bin:/usr/bin:/bin
​

需要配置下go的工具链,让我比较疑惑的是plz似乎并不能识别环境变量,至少在我测试的过程中是这样的。

总结下来,plz还是挺不错的,使用门槛也不高,只是对于常规业务小型项目,与go mod对比起来,无任何优势,这么说也不太公平,毕竟plz/bazel也有自己的优势与适用场景。目前我就看到国内TiDB有在项目中用到了bazel,听说效果不错。这一篇算是真正意义上入坑,毕竟只是小小demo了一把,期待以后能在合适的工作场景中用到,这正是探索新技术的乐趣所在,just for fun!