Skip to content

Commit

Permalink
Add documentation for modifiers
Browse files Browse the repository at this point in the history
  • Loading branch information
cbarrete committed Jan 20, 2025
1 parent 64e3cf8 commit df4d7aa
Show file tree
Hide file tree
Showing 7 changed files with 268 additions and 3 deletions.
51 changes: 51 additions & 0 deletions docs/concepts/modifiers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
id: modifiers
title: Configuration modifiers
---

Configuration modifiers (or just "modifiers" for short) are a feature
that lets users add ad-hoc [configuration
constraints](../rule_authors/configurations) to individual
directories, target definitions and individual `buck2` invocations.

## Adding modifiers to a project

To add support for modifiers in your project, simply call `set_cfg_constructor` in your root `PACKAGE` file.

See the [dedicated how-to](../users/how_tos/modifiers_setup) for more
information.

## Modifiers in `PACKAGE` files

Modifiers can be specified per-directory. In that case, they are used as
the default build configurations defined in that directory.

See the [dedicated how-to](../users/how_tos/modifiers_package) for more
information.

## Modifiers on targets

Modifiers can be added to individual targets. This can be used as an
alternative to the missing [per-target
transitions](../rule_authors/configurations#per-target-transition).

See the [dedicated how-to](../users/how_tos/modifiers_target) for more
information.

## Modifiers on the CLI

Custom modifiers can be specified on the CLI to build a target with a
specific build configuration. For example, this can be used to build a
target with a non-default compiler, or to run a test using a specific
sanitizer.

See the [dedicated how-to](../users/how_tos/modifiers_cli) for more
information.

## More information

Official documentation on modifiers is sparse at the moment, so you
might be interested in the following documents:

- [The original RFC](../rfcs/cfg-modifiers/modifiers.pdf)
- [The @ configuration CLI RFC](../rfcs/drafts/configuration-at-syntax)
4 changes: 1 addition & 3 deletions docs/users/how_tos/compilation_database.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
---
id: compilation_database
title: Compilation databases
title: Generate C++ compilation databases
---

# Generating compilation databases

You can generate compilation databases for consumption by tools such as clangd
and clang-tidy by running the following BXL script:

Expand Down
29 changes: 29 additions & 0 deletions docs/users/how_tos/modifiers_cli.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
id: modifiers_cli
title: Specify configuration modifiers from the CLI
---

Modifiers can be specified on the command line to override the values
set in `PACKAGE` files or on targets directly. To do so, pass constraint
targets via the `-m`/`--modifiers` flag:

```sh
# Assuming that `//constraints:BUCK` contains the appropriate constraint
# definitions.
buck build :my_target -m //constraints:debug
buck build :my_target -m //constraints:release
```

Aliases can be used as shorthands (see the [setup how-to](./modifiers_setup) for more
information):

```sh
buck build :my_target -m debug
```

The following shorthand syntax is planned, but is currently
unimplemented:

```sh
buck2 build :my_target?debug
```
27 changes: 27 additions & 0 deletions docs/users/how_tos/modifiers_package.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
---
id: package_modifiers
title: Add configuration modifiers to entire directories
---

Modifiers can be set in [`PACKAGE` files](../../rule_authors/package)
using the prelude's `set_cfg_modifiers`. In this case they will be
applied to all targets affected by that `PACKAGE` file.

For example, assuming that `root//build:debug` is an existing constraint
value and [modifiers have been setup](./modifiers_setup), the following
will apply it by default to all targets defined in that `PACKAGE`'s
directory:

```python
load("@prelude//cfg/modifier/set_cfg_modifiers.bzl", "set_cfg_modifiers")

set_cfg_modifiers([
"root//build:debug",
])
```

`set_cfg_modifiers` takes 2 arguments:

- `cfg_modifiers`, a list of modifiers to set.
- `extra_cfg_modifiers_per_rule`, a dictionary mapping rule names to
lists of modifiers that should be applied only for that rule.
93 changes: 93 additions & 0 deletions docs/users/how_tos/modifiers_setup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
---
id: modifiers_setup
title: Setup configuration modifiers
---

To start using configuration modifiers, all you need to do is call
`set_cfg_constructor` from a `PACKAGE` file.

Start by adding the following to your root `PACKAGE` file:

```python
load("@prelude//cfg/modifier:cfg_constructor.bzl", "cfg_constructor_post_constraint_analysis", "cfg_constructor_pre_constraint_analysis")
load("@prelude//cfg/modifier:common.bzl", "MODIFIER_METADATA_KEY")

native.set_cfg_constructor(
stage0 = cfg_constructor_pre_constraint_analysis,
stage1 = cfg_constructor_post_constraint_analysis,
key = MODIFIER_METADATA_KEY,
aliases = struct(),
extra_data = struct(),
)
```

`set_cfg_constructor` is a Buck2 builtin used to setup configuration
modifiers. It supports a few configuration points:

- `stage0` and `stage1` are used to resolve modifiers from the [target
platform](../../rule_authors/configurations) (which is now considered
deprecated) and the modifiers set in the nearest `PACKAGE` file, on
the target, and on the CLI. You _can_ override those, but the
functions provided by the prelude basically do what you would expect.
- `key` is used to fetch modifiers defined on `metadata` attributes. It
is only supported for legacy reasons, so you should not have to worry
about it.
- `aliases` contains modifier aliases to modifier modifiers. Populate it
to make aliases available from the CLI.
- `extra_data` is used for logging/validation by Meta's internal
modifier implementation.

As you can see, `aliases` is the the only value that one would commonly
want to configure, and it might make sense to call `set_cfg_constructor`
with different `aliases` values in different `PACKAGE` files, if some
aliases only make sense in specific projects (e.g. because they have
custom configuration constraints).

The following is an example of exposing custom aliases for build
constraints. We create a `build_mode` constraint with 2 values (`debug`
and `release`), which would most likely be `select`ed in a toolchain
definition.

`BUCK`:

```python
constraint_setting(name = "build_mode")

constraint_value(
name = "debug",
constraint_setting = ":build_mode",
)

constraint_value(
name = "release",
constraint_setting = ":build_mode",
)
```

`PACKAGE`:

```python

load("@prelude//cfg/modifier:cfg_constructor.bzl", "cfg_constructor_post_constraint_analysis", "cfg_constructor_pre_constraint_analysis")
load("@prelude//cfg/modifier:common.bzl", "MODIFIER_METADATA_KEY")

native.set_cfg_constructor(
stage0 = cfg_constructor_pre_constraint_analysis,
stage1 = cfg_constructor_post_constraint_analysis,
key = MODIFIER_METADATA_KEY,
aliases = struct(
debug = "//build:debug",
release = "//build:release",
),
extra_data = struct(),
)
```

Now, assuming that `:my_target` exists and is affected by the
`build_mode` constraint, we can build it in debug and release mode
from the command line using the `-m`/`--modifier` flag:

```sh
buck2 build :my_target -m debug
buck2 build :my_target -m release
```
55 changes: 55 additions & 0 deletions docs/users/how_tos/modifiers_target.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
id: modifiers_target
title: Add configuration modifiers to a specific target
---

Modifiers can be added to individual targets via the `modifiers`
attribute which is exposed by all rules (this is handled by Buck2
itself, so rule authors do not have to add it themselves).

For example, lets assume that we have a `release_package` rule that
references various `dep`s and packages them, and that our [`PACKAGE`
file defaults our build mode to debug](./modifiers_package). We could
add the `release` modifier to our artifact target to build all
dependencies in release mode rather than debug:

```python
release_package(
name = "my_package",
binaries = [
":my_cxx_bin",
":my_rust_bin",
],
modifiers = [
"//constraints:debug",
],
)
```

As another example, imagine that we have a constraint that controls
whether we use real or simulated IO:

```python
constraint_setting(name = "io_mode")

constraint_value(
name = "real_io",
constraint_setting = ":io_mode",
)

constraint_value(
name = "simulated_io",
constraint_setting = ":io_mode",
)
```

The default IO mode would be `real_io`, but we would like to override it
for a specific test:

```python
go_test(
name = "simulated_io_test",
srcs = ["test.go"],
modifiers = ["//constraints:simulated_io"],
)
```
12 changes: 12 additions & 0 deletions website/sidebars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export const sidebars: SidebarsConfig = {
'concepts/isolation_dir',
'concepts/buckconfig',
'concepts/configurations',
'concepts/modifiers',
'concepts/glossary',
],
},
Expand All @@ -82,6 +83,17 @@ export const sidebars: SidebarsConfig = {
{ type: 'autogenerated' as const, dirName: 'users/commands' },
],
},
{
type: 'category' as const,
label: 'How-tos',
items: [
'users/how_tos/modifiers_setup',
'users/how_tos/modifiers_package',
'users/how_tos/modifiers_target',
'users/how_tos/modifiers_cli',
'users/how_tos/compilation_database',
],
},
'users/cheat_sheet',
{
type: 'category' as const,
Expand Down

0 comments on commit df4d7aa

Please sign in to comment.