Aller au contenu

Feuilles chauffantes de Bazel

Aperçu général

Bazel est un outil de construction rapide, évolutif et multilingue développé par Google. Il prend en charge les grandes bases de code, fournit des constructions progressives rapides et offre des constructions reproductibles sur différentes plateformes.

Installation

Gestionnaires de paquets

# macOS
brew install bazel

# Ubuntu/Debian
curl -fsSL https://bazel.build/bazel-release.pub.gpg|gpg --dearmor > bazel.gpg
sudo mv bazel.gpg /etc/apt/trusted.gpg.d/
echo "deb [arch=amd64] https://storage.googleapis.com/bazel-apt stable jdk1.8"|sudo tee /etc/apt/sources.list.d/bazel.list
sudo apt update && sudo apt install bazel

# CentOS/RHEL
sudo dnf copr enable vbatts/bazel
sudo dnf install bazel

# Windows (Chocolatey)
choco install bazel

# Manual installation
wget https://github.com/bazelbuild/bazel/releases/download/6.0.0/bazel-6.0.0-installer-linux-x86_64.sh
chmod +x bazel-6.0.0-installer-linux-x86_64.sh
./bazel-6.0.0-installer-linux-x86_64.sh --user

Vérification

bazel version
```_

## Concepts de base

### Termes clés

Workspace # Root directory containing WORKSPACE file Package # Directory containing BUILD file Target # Buildable unit (binary, library, test) Label # Unique identifier for targets Rule # Function that defines how to build targets


### Structure du projet

workspace/ ├── WORKSPACE ├── .bazelrc ├── BUILD ├── src/ │ ├── main/ │ │ ├── java/ │ │ └── BUILD │ └── test/ │ ├── java/ │ └── BUILD └── third_party/ └── BUILD


## ESPACE DE TRAVAIL Fichier

### ESPACE DE TRAVAIL DE BASE
```python
workspace(name = "my_project")

# Load rules
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")

# Java rules
http_archive(
    name = "rules_java",
    urls = ["https://github.com/bazelbuild/rules_java/releases/download/6.0.0/rules_java-6.0.0.tar.gz"],
    sha256 = "469b7f3b580b4fcf8112f4d6d0d5a4ce8e1ad5e21fee67d8e8335d5f018f7a4a",
)

# Python rules
http_archive(
    name = "rules_python",
    sha256 = "8c8fe44ef0a9afc256d1e75ad5f448bb59b81aba149b8958f02f7b3a98f5d9b4",
    strip_prefix = "rules_python-0.13.0",
    url = "https://github.com/bazelbuild/rules_python/archive/refs/tags/0.13.0.tar.gz",
)

# Go rules
http_archive(
    name = "io_bazel_rules_go",
    sha256 = "099a9fb96a376ccbbb7d291ed4ecbdfd42f6bc822ab77ae6f1b5cb9e914e94fa",
    urls = [
        "https://mirror.bazel.build/github.com/bazelbuild/rules_go/releases/download/v0.35.0/rules_go-v0.35.0.zip",
        "https://github.com/bazelbuild/rules_go/releases/download/v0.35.0/rules_go-v0.35.0.zip",
    ],
)

load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")
go_rules_dependencies()
go_register_toolchains(version = "1.19.3")

Dépendances extérieures

# Maven dependencies
load("@rules_jvm_external//:defs.bzl", "maven_install")

maven_install(
    artifacts = [
        "junit:junit:4.13.2",
        "com.google.guava:guava:31.1-jre",
        "org.apache.commons:commons-lang3:3.12.0",
    ],
    repositories = [
        "https://repo1.maven.org/maven2",
    ],
)

# Git repository
load("@bazel_tools//tools/build_defs/repo:git.bzl", "git_repository")

git_repository(
    name = "com_google_protobuf",
    remote = "https://github.com/protocolbuffers/protobuf",
    tag = "v3.21.7",
)

# Local repository
local_repository(
    name = "my_local_repo",
    path = "/path/to/local/repo",
)

Bâtir des fichiers

Exemple de Java

# Load rules
load("@rules_java//java:defs.bzl", "java_binary", "java_library", "java_test")

