返回

如何在 Bazel 中根据构建目标有条件地下载依赖项?

Android

在 Bazel 中有条件地下载依赖项

问题

你在一个项目中工作,需要构建 Android 和非 Android 目标。你的 WORKSPACE.bazel 文件包含与 Android 相关的依赖项,但你不希望所有开发者下载 Android SDK,尤其是那些不参与 Android 目标的人。

解决方法

Bazel 提供两种方法来根据构建目标选择性地下载依赖项:

方法 1:使用配置

使用配置,你可以定义条件并根据条件构建相同的目标。例如,你可以创建一个名为 "android" 的配置,如下所示:

config_setting(
  name = "android",
  values = {"define": "ANDROID=true"},
)

然后,在构建文件中,你可以使用 select 语句根据配置有条件地加载依赖项:

android_sdk_repository(
  name = "androidsdk",
  api_level = 33,
)

http_archive(
  name = "rules_android_ndk",
  ...
)

load("@rules_android_ndk//:rules.bzl", "android_ndk_repository")
android_ndk_repository(
  name = "androidndk",
  api_level = 33,
)

register_toolchains("@androidndk//:all")

select({
  "//:android": {
    deps = [":androidsdk", ":rules_android_ndk", ":androidndk"],
  },
  "//conditions:default": {
    deps = [],
  },
})

最后,在构建命令中指定配置:

bazel build //... --config=android

方法 2:使用宏

宏允许你在构建文件中定义自定义函数。你可以创建一个名为 android_deps 的宏,如下所示:

def android_deps():
  android_sdk_repository(
    name = "androidsdk",
    api_level = 33,
  )

  http_archive(
    name = "rules_android_ndk",
    ...
  )

  load("@rules_android_ndk//:rules.bzl", "android_ndk_repository")
  android_ndk_repository(
    name = "androidndk",
    api_level = 33,
  )

  register_toolchains("@androidndk//:all")

然后,在 WORKSPACE 文件中使用宏:

android_deps()

select({
  "//:android": {
    deps = [],
  },
  "//conditions:default": {
    deps = [],
  },
})

最后,在构建命令中指定宏:

bazel build //... --define=ANDROID=true

选择合适的方法

配置 更适合需要根据多个条件构建目标的情况,而 更适合需要根据单个条件构建目标的情况。

结论

通过使用配置或宏,你可以根据构建目标选择性地下载依赖项,优化开发流程,减少不必要的下载。

常见问题解答

1. 如何在构建命令中同时使用配置和宏?

你可以使用 --define 标志设置宏,然后使用 --config 标志设置配置。例如:

bazel build //... --config=android --define=ANDROID=true

2. 是否可以将条件应用于 WORKSPACE 文件中的其他内容?

是的,配置和宏也可以用来有条件地加载工作空间中的其他文件。

3. 如何调试有条件加载依赖项时遇到的问题?

你可以使用 --output_groups=deps 标志来打印构建过程中加载的依赖项列表。

4. 有没有其他方法可以有条件地加载依赖项?

除了配置和宏之外,你还可以使用 if 语句或 external 函数。

5. 有哪些最佳实践可以遵循以有效地使用有条件加载?

  • 将条件保持简洁明了。
  • 使用注释来解释条件。
  • 测试不同的构建配置以确保它们按预期工作。