bazel_ci_rules)This folder contains the unified, GCS-free, and Remote Build Execution (RBE) toolchain generator rule (rbe_config).
It automates the generation of RBE toolchain configurations dynamically on-the-fly, eliminating the maintenance overhead of pre-generating and uploading configurations to Google Cloud Storage (GCS) buckets when new Bazel versions are released.
docker vs host): Supports both standard Docker-out-of-Docker generation (default when RBE_CONFIG_CONTAINER is unset) and direct host environment generation (automatically enabled when RBE_CONFIG_CONTAINER is set).RBE_CONFIG_CONTAINER is exported, rbe_configs_gen compiles natively on the host using go build and runs with --exec_mode=host, executing C++ and Java auto-detection (@@rules_cc..., java -version) against the host filesystem without Docker. The target container image is authoritative from the RBE_CONFIG_CONTAINER environment variable.rules/rbe_presets.json) on the master branch of this repository. At runtime, the repository rule dynamically downloads this file. If the CI maintainers update a container image tag or environment parameter on master, all projects immediately receive the update without modifying their pinned ruleset commit hashes!MODULE.bazel)To configure RBE toolchains using Bzlmod (Bazel 8.0.0+), load and use the rbe_config_extension module extension:
Simply pass the name of a standard preset (e.g. "ubuntu"):
bazel_dep(name = "bazel_ci_rules", version = "2.0.0") # Load and instantiate the RBE config module extension rbe = use_extension("@bazel_ci_rules//:rbe_config.bzl", "rbe_config_extension") rbe.config( name = "rbe_ubuntu", # Standard target repository name preset = "ubuntu", # Request the generic latest Ubuntu preset ) use_repo(rbe, "rbe_ubuntu")
If you are using a custom compiler container or customized settings, specify the target image and C++ compiler environment directly inside the tag:
bazel_dep(name = "bazel_ci_rules", version = "2.0.0") rbe = use_extension("@bazel_ci_rules//:rbe_config.bzl", "rbe_config_extension") rbe.config( name = "rbe_ubuntu", container = "gcr.io/my-custom/image:latest", cpp_env = { "CC": "gcc", "ABI_LIBC_VERSION": "glibc_2.39", "ABI_VERSION": "gcc", "BAZEL_COMPILER": "gcc", "BAZEL_HOST_SYSTEM": "i686-unknown-linux-gnu", "BAZEL_TARGET_CPU": "k8", "BAZEL_TARGET_LIBC": "glibc_2.39", "BAZEL_TARGET_SYSTEM": "x86_64-unknown-linux-gnu", "CC_TOOLCHAIN_NAME": "linux_gnu_x86" } ) use_repo(rbe, "rbe_ubuntu")
If your repository has not migrated to Bzlmod yet, load and call the rbe_config macro inside your WORKSPACE file:
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") http_archive( name = "bazel_ci_rules", strip_prefix = "bazel_ci_rules-2.0.0", # Pre-packaged release prefix url = "https://github.com/bazelbuild/continuous-integration/releases/download/rules-2.0.0/bazel_ci_rules-2.0.0.tar.gz", # Official 2.0.0 tarball release ) load("@bazel_ci_rules//:rbe_config.bzl", "rbe_config") rbe_config( name = "rbe_ubuntu", preset = "ubuntu", # Request the standard 'ubuntu' preset dynamically )
load("@bazel_ci_rules//:rbe_config.bzl", "rbe_config") rbe_config( name = "rbe_ubuntu", spec = { "container": "gcr.io/my-custom/image:latest", "cpp_env": { "CC": "gcc", "CC_TOOLCHAIN_NAME": "linux_gnu_x86", # ... } } )
Once your workspace is configured with the rbe_ubuntu repository, you can compile and test your targets remotely on GCP by passing the standard Remote Execution flags:
bazel build \ --extra_toolchains=@rbe_ubuntu//config:cc-toolchain \ --extra_execution_platforms=@rbe_ubuntu//config:platform \ --host_platform=@rbe_ubuntu//config:platform \ --platforms=@rbe_ubuntu//config:platform \ --javabase=@rbe_ubuntu//java:jdk \ --host_javabase=@rbe_ubuntu//java:jdk \ --remote_executor=remotebuildexecution.googleapis.com \ --remote_instance_name=projects/YOUR_GCP_PROJECT/instances/YOUR_RBE_INSTANCE \ --google_default_credentials \ //path/to:your_target
--extra_toolchains=@rbe_ubuntu//config:cc-toolchain: Registers the dynamically auto-detected C++ compiler toolchain.--extra_execution_platforms / --platforms: Configures Bazel to execute actions and target outputs inside the container's platform environment.--javabase / --host_javabase=@rbe_ubuntu//java:jdk: Resolves Java compilations and host execution using the JDK detected inside the container.--remote_executor: The gRPC endpoint of the Google Remote Build Execution service.--remote_instance_name: The RBE instance mapped specifically to your Google Cloud Platform (GCP) project.--google_default_credentials: Authenticates your remote requests natively using your Google Application Default Credentials (ADC) or system gcloud login.docker vs host)rbe_config supports two execution modes for toolchain auto-detection, automatically selected based on your environment:
--exec_mode=docker, Default)When RBE_CONFIG_CONTAINER is unset (e.g., on developer workstations running macOS or Linux):
rbe_configs_gen is compiled inside a sibling golang:1.21 Docker container using Docker-out-of-Docker (/var/run/docker.sock). No local Go compiler is required.rbe_configs_gen pulls and runs the target toolchain container image (from preset or spec["container"]), mounts host Bazel, and runs C++ and Java auto-detection inside the sandboxed container.--exec_mode=host, Automatic in Container CI)When the RBE_CONFIG_CONTAINER environment variable is exported (e.g., in containerized CI workers or Buildkite pipelines):
rbe_config automatically switches to host mode.rbe_configs_gen is compiled natively on the host using go build (requires Go installed in PATH; no Docker required).rbe_configs_gen runs with --exec_mode=host, discovering C++ compilers (gcc/clang) and JDK runtimes directly from the host filesystem without invoking Docker.host mode, because detection happens against the host filesystem, the RBE execution platform image in @rbe_ubuntu//config:platform is authoritatively determined by RBE_CONFIG_CONTAINER (overriding any requested preset container image to prevent ABI or toolchain discrepancies).To generate toolchain configurations, rbe_config must determine which Bazel version to target and potentially mount a host Bazel binary inside the compiler container. It resolves this using the following four-tier precedence lookup strategy:
RBE_CONFIG_BAZEL_PATH Environment Variable: (Highest Precedence) Explicitly forces the generator to use this host Bazel binary (passes --host_bazel_path to the generator).BAZEL_REAL Environment Variable: Forces the generator to use this real host Bazel binary (usually set by wrappers like Bazelisk) and passes it as --host_bazel_path.native.bazel_version Detection: Automatically detects the version string of the running Bazel (e.g., "9.1.0" or "8.4.2"). If found, it passes --bazel_version to rbe_configs_gen, which allows the generator to fetch the matching Bazel release inside the container cleanly without copying host binaries.PATH scan: (Fallback) If no explicit path is set and version detection fails (e.g., on untagged development builds), it scans the host PATH for bazel and copies it into the container.If you run custom development layouts or want to force a specific Bazel binary override, choose one of the following methods:
Export the path to your executable in your active terminal session before running the build:
export RBE_CONFIG_BAZEL_PATH=/path/to/your/custom_bazel bazel build //...
tools/bazel Wrapper (Recommended)Creating a wrapper script at tools/bazel at the root of your workspace is the cleanest, zero-configuration way. Bazel and Bazelisk automatically execute this wrapper, which can capture the real running binary path (BAZEL_REAL). Our rule will automatically pick up BAZEL_REAL and prioritize it over native.bazel_version:
#!/bin/bash # tools/bazel # This wrapper script is executed automatically by Bazelisk # BAZEL_REAL will be automatically detected and prioritized by rbe_config exec "${BAZEL_REAL}" "$@"