# Java library
java_library(
    name = "hello-lib",
    srcs = ["src/main/java/com/example/Hello.java"],
    deps = [
        "@maven//:com_google_guava_guava",
        "@maven//:org_apache_commons_commons_lang3",
    ],
    visibility = ["//visibility:public"],
)

# Java binary
java_binary(
    name = "hello-world",
    srcs = ["src/main/java/com/example/Main.java"],
    main_class = "com.example.Main",
    deps = [":hello-lib"],
)

# Java test
java_test(
    name = "hello-test",
    srcs = ["src/test/java/com/example/HelloTest.java"],
    test_class = "com.example.HelloTest",
    deps = [
        ":hello-lib",
        "@maven//:junit_junit",
    ],
)

Exemple de python

load("@rules_python//python:defs.bzl", "py_binary", "py_library", "py_test")

# Python library
py_library(
    name = "hello_lib",
    srcs = ["hello_lib.py"],
    deps = [
        "@pip//requests",
        "@pip//numpy",
    ],
    visibility = ["//visibility:public"],
)

# Python binary
py_binary(
    name = "hello_world",
    srcs = ["main.py"],
    deps = [":hello_lib"],
    python_version = "PY3",
)

# Python test
py_test(
    name = "hello_test",
    srcs = ["hello_test.py"],
    deps = [
        ":hello_lib",
        "@pip//pytest",
    ],
)

Go Exemple

load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library", "go_test")

# Go library
go_library(
    name = "hello_lib",
    srcs = ["hello.go"],
    importpath = "github.com/example/hello",
    visibility = ["//visibility:public"],
    deps = [
        "@com_github_gorilla_mux//:mux",
    ],
)

# Go binary
go_binary(
    name = "hello_world",
    embed = [":hello_lib"],
)

# Go test
go_test(
    name = "hello_test",
    srcs = ["hello_test.go"],
    embed = [":hello_lib"],
)

C++ Exemple

load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library", "cc_test")

# C++ library
cc_library(
    name = "hello_lib",
    srcs = ["hello.cc"],
    hdrs = ["hello.h"],
    deps = [
        "@com_google_absl//absl/strings",
    ],
    visibility = ["//visibility:public"],
)

# C++ binary
cc_binary(
    name = "hello_world",
    srcs = ["main.cc"],
    deps = [":hello_lib"],
)

# C++ test
cc_test(
    name = "hello_test",
    srcs = ["hello_test.cc"],
    deps = [
        ":hello_lib",
        "@com_google_googletest//:gtest_main",
    ],
)

Utilisation de la ligne de commande

Commandes de base

# Build target
bazel build //src:hello-world
bazel build //...  # Build all targets

# Run binary
bazel run //src:hello-world

# Test
bazel test //src:hello-test
bazel test //...  # Test all targets

# Clean
bazel clean
bazel clean --expunge  # Deep clean

# Query
bazel query //...
bazel query "deps(//src:hello-world)"

# Info
bazel info
bazel version

Options avancées

# Parallel builds
bazel build //... --jobs=8

# Verbose output
bazel build //... --verbose_failures

# Compilation mode
bazel build //... --compilation_mode=opt  # optimized
bazel build //... --compilation_mode=dbg  # debug

# Platform-specific builds
bazel build //... --platforms=@io_bazel_rules_go//go/toolchain:linux_amd64

# Remote execution
bazel build //... --remote_executor=grpc://remote-executor:8980

# Build with specific flags
bazel build //... --copt=-O2 --linkopt=-static

# Test with specific options
bazel test //... --test_output=all --test_verbose_timeout_warnings

Configuration

# Use .bazelrc file
bazel build //...  # Uses settings from .bazelrc

# Override config
bazel build //... --config=release

# Set flags
bazel build //... --define=version=1.0.0

Configuration (.bazelrc)

Configuration de base

# Build settings
build --compilation_mode=opt
build --copt=-O2
build --copt=-DNDEBUG

# Test settings
test --test_output=errors
test --test_verbose_timeout_warnings

# Common flags
common --enable_platform_specific_config

# Platform-specific settings
build:linux --copt=-fPIC
build:macos --copt=-Wno-deprecated-declarations
build:windows --copt=/W3

# Configuration aliases
build:release --compilation_mode=opt --strip=always
build:debug --compilation_mode=dbg --strip=never

