参考文档:

1. Bazel介绍

Bazel 是一个开源的构建和测试工具,由 Google 开发,主要用于管理大型项目的构建过程。

1.1 Bazel构建工作流程

当我们使用Bazel来构建的时候,其工作流程大致如下:

  • Load: 加载target相关的BUILD文件

  • Analyze: Bazel通过分析所有BUILD文件,使用指定的构建规则,生成一个表示依赖关系的有向无环图(DAG)

  • Execute: 针对target的输入执行相应动作产生输出。

1.2 Bazel的使用

参看:

使用Bazel来构建工程时,我们通常按如下步骤:

  1. 安装Bazel

    下载并安装Bazel.

  2. 创建工程workspace

    workspace是bazel用于查找Inputs及BUILD文件的目录,构建时的输出也会保存到该牡蛎

  3. 编写BUILD文件

    BUILD文件用于告诉Bazel如何进行构建。在BUILD文件中声明了build targets,构建时Bazel读取该文件,按照对应的build rule完成构建目标的输出。

    BUILD文件采用Starlark语言进行编写,后面会有介绍。

    • build target指明了构建时的输入(inputs)、依赖(dependencies)、规则(build rule)以及规则的相关配置选项。

    • build rule指明了Bazel构建时所使用的工具(比如:编译器和链接器)及工具的相关配置。Bazel内置了一系列的build rules,覆盖了所支持目标平台编程语言的大部分构建类型。 我们可以从这里找到这些内置的构建规则,当然也可以使用Starlark来扩展build rule。

  4. 运行Bazel

    从命令行Bazel完成构建,对应的构建输出也会在工程目录内。

2. 安装Bazel

参看:

我们有两种方式来安装Bazel:可以使用官方推荐的Bazelisk来安装,也可以到Release下载对应的Bazel二进制文件来安装。

2.1 直接下载二进制安装

我们可以到Bazel Releases页面下载。这里针对我们的Ubuntu操作系统下载如下文件即可:

# wget https://github.com/bazelbuild/bazel/releases/download/8.0.0rc6/bazel-8.0.0rc6-installer-linux-x86_64.sh

# chmod 777 ./bazel-8.0.0rc6-installer-linux-x86_64.sh
# ./bazel-8.0.0rc6-installer-linux-x86_64.sh

2.2 采用bazelisk安装bazel

bazelisk采用golang编写,是对bazel的一个包装。它可以自动的为当前工作目录选择一个合适的Bazel版本,然后有必要的话就从官方网站上进行下载,并将传递给bazelisk的命令转发到bazel上。

bazelisk官网: https://github.com/bazelbuild/bazelisk

这里我们简单记录一下bazelisk的安装过程。

2.2.1 下载bazelisk

bazelisk release页面下载bazelisk安装包。这里我们下载linux-amd64版本:

# uname -p
    x86_64

# cd /usr/local/
# mkdir bazel && cd bazel
# wget https://github.com/bazelbuild/bazelisk/releases/download/v1.24.1/bazelisk-linux-amd64

# chmod 777 ./bazelisk-linux-amd64

2.2.2 为bazelisk-linux-amd64创建软连接

因为我们使用的使用都是直接输入bazelbazelisk命令,因此我们在这里为步骤1)下载的二进制文件创建两个软连接:

# pwd
/usr/local/bazel
# ln -sf ./bazelisk-linux-amd64 bazel
# ln -sf ./bazelisk-linux-amd64 bazelisk

2.2.3 将bazelisk安装目录添加到环境变量

修改`~/.bashrc`文件,将bazelisk安装目录添加到环境变量:
```
export BAZELROOT=/usr/local/bazel
export PATH=$PATH:$BAZELROOT
```
记得修改完后执行`source ~/.bashrc`使设置生效。

2.2.4 指定bazel版本

