Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .bazelci/configurations.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,17 @@ configurations: &configurations
# These targets demonstrate failures: they're never meant to build.
- "-//read_attr_in_transition:will-break"
- "-//cc_binary_selectable_copts:app_forgets_to_set_features"
# These targest are not supposed to build at the top level: only as
# These targets are not supposed to build at the top level: only as
# dependencies of other targets.
- "-//cc_binary_selectable_copts:lib"
- "-//cc_binary_selectable_copts:app_forgets_to_set_features_native_binary"
- "-//cc_binary_selectable_copts:app_with_feature1_native_binary"
- "-//cc_binary_selectable_copts:app_with_feature2_native_binary"
# Checking in examples before supported by Bazel 9.0. Also note these examples
# auto-set flags, so building /... may trigger targets that set confliciting
# flags and fail the build. We could mitigate this by having dedicated test
# sets for compatible target combingations.
- "-//auto_configured_builds/..."
# TODO: why is this crashing bazel?
- "-//cc_test/..."
# test_targets:
Expand Down
7 changes: 7 additions & 0 deletions configurations/auto_configured_builds/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
platform(
name = "myplatform",
constraint_values = [
"@platforms//os:linux",
"@platforms//cpu:arm",
],
)
5 changes: 5 additions & 0 deletions configurations/auto_configured_builds/MODULE.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
bazel_dep(name = "platforms", version = "1.0.0")
bazel_dep(name = "bazel_skylib", version = "1.8.2")

local_repository = use_repo_rule("@bazel_tools//tools/build_defs/repo:local.bzl", "local_repository")
local_repository(name = "custom_flags", path = "custom_flags_impl")
178 changes: 178 additions & 0 deletions configurations/auto_configured_builds/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
## Auto-configured builds examples
**Requirements: Bazel 9.0 or newer.**

*Auto-configured builds* is a Bazel 9.0+ feature that lets project owners declare which build flags should apply to their project's targets.

This makes it possible to write

$ bazel test //foo/...

and bazel automatically adds whatever flags are appropriate for `foo`'s builds.