# Remote execution
build:remote --remote_executor=grpc://remote-executor:8980
build:remote --remote_cache=grpc://remote-cache:8981

Configuration avancée

# Memory settings
build --local_ram_resources=8192
build --local_cpu_resources=8

# Disk cache
build --disk_cache=/tmp/bazel-cache

# Remote cache
build --remote_cache=https://storage.googleapis.com/my-bazel-cache

# Build event service
build --bes_backend=grpc://build-event-service:8982
build --bes_results_url=https://my-build-results.com/

# Execution strategies
build --spawn_strategy=sandboxed
build --strategy=Javac=worker
build --strategy=CppCompile=sandboxed

# Sandboxing
build --sandbox_debug
build --sandbox_writable_path=/tmp

Règles et Macros

Règles douanières

# rules.bzl
def _my_rule_impl(ctx):
    output = ctx.actions.declare_file(ctx.label.name + ".out")
    ctx.actions.run_shell(
        inputs = ctx.files.srcs,
        outputs = [output],
        command = "cat \\\\{\\\\} > \\\\{\\\\}".format(" ".join([f.path for f in ctx.files.srcs]), output.path),
    )
    return [DefaultInfo(files = depset([output]))]

my_rule = rule(
    implementation = _my_rule_impl,
    attrs = \\\\{
        "srcs": attr.label_list(allow_files = True),
    \\\\},
)

Macros

# macros.bzl
def java_service(name, srcs, deps = [], **kwargs):
    """Macro to create a Java service with common dependencies."""
    java_library(
        name = name + "_lib",
        srcs = srcs,
        deps = deps + [
            "@maven//:com_google_guava_guava",
            "@maven//:org_slf4j_slf4j_api",
        ],
        **kwargs
    )

    java_binary(
        name = name,
        main_class = "com.example.Main",
        runtime_deps = [name + "_lib"],
        **kwargs
    )

# Usage in BUILD file
load("//tools:macros.bzl", "java_service")

java_service(
    name = "my_service",
    srcs = ["Main.java", "Service.java"],
    deps = ["//common:utils"],
)

Aspects

# aspects.bzl
def _print_aspect_impl(target, ctx):
    print("Target: %s" % target.label)
    return []

print_aspect = aspect(
    implementation = _print_aspect_impl,
    attr_aspects = ["deps"],
)

# Usage
bazel build //src:hello-world --aspects=//tools:aspects.bzl%print_aspect

Essais

Configuration d'essai

# BUILD file
java_test(
    name = "integration_test",
    srcs = ["IntegrationTest.java"],
    deps = [
        ":hello_lib",
        "@maven//:junit_junit",
    ],
    size = "large",
    timeout = "long",
    tags = ["integration"],
    data = ["//testdata:sample_files"],
    jvm_flags = ["-Xmx2g"],
)

# Test suite
test_suite(
    name = "all_tests",
    tests = [
        ":unit_tests",
        ":integration_tests",
    ],
)

Exécution des essais

# Run specific test
bazel test //src:hello_test

# Run tests by tag
bazel test //... --test_tag_filters=unit
bazel test //... --test_tag_filters=-integration

# Run tests by size
bazel test //... --test_size_filters=small,medium

# Parallel test execution
bazel test //... --local_test_jobs=4

# Test with coverage
bazel coverage //src:hello_test

Projets multilingues

Configuration de l'espace de travail

# WORKSPACE
workspace(name = "multi_lang_project")

# Java
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
http_archive(name = "rules_java", ...)

# Python
http_archive(name = "rules_python", ...)
load("@rules_python//python:pip.bzl", "pip_install")
pip_install(
    name = "pip",
    requirements = "//python:requirements.txt",
)

# Go
http_archive(name = "io_bazel_rules_go", ...)
load("@io_bazel_rules_go//go:deps.bzl", "go_register_toolchains", "go_rules_dependencies")
go_rules_dependencies()
go_register_toolchains(version = "1.19.3")

# Protocol Buffers
http_archive(name = "com_google_protobuf", ...)
load("@com_google_protobuf//:protobuf_deps.bzl", "protobuf_deps")
protobuf_deps()

Dépendances entre langues

