Contents

Bazel 简介

1. 概述

Bazel 是一个用于构建和测试源代码的开源工具,类似于 Maven 和 Gradle。它支持多种语言的项目并为多个平台构建输出

在本教程中,我们将完成使用 Bazel 构建简单 Java 应用程序所需的步骤。为了说明,我们将从一个多模块 Maven 项目开始,然后使用 Bazel 构建源代码。

我们将从安装 Bazel 开始。

2. 项目结构

让我们创建一个多模块 Maven 项目:

bazel (root)
    pom.xml
    WORKSPACE (bazel workspace)
    |— bazelapp
        pom.xml
        BUILD (bazel build file)
        |— src
            |— main
                |— java
            |— test
                |— java
    |— bazelgreeting
        pom.xml
        BUILD (bazel build file)
        |— src
            |— main
                |— java
            |— test
                |— java

WORKSPACE文件的存在为 Bazel 设置了工作空间。一个项目中可能有一个或多个。对于我们的示例,我们将在顶级项目目录中仅保留一个文件。

下一个重要文件是BUILD文件,其中包含构建规则。它用唯一的target name标识每个规则。

Bazel提供了灵活性,可以根据需要拥有任意数量的BUILD文件,并配置为任何粒度级别。这意味着我们可以通过相应地配置BUILD规则来构建较少数量的 Java 类。为了简单起见,我们将在示例中保留最少的BUILD文件。

由于 Bazel BUILD配置的输出通常是一个 jar 文件,我们将包含BUILD文件的每个目录称为构建包。

3. 构建文件

3.1. 规则配置

是时候配置我们的第一个构建规则来构建 Java 二进制文件了。让我们在属于bazelapp模块的BUILD文件中配置一个:

java_binary (
    name = "BazelApp",
    srcs = glob(["src/main/java/com/blogdemo/*.java"]),
    main_class = "com.blogdemo.BazelApp"
)

让我们一一了解配置设置:

  • java_binary – 规则的名称;它需要额外的属性来构建二进制文件
  • name – 构建目标的名称
  • srcs – 一个文件位置模式数组,用于告诉要构建哪些 Java 文件
  • main_class – 应用程序主类的名称(可选)

3.2. 构建执行

我们现在可以构建应用程序了。从包含WORKSPACE文件的目录中*,让我们在 shell 中执行bazel build*命令来构建我们的目标:

$ bazel build //bazelapp:BazelApp

最后一个参数是在其中一个BUILD文件中配置的目标名称。它具有“ //path_to_build:target_name ”模式。

模式的第一部分“//”表示我们从工作区目录开始。下一个*“bazelapp”是工作区目录中**BUILD文件的相对路径。最后,“BazelApp”*是要构建的目标名称。

3.3. 构建输出

我们现在应该注意到上一步的两个二进制输出文件:

bazel-bin/bazelapp/BazelApp.jar
bazel-bin/bazelapp/BazelApp

BazelApp.jar包含所有类,而BazelApp是执行 jar 文件的包装脚本。

3.4. 可部署的 JAR

我们可能需要将 jar 及其依赖项运送到不同的位置进行部署。

上一节中的包装脚本将所有依赖项(jar 文件)指定为BazelApp.jar的启动命令的一部分。

但是,我们也可以制作一个包含所有依赖项的胖 jar:

$ bazel build //bazelapp:BazelApp_deploy.jar

使用*“_deploy”* 作为目标名称的后缀指示 Bazel 将所有依赖项打包到 jar 中并准备好部署。

4. 依赖

到目前为止,我们只使用*bazelapp 中的文件进行构建。*但是,大多数应用程序都有依赖项。

在本节中,我们将了解如何将依赖项与 jar 文件一起打包。

4.1. 创建库

不过,在我们这样做之前,我们需要一个bazelapp可以使用的依赖项。 让我们创建另一个名为bazelgreeting的 Maven 模块,并使用java_library规则为新模块 配置*BUILD文件。*我们将这个目标命名为“ greeter”

