ABOUT BAZEL
什么是Bazel?
-
构建系统,而不是构建生成器(直接调用编译器)【A build system, not a build generator (invokes directly the compiler)】
-
具有完整的测试功能(测试报告、片状测试处理等)【With full of functionality for testing (test reports, flaky tests handling, etc.)】
-
Bazel核心是用Java编写的,规则和宏是用Starlark编写的【Bazel core is written in Java, rules and macros written in Starlark】
历史-从Blaze到Bazel
- Blaze是谷歌的构建系统(开发始于2007年左右)
- Blaze的一部分于2015年作为Bazel开源【Part of Blaze was open sourced on 2015 as Bazel】
- 它于2019年10月从测试版转向普遍可用性
发布过程
- 自通用可用性发布以来,Bazel遵循语义版本【Since the general availability release, Bazel follows semantic versioning】
- 主要版本之间至少3个月
- 每月发布基于GitHub HEAD的小版本
- 长期支持(LTS)从Bazel 4.0(2020年12月)开始,每9个月将提供一次新的LTS版本【Long Term Support (LTS) starting from Bazel 4.0 (December 2020), a new LTS release will be provided every 9 months】
- https://blog.bazel.build/2020/11/10/long-term-support-release.html
https://docs.bazel.build/
BAZEL FEATURES
快速且正确
- 增量构建和测试执行【Incremental builds and test execution】
- 并行执行
- 本地和远程缓存【Local and remote cache】
- 由于沙盒,密封构建【Hermetic builds thanks to sandboxing】
多语言,多平台
- Java、C/C++、Android、iOS、Go、Python等。
- Linux、Windows和macOS
可伸缩的【Scalable】
- 它可以处理任何大小的代码库【It can handle codebases of any size】
- 多个存储库或巨大的单核存储库,它同时处理两者【Multiple repositories or huge monorepo , it handles both】
可扩展的【Extensible】
- 如果不支持平台或语言,可以轻松添加
- 扩展是用Skylark编写的,这是一种类似于Python的语言【Extensions are written in Skylark, a language similar to Python】
https://docs.bazel.build/versions/3.7.0/bazel-overview.html#why-should-i-use-bazel
BAZEL IN A NUTSHELL
这是一个基于工件的系统【It is an artifact based system】
- 输入被视为工件
- 输出被视为工件
- 行动也被视为人工制品【Actions are treated as artifacts as well】
- 对于每个工件,都可以提前计算散列,以允许缓存【For every artifact a hash can be computed in advance to allow caching】
每个动作都在沙盒上运行
- 提高可重现性【Improving reproducibility】
- 更好地检测未声明的依赖项
可组合性
- 一个动作的输出可以用作另一个动作的输入【Outputs of an action can be used as inputs of another action】
- 一个动作可以是另一个动作的输出【An action can be the output of another action】
BAZEL DESIGN
客户端/服务器架构【Client/server architecture】
- 首次执行Bazel命令时,将启动Bazel服务器
- Bazel命令完成后,服务器继续运行
- 以下命令使用已运行的服务器执行【The following commands executed use the already running server】
- 两个Bazel客户端不能并行运行(例外)【Two Bazel clients cannot run in parallel (with exception)】
- Bazel服务器可以通过
bazel shutdown
来停止 - 此架构允许服务器缓存信息【This architecture allows the server to cache information】
BAZEL FILES
工作空间【WORKSPACE】
- 在您想要构建的源代码的根部【At the root of the source code that you want to build】
- 它可能是空的
- 用于声明外部依赖项【Used to declare external dependencies】
BUILD
- 在package的根部【At the root of a package】
- 软件包由所有文件、文件夹和子文件夹定义,与BUILD文件相同级别,但包含BUILD文件的文件除外【A package is defined by all files, folders, and subfolders at the same level like the BUILD file except the ones that contain a BUILD file】
- 定义目标的地方【Where targets are defined】
*.bzl
- 用于定义Bazel扩展【Use to define Bazel extensions】
- 它们可以使用load语句加载到BUILD或WORKSPACE文件中【They can be loaded in a BUILD or WORKSPACE file using the load statement】
BAZEL LABELS
@repository//folder/subfolder:my_target
省略存储库假设当前存储库:
@repository//folder/subfolder:my_target
//folder/subfolder:my_target
省略冒号的名称与文件夹相同【Omitting the colon assumes the same name like the folder】:
//lib:lib
//lib
从同一BUILD文件中的lib的冒号搜索开始【Starting with colon search for lib in the same BUILD file】
:lib
From the same or another file:
@example//client:small_client
//client:small_client
@example//client:client
@example//client
//client:client
//client
从同一个BUILD文件中
From the same BUILD file:
:client
:small_client
TARGET VISIBILITY
Private: Visible only from the same BUILD file
visibility:private
Public: Anyone can see this target
visibility:public
Visible by a specific package and subpackages
//foo/bar:__subpackages__
Visible by a specific package but not subpackages
//foo/bar::__pkg__
可见性可以按包、每个目标或两者定义【Visibility can be defined per package, per target or both】
默认情况下,目标可见性与软件包相同【By default the target visibility is the same like the package】
如果未定义可见性,则目标仅在BUILD文件中可见【If visibility is not defined, a target is only visible within the BUILD file】
https://docs.bazel.build/versions/3.7.0/visibility.html
PHASES OF A BUILD
加载阶段【Loading phase】
- 加载扩展、BULD文件、传递依赖项【Load extensions, BULD files, transitive dependencies】
- 持续时间:第一次几秒钟,之后由于缓存而更快【Duration: Several seconds the first time, faster afterwards thanks to caching】
分析阶段
- 每条规则的语义分析【Semantic analysis of each rule】
- 构建依赖图
- 分析需要完成的工作【Analyze what work needs to be done】
- 持续时间:第一次几秒钟,之后由于缓存而更快【Duration: Several seconds the first time, faster afterwards thanks to caching】
执行阶段
- 构建目标:编译、链接等。
- 执行目标、运行测试等。【Execution of targets, tests running, etc.】
- 持续时间:大部分时间都花在执行阶段,由于缓存,也可以加快速度【Duration: Most of the time is spend in the execution phase, also can be speeded up thanks to caching】
https://docs.bazel.build/versions/3.7.0/guide.html#phases-of-a-build
BAZEL CACHE
Bazel提供四个不同级别的缓存
-
在内存缓存中(Bazel服务器)【In memory cache ( Bazel server)】
- Bazel服务器停止后丢失/清理
-
输出目录(bazel-out)
- 工作区本地【Local to the workspace】
- 可以用bazel clean和bazel clean --expunge来去除
-
磁盘缓存(本地机器中的文件夹)【Disk cache (folder in local machine)】
- 切换分支时共享工件很有用
- 如果您有同一项目的多个工作区/checkout,则非常有用【Useful if you have multiple workspaces/checkouts of the same project】
- 它可以让你的磁盘使用量增加很多
-
远程缓存(HTTP/1.1服务器)
- 有助于在团队成员之间或与CI共享工件
https://docs.bazel.build/versions/3.7.0/remote-caching.html
Bazel缓存“总是”有效且正确
- 删除缓存的唯一原因是释放空间
- 每次你解决bazel clean的问题时,都应该创建一个错误票
- 它可能是Bazel核心:
- https://github.com/bazelbuild/bazel/issues
- 这可能是一些Bazel规则:
- https://github.com/bazelbuild/rules_go/issues
- https://github.com/bazelbuild/rules_python
- https://github.com/bazelbuild/rules_docker
- …
- 它可能在您的工具链配置之一中
- 它可能在你的一个Bazel扩展中【It might be in one of your Bazel extensions】
- 它可能是Bazel核心:
BAZEL LOCAL CACHE SETUP
Common setup:
BAZEL REMOTE CACHE SETUP
Recommended by Bazel:
- CI read and write, developers read only
https://archive.fosdem.org/2018/schedule/event/datacenter_build/
更分散的方法:【A more distributed approach:】
- 每个开发人员团队一个远程缓存【One remote cache per developer team】
- 仅适用于CI的一个远程缓存【One remote cache for CI only】
- 在每个远程缓存上,一个实体向其写入【On each remote cache one single entity writes to it】
- 此外,每个开发人员都使用磁盘缓存【In addition each developer uses disk cache】
BAZEL REMOTE EXECUTION
Bazel, compilation, and execution can run in different machines
https://docs.bazel.build/versions/3.7.0/remote-execution.html
BAZEL FOR C++ AND PYTHON
BUILD SYSTEM FOR PYTHON?
- 更难通过沙盒泄露依赖项
- 跨语言运行目标的统一方式
- 您从Bazel测试实用程序中受益
- 除了bazel构建,你仍然需要所有其余的
C++ EXAMPLE WITH BAZEL
https://github.com/limdor/bazel-examples/tree/master/cpp
PYTHON EXAMPLE WITH BAZEL
https://github.com/limdor/bazel-examples/tree/master/python
COMPILE C++ CODE GENERATED WITH PYTHON
https://github.com/limdor/bazel-examples/tree/master/cpp_and_python
https://github.com/limdor/bazel-examples/tree/master/cpp_and_python
BAZEL TOOLCHAINS
等等!如果它如此密封,为什么我们不必指定我们的编译器?【Wait! If it is so hermetic, why we did not have to specify our compiler?】
- 出于实际原因,Bazel提供了一些预定义的工具链,如果在您的机器中安装了一些编译器,可以使用这些工具链
- 选项–toolchain_resolution_debug可用于查看正在使用哪些工具链
- 选定的工具链 @local_config_cc//:cc-compiler-k8【Selected toolchain @local_config_cc//:cc compiler k8】
- 对于任何生产项目,您都应该定义一个密封的工具链
- 如果工具链指向本地安装的编译器,那么定义工具链是不够的
- 编译器和链接器应该像任何输入工件一样提供
- 应该像任何输入工件一样提供Python解释器
- 如果用户需要在Bazel之外的机器上安装一些东西,你做错了什么【If a user needs to install something in his machine apart from Bazel , you are doing something wrong】
- Bazel提供了许多关于如何定义工具链的文档
- https://docs.bazel.build/versions/3.7.0/tutorial/cc-toolchain-config.html
- https://docs.bazel.build/versions/3.7.0/toolchains.html
https://docs.bazel.build/versions/master/tutorial/cc-toolchain-config.html
BAZEL TEST RUNNER
https://docs.bazel.build/versions/3.7.0/test-encyclopedia.html
BAZEL TEST RUNNER
BAZEL COVERAGE
https://github.com/limdor/bazel-examples/tree/master/cpp_coverage
BAZEL QUERY
https://docs.bazel.build/versions/3.7.0/query-how-to.html
BAZELISK
https://github.com/bazelbuild/bazelisk
https://docs.bazel.build/versions/3.7.0/skylark/aspects.html
WORKSPACE+BUILD
如下图:每个bazel工程建立在git 仓库中,外部依赖通过WORKSPACE定义,BUILD定义目标的依赖关系。