Summary Table
| Concept | What it is | Analogy |
| Constraint Setting | A property category | “Vehicle Type” |
| Constraint Value | A specific option | “Car”, “Truck”, “Motorcycle” |
| Platform | A group of settings | “Vehicle configured for highway use” (Car + 4 Tires) |
The Core Concepts
To understand how they relate, think of them in terms of a property-based system:
constraint_setting: Defines a category or type of property that distinguishes machines (e.g., “CPU architecture”, “Operating System”).constraint_value: Defines a specific choice within a category (e.g., within the “CPU architecture” setting, choices could be “x86”, “ARM”, “RISC-V”).platform: A collection ofconstraint_valuesthat defines a complete environment (e.g., a “Linux-x86” platform is a collection ofOS:LinuxandCPU:x86).
Example: Defining Custom Constraints
Suppose you are building an embedded system and you need to distinguish between different GPU types and glibc versions. You would define these in your own BUILD file.
1. Define the “Categories” (Settings)
Create a BUILD file (e.g., //tools/platforms:BUILD) to hold your custom logic.
# //tools/platforms/BUILD
# A new dimension for GPU hardware
constraint_setting(name = "gpu_type")
# A new dimension for C library versions
constraint_setting(name = "glibc_version")
2. Define the “Choices” (Values)
Now, define the specific values that belong to those categories.
# //tools/platforms/BUILD
# Values for gpu_type
constraint_value(name = "nvidia_rtx", constraint_setting = ":gpu_type")
constraint_value(name = "amd_radeon", constraint_setting = ":gpu_type")
# Values for glibc_version
constraint_value(name = "glibc_2_25", constraint_setting = ":glibc_version")
constraint_value(name = "glibc_2_28", constraint_setting = ":glibc_version")
3. Bundle them into a Platform
Now that you have defined these custom constraints, you can use them alongside standard ones to define your custom platform.
# //tools/platforms/BUILD
platform(
name = "custom_embedded_gpu_linux",
constraint_values = [
"@platforms//os:linux", # Standard constraint
"@platforms//cpu:aarch64", # Standard constraint
":nvidia_rtx", # YOUR custom constraint
":glibc_2_28", # YOUR custom constraint
],
)
How to use these in your build
Once you’ve defined these, you can use select() in your rules to change behavior based on these custom constraints.
# //myapp/BUILD
cc_library(
name = "gpu_driver",
srcs = select({
"//tools/platforms:nvidia_rtx": ["driver_nvidia.cc"],
"//tools/platforms:amd_radeon": ["driver_amd.cc"],
"//conditions:default": ["driver_stub.cc"],
}),
)
Why this approach is powerful:
- Strict Typing: Bazel ensures that
nvidia_rtxis only used for thegpu_typesetting. You can’t accidentally assign it to an OS setting. - Organization: You keep your project-specific needs (like “is this a high-security build?”) inside your own repository, while using
@platformsfor universal things likecpuandos. - Cross-Project Compatibility: If another team in your company wants to build for the same
custom_embedded_gpu_linuxplatform, they can import the label//tools/platforms:custom_embedded_gpu_linuxand get all the same settings.