Skip to content

Instantly share code, notes, and snippets.

View rrbutani's full-sized avatar
🐢
slowly but surely

Rahul Butani rrbutani

🐢
slowly but surely
  • 03:42 (UTC -08:00)
View GitHub Profile
We couldn’t find that file to show.

takeaways:

  • actions made by an aspect get to make files in the package of the target they are visiting
  • have "anonymous" action-like semantics, kind of
    • will not get built multiple times if the same aspect for the same target is requested by two different consuming rules
bazel build //:yo @foo//:all

Background

See this gist about post-hoc action input pruning and the limitations w.r.t to caching.

buck2 has starlark APIs for (limited) dynamic deps (i.e. dynamic action creation albeit only with input subsetting): https://buck2.build/docs/rule_authors/dynamic_dependencies/

Bazel's internal dependency engine (skyframe) is capable of representing such dependencies and internal rulesets make use of this functionality (i.e. ThinLTO and C++20 module support in rules_cc) however — starlark rules have no way to express such graphs.

This PoC

buck2 is very explicit re: the interactions dep files have w/caching:

  • dep files can (after execution) narrow the set of inputs for an action
  • the input set of the action as known to your buck2 daemon will have this narrowed set but...
    • the actual action cache key (as is given to disk/remote caches, etc.) will still have the full set of inputs
  • ultimately this means that as far as remote caching for cold builds is concerned, the action at hand is still keyed on all of its inputs — including the ones that are pruned
    • this means that — for cold builds — if there have been any changes to any of the "pruned out" files since the last run of the action (+ cache population), the action will not hit in the cache
  • additionally, in the event that there are analysis-level changes that result in the starlark action being reconstructed (i.e. BUILD file is edited), we also lose the narrowed set of inputs
  • for changes that materially affect t
use clap::Parser;
// NOTE: we want to model reporting args as an enum (of which we have multiple
// copies) instead of a struct of vecs (one per option) because we wish to
// preserve the order of these args.
//
// The clap cookbook entry for `find` provides a reference for how to model
// these kinds of "order matters" flags:
// https://docs.rs/clap/4.5.16/clap/_derive/_cookbook/find/index.html
//
#!/usr/bin/env nix-shell
#!nix-shell -p python3 -i python3
# in its graphviz output (i.e. `ninja -t graph`), ninja uses memory addresses
# for node identifiers as an easy way to guarantee that they are unique
#
# for tools (i.e. dot-viewer: https://github.com/rrbutani/dot-viewer) that rely
# on human-readable node ids this is... annoying
#
# this hacky script (tightly coupled to ninja's graphviz output style; doesn't
{ stdenvNoCC
, writeScript
, lib
, gradle
, python312
}:
# NOTE: prior art re: packaging Gradle projects + dealing with external
# dependencies:
# - https://github.com/NixOS/nixpkgs/blob/99dec1f6b06290f64a8d1711c41e5e13653a14c7/pkgs/development/tools/build-managers/gradle/README.md
# - https://github.com/NixOS/nixpkgs/blob/c12b2a0b196a42a20949cf648c86acfbe6418ad3/doc/languages-frameworks/gradle.section.md

Prototypes a stage-based toolchain bootstrap with transitions using "quux-lang" — a fictitious language — as an example.

bazel cquery 'filter("^//:*", deps(:foo) - filter("//:_quux_toolchain_current_bootstrap_stage_is_[0-9]*", //:*)) - //:defs.bzl - //:toolchain - //:quux_toolchain_type' --output=graph > out.dot

bazel query 'filter("^_version_is_at_.*$", ...) + true + false' --output=graph

flowchart TD
  classDef true stroke:#1F0
  classDef false stroke:#F00
  classDef m stroke:#F90
  classDef l stroke:#C0F