bazel-build-optimization

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Bazel Build Optimization

Bazel构建优化

Production patterns for Bazel in large-scale monorepos.
适用于大规模单体仓库的Bazel生产实践模式。

When to Use This Skill

何时使用此技能

  • Setting up Bazel for monorepos
  • Configuring remote caching/execution
  • Optimizing build times
  • Writing custom Bazel rules
  • Debugging build issues
  • Migrating to Bazel
  • 为单体仓库搭建Bazel
  • 配置远程缓存/执行
  • 优化构建时间
  • 编写自定义Bazel规则
  • 调试构建问题
  • 迁移至Bazel

Core Concepts

核心概念

1. Bazel Architecture

1. Bazel架构

workspace/
├── WORKSPACE.bazel       # External dependencies
├── .bazelrc              # Build configurations
├── .bazelversion         # Bazel version
├── BUILD.bazel           # Root build file
├── apps/
│   └── web/
│       └── BUILD.bazel
├── libs/
│   └── utils/
│       └── BUILD.bazel
└── tools/
    └── bazel/
        └── rules/
workspace/
├── WORKSPACE.bazel       # 外部依赖
├── .bazelrc              # 构建配置
├── .bazelversion         # Bazel版本
├── BUILD.bazel           # 根构建文件
├── apps/
│   └── web/
│       └── BUILD.bazel
├── libs/
│   └── utils/
│       └── BUILD.bazel
└── tools/
    └── bazel/
        └── rules/

2. Key Concepts

2. 关键概念

ConceptDescription
TargetBuildable unit (library, binary, test)
PackageDirectory with BUILD file
LabelTarget identifier
//path/to:target
RuleDefines how to build a target
AspectCross-cutting build behavior
概念描述
Target可构建单元(库、二进制文件、测试用例)
Package包含BUILD文件的目录
Label目标标识符
//path/to:target
Rule定义目标的构建方式
Aspect跨切面的构建行为

Templates

模板

Template 1: WORKSPACE Configuration

模板1:WORKSPACE配置

python
undefined
python
undefined

WORKSPACE.bazel

WORKSPACE.bazel

workspace(name = "myproject")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
workspace(name = "myproject")
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

Rules for JavaScript/TypeScript

JavaScript/TypeScript规则

http_archive( name = "aspect_rules_js", sha256 = "...", strip_prefix = "rules_js-1.34.0", url = "https://github.com/aspect-build/rules_js/releases/download/v1.34.0/rules_js-v1.34.0.tar.gz", )
load("@aspect_rules_js//js:repositories.bzl", "rules_js_dependencies") rules_js_dependencies()
load("@rules_nodejs//nodejs:repositories.bzl", "nodejs_register_toolchains") nodejs_register_toolchains( name = "nodejs", node_version = "20.9.0", )
load("@aspect_rules_js//npm:repositories.bzl", "npm_translate_lock") npm_translate_lock( name = "npm", pnpm_lock = "//:pnpm-lock.yaml", verify_node_modules_ignored = "//:.bazelignore", )
load("@npm//:repositories.bzl", "npm_repositories") npm_repositories()
http_archive( name = "aspect_rules_js", sha256 = "...", strip_prefix = "rules_js-1.34.0", url = "https://github.com/aspect-build/rules_js/releases/download/v1.34.0/rules_js-v1.34.0.tar.gz", )
load("@aspect_rules_js//js:repositories.bzl", "rules_js_dependencies") rules_js_dependencies()
load("@rules_nodejs//nodejs:repositories.bzl", "nodejs_register_toolchains") nodejs_register_toolchains( name = "nodejs", node_version = "20.9.0", )
load("@aspect_rules_js//npm:repositories.bzl", "npm_translate_lock") npm_translate_lock( name = "npm", pnpm_lock = "//:pnpm-lock.yaml", verify_node_modules_ignored = "//:.bazelignore", )
load("@npm//:repositories.bzl", "npm_repositories") npm_repositories()

Rules for Python

Python规则

http_archive( name = "rules_python", sha256 = "...", strip_prefix = "rules_python-0.27.0", url = "https://github.com/bazelbuild/rules_python/releases/download/0.27.0/rules_python-0.27.0.tar.gz", )
load("@rules_python//python:repositories.bzl", "py_repositories") py_repositories()
undefined
http_archive( name = "rules_python", sha256 = "...", strip_prefix = "rules_python-0.27.0", url = "https://github.com/bazelbuild/rules_python/releases/download/0.27.0/rules_python-0.27.0.tar.gz", )
load("@rules_python//python:repositories.bzl", "py_repositories") py_repositories()
undefined

