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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ deterministic diff drives the loop — an LLM does only the creative work
equivalent builds converge to zero errors.
- **Grouping-agnostic** for libraries and Java source sets — library renames
and object-library fold-ins converge with no mapping.
- **Reviewer-auditable** suppressions in a checked-in `cmake2bazel.json`.
- **Reviewer-auditable** suppressions in a checked-in `any2bazel.json`.
- **MVP scope** — no codegen, custom commands, or packaging yet.

> [!NOTE]
Expand Down
30 changes: 13 additions & 17 deletions SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@ driven by a deterministic diff, so each round is cheap and the LLM only does the
creative work (generating and fixing BUILD files), never the mechanical
comparison.

> **Formerly `cmake2bazel`.** The engine grew a language-neutral, action-based
> IR with multiple frontends. One artifact still carries the old name: the
> migration config file is still literally `cmake2bazel.json`.

## Frontends and maturity

All frontends extract into one shared **action-based model**; a language/
Expand All @@ -46,7 +42,7 @@ CMake File API codemodel ──extract_cmake.py──┐
├─► reconstruct.py ─► diff.py ─► worklist / converged?
Bazel aquery jsonproto ──extract_bazel.py──┘ ▲
cmake2bazel.json (migration decisions)
any2bazel.json (migration decisions)
```

- **CMake side = File API codemodel-v2** (not `compile_commands.json`, which
Expand Down Expand Up @@ -88,11 +84,11 @@ Bazel aquery jsonproto ──extract_bazel.py──┘ ▲
`canonicalize.py` strips noise before comparing flags. Universal mechanics
(driver/wrapper paths, `-c`/`-o`, sysroot, reproducibility defines, `-O*`/`-g*`)
are dropped in code — never your concern. Judgment calls (warning-set or cosmetic
differences) go in `cmake2bazel.json`'s `ignore`. Correctness flags (`-std=*`,
differences) go in `any2bazel.json`'s `ignore`. Correctness flags (`-std=*`,
`-fno-exceptions`, `-fno-rtti`, …) must never be ignored — they surface as hard
errors by design.

## The migration config: `cmake2bazel.json`
## The migration config: `any2bazel.json`

Lives at the **migrated project's repo root**, committed alongside the BUILD
files as the durable record of migration decisions. The filename still carries
Expand Down Expand Up @@ -197,7 +193,7 @@ flags. Tests are opt-in (`include_tests`) and get the compile-parity stage only
> `python3 "$SKILL_DIR/scripts/extract_cmake.py" …` where `$SKILL_DIR` is this
> skill's install location (e.g. `~/.claude/skills/any2bazel`). The artifacts
> you *produce* — `model.*.json`, `aquery.json`, `diff.json`, the generated
> `BUILD.bazel`/`MODULE.bazel`, and `cmake2bazel.json` — live in or beside the
> `BUILD.bazel`/`MODULE.bazel`, and `any2bazel.json` — live in or beside the
> target repo.
>
> **Working directory:** run `cmake` and `bazel` from the **target repo root**
Expand Down Expand Up @@ -254,7 +250,7 @@ instead of being a warning nobody reads.
> that are **not** in `.bazelrc` (e.g. boringssl expects `-fno-exceptions
> -fno-rtti` to be set at the top level, not in libraries). The tool cannot
> infer these — get them from the project's build instructions and pass them
> through, or record genuinely-irreducible differences in `cmake2bazel.json`.
> through, or record genuinely-irreducible differences in `any2bazel.json`.
> - Use the **same platform/options** as the CMake configure in step 2, or the
> two sides aren't comparable.

Expand All @@ -266,13 +262,13 @@ python3 scripts/extract_bazel.py aquery.json <repo_root> model.bazel.json
```
If analysis fails, fix that first before trusting the diff. If a flag differs
only because of a build-convention gap (e.g. `-std=gnu++17` vs `-std=c++17`,
GNU-extensions on/off), that's a judgment call for `cmake2bazel.json`, not a
GNU-extensions on/off), that's a judgment call for `any2bazel.json`, not a
BUILD-file bug.

