blob: b04cacb11fe0c191db455ab6235ca30d94f8697a [file] [view]
---
trigger: glob
description: Starlark Language, Macro, and Testing Invariants
globs: "*.bzl,BUILD,BUILD.bazel,*.bazel"
---
# Starlark Language & Macro Invariants
## Macro Target Canonicalization
* In macro implementations, internal repository target references **MUST** be
canonicalized using `str(Label("//path/to:target"))` so they resolve in the
macro's module context rather than the caller's repository context.
* Note that `python/private/common_labels.bzl` defines `labels`, a struct
containing common canonicalized label strings used across the project.
## Manual Tag on Internal Macro Helper Targets
* When macros instantiate internal helper targets (such as private rule targets
for artifact extraction or linking support), always include `tags = ["manual"]`.
* **Why**: This prevents internal helper targets from being implicitly built when
wildcard target patterns (e.g., `//...`) are expanded.
## Private Alias Pattern when Appending to User `deps`
* When macros append internal helper targets to user-provided dependency lists
(`deps`), use private alias targets (e.g.
`//python/private/cc:current_py_cc_headers_private_alias`) to prevent
"duplicate dependency label" analysis errors if the user also explicitly
passes the public target label in their `deps` (including in `select()`
expressions).
## Attribute Normalization at Function Entry
* Always normalize input list attributes at the start of macro definitions
(e.g., `deps = deps or []`, `copts = copts or []`).
* **Why**: This avoids inlining the normalization as part of a complex
expression later in the macro expansion.
## native.test_suite API
* Don't forward target `tags` to `native.test_suite`; tags on test suites filter
tests instead of setting target execution behavior.
## Control Flow & Algorithmic Restrictions
* **Iterative Algorithms Only (No Recursion)**: Starlark does not support
recursive function calls; always implement iterative algorithms using bounded
loops.
* **Iterable `for` Loops Only (No `while` Loops)**: Starlark does not support
`while` loops; iterate over fixed-size ranges or explicit collections.
## Depset Element Invariants & Optimizations
* **Providers over Structs for Depset Elements**: Use `provider()` (without
`-Info` suffix, e.g. `*Fileset`) instead of `struct()` for composite objects
in depsets; providers perform key sharing and reduce memory overhead.
* **Depset Element Immutability**: All depset elements and nested provider
fields must be immutable when `depset()` is called (eager check before rule
freeze). Use `tuple[T]` or `depset[T]` in providers placed into depsets; do
not use mutable `list[T]`.
## Code Style & Conventions
* **Dict union (`|`)**: Use `|` instead of `dicts.add(...)` from
`@bazel_skylib//lib:dicts.bzl` when merging dictionaries.
* **Non-Info Provider Naming**: Add `# buildifier: disable=name-conventions`
above `provider()` declarations that do not end in `Info` (e.g. `*Fileset`).
* **Docstring Formatting Invariants**: Use triple-quoted strings for multi-line
docstrings without trailing backslashes (`\`) for line continuation.
* **No Bazel Copyright Headers**: Do not add Bazel copyright headers to new or
existing files unless explicitly directed by the user.
* **Line Length & Wrapping**: Wrap Markdown and Starlark lines to 80 columns in
accordance with `.editorconfig`.
## Starlark Testing (`rules_testing`)
* **`rules_testing` over `bazel_skylib`**: Always use `@rules_testing` (analysis
tests with `env.expect.that_...`) rather than `bazel_skylib` for Starlark
rule analysis tests.
* **Analysis Test Two-Part Structure**: Separate tests into a setup target
function `def _test_foo(name)` calling `analysis_test` and an implementation
function `def _test_foo_impl(env, target)`.
* **Test Suite Registration**: Collect test setup functions in a private
`_tests` list and register them cleanly via `test_suite(name = name, tests =
_tests)`.