Template 2: .bazelrc Configuration

模板2:.bazelrc配置

bash
undefined
bash
undefined

.bazelrc

.bazelrc

Build settings

构建设置

build --enable_platform_specific_config build --incompatible_enable_cc_toolchain_resolution build --experimental_strict_conflict_checks
build --enable_platform_specific_config build --incompatible_enable_cc_toolchain_resolution build --experimental_strict_conflict_checks

Performance

性能设置

build --jobs=auto build --local_cpu_resources=HOST_CPUS*.75 build --local_ram_resources=HOST_RAM*.75
build --jobs=auto build --local_cpu_resources=HOST_CPUS*.75 build --local_ram_resources=HOST_RAM*.75

Caching

缓存设置

build --disk_cache=/.cache/bazel-disk build --repository_cache=/.cache/bazel-repo
build --disk_cache=/.cache/bazel-disk build --repository_cache=/.cache/bazel-repo

Remote caching (optional)

远程缓存(可选)

build:remote-cache --remote_cache=grpcs://cache.example.com build:remote-cache --remote_upload_local_results=true build:remote-cache --remote_timeout=3600
build:remote-cache --remote_cache=grpcs://cache.example.com build:remote-cache --remote_upload_local_results=true build:remote-cache --remote_timeout=3600

Remote execution (optional)

远程执行(可选)

build:remote-exec --remote_executor=grpcs://remote.example.com build:remote-exec --remote_instance_name=projects/myproject/instances/default build:remote-exec --jobs=500
build:remote-exec --remote_executor=grpcs://remote.example.com build:remote-exec --remote_instance_name=projects/myproject/instances/default build:remote-exec --jobs=500

Platform configurations

平台配置

build:linux --platforms=//platforms:linux_x86_64 build:macos --platforms=//platforms:macos_arm64
build:linux --platforms=//platforms:linux_x86_64 build:macos --platforms=//platforms:macos_arm64

CI configuration

CI配置

build:ci --config=remote-cache build:ci --build_metadata=ROLE=CI build:ci --bes_results_url=https://results.example.com/invocation/ build:ci --bes_backend=grpcs://bes.example.com
build:ci --config=remote-cache build:ci --build_metadata=ROLE=CI build:ci --bes_results_url=https://results.example.com/invocation/ build:ci --bes_backend=grpcs://bes.example.com

Test settings

测试设置

test --test_output=errors test --test_summary=detailed
test --test_output=errors test --test_summary=detailed

Coverage

覆盖率设置

coverage --combined_report=lcov coverage --instrumentation_filter="//..."
coverage --combined_report=lcov coverage --instrumentation_filter="//..."

Convenience aliases

便捷别名

build:opt --compilation_mode=opt build:dbg --compilation_mode=dbg
build:opt --compilation_mode=opt build:dbg --compilation_mode=dbg

Import user settings

导入用户设置

try-import %workspace%/user.bazelrc
undefined
try-import %workspace%/user.bazelrc
undefined

Template 3: TypeScript Library BUILD

模板3:TypeScript库BUILD文件

python
undefined
python
undefined

libs/utils/BUILD.bazel

libs/utils/BUILD.bazel

load("@aspect_rules_ts//ts:defs.bzl", "ts_project") load("@aspect_rules_js//js:defs.bzl", "js_library") load("@npm//:defs.bzl", "npm_link_all_packages")
npm_link_all_packages(name = "node_modules")
ts_project( name = "utils_ts", srcs = glob(["src/**/*.ts"]), declaration = True, source_map = True, tsconfig = "//:tsconfig.json", deps = [ ":node_modules/@types/node", ], )
js_library( name = "utils", srcs = [":utils_ts"], visibility = ["//visibility:public"], )
load("@aspect_rules_ts//ts:defs.bzl", "ts_project") load("@aspect_rules_js//js:defs.bzl", "js_library") load("@npm//:defs.bzl", "npm_link_all_packages")
npm_link_all_packages(name = "node_modules")
ts_project( name = "utils_ts", srcs = glob(["src/**/*.ts"]), declaration = True, source_map = True, tsconfig = "//:tsconfig.json", deps = [ ":node_modules/@types/node", ], )
js_library( name = "utils", srcs = [":utils_ts"], visibility = ["//visibility:public"], )

Tests

测试

load("@aspect_rules_jest//jest:defs.bzl", "jest_test")
jest_test( name = "utils_test", config = "//:jest.config.js", data = [ ":utils", "//:node_modules/jest", ], node_modules = "//:node_modules", )
undefined
load("@aspect_rules_jest//jest:defs.bzl", "jest_test")
jest_test( name = "utils_test", config = "//:jest.config.js", data = [ ":utils", "//:node_modules/jest", ], node_modules = "//:node_modules", )
undefined