# proto/BUILD
load("@rules_proto//proto:defs.bzl", "proto_library")
load("@rules_java//java:defs.bzl", "java_proto_library")
load("@io_bazel_rules_go//proto:def.bzl", "go_proto_library")

proto_library(
    name = "api_proto",
    srcs = ["api.proto"],
    visibility = ["//visibility:public"],
)

java_proto_library(
    name = "api_java_proto",
    deps = [":api_proto"],
)

go_proto_library(
    name = "api_go_proto",
    importpath = "github.com/example/api",
    proto = ":api_proto",
)

# java/BUILD
java_library(
    name = "java_service",
    srcs = ["Service.java"],
    deps = ["//proto:api_java_proto"],
)

# go/BUILD
go_library(
    name = "go_service",
    srcs = ["service.go"],
    deps = ["//proto:api_go_proto"],
)

Optimisation des performances

Construire les performances

# .bazelrc optimizations
build --local_ram_resources=HOST_RAM*.8
build --local_cpu_resources=HOST_CPUS
build --jobs=auto

# Disk cache
build --disk_cache=/tmp/bazel-cache

# Remote cache
build --remote_cache=grpc://cache-server:8080

# Build without the bytes
build --remote_download_minimal

# Incremental builds
build --experimental_reuse_sandbox_directories

Gestion de la mémoire

# Limit memory usage
build --local_ram_resources=8192  # 8GB
startup --host_jvm_args=-Xmx4g

# Garbage collection
startup --host_jvm_args=-XX:+UseG1GC
startup --host_jvm_args=-XX:MaxGCPauseMillis=200

Déboguement

Construire le débogage

# Verbose output
bazel build //... --verbose_failures
bazel build //... --subcommands

# Explain build
bazel build //... --explain=explain.log
bazel build //... --verbose_explanations

# Profile build
bazel build //... --profile=profile.json

# Sandbox debugging
bazel build //... --sandbox_debug
bazel build //... --spawn_strategy=standalone

Demande et analyse

# Dependency analysis
bazel query "deps(//src:hello-world)"
bazel query "rdeps(//..., //common:utils)"

# Build graph
bazel query --output=graph //...|dot -Tpng > graph.png

# Action graph
bazel aquery //src:hello-world

# Configuration
bazel cquery //src:hello-world --output=starlark --starlark:expr="target.label"

Meilleures pratiques

Structure du projet

workspace/
├── WORKSPACE
├── .bazelrc
├── BUILD.bazel
├── tools/
│   ├── BUILD.bazel
│   └── rules.bzl
├── third_party/
│   └── BUILD.bazel
├── src/
│   ├── main/
│   │   └── BUILD.bazel
│   └── test/
│       └── BUILD.bazel
└── docs/
    └── BUILD.bazel

Désignation des cibles

# Use descriptive names
java_library(
    name = "user_service_lib",  # Not just "lib"
    srcs = ["UserService.java"],
)

# Group related targets
java_library(name = "auth_lib", ...)
java_test(name = "auth_test", ...)
java_binary(name = "auth_server", ...)

# Use consistent patterns
cc_library(name = "foo_lib", ...)
cc_test(name = "foo_test", ...)

Gestion de la visibilité

# Package-level visibility
package(default_visibility = ["//visibility:private"])

# Specific visibility
java_library(
    name = "internal_lib",
    visibility = ["//src/main:__subpackages__"],
)

# Public libraries
java_library(
    name = "public_api",
    visibility = ["//visibility:public"],
)

Dépannage

Questions communes

# Clear cache
bazel clean --expunge

# Check workspace
bazel info workspace

# Verify dependencies
bazel query "deps(//src:target)"

# Check build configuration
bazel config

# Analyze failures
bazel build //... --verbose_failures --keep_going

Problèmes de performance

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

# Memory analysis
bazel dump --rules
bazel dump --skylark_memory

# Cache analysis
bazel info repository_cache
bazel info output_base

Ressources

  • Documentation officielle: [bazel.build] (LINK_4)
  • Guide de l'utilisateur: bazel.build/docs
  • Répertoire des règles: [github.com/bazelbuild] (LINK_4)
  • Meilleures pratiques: [bazel.build/docs/meilleures pratiques] (LINK_4)