java_library (
    name = "greeter",
    srcs = glob(["src/main/java/com/blogdemo/*.java"])
)

在这里,我们使用java_library规则来创建库。构建此目标后,我们将获得libgreetings.jar文件:

INFO: Found 1 target...
Target //bazelgreeting:greetings up-to-date:
  bazel-bin/bazelgreeting/libgreetings.jar

4.2. 配置依赖

要在 bazelapp 中使用 greeter ,我们需要一些额外的配置。首先,我们需要让包对bazelapp可见。我们可以通过在greeter 包的java_library规则中添加visibility属性来实现这一点:

java_library (
    name = "greeter",
    srcs = glob(["src/main/java/com/blogdemo/*.java"]),
    visibility = ["//bazelapp:__pkg__"]
)

visibility属性使当前包对数组中列出的包可见。

现在在bazelapp包中,我们必须配置对greeter包的依赖 。让我们用deps属性来做这件事:

java_binary (
    name = "BazelApp",
    srcs = glob(["src/main/java/com/blogdemo/*.java"]),
    main_class = "com.blogdemo.BazelApp",
    deps = ["//bazelgreeting:greeter"]
)

deps属性使当前包依赖于数组中列出的那些。

5. 外部依赖

我们可以处理具有多个工作区并相互依赖的项目。或者,我们可以从远程位置导入库。我们可以将这样的外部依赖分类为:

  • 本地依赖关系:我们在上一节中看到的相同工作空间内管理它们,或者跨越多个工作空间
  • HTTP 档案:我们通过 HTTP 从远程位置导入库

有许多 Bazel 规则可用于管理外部依赖 项。我们将在后续部分中了解如何从远程位置导入 jar 文件。

5.1. HTTP URL 位置

对于我们的示例,让我们将Apache Commons Lang 导入我们的应用程序。由于我们必须从 HTTP 位置导入这个 jar,我们将使用http_jar 规则。我们将首先从 Bazel HTTP 构建定义中加载规则,并在WORKSPACE文件中使用 Apache Commons 的位置对其进行配置:

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_jar")
http_jar (
    name = "apache-commons-lang",
    url = "https://repo1.maven.org/maven2/org/apache/commons/commons-lang3/3.12.0/commons-lang3-3.12.0.jar"
)

我们必须在*“ bazelapp”包的BUILD*文件中进一步添加依赖:

deps = ["//bazelgreeting:greeter", "@apache-commons-lang//jar"]

注意,我们需要从WORKSPACE文件中指定用于http_jar规则的相同名称。

5.2. Maven 依赖项

管理单个 jar 文件成为一项乏味的任务。或者,我们可以使用WORKSPACE文件中的**rules_jvm_external 规则配置 Maven 存储库。**这将使我们能够从存储库中获取项目中所需的尽可能多的依赖项。

首先,我们必须使用WORKSPACE文件中的http_archive规则从远程位置导入rules_jvm_external规则:

load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
RULES_JVM_EXTERNAL_TAG = "2.0.1"
RULES_JVM_EXTERNAL_SHA = "55e8d3951647ae3dffde22b4f7f8dee11b3f70f3f89424713debd7076197eaca"
http_archive(
    name = "rules_jvm_external",
    strip_prefix = "rules_jvm_external-%s" % RULES_JVM_EXTERNAL_TAG,
    sha256 = RULES_JVM_EXTERNAL_SHA,
    url = "https://github.com/bazelbuild/rules_jvm_external/archive/%s.zip" % RULES_JVM_EXTERNAL_TAG,
)

接下来,我们将使用maven_install规则并配置 Maven 存储库 URL 和所需的工件:

load("@rules_jvm_external//:defs.bzl", "maven_install")
maven_install(
    artifacts = [
        "org.apache.commons:commons-lang3:3.12.0" ], 
    repositories = [ 
        "https://repo1.maven.org/maven2", 
    ] )

最后,我们将在BUILD文件中添加依赖项:

deps = ["//bazelgreeting:greeter", "@maven//:org_apache_commons_commons_lang3"]

它使用下划线 (_) 字符解析工件的名称。