Template 4: Python Library BUILD

模板4:Python库BUILD文件

python
undefined
python
undefined

libs/ml/BUILD.bazel

libs/ml/BUILD.bazel

load("@rules_python//python:defs.bzl", "py_library", "py_test", "py_binary") load("@pip//:requirements.bzl", "requirement")
py_library( name = "ml", srcs = glob(["src/**/*.py"]), deps = [ requirement("numpy"), requirement("pandas"), requirement("scikit-learn"), "//libs/utils:utils_py", ], visibility = ["//visibility:public"], )
py_test( name = "ml_test", srcs = glob(["tests/**/*.py"]), deps = [ ":ml", requirement("pytest"), ], size = "medium", timeout = "moderate", )
py_binary( name = "train", srcs = ["train.py"], deps = [":ml"], data = ["//data:training_data"], )
undefined
load("@rules_python//python:defs.bzl", "py_library", "py_test", "py_binary") load("@pip//:requirements.bzl", "requirement")
py_library( name = "ml", srcs = glob(["src/**/*.py"]), deps = [ requirement("numpy"), requirement("pandas"), requirement("scikit-learn"), "//libs/utils:utils_py", ], visibility = ["//visibility:public"], )
py_test( name = "ml_test", srcs = glob(["tests/**/*.py"]), deps = [ ":ml", requirement("pytest"), ], size = "medium", timeout = "moderate", )
py_binary( name = "train", srcs = ["train.py"], deps = [":ml"], data = ["//data:training_data"], )
undefined

Template 5: Custom Rule for Docker

模板5:Docker自定义规则

python
undefined
python
undefined

tools/bazel/rules/docker.bzl

tools/bazel/rules/docker.bzl

def _docker_image_impl(ctx): dockerfile = ctx.file.dockerfile base_image = ctx.attr.base_image layers = ctx.files.layers
# Build the image
output = ctx.actions.declare_file(ctx.attr.name + ".tar")

args = ctx.actions.args()
args.add("--dockerfile", dockerfile)
args.add("--output", output)
args.add("--base", base_image)
args.add_all("--layer", layers)

ctx.actions.run(
    inputs = [dockerfile] + layers,
    outputs = [output],
    executable = ctx.executable._builder,
    arguments = [args],
    mnemonic = "DockerBuild",
    progress_message = "Building Docker image %s" % ctx.label,
)

return [DefaultInfo(files = depset([output]))]
docker_image = rule( implementation = _docker_image_impl, attrs = { "dockerfile": attr.label( allow_single_file = [".dockerfile", "Dockerfile"], mandatory = True, ), "base_image": attr.string(mandatory = True), "layers": attr.label_list(allow_files = True), "_builder": attr.label( default = "//tools/docker:builder", executable = True, cfg = "exec", ), }, )
undefined
def _docker_image_impl(ctx): dockerfile = ctx.file.dockerfile base_image = ctx.attr.base_image layers = ctx.files.layers
# 构建镜像
output = ctx.actions.declare_file(ctx.attr.name + ".tar")

args = ctx.actions.args()
args.add("--dockerfile", dockerfile)
args.add("--output", output)
args.add("--base", base_image)
args.add_all("--layer", layers)

ctx.actions.run(
    inputs = [dockerfile] + layers,
    outputs = [output],
    executable = ctx.executable._builder,
    arguments = [args],
    mnemonic = "DockerBuild",
    progress_message = "Building Docker image %s" % ctx.label,
)

return [DefaultInfo(files = depset([output]))]
docker_image = rule( implementation = _docker_image_impl, attrs = { "dockerfile": attr.label( allow_single_file = [".dockerfile", "Dockerfile"], mandatory = True, ), "base_image": attr.string(mandatory = True), "layers": attr.label_list(allow_files = True), "_builder": attr.label( default = "//tools/docker:builder", executable = True, cfg = "exec", ), }, )
undefined

Template 6: Query and Dependency Analysis

模板6:查询与依赖分析

bash
undefined
bash
undefined

Find all dependencies of a target

查找某个目标的所有依赖

bazel query "deps(//apps/web:web)"
bazel query "deps(//apps/web:web)"

Find reverse dependencies (what depends on this)

查找反向依赖(哪些目标依赖当前目标)

bazel query "rdeps(//..., //libs/utils:utils)"
bazel query "rdeps(//..., //libs/utils:utils)"

Find all targets in a package

查找某个包下的所有目标

bazel query "//libs/..."
bazel query "//libs/..."

