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).