Skip to content

Commit 013931f

Browse files
avrabeclaude
andauthored
feat: migrate wasm_optimize to native loom toolchain v1.1.14 (#512) (#514)
* feat(toolchains): add native loom toolchain (#512 step 2) loom v1.x ships native per-OS binaries (no loom.wasm). Add a hermetic loom toolchain, mirroring meld_toolchain.bzl but extracting the tarball (meld ships a bare binary): - toolchains/loom_toolchain.bzl: loom_repository (download+extract loom-v{ver}- {triple}.tar.gz, expose the loom binary; stub for unsupported/Windows hosts) + loom_toolchain rule -> ToolchainInfo(loom=...). - toolchains/BUILD.bazel: loom_toolchain_type + bzl_library. - toolchains/tool_registry.bzl: _URL_PATTERNS["loom"] (tarball; strip_prefix "" and binary "loom" via the existing defaults). - wasm/extensions.bzl + MODULE.bazel: register @loom_toolchain (v1.1.14). Registered but not yet consumed — wasm_optimize still uses the @loom_wasm 0.3.0 component; the rewire to the native toolchain is the next step (#512). Windows loom (loom.exe) stubbed for now (follow-up). Verified: `bazel build @loom_toolchain//:loom` fetches + extracts loom 1.1.14 for the host and resolves the binary. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * feat(wasm_optimize): run native loom toolchain; drop loom.wasm/loom_wrapper (#512) Rewire wasm_optimize to the native loom toolchain (added in the previous commit) instead of running the loom.wasm component under wasmtime: - executable = ctx.toolchains[loom_toolchain_type].loom; args `optimize <input> -o <output> [flags]` (loom CLI unchanged). Native loom reads the input directly through the OS, so the wasmtime/WASI-preopen/symlink workaround (#490, loom_wrapper) and the wasmtime toolchain dep are no longer needed and are removed from the rule. - Drop the @loom_wasm 0.3.0 wasm_component_download from MODULE.bazel. - Add //test/p3:loom_optimize_build_test (wasm_optimize on the P2 component) for coverage. Verified locally: //test/p3:hello_p2_optimized builds — native loom 1.1.14 optimizes the component (4/4 core modules, "Optimization complete"). (tools/loom_wrapper is now unused by loom; left in place — wasmsign2 patterns may still reference the approach — removable in a cleanup follow-up.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 451f3f7 commit 013931f

8 files changed

Lines changed: 263 additions & 59 deletions

File tree

MODULE.bazel

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,18 @@ use_repo(meld, "meld_toolchain")
261261

262262
register_toolchains("@meld_toolchain//:meld_toolchain")
263263

264+
# Loom toolchain for WebAssembly component optimization (native binary, v1.x).
265+
# wasm_optimize consumes this (loom_toolchain_type); the old @loom_wasm 0.3.0
266+
# component path was removed (#512).
267+
loom = use_extension("//wasm:extensions.bzl", "loom")
268+
loom.register(
269+
name = "loom",
270+
version = "1.1.14",
271+
)
272+
use_repo(loom, "loom_toolchain")
273+
274+
register_toolchains("@loom_toolchain//:loom_toolchain")
275+
264276
# spar toolchain: AADL architecture model -> WIT generation
265277
spar = use_extension("//wasm:extensions.bzl", "spar")
266278
spar.register(
@@ -331,13 +343,9 @@ wasm_component_download(
331343
version = "0.7.0",
332344
)
333345

334-
# LOOM WebAssembly optimizer (version in //checksums/tools/loom.json)
335-
wasm_component_download(
336-
name = "loom_wasm",
337-
filename = "loom.wasm",
338-
tool_name = "loom",
339-
version = "0.3.0",
340-
)
346+
# LOOM: consumed via the native loom toolchain (@loom_toolchain, above).
347+
# The old @loom_wasm 0.3.0 component download was removed — loom v1.x is
348+
# native-only and wasm_optimize now runs the native binary directly (#512).
341349

342350
# WASM Tools Component toolchain for universal wasm-tools operations
343351
register_toolchains("//toolchains:wasm_tools_component_toolchain_local")

MODULE.bazel.lock

Lines changed: 37 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/p3/BUILD.bazel

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ P2 tests verify no regression, P3 tests verify the new attribute is accepted.
66

77
load("@bazel_skylib//rules:build_test.bzl", "build_test")
88
load("@rules_wasm_component//rust:defs.bzl", "rust_wasm_component", "rust_wasm_component_bindgen")
9+
load("@rules_wasm_component//wasm:defs.bzl", "wasm_optimize")
910
load("@rules_wasm_component//wit:defs.bzl", "wit_library")
1011

1112
package(default_visibility = ["//visibility:public"])
@@ -38,6 +39,20 @@ build_test(
3839
targets = [":hello_p2"],
3940
)
4041

42+
# ============================================================================
43+
# Native loom optimize (covers wasm_optimize on the native loom toolchain, #512)
44+
# ============================================================================
45+
46+
wasm_optimize(
47+
name = "hello_p2_optimized",
48+
component = ":hello_p2",
49+
)
50+
51+
build_test(
52+
name = "loom_optimize_build_test",
53+
targets = [":hello_p2_optimized"],
54+
)
55+
4156
# ============================================================================
4257
# P3 build (experimental — async bindings via wit-bindgen crate runtime)
4358
# ============================================================================

toolchains/BUILD.bazel

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,12 @@ toolchain_type(
9090
visibility = ["//visibility:public"],
9191
)
9292

93+
# Toolchain type for Loom (WebAssembly component optimization)
94+
toolchain_type(
95+
name = "loom_toolchain_type",
96+
visibility = ["//visibility:public"],
97+
)
98+
9399
# Toolchain type for spar (AADL architecture model -> WIT generation)
94100
toolchain_type(
95101
name = "spar_toolchain_type",
@@ -349,6 +355,14 @@ bzl_library(
349355
deps = [":tool_registry"],
350356
)
351357

358+
# Bzl library for Loom toolchain implementation
359+
bzl_library(
360+
name = "loom_toolchain",
361+
srcs = ["loom_toolchain.bzl"],
362+
visibility = ["//visibility:public"],
363+
deps = [":tool_registry"],
364+
)
365+
352366
# Export .bzl files for testing
353367
exports_files([
354368
"tool_registry.bzl",

toolchains/loom_toolchain.bzl

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
# Copyright 2026 Ralf Anton Beier. All rights reserved.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
9+
"""Loom toolchain: native binary for WebAssembly component optimization.
10+
11+
loom optimizes a WebAssembly component (constant folding, CSE, inlining, DCE,
12+
fused-component passes, optional Z3 verification). As of v1.x loom is
13+
distributed as native per-OS binaries (the v0.x `loom.wasm` component was
14+
dropped), so wasm_optimize runs the native binary directly instead of running
15+
loom.wasm under wasmtime. Mirrors toolchains/meld_toolchain.bzl, but loom ships
16+
tarballs (extracted) rather than a bare binary.
17+
"""
18+
19+
load("//checksums:registry.bzl", "validate_tool_exists")
20+
load("//toolchains:tool_registry.bzl", "tool_registry")
21+
22+
# Platforms where loom native binaries are downloaded + extracted here. loom
23+
# also ships a Windows binary (loom.exe), but that path is not wired yet
24+
# (binary-name differs); Windows gets the stub for now (see #512 follow-up).
25+
_SUPPORTED_PLATFORMS = [
26+
"darwin_amd64",
27+
"darwin_arm64",
28+
"linux_amd64",
29+
]
30+
31+
def _loom_toolchain_impl(ctx):
32+
"""Implementation of loom_toolchain rule."""
33+
return [platform_common.ToolchainInfo(
34+
loom = ctx.file.loom,
35+
)]
36+
37+
loom_toolchain = rule(
38+
implementation = _loom_toolchain_impl,
39+
attrs = {
40+
"loom": attr.label(
41+
allow_single_file = True,
42+
executable = True,
43+
cfg = "exec",
44+
doc = "loom binary for component optimization",
45+
),
46+
},
47+
doc = "Declares a Loom toolchain for WebAssembly component optimization",
48+
)
49+
50+
_STUB_BUILD = '''"""Loom toolchain stub: unsupported platform.
51+
52+
loom has no wired native binary for this host, so we register a toolchain that
53+
is marked incompatible with any target. Toolchain resolution for wasm_optimize
54+
targets fails cleanly here; builds that never touch wasm_optimize are unaffected.
55+
"""
56+
57+
load("@rules_wasm_component//toolchains:loom_toolchain.bzl", "loom_toolchain")
58+
59+
package(default_visibility = ["//visibility:public"])
60+
61+
exports_files(["loom_stub"])
62+
63+
loom_toolchain(
64+
name = "loom_toolchain_impl",
65+
loom = "loom_stub",
66+
)
67+
68+
toolchain(
69+
name = "loom_toolchain",
70+
target_compatible_with = ["@platforms//:incompatible"],
71+
toolchain = ":loom_toolchain_impl",
72+
toolchain_type = "@rules_wasm_component//toolchains:loom_toolchain_type",
73+
)
74+
'''
75+
76+
def _loom_repository_impl(repository_ctx):
77+
"""Download + extract the loom native binary and create a toolchain repo."""
78+
platform = tool_registry.detect_platform(repository_ctx)
79+
version = repository_ctx.attr.version
80+
81+
if platform not in _SUPPORTED_PLATFORMS or not validate_tool_exists(repository_ctx, "loom", version, platform):
82+
print("Loom: no wired native binary for platform {} (version {}); emitting stub".format(platform, version))
83+
repository_ctx.file("loom_stub", content = "", executable = True)
84+
repository_ctx.file("BUILD.bazel", _STUB_BUILD)
85+
return
86+
87+
print("Setting up loom {} for platform {}".format(version, platform))
88+
89+
# loom ships a tarball containing ./loom; tool_registry extracts it (the
90+
# 1.1.14 registry entries have no `binary: true`) and returns the binary
91+
# path. strip_prefix is "" (flat archive) — see _calculate_strip_prefix.
92+
tool_registry.download(
93+
repository_ctx,
94+
"loom",
95+
version,
96+
platform,
97+
)
98+
99+
repository_ctx.file("BUILD.bazel", '''"""Loom toolchain repository"""
100+
101+
load("@rules_wasm_component//toolchains:loom_toolchain.bzl", "loom_toolchain")
102+
103+
package(default_visibility = ["//visibility:public"])
104+
105+
loom_toolchain(
106+
name = "loom_toolchain_impl",
107+
loom = ":loom",
108+
)
109+
110+
toolchain(
111+
name = "loom_toolchain",
112+
exec_compatible_with = [],
113+
target_compatible_with = [],
114+
toolchain = ":loom_toolchain_impl",
115+
toolchain_type = "@rules_wasm_component//toolchains:loom_toolchain_type",
116+
)
117+
''')
118+
119+
loom_repository = repository_rule(
120+
implementation = _loom_repository_impl,
121+
attrs = {
122+
"version": attr.string(
123+
default = "1.1.14",
124+
doc = "Loom version to download",
125+
),
126+
},
127+
doc = "Downloads loom and creates a toolchain repository",
128+
)

toolchains/tool_registry.bzl

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,11 @@ _URL_PATTERNS = {
143143
"filename": "{suffix}", # e.g., "meld-aarch64-apple-darwin"
144144
"is_binary": True,
145145
},
146+
"loom": {
147+
# loom v1.x releases are tarballs (extracted; url_suffix IS the filename)
148+
"base": "https://github.com/{repo}/releases/download/v{version}",
149+
"filename": "{suffix}", # e.g., "loom-v1.1.14-aarch64-apple-darwin.tar.gz"
150+
},
146151
"spar": {
147152
# spar releases are tar.gz/zip archives: spar-v{version}-{triple}.{ext}
148153
"base": "https://github.com/{repo}/releases/download/v{version}",

0 commit comments

Comments
 (0)