Find changed targets since commit

查找自上次提交后变更的目标

bazel query "rdeps(//..., set($(git diff --name-only HEAD~1 | sed 's/.*/"&"/' | tr '\n' ' ')))"
bazel query "rdeps(//..., set($(git diff --name-only HEAD~1 | sed 's/.*/"&"/' | tr '\n' ' ')))"

Generate dependency graph

生成依赖图

bazel query "deps(//apps/web:web)" --output=graph | dot -Tpng > deps.png
bazel query "deps(//apps/web:web)" --output=graph | dot -Tpng > deps.png

Find all test targets

查找所有测试目标

bazel query "kind('.*_test', //...)"
bazel query "kind('.*_test', //...)"

Find targets with specific tag

查找带有特定标签的目标

bazel query "attr(tags, 'integration', //...)"
bazel query "attr(tags, 'integration', //...)"

Compute build graph size

计算构建图大小

bazel query "deps(//...)" --output=package | wc -l
undefined
bazel query "deps(//...)" --output=package | wc -l
undefined

Template 7: Remote Execution Setup

模板7:远程执行设置

python
undefined
python
undefined

platforms/BUILD.bazel

platforms/BUILD.bazel

platform( name = "linux_x86_64", constraint_values = [ "@platforms//os:linux", "@platforms//cpu:x86_64", ], exec_properties = { "container-image": "docker://gcr.io/myproject/bazel-worker:latest", "OSFamily": "Linux", }, )
platform( name = "remote_linux", parents = [":linux_x86_64"], exec_properties = { "Pool": "default", "dockerNetwork": "standard", }, )
platform( name = "linux_x86_64", constraint_values = [ "@platforms//os:linux", "@platforms//cpu:x86_64", ], exec_properties = { "container-image": "docker://gcr.io/myproject/bazel-worker:latest", "OSFamily": "Linux", }, )
platform( name = "remote_linux", parents = [":linux_x86_64"], exec_properties = { "Pool": "default", "dockerNetwork": "standard", }, )

toolchains/BUILD.bazel

toolchains/BUILD.bazel

toolchain( name = "cc_toolchain_linux", exec_compatible_with = [ "@platforms//os:linux", "@platforms//cpu:x86_64", ], target_compatible_with = [ "@platforms//os:linux", "@platforms//cpu:x86_64", ], toolchain = "@remotejdk11_linux//:jdk", toolchain_type = "@bazel_tools//tools/jdk:runtime_toolchain_type", )
undefined
toolchain( name = "cc_toolchain_linux", exec_compatible_with = [ "@platforms//os:linux", "@platforms//cpu:x86_64", ], target_compatible_with = [ "@platforms//os:linux", "@platforms//cpu:x86_64", ], toolchain = "@remotejdk11_linux//:jdk", toolchain_type = "@bazel_tools//tools/jdk:runtime_toolchain_type", )
undefined

Performance Optimization

性能优化

bash
undefined
bash
undefined

Profile build

分析构建性能

bazel build //... --profile=profile.json bazel analyze-profile profile.json
bazel build //... --profile=profile.json bazel analyze-profile profile.json

Identify slow actions

识别缓慢的构建动作

bazel build //... --execution_log_json_file=exec_log.json
bazel build //... --execution_log_json_file=exec_log.json

Memory profiling

内存分析

bazel build //... --memory_profile=memory.json
bazel build //... --memory_profile=memory.json

Skip analysis cache

跳过分析缓存

bazel build //... --notrack_incremental_state
undefined
bazel build //... --notrack_incremental_state
undefined

Best Practices

最佳实践

Do's

建议

  • Use fine-grained targets - Better caching
  • Pin dependencies - Reproducible builds
  • Enable remote caching - Share build artifacts
  • Use visibility wisely - Enforce architecture
  • Write BUILD files per directory - Standard convention
  • 使用细粒度目标 - 提升缓存效率
  • 固定依赖版本 - 实现可复现构建
  • 启用远程缓存 - 共享构建产物
  • 合理使用可见性 - 架构强制约束
  • 每个目录编写BUILD文件 - 遵循标准约定

Don'ts

禁忌

  • Don't use glob for deps - Explicit is better
  • Don't commit bazel-* dirs - Add to .gitignore
  • Don't skip WORKSPACE setup - Foundation of build
  • Don't ignore build warnings - Technical debt
  • 不要在依赖中使用glob - 显式声明更优
  • *不要提交bazel-目录 - 添加至.gitignore
  • 不要跳过WORKSPACE配置 - 构建的基础核心
  • 不要忽略构建警告 - 避免技术债务积累

Resources

参考资源