由于下载下来的bazelisk只是bazel的一个包装壳,我们直接执行bazelisk-linux-amd64的话可能会卡很长时间。下面我们来介绍一下bazelisk选择Bazel版本的内部算法:

  • 如果指定了USE_BAZEL_VERSION 环境变量,那么bazelisk会使用该环境变量所指定的bazel版本

  • 否则,假如当前workspace的根目录下存在.bazeliskrc文件并且在其中通过USE_BAZEL_VERSION变量指定了bazel版本的话,那么就使用该版本的bazel

  • 否则,假如当前目录或者递归的父目录中存在.bazelversion,bazelisk就会尝试读取该文件并使用其指定版本的bazel

  • 否则,假如环境变量USE_BAZEL_FALLBACK_VERSION指定了的话,就使用该环境变量所设置的bazel。设置格式如下:

    • 假如所设置的值以error:开头,则在使用bazelisk时会报告一个错误,并且不去探测所设定版本的bazel

    • 假如所设置的值以warn:开头,那么在使用bazelisk时就会产生一个警告信息,并且使用其所指定版本的bazel

    • 假如所设置的值以silent:开头,那么bazelisk就会使用其所指定版本的bazel

  • 否则,bazelisk会使用官方最新的Bazel版本


根据上面的描述,如果我们有workspace的话我们倾向于通过.bazeliskrc来指定;如果作为学习,在命令行中使用的话,我们倾向于通过USE_BAZEL_FALLBACK_VERSION环境变量来指定。这里我们修改~/.bashrc文件,添加如下内容:

export USE_BAZEL_FALLBACK_VERSION=warn:8.0.0rc6

执行如下命令使环境变量生效:

# source ~/.bashrc

2.2.5 执行bazel(或bazelisk)命令,查看版本号

到此步骤我们就可以执行如下命令查看bazel的版本号了:

# bazel --version
2024/12/04 00:27:40 Warning: used fallback version "8.0.0rc6"
2024/12/04 00:27:40 Downloading https://releases.bazel.build/8.0.0/rc6/bazel-8.0.0rc6-linux-x86_64...
Downloading: 61 MB out of 61 MB (100%) 
bazel 8.0.0rc6

# ls
bazel  bazelisk  bazelisk-linux-amd64

通过上面的执行过程,我们看到第一次执行的时候bazelisk会从类似https://github.com/<FORK>/bazel/releases/download/<VERSION>/<FILENAME>的位置去下载指定版本的bazel。

2.2.6 备注说明