### 5. Diff
```bash
python3 scripts/diff.py model.cmake.json model.bazel.json \
<repo_root>/cmake2bazel.json > diff.json # 3rd arg optional
<repo_root>/any2bazel.json > diff.json # 3rd arg optional
```
`diff.json` has `converged` (⇔ zero `error` discrepancies), a `discrepancies`
worklist (each with `kind`, `severity`, `target`, `tu`, `cmake_only`,
Expand Down Expand Up @@ -309,7 +305,7 @@ hand-reading the worklist.

### 7. Fix *(LLM step)*, then loop
For each `error`, decide: real defect → fix the BUILD file; accepted difference
→ add to `cmake2bazel.json` `ignore` (only for warning/cosmetic flags, **never**
→ add to `any2bazel.json` `ignore` (only for warning/cosmetic flags, **never**
correctness flags).

| kind | fix |
Expand All @@ -325,7 +321,7 @@ correctness flags).
| `test_binary_count` | (tests on, warning) differing number of test executables — investigate which side has the extra/missing binary |

Then re-diff: if you edited `BUILD.bazel`/`MODULE.bazel`, re-run from step 4
(re-extract the Bazel side); if you only edited `cmake2bazel.json`, re-run from
(re-extract the Bazel side); if you only edited `any2bazel.json`, re-run from
step 5. Repeat until `converged: true`. Report remaining `warn` items and the
`excluded` roles.

Expand All @@ -334,7 +330,7 @@ Once production parity is reached, opt into test diffing:
- Re-extract **both** sides with tests enabled and the **same** scope: CMake
configured without `-D..._BUILD_TESTING=OFF`; aquery over `//...` (not a
single target). Asymmetric scope fabricates findings.
- Set `"include_tests": true` in `cmake2bazel.json`, re-extract both models
- Set `"include_tests": true` in `any2bazel.json`, re-extract both models
(steps 2 and 4) with the test-inclusive configure/aquery, then re-run the
diff/triage/fix loop (steps 5–7).
- Test sources are compared as a project-wide TU-set union (grouping/naming
Expand All @@ -345,21 +341,21 @@ Once production parity is reached, opt into test diffing:

### 9. Report
Summarize: production targets reconciled, rounds taken, suppressions recorded in
`cmake2bazel.json` (with rationale), excluded roles (dashboard/codegen) for
`any2bazel.json` (with rationale), excluded roles (dashboard/codegen) for
human follow-up, and — if `include_tests` was on — test-source parity and any
test-binary count gap.

## What you edit

`$SKILL_DIR/scripts/` are deterministic and must **not** be edited per-run. All
per-iteration judgment goes into the generated `BUILD.bazel`/`MODULE.bazel` and
`cmake2bazel.json` (reviewed).
`any2bazel.json` (reviewed).

## Other frontends

The Maven and VSCode/npm frontends share the action model and differ but are
newer captures — treat their output as exploratory, and don't apply the CMake
`cmake2bazel.json` machinery to them (they don't read it).
`any2bazel.json` machinery to them (they don't read it).

### Maven → Bazel (early)
Maven has no action graph; the reference is the **forked `javac` argument
Expand Down
2 changes: 1 addition & 1 deletion docs/CASE-dolphin-migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ fell out that no code review would have caught:
| `-DOFF` reaching 554 TUs | an upstream CMake bug: `Externals/pugixml/CMakeLists.txt` does `set(PUGIXML_BUILD_DEFINES OFF)` meaning "none", and pugixml forwards `${PUGIXML_BUILD_DEFINES}` into `target_compile_definitions(... PUBLIC)`, so the literal string becomes a define on pugixml and every consumer |

The last row is worth its own note on **process**: the right move was to record it
in `cmake2bazel.json`'s `ignore.defines` with the explanation, *not* to add
in `any2bazel.json`'s `ignore.defines` with the explanation, *not* to add
`-DOFF` to the Bazel build so the diff would go quiet. A parity diff exists to
find differences worth explaining; copying an upstream bug to silence one turns
the tool into a rubber stamp. Every suppression being a reviewable line in a
Expand Down
2 changes: 1 addition & 1 deletion docs/CASE-ladybird-migration.md
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,7 @@ src/hdr lists from `generated_srcs.bzl`).
exclude = LIBWEB_GENERATED_HDRS) + LIBWEB_GENERATED_HDRS` (generated wins).
The remaining 689 "missing_tu" in the LibWeb diff are purely the
`bazel-out/…/bin/` vs `Build/full/` genfile-path prefix, not real gaps
(add a genfiles-prefix normalization to `cmake2bazel.json` to silence).
(add a genfiles-prefix normalization to `any2bazel.json` to silence).

11. **Extractor OOM on large targets (real tool bug — FIXED).** LibWeb's single
link action pulls a `depSetOfFiles` DAG of ~4k depsets over a ~13k-artifact
Expand Down
2 changes: 1 addition & 1 deletion docs/TODO-configure-time-generation.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ must not be merged in the model:

2. **The differ.** Compare `configured_files` across sides by **CONTENT**
(read `output_path` on each side, byte-compare; escalate to LLM judgment;
record normalization rules in `cmake2bazel.json`). Only `is_compile_input`
record normalization rules in `any2bazel.json`). Only `is_compile_input`
files block parity; benign outputs (.pc, install .cmake) are reported, not
enforced. The content check is filesystem-dependent — degrade gracefully
("output not on disk → report, never silently pass"), like the include-order
Expand Down
8 changes: 4 additions & 4 deletions scripts/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

"""Migration config -- the checked-in record of human decisions.

Lives at the migrated project's repo root as `cmake2bazel.json`. Unlike the
Lives at the migrated project's repo root as `any2bazel.json`. Unlike the
hardcoded canonicalization rules (driver mechanics, toolchain/sysroot,
reproducibility injections -- universal facts baked into canonicalize.py), this
file holds the JUDGMENT CALLS a migration must make and that deserve review:
Expand All @@ -31,7 +31,7 @@
Because it's a file, every suppression is an explicit, reviewable, version-
controlled line -- a durable record of why a given difference was accepted.

Example cmake2bazel.json:
Example any2bazel.json:
{
"target_map": { },
"ignore": {
Expand All @@ -49,7 +49,7 @@
from dataclasses import dataclass, field
from typing import Dict, List, Set

CONFIG_FILENAME = "cmake2bazel.json"
CONFIG_FILENAME = "any2bazel.json"


@dataclass
Expand Down Expand Up @@ -188,5 +188,5 @@ def load(path: str) -> MigrationConfig:


def find_and_load(repo_root: str) -> MigrationConfig:
"""Load <repo_root>/cmake2bazel.json if it exists."""
"""Load <repo_root>/any2bazel.json if it exists."""
return load(os.path.join(repo_root, CONFIG_FILENAME))
2 changes: 1 addition & 1 deletion scripts/diff.py
Original file line number Diff line number Diff line change
Expand Up @@ -512,7 +512,7 @@ def summarize(discs: List[Discrepancy],
if __name__ == "__main__":
import sys
# Used as a CLI by the skill loop:
# diff.py <cmake.json> <bazel.json> [cmake2bazel.json]
# diff.py <cmake.json> <bazel.json> [any2bazel.json]
# The 3rd arg is the migration config (target_map + ignore lists). If
# omitted, the diff runs with no human-approved suppressions.
import config as config_mod
Expand Down
2 changes: 1 addition & 1 deletion scripts/extract_bazel.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
# both Bazel-specific, not real compilations -- skipped, like C++ header
# processing.) Mapped to the neutral 'JavaCompile' mnemonic the differ groups on.
_JAVAC = {"Javac"}
# Custom TS rule mnemonic emitted by cmake2bazel/bazel/rules/ts_program.bzl.
# Custom TS rule mnemonic emitted by any2bazel/bazel/rules/ts_program.bzl.
_TSPROGRAM = {"TsProgram"}

# Infer target kind from the link ACTION, not just the output extension.
Expand Down
4 changes: 2 additions & 2 deletions scripts/extract_npm.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@

Usage:
# Run the instrumented build first:
NODE_OPTIONS="--import file://$PWD/cmake2bazel/scripts/npm_instrument/preload.mjs" \\
NODE_OPTIONS="--import file://$PWD/any2bazel/scripts/npm_instrument/preload.mjs" \\
VSCODE_EMIT_BUILD_IR=$PWD/actions.ndjson \\
npm run transpile-client

python3 cmake2bazel/scripts/extract_npm.py actions.ndjson "$PWD" model.npm.json
python3 any2bazel/scripts/extract_npm.py actions.ndjson "$PWD" model.npm.json
"""

from __future__ import annotations
Expand Down
2 changes: 1 addition & 1 deletion tests/test_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -548,7 +548,7 @@ def test_exclude_targets_suppresses_structural_diffs():


def test_config_loads_all_fields_from_json():
# The skill drives the diff via a cmake2bazel.json on disk, so loading must
# The skill drives the diff via a any2bazel.json on disk, so loading must
# populate every lever. Guards against a field added to the dataclass but
# not wired into load().
import json
Expand Down