This is similar to [bazelrc](https://bazel.build/run/bazelrc) with the crucial difference that bazelrc files are *user-registered*, not *project-registered*. That means `bazelrc`-added flags depend on who does the build and which `bazelrcs` they've registered, not which targets they're building.

The features described here make it easier for *anyone* to write `$ bazel test //foo/...` - a project dev, external contributor, library maintainer, IDE, AI agent, or CI system - and consistently get the same results with the same flags regardless of how they've set up their workspace or if they've ever built the project before. Project owners can then ensure everyone builds with correct, project-approved flags.

More info at https://github.com/bazelbuild/bazel/issues/24839.

### `PROJECT.scl`
Flag settings are declared in a file called `PROJECT.scl`. This lives in your source repository next to your `BUILD` files.

`$ bazel test //foo/bar/baz:all` looks for a `PROJECT.scl` in `foo/bar/baz/` to find the project's flag settings. If that file doesn't exist, it looks in `foo/bar/`, then `foo/`, and so on until it either finds a match or determines the project has no flag settings.

This also applies to `bazel build` and `bazel cquery`.

### Project-wide settings with warnings for unexpected flags
[warn](warn) is an example that sets two sets of flags for a project. The first set, `default_config`, triggers by default. The second, `debug_config`, can be set with `--scl_config=debug_config`. If the user sets any other flags, bazel emits a warning that the build is non-canonical.

*Default flags:*
```sh
$ bazel build //warn:all
INFO: Reading project settings from //warn:PROJECT.scl.
INFO: Applying flags from the config 'default_config' defined in //warn:PROJECT.scl: [--platforms=//:myplatform,
--compilation_mode=opt, --@custom_flags//:project_flag="custom flag value"]
INFO: Found 2 targets...
INFO: Build completed successfully, 3 total actions
```

*Non-default supported flags:*
```sh
$ bazel build //warn:all --scl_config=debug_config
INFO: Reading project settings from //warn:PROJECT.scl.
INFO: Applying flags from the config 'debug_config' defined in //warn:PROJECT.scl: [--platforms=//:myplatform,
--compilation_mode=dbg, --@custom_flags//:project_flag="debug value"]
INFO: Found 2 targets...
INFO: Build completed successfully, 3 total actions
```

*Unexpected flags:*
```sh
$ bazel build //warn:all --copt=abc
INFO: Reading project settings from //warn:PROJECT.scl.
WARNING: This build uses a project file (//warn:PROJECT.scl), but also sets output-affecting flags in the command
line or user bazelrc: ['--copt=abc']. Please consider removing these flags.
INFO: Applying flags from the config 'default_config' defined in //warn:PROJECT.scl: [--platforms=//:myplatform,
--compilation_mode=opt, --@custom_flags//:project_flag="custom flag value"
INFO: Found 2 targets...
INFO: Build completed successfully, 3 total actions
```

### Project-wide settings with incompatible flag checks
[compatible](compatible) is an example that sets two sets of flags for a project. It lets the user set other, unrelated flags with a warning but fails the build if the user sets contradictory flags.

*Default flags:*
```sh
$ bazel build //compatible:all
INFO: Reading project settings from //compatible:PROJECT.scl.
INFO: Applying flags from the config 'default_config' defined in //compatible:PROJECT.scl:
[--platforms=//:myplatform, --compilation_mode=opt, --@custom_flags//:project_flag="custom flag value"]
INFO: Found 2 targets...
INFO: Build completed successfully, 3 total actions
```

*Unexpected non-conflicting flag:*
```sh
$ bazel build //compatible:all --copt=abc
INFO: Reading project settings from //compatible:PROJECT.scl.
WARNING: This build uses a project file (//compatible:PROJECT.scl), but also sets output-affecting flags in
the command line or user bazelrc: ['--copt=abc']. Please consider removing these flags.
INFO: Applying flags from the config 'default_config' defined in //compatible:PROJECT.scl:
[--platforms=//:myplatform, --compilation_mode=opt, --@custom_flags//:project_flag="custom flag value"]
INFO: Build completed successfully, 3 total actions
```

*Unexpected conflicting flag:*
```sh
$ bazel build //compatible:all --compilation_mode=fastbuild
INFO: Reading project settings from //compatible:PROJECT.scl.
ERROR: Cannot parse options: This build uses a project file (//compatible:PROJECT.scl) that does not allow
conflicting flags in the command line or user bazelrc. Found ['--compilation_mode=fastbuild']. Please remove
these flags or disable project file resolution via --noenforce_project_configs.
ERROR: Build did NOT complete successfully
```

### Project-wide settings with strict checks
[strict](strict) is an example that sets two sets of flags for a project. It fails the build if the user sets any flags to any values different than the project settings. This is the strictest form of flag checking. It ensures all builds use pre-approved, canonical flags.

*Default flags:*
```sh
$ bazel build //strict:all
INFO: Reading project settings from //strict:PROJECT.scl.
INFO: Applying flags from the config 'default_config' defined in //strict:PROJECT.scl: [--platforms=//:myplatform,
--compilation_mode=opt, --@custom_flags//:project_flag="custom flag value"]
INFO: Found 2 targets...
INFO: Build completed successfully, 3 total actions
```

*Unexpected non-conflicting flag:*
```sh
$ bazel build //strict:all --copt=abc
INFO: Reading project settings from //strict:PROJECT.scl.
ERROR: Cannot parse options: This build uses a project file (//strict:PROJECT.scl) that does not allow
output-affeccting flags in the command line or user bazelrc. Found ['--copt=abc']. Please remove these flags or
disable project file resolution via --noenforce_project_configs.
ERROR: Build did NOT complete successfully
```

### Per-target flag settings
[target_specific](target_specific) sets different default flags for different targets. This example applies the [warn](warn) enforcement policy.

*`//target_specific:one`:*
```sh
$ bazel build //target_specific:one
INFO: Reading project settings from //target_specific:PROJECT.scl.
INFO: Applying flags from the config 'default_config_for_target_one' defined in //target_specific:PROJECT.scl:
[--platforms=//:myplatform, --@custom_flags//:project_flag="settings for target one"]
INFO: Found 1 target...
INFO: Build completed successfully, 1 total action
```

*`//target_specific:two`:*
```sh
$ bazel build //target_specific:two
INFO: Reading project settings from //target_specific:PROJECT.scl.
INFO: Applying flags from the config 'default_config_for_target_two' defined in //target_specific:PROJECT.scl:
[--platforms=//:myplatform, --@custom_flags//:project_flag="settings for target two"]
INFO: Found 1 target...
INFO: Build completed successfully, 1 total action
```

**Note:** `$ bazel build //target_specific:all` fails because no common set of flags applies to both targets. You can resolve this either by explicitly setting `--scl_config` or disabling project flags with `--noenforce_project_configs`. Comment on https://github.com/bazelbuild/bazel/issues/24839 if you're interested in more automatic behavior.

### Aliases
[alias](alias) is a project with different disjoint directories. You can refer them all to the same souce of flag truth with `PROJECT.scl` aliases.

*Main project definition in `alias/project_main`:*
```sh
$ bazel build //alias/project_main:main
INFO: Reading project settings from //alias/project_main:PROJECT.scl.
INFO: Applying flags from the config 'default_config' defined in //alias/project_main:PROJECT.scl:
[--platforms=//:myplatform, --compilation_mode=opt, --@custom_flags//:project_flag="custom flag value"]
INFO: Found 1 target...
INFO: Build completed successfully, 1 total action
```

*`alias/project_lib` is a different directory but part of the same project:*
```sh
$ cat alias/project_lib/PROJECT.scl
project = {
"actual": "//alias/project_main:PROJECT.scl",
}
```

```sh
$ bazel build //alias/project_lib:lib
INFO: Reading project settings from //alias/project_main:PROJECT.scl.
INFO: Applying flags from the config 'default_config' defined in //alias/project_main:PROJECT.scl:
[--platforms=//:myplatform, --compilation_mode=opt, --@custom_flags//:project_flag="custom flag value"]
INFO: Found 1 target...
INFO: Build completed successfully, 1 total action
```

**Note:** In this example both directories have the same parent directory. You can alternatively move the project definition to `alias/PROJECT.scl` for the same effect. This also requires an `alias/BUILD` file, which may be empty.

### Questions?
This is an evolving feature. These examples don't cover everything.

Comment at https://github.com/bazelbuild/bazel/issues/24839 with more questions and requests.

6 changes: 6 additions & 0 deletions configurations/auto_configured_builds/alias/project_lib/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
genrule(
name = "lib",
srcs = [],
outs = ["lib.out"],
cmd = "echo lib > $@",
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# This package is part of the //alias/project_main project. Use that
# package's PROJECT.scl.
project = {
"actual": "//alias/project_main:PROJECT.scl",
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
genrule(
name = "main",
srcs = [],
outs = ["main.out"],
cmd = "echo main > $@",
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# A project file that automatically sets build flags for all targets in the
# project and warns if the user sets any other flags.
load(
"@bazel_tools//src/main/protobuf/project:project_proto.scl",
"buildable_unit_pb2",
"project_pb2",
)

project = project_pb2.Project.create(
# "WARN" means bazel emits a warning if the user sets flags to different
# values than they're set here. This can be used as a signal to determine if
# the project is built canonically.
#
# "WARN" is the default value. You can omit the below line and keep the same behavior.
enforcement_policy = "WARN",
buildable_units = [
# Since this buildable unit sets "is_default = True", these flags apply
# to any target in this package or its subpackages by default. You can
# also request these flags explicitly with "--scl_config=default_config".
buildable_unit_pb2.BuildableUnit.create(
name = "default_config",
flags = [
"--platforms=//:myplatform",
"--compilation_mode=opt",
'--@custom_flags//:project_flag="custom flag value"',
],
is_default = True,
# If a build sets an unknown --scl_config value or omits
# --scl_config on a project with no default config, bazel errors
# with a summary of valid configurations. The "description" field
# tells bazel how to describe this configuration.
description = "this project's default flags",
),
],
)
13 changes: 13 additions & 0 deletions configurations/auto_configured_builds/compatible/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
genrule(
name = "one",
srcs = [],
outs = ["one.out"],
cmd = "echo one > $@",
)

genrule(
name = "two",
srcs = [],
outs = ["two.out"],
cmd = "echo two > $@",
)
50 changes: 50 additions & 0 deletions configurations/auto_configured_builds/compatible/PROJECT.scl
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# A project file that automatically sets build flags for all targets in the
# project and fails if the users set any flags that conflict with the project's
# flags.
#
# For example:
# --compilation_mode=dbg conflicts with --compilation_mode=opt
# --compilation_mode=dbg does not conflict with --//some:unrelated_flag=1
load(
"@bazel_tools//src/main/protobuf/project:project_proto.scl",
"buildable_unit_pb2",
"project_pb2",
)

project = project_pb2.Project.create(
# "COMPATIBLE" means bazel errors if the user sets flags that conflict with
# project's flags. However, bazel permits other user flags that don't
# directly conflict. See top of this file for examples.
enforcement_policy = "COMPATIBLE",
buildable_units = [
# Since this buildable unit sets "is_default = True", these flags apply
# to any target in this package or its subpackages by default. You can
# also request these flags explicitly with "--scl_config=default_config".
buildable_unit_pb2.BuildableUnit.create(
name = "default_config",
flags = [
"--platforms=//:myplatform",
"--compilation_mode=opt",
'--@custom_flags//:project_flag="custom flag value"',
],
is_default = True,
# If a build sets an unknown --scl_config value or omits
# --scl_config on a project with no default config, bazel errors
# with a summary of valid configurations. The "description" field
# tells bazel how to describe this configuration.
description = "this project's default flags",
),

# A different flag configuration. Since this doesn't set "is_default
# True", you have to request it explicitly with "--scl_config=debug_config".
buildable_unit_pb2.BuildableUnit.create(
name = "debug_config",
flags = [
"--platforms=//:myplatform",
"--compilation_mode=dbg",
'--@custom_flags//:project_flag="debug value"',
],
description = "debug configuration for developers",
),
],
)
11 changes: 11 additions & 0 deletions configurations/auto_configured_builds/custom_flags_impl/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
load("@bazel_skylib//rules:common_settings.bzl", "string_flag")

string_flag(
name = "project_flag",
build_setting_default = "default value",
)

string_flag(
name = "some_unrelated_flag",
build_setting_default = "default value",
)
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#bazel_dep(name = "bazel_skylib", version = "1.8.2")
13 changes: 13 additions & 0 deletions configurations/auto_configured_builds/strict/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
genrule(
name = "one",
srcs = [],
outs = ["one.out"],
cmd = "echo one > $@",
)

genrule(
name = "two",
srcs = [],
outs = ["two.out"],
cmd = "echo two > $@",
)
Loading