经过前面的步骤,安装过程就完成了,但是还有个点我们简单介绍一下:bazelisk下载下载下来的指定版本的bazel放在什么位置呢?其实在官网中也有描述:

 It creates a directory called "bazelisk" inside your [user cache directory]
 (https://golang.org/pkg/os/#UserCacheDir) and will store them there. Feel 
 free to delete this directory at any time, as it can be regenerated 
 automatically when required.

这里在Linux操作系统下的cache目录为~/.cache

# ls ~/.cache
bazelisk  Microsoft  motd.legal-displayed  vscode-cpptools

# tree ~/.cache/bazelisk/
/root/.cache/bazelisk/
└── downloads
    ├── metadata
    │   └── bazelbuild
    │       └── bazel-8.0.0rc6-linux-x86_64
    ├── sha256
    │   └── db6de55999ddbbf28215eddfb19b7d0f688a42945193887048183bd5d3e991d9
    │       └── bin
    │           └── bazel
    └── _tmp

7 directories, 2 files

3. Bazel工程示例

可以直接从Github上克隆相应的示例:

# git clone https://github.com/bazelbuild/examples

4. 编写BUILD文件

这里我们先来看看Bazel工程示例中两个典型的example:

  • examples/cpp-tutorial/stage1

  • examples/go-tutorial/stage1

  1. cpp: stage1示例

    该工程的目录结构如下:

     .
     |-- main
     |    |---- BUILD
     |    |---- hello-world.cc
     |-- MODULE.bazel
     |-- README.md
    

    这里我们来看看main/BUILD的内容:

     cc_binary(
       name = "hello-world",
       srcs = ["hello-world.cc"],
     )
    
  2. go: stage1示例

    该工程的目录结构如下:

     .
     |-- .bazelversion
     |-- BUILD
     |-- MODULE.bazel
     |-- hello.go
    

    其中:

    • .bazelversion文件用于指明所使用的Bazel版本

    • BUILD文件用于指明所构建的目标及规则

    • MODULE.bazel用于管理项目模块化和依赖关系的关键文件

    这里我们主要来看看BUILD文件的相关内容:

     load("@rules_go//go:def.bzl", "go_binary")
    
     go_binary(
       name = "hello",
       srcs = ["hello.go"],
     )
    

4.1 StarLark语言

Bazel的BUILD文件是采用StarLark语言进行编写的,这里我们先简单介绍该语言。

参看:

StarLark是Python的一种方言(dialect),主要用作配置语言。StarLark解释器通常是会被嵌入到另一个更大型的应用程序中,除了使用其基本语言核心功能之外,还可能会在应用程序中定义一些额外的领域特定函数和数据类型。比如,StarLark就被嵌入到了Bazel构建工具当中。

我们可以搭建独立的StarLark运行环境,也可以直接使用Bazel来运行。

4.1.1 搭建独立的StarLark运行环境

  1. 安装golang环境

  2. 安装StarLark CLI

     # go install go.starlark.net/cmd/starlark@latest
    
  3. 编写StarLark脚本

    示例: src/main.star

       print("hello, world")
    
  4. 运行脚本

     # starlark src/main.star
     hello, world
    

4.1.2 使用Bazel来运行Starlark

  1. 创建Starlark脚本并定义构建规则

    • 示例: src/main.bzl

      def _hello_world_impl(ctx):
      output = ctx.actions.declare_file("hello.txt")
      ctx.actions.write(
          output = output,
          content = "Hello from Starlark!",
      )
      return [DefaultInfo(files = depset([output]))]
      
      hello_world = rule(
          implementation = _hello_world_impl,
      )
      
    • 定义构建目标:BUILD

      load("//:src/main.bzl", "hello_world")
      
      hello_world(
        name = "generate_hello",
        visibility = ["//visibility:public"],
      )
      
    • 创建MODULE.bazel

      这里直接创建一个空文件即可。

  2. 构建与运行

    通过 Bazel 执行构建和测试。

     # bazel build //:generate_hello
    

4.2 Bazel内置rule

在我们前面的examples/cpp-tutorial/stage1示例中,有如下规则:

cc_binary(
      name = "hello-world",
      srcs = ["hello-world.cc"],
)

这是一个Bazel工具内置的规则。关于Bazel的内置规则,我们可以从如下地方找到相关资料:

下面我们介绍几个内置的Bazel rule:

  1. cc_binary规则

    该规则规则用于产生一个可执行的二进制文件,实现代码在:https://github.com/bazelbuild/bazel/tree/master/src/main/starlark/builtins_bzl/common/cc/cc_binary.bzl

    通过源代码我们可以看到cc_binary支持如下参数:

     cc_binary = rule(
         attrs = cc_binary_attrs,
     )
    

4.2.1 如何修改cc_binary的toolchains来调整链接顺序

如下是来自deepseek关于如何修改bazel cc_binary的toolchains来调整链接顺序的回答。

在 Bazel 中调整 cc_binary 的链接顺序,通常需要修改 C++ 工具链(C++ Toolchain)的配置,尤其是链接器(Linker)的参数。以下是分步实现方法:

  1. 理解 Bazel 的 C++ 工具链

    Bazel 的 C++ 工具链通过 cc_toolchain_config 规则定义,其核心配置文件会指定编译、链接等操作的命令行参数。链接顺序通常由以下因素决定:

    • deps 的顺序:cc_binary 的 deps 中库的顺序会影响链接顺序(后依赖的库优先)。

    • 工具链的链接参数:工具链中定义的链接器标志(如 linker_flag)可以强制调整顺序。

    若需要全局调整链接顺序(而非逐个目标修改 deps),需自定义工具链。

  2. 自定义 C++ 工具链

    • 步骤 1:创建工具链配置文件

      在项目目录(如 //toolchains/cpp)中创建工具链定义文件 BUILD.bazel 和 cc_toolchain_config.bzl。

      # toolchains/cpp/BUILD.bazel
      load(":cc_toolchain_config.bzl", "cc_toolchain_config")
      
      cc_toolchain_config(
          name = "my_cc_toolchain_config",
          cpu = "k8",  # 根据目标平台调整,如 x86_64、arm64
      )
      
      filegroup(name = "empty")
      
      cc_toolchain(
          name = "my_cc_toolchain",
          toolchain_config = ":my_cc_toolchain_config",
          all_files = ":empty",
          ar_files = ":empty",
          as_files = ":empty",
          compiler_files = ":empty",
          dwp_files = ":empty",
          linker_files = ":empty",
          objcopy_files = ":empty",
          strip_files = ":empty",
      )
      
      toolchain(
          name = "my_cc_toolchain_impl",
          exec_compatible_with = ["@platforms//os:linux"],
          target_compatible_with = ["@platforms//os:linux"],
          toolchain = ":my_cc_toolchain",
          toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
      )
      
    • 步骤 2:定义链接参数

      在 cc_toolchain_config.bzl 中调整链接顺序。例如,强制将某些库放在前面或后面:

        # toolchains/cpp/cc_toolchain_config.bzl
        load("@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl", "feature", "flag_group", "flag_set")
      
        def _impl(ctx):
            # 基础工具链配置(参考 Bazel 官方模板)
            features = [
                feature(
                    name = "default_linker_flags",
                    enabled = True,
                    flag_sets = [
                        flag_set(
                            actions = ["all_link_actions"],
                            flag_groups = [
                                flag_group(
                                    flags = [
                                        # 调整链接顺序的示例:
                                        # 1. 强制链接 libA 在 libB 之前
                                        "-Wl,--start-group",
                                        "-lA",
                                        "-lB",
                                        "-Wl,--end-group",
                                        # 2. 添加全局库路径
                                        "-L/path/to/custom/libs",
                                    ],
                                ),
                            ],
                        ),
                    ],
                ),
            ]
      
        # 返回工具链配置
        return cc_common.create_cc_toolchain_config_info(
            ctx = ctx,
            features = features,
            cxx_builtin_include_directories = [
                "/usr/include",
                "/usr/local/include",
            ],
            toolchain_identifier = "my-custom-toolchain",
            host_system_name = "local",
            target_system_name = "local",
            target_cpu = "k8",
            target_libc = "glibc_2.31",
            compiler = "gcc",
            abi_version = "gcc",
            abi_libc_version = "glibc_2.31",
        )
      
        cc_toolchain_config = rule(
            implementation = _impl,
            attrs = {},
            provides = [CcToolchainConfigInfo],
        )
      
  3. 注册自定义工具链

    在 WORKSPACE 或 WORKSPACE.bzlmod 中注册工具链:

     # WORKSPACE
     register_toolchains("//toolchains/cpp:my_cc_toolchain_impl")
    

    或在命令行中指定:

     # bazel build --extra_toolchains=//toolchains/cpp:my_cc_toolchain_impl ...
    
  4. 在 cc_binary 中使用自定义工具链

    在 cc_binary 中显式指定工具链(可选):

     cc_binary(
         name = "my_binary",
         srcs = ["main.cpp"],
         deps = ["//mylib"],
         toolchains = ["//toolchains/cpp:my_cc_toolchain_impl"],
     )
    
  5. 高级调整:通过 –linkopt 或 features

    • 方法 1:通过 --linkopt 传递参数

      在命令行中直接覆盖链接参数:

      bazel build //:my_binary --linkopt="-Wl,--start-group" --linkopt="-lA" --linkopt="-lB" --linkopt="-Wl,--end-group"
      
    • 方法 2:使用 features 动态控制

      在工具链配置中定义可开关的 feature:

        # cc_toolchain_config.bzl
        feature(
            name = "custom_link_order",
            enabled = False,
            flag_sets = [
                flag_set(
                    actions = ["all_link_actions"],
                    flag_groups = [
                        flag_group(flags = ["-Wl,--start-group", "-lA", "-lB", "-Wl,--end-group"]),
                    ],
                ),
            ],
        )
      

      在 cc_binary 中启用该特性:

      cc_binary(
          name = "my_binary",
          srcs = ["main.cpp"],
          features = ["custom_link_order"],
      )
      
  6. 验证链接顺序

    检查生成的链接命令:

     # bazel build --subcommands //:my_binary
    

    输出中应包含类似以下内容:

     SUBCOMMAND: linking my_binary
     ...
     /usr/bin/gcc ... -Wl,--start-group -lA -lB -Wl,--end-group ...
    

    关键注意事项:

    • 平台兼容性:

      • 不同平台(Linux/macOS/Windows)的链接器(ld/lld/link)参数不同,需针对性调整。

      • 例如 macOS 使用 -force_load 或 -all_load 替代 –start-group。

    • 工具链覆盖范围:

      • 自定义工具链会影响所有使用该工具链的目标,确保全局调整是必要的。
    • 依赖顺序:

      • 即使调整工具链,deps 中的顺序仍可能影响链接结果,建议同时检查 deps 顺序。
    • 工具链继承

      • 可基于 Bazel 默认工具链扩展,避免重复配置。例如:

        load("@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl", "feature", "flag_group", "flag_set")
        

4.3 Bazel扩展rule

参看:

4.4 高级: bazel中rule函数的实现

通过上面Bazel扩展rule一节,我们发现要实现一个自己的简单扩展rule并不复杂。本身rule是bazel的一个内置函数。这里我们来看看该内置函数的实现,以进一步理解bazel。

如下是来自于deepseek的关于bazel rule函数的实现源代码位置的回答。

4.4.1 Bazel的rule()函数

Bazel 的 rule() 函数是 Starlark 语言中用于自定义构建规则的核心接口,其底层实现主要位于 Bazel 的 Java 源代码中。以下是其实现的关键代码位置及功能解析:


  1. Starlark 层的 rule() 函数定义

    • 代码位置:Bazel 的 Starlark 内置函数 rule() 通过 Java 代码暴露给 Starlark 环境。其入口点位于 NativeModule 类中,负责将 Java 实现的函数绑定到 Starlark 的全局命名空间。

      • 相关文件:src/main/java/com/google/devtools/build/lib/starlarkbuildapi/StarlarkRuleFunctionsApi.java

      • 功能:定义 rule() 函数的参数(如 implementation、attrs 等),并验证参数合法性

  2. 规则类的构建与注册

    • RuleClass 类:规则的核心元数据(属性、输出模板、实现函数等)通过 RuleClass 类存储

      • 代码位置:src/main/java/com/google/devtools/build/lib/packages/RuleClass.java

      • 关键逻辑

        • 解析 attrs 参数,生成属性类型和约束条件。

        • 注册规则的输出文件模板(如 outs)。

        • 处理规则的隐式依赖和配置过渡(configuration transitions)

    • RuleFactory 类:负责将 Starlark 层的规则定义转换为 Java 层的 RuleClass 对象

      • 代码位置:src/main/java/com/google/devtools/build/lib/packages/RuleFactory.java

      • 功能:验证规则属性、处理继承关系(如 parent 规则)并生成最终的 RuleClass

  3. 规则实现函数的执行

    • StarlarkRuleImplementation 类:处理规则的分析阶段逻辑,即调用用户定义的 implementation 函数

      • 代码位置:src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkRuleImplementation.java

      • 关键流程:

        • 创建 ctx 对象(StarlarkRuleContext),提供属性访问、动作声明等接口。

        • 执行用户定义的 implementation 函数,生成动作(Action)和提供程序(Provider)

  4. 动作(Action)的生成与管理

    • ctx.actions 的实现:通过 StarlarkActionFactory 类将 Starlark 中的动作声明(如 run(), write())转换为 Bazel 内部的 Action 对象。

      • 代码位置:src/main/java/com/google/devtools/build/lib/analysis/starlark/StarlarkActionFactory.java 713。

      • 关联类:ActionOwner(动作所有者)、CommandLine(命令行参数生成)等

  5. 底层依赖与工具链集成

    • 工具链解析:规则可能依赖工具链(如 C++ 编译器、Sass 编译器),相关逻辑位于 ToolchainResolutionFunction

      • 代码位置:src/main/java/com/google/devtools/build/lib/analysis/ToolchainResolutionFunction.java
    • 平台与配置过渡:处理跨平台构建和配置参数传递,涉及 Transition 接口和 ConfigurationResolver 类

4.4.2 如何用java扩展starlark

如下是来自于deepseek关于如何用java扩展starlark的回答:

在 Bazel 中,Starlark(一种 Python 方言)的运行环境是由 Java 实现的,因此通过 Java 扩展 Starlark 的核心方法是定义新的 Starlark 内置函数或类型,并将其暴露给 Starlark 脚本使用。以下是具体实现步骤和示例。

  1. 扩展 Starlark 的基本流程

    要实现 Java 对 Starlark 的扩展,需要:

    • 定义 Java 类:实现函数逻辑或自定义数据类型。

    • 暴露给 Starlark:通过注解或注册机制,将 Java 类的方法绑定到 Starlark 环境。

    • 集成到 Bazel:将扩展代码编译到 Bazel 或插件中,供 Starlark 脚本调用

  2. 扩展 Starlark 函数(示例)

    假设我们要在 Starlark 中添加一个 hello(name) 函数,打印问候语。

    • 步骤 1:定义 Java 类

        // 文件路径: src/main/java/com/example/starlark/HelloModule.java
        package com.example.starlark;
      
        import net.starlark.java.annot.Param;
        import net.starlark.java.annot.StarlarkMethod;
        import net.starlark.java.eval.StarlarkValue;
        import net.starlark.java.eval.Starlark;
      
        public class HelloModule implements StarlarkValue {
      
            // 定义 Starlark 方法
            @StarlarkMethod(
                name = "hello",
                documented = false,
                parameters = {
                    @Param(name = "name", type = String.class, named = true)
                }
            )
            public String hello(String name) {
                return "Hello, " + name + "!";
            }
        }
      
    • 步骤 2:注册到 Starlark 环境

      在 Bazel 的全局模块中注册自定义模块:

        // 文件路径: src/main/java/com/example/starlark/CustomStarlarkModule.java
        package com.example.starlark;
      
        import com.google.devtools.build.lib.starlarkbuildapi.Core;
      
        public class CustomStarlarkModule implements Core {
            @Override
            public void addBindingsToBuilder(ImmutableMap.Builder<String, Object> builder) {
                builder.put("hello", new HelloModule());
            }
        }
      
    • 步骤 3:在 Bazel 中加载扩展

      在 Bazel 的初始化流程中加载自定义模块:

        // 修改 Bazel 的初始化代码(通常需要重新编译 Bazel)
        public class BazelMain {
            public static void main(String[] args) {
                // 注册自定义模块
                Starlark.addModule(new CustomStarlarkModule());
                // 启动 Bazel
                ...
            }
        }
      
  3. 扩展 Starlark 数据类型

    若需要定义新的 Starlark 类型(如自定义对象),可以继承 StarlarkValue:

    • 示例:定义 User 类型

        // 文件路径: src/main/java/com/example/starlark/User.java
        @StarlarkBuiltin(name = "User", doc = "Represents a user object.")
        public class User implements StarlarkValue {
            private final String name;
      
            public User(String name) {
                this.name = name;
            }
      
            @StarlarkMethod(name = "name", doc = "Returns the user's name.")
            public String getName() {
                return name;
            }
        }
      
    • 在 Starlark 中创建对象

      通过工厂方法暴露给 Starlark:

        @StarlarkMethod(name = "create_user", parameters = {@Param(name = "name", type = String.class)})
        public User createUser(String name) {
            return new User(name);
        }
      
  4. 在 Starlark 脚本中使用扩展

    编译并集成后,可以在 .bzl 文件中直接调用:

     # 调用自定义函数
     greeting = hello("World")  # 返回 "Hello, World!"
    
     # 使用自定义类型
     user = create_user("Alice")
     print(user.name)  # 输出 "Alice"
    
  5. 关键技术点

    • 注解驱动:

      • @StarlarkMethod:标记方法或类型,定义 Starlark 可见性。

      • @Param:定义函数参数类型和约束。

      • @StarlarkBuiltin:定义自定义类型的元数据

    • 类型映射:

      • Java 类型(如 String、List)会自动映射到 Starlark 类型。

      • 复杂类型需实现 StarlarkValue 接口。

    • 线程安全:

      Starlark 是线程安全的,确保扩展代码无副作用

    • 集成到 Bazel:

      • 若扩展是为 Bazel 定制,需将代码编译到 Bazel 的 @_builtins 或通过插件机制加载。
  6. 调试与验证

    • 单元测试:使用 Starlark 的 Java 测试框架

        @Test
        public void testHelloFunction() throws Exception {
            StarlarkThread thread = new StarlarkThread();
            Object result = Starlark.call(thread, new HelloModule(), "hello", ImmutableList.of("Alice"));
            assertThat(result).isEqualTo("Hello, Alice!");
        }
      
    • Bazel 加载:通过 –experimental_builtins_bzl_path 参数加载自定义模块。

  7. 实际应用场景

    • 自定义构建规则:封装复杂构建逻辑(如代码生成、工具链调用)。

    • 工具链集成:将外部工具(如代码检查器)暴露为 Starlark 函数。

    • 元编程:动态生成 BUILD 文件内容

5. 运行Bazel

参看:

从命令行中运行Bazel很简单,基本语法格式如下:

# bazel [<startup options>] <command> [<args>] -- [<target patterns>]

举例:

# bazel build //main:hello-world