feat(build): migrated native pipeline to bazel with remote caching

- Replaced the napi-cli/cargo-zigbuild/cargo-xwin/sccache build path with
  Bazel: rules_rust + crate_universe over Cargo.lock, hermetic zig cc
  toolchains (linux-gnu pinned to glibc 2.17, linux-musl), host Xcode for
  darwin, and a repo-local hermetic clang-cl + llvm-ml + xwin toolchain for
  windows-msvc (bazel/toolchains/msvc).
- All eight shipped addons build as //:natives-<target> via the release
  transition in bazel/defs.bzl (opt, thin LTO, cgu=16, stripped, canonical
  .node naming); scripts/bazel-natives.ts is the single driver for local
  dev and CI.
- Rust validation moved to bazel test + clippy aspects (strict workspace
  policy for opted-in crates, default lints elsewhere, mirroring cargo
  semantics) and the rustfmt aspect; cargo stays as the dev-iteration
  surface, with brush-core/brush-builtins promoted to workspace members
  and excluded from cargo dev tasks to keep their historical scope.
- CI caches through an in-cluster bazel-remote action cache (TLS + basic
  auth, cluster-internal only); GitHub-hosted runners never touch the
  infrastructure and use an actions/cache-backed disk cache instead.
- Deleted the hand-rolled caching machinery: ci-target-cache,
  ci-native-artifact-cache, ci-build-native, native-source-hash,
  find-native-artifacts, restore-linux-native, native-prewarm workflow,
  ensure-* toolchain actions, and all sccache/Swatinem wiring.
- Warm native rebuilds drop from ~20 minutes to seconds; a cold client
  with a warm remote cache rebuilds the linux x64 pair in ~2.5 minutes.
This commit is contained in:
can1357
2026-07-27 12:22:19 +02:00
parent 5f988a8270
commit 8facd237d5
121 changed files with 66794 additions and 2630 deletions
+1
View File
@@ -0,0 +1 @@
# Namespace package for repo-local Bazel rules (defs.bzl).
+48
View File
@@ -0,0 +1,48 @@
# Generated from [workspace.lints] in Cargo.toml (see .bazelrc clippy-strict).
# Applies only to crates that opt in via `[lints] workspace = true`.
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Amismatched_lifetime_syntaxes
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Wclippy::all
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Dclippy::correctness
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Wclippy::nursery
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Wclippy::pedantic
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Wclippy::perf
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Wclippy::style
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Dclippy::suspicious
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Wclippy::allow_attributes_without_reason
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Aclippy::borrow_as_ptr
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Aclippy::cast_lossless
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Aclippy::cast_possible_truncation
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Aclippy::cast_possible_wrap
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Aclippy::cast_precision_loss
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Aclippy::cast_ptr_alignment
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Aclippy::cast_sign_loss
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Aclippy::default_trait_access
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Aclippy::enum_glob_use
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Aclippy::float_cmp
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Aclippy::inconsistent_struct_constructor
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Aclippy::inline_always
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Aclippy::items_after_statements
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Aclippy::let_underscore_untyped
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Aclippy::match_same_arms
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Aclippy::match_wildcard_for_single_variants
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Aclippy::missing_errors_doc
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Aclippy::missing_fields_in_debug
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Aclippy::missing_panics_doc
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Aclippy::must_use_candidate
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Aclippy::needless_pass_by_value
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Aclippy::option_if_let_else
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Aclippy::ptr_as_ptr
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Aclippy::redundant_closure_for_method_calls
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Aclippy::ref_as_ptr
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Aclippy::return_self_not_must_use
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Aclippy::significant_drop_tightening
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Aclippy::similar_names
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Aclippy::struct_excessive_bools
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Aclippy::too_many_arguments
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Aclippy::too_many_lines
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Aclippy::tuple_array_conversions
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Wclippy::undocumented_unsafe_blocks
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Aclippy::unreadable_literal
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Aclippy::unsafe_derive_deserialize
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Aclippy::verbose_bit_mask
build:clippy-strict --@rules_rust//rust/settings:clippy_flag=-Aclippy::wildcard_imports
+78
View File
@@ -0,0 +1,78 @@
"""Rules for producing release-grade, canonically named pi_natives addons.
`native_addon` transitions //crates/pi-natives:pi_natives onto a shipping
platform with the release codegen profile (opt, thin LTO, cgu=16, stripped —
mirrors the cargo `ci` profile) and renames the produced shared library to the
loader's canonical `pi_natives.<platform>-<arch>[-<variant>].node` filename.
Encoding the profile in the transition means `bazel build //:natives-<t>` is
always release-grade regardless of -c, and every addon shares one cache entry
per (platform, source) pair.
"""
_ADDON_RUSTC_FLAGS = [
"-Ccodegen-units=16",
"-Cstrip=symbols",
]
def _addon_transition_impl(settings, attr):
return {
"//command_line_option:platforms": str(attr.platform),
"//command_line_option:compilation_mode": "opt",
"@rules_rust//rust/settings:lto": "thin",
"@rules_rust//rust/settings:extra_rustc_flags": _ADDON_RUSTC_FLAGS,
}
_addon_transition = transition(
implementation = _addon_transition_impl,
inputs = [],
outputs = [
"//command_line_option:platforms",
"//command_line_option:compilation_mode",
"@rules_rust//rust/settings:lto",
"@rules_rust//rust/settings:extra_rustc_flags",
],
)
_SHARED_LIB_EXTENSIONS = ("so", "dylib", "dll")
def _native_addon_impl(ctx):
libs = [
f
for f in ctx.attr.lib[0][DefaultInfo].files.to_list()
if f.extension in _SHARED_LIB_EXTENSIONS
]
if len(libs) != 1:
fail("expected exactly one shared library from {}, got: {}".format(
ctx.attr.lib[0].label,
[f.short_path for f in libs],
))
# Scope under the rule name: gnu and musl addons share canonical filenames
# (the loader never sees both), so bare package-level outputs would collide.
out = ctx.actions.declare_file(ctx.label.name + "/" + ctx.attr.out)
ctx.actions.symlink(output = out, target_file = libs[0])
return [DefaultInfo(files = depset([out]))]
native_addon = rule(
implementation = _native_addon_impl,
doc = "Release build of the pi_natives cdylib for one shipping platform, " +
"renamed to the loader's canonical .node filename.",
attrs = {
"lib": attr.label(
cfg = _addon_transition,
mandatory = True,
doc = "The rust_shared_library target (//crates/pi-natives:pi_natives).",
),
"platform": attr.label(
mandatory = True,
doc = "//bazel/platforms platform to build for.",
),
"out": attr.string(
mandatory = True,
doc = "Canonical addon filename, e.g. pi_natives.linux-x64-baseline.node.",
),
"_allowlist_function_transition": attr.label(
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
),
},
)
+61
View File
@@ -0,0 +1,61 @@
# One platform per shipped pi_natives addon. linux platforms inherit the zig
# libc-aware platforms so cc toolchain resolution pins glibc 2.17 (the shipped
# portability floor) or musl; the cpu_variant constraint selects -Ctarget-cpu
# in //crates/pi-natives. darwin/win32 resolve against the host Xcode toolchain
# and //bazel/toolchains/msvc respectively.
package(default_visibility = ["//visibility:public"])
platform(
name = "linux-x64-baseline",
constraint_values = ["//bazel/variants:baseline"],
parents = ["@zig_sdk//libc_aware/platform:linux_amd64_gnu.2.17"],
)
platform(
name = "linux-x64-modern",
constraint_values = ["//bazel/variants:modern"],
parents = ["@zig_sdk//libc_aware/platform:linux_amd64_gnu.2.17"],
)
platform(
name = "linux-arm64",
parents = ["@zig_sdk//libc_aware/platform:linux_arm64_gnu.2.17"],
)
platform(
name = "linux-musl-x64-baseline",
constraint_values = ["//bazel/variants:baseline"],
parents = ["@zig_sdk//libc_aware/platform:linux_amd64_musl"],
)
platform(
name = "linux-musl-arm64",
parents = ["@zig_sdk//libc_aware/platform:linux_arm64_musl"],
)
platform(
name = "darwin-x64-baseline",
constraint_values = [
"@platforms//os:macos",
"@platforms//cpu:x86_64",
"//bazel/variants:baseline",
],
)
platform(
name = "darwin-arm64",
constraint_values = [
"@platforms//os:macos",
"@platforms//cpu:arm64",
],
)
platform(
name = "win32-x64-baseline",
constraint_values = [
"@platforms//os:windows",
"@platforms//cpu:x86_64",
"//bazel/variants:baseline",
],
)
+83
View File
@@ -0,0 +1,83 @@
# Repo-local toolchains, registered in MODULE.bazel BEFORE @rust_toolchains//:all.
#
# musl wrappers: rules_rust's generated gnu and musl rust toolchains share
# (os, cpu) constraints, so plain registration order would hand musl platforms
# the gnu std. These wrappers re-register the musl toolchains gated on
# @zig_sdk//libc:musl (carried by //bazel/platforms:linux-musl-*), and lose to
# nothing on gnu platforms because the constraint cannot match there.
#
# //bazel/toolchains/msvc: hermetic clang-cl + lld-link + xwin CRT/SDK
# cc toolchain for x86_64-pc-windows-msvc cross builds from linux.
package(default_visibility = ["//visibility:public"])
_MUSL_RUST_TOOLCHAINS = {
"linux-x64-to-musl-x64": (
["@platforms//os:linux", "@platforms//cpu:x86_64"],
["@platforms//os:linux", "@platforms//cpu:x86_64"],
"@rust_linux_x86_64__x86_64-unknown-linux-musl__nightly_tools//:rust_toolchain",
),
"linux-x64-to-musl-arm64": (
["@platforms//os:linux", "@platforms//cpu:x86_64"],
["@platforms//os:linux", "@platforms//cpu:aarch64"],
"@rust_linux_x86_64__aarch64-unknown-linux-musl__nightly_tools//:rust_toolchain",
),
"darwin-arm64-to-musl-x64": (
["@platforms//os:osx", "@platforms//cpu:aarch64"],
["@platforms//os:linux", "@platforms//cpu:x86_64"],
"@rust_macos_aarch64__x86_64-unknown-linux-musl__nightly_tools//:rust_toolchain",
),
"darwin-arm64-to-musl-arm64": (
["@platforms//os:osx", "@platforms//cpu:aarch64"],
["@platforms//os:linux", "@platforms//cpu:aarch64"],
"@rust_macos_aarch64__aarch64-unknown-linux-musl__nightly_tools//:rust_toolchain",
),
"linux-arm64-to-musl-arm64": (
["@platforms//os:linux", "@platforms//cpu:aarch64"],
["@platforms//os:linux", "@platforms//cpu:aarch64"],
"@rust_linux_aarch64__aarch64-unknown-linux-musl__nightly_tools//:rust_toolchain",
),
"linux-arm64-to-musl-x64": (
["@platforms//os:linux", "@platforms//cpu:aarch64"],
["@platforms//os:linux", "@platforms//cpu:x86_64"],
"@rust_linux_aarch64__x86_64-unknown-linux-musl__nightly_tools//:rust_toolchain",
),
}
[
toolchain(
name = "rust-musl-" + name,
exec_compatible_with = exec_cv,
target_compatible_with = target_cv + ["@zig_sdk//libc:musl"],
target_settings = ["@rules_rust//rust/toolchain/channel:nightly"],
toolchain = tools,
toolchain_type = "@rules_rust//rust:toolchain",
)
for name, (exec_cv, target_cv, tools) in _MUSL_RUST_TOOLCHAINS.items()
]
# msvc cross cc toolchain: @msvc_cc generates its wrappers for whichever host
# fetches it, so one toolchain() per supported exec host points at the same
# cc_toolchain — only the variant matching the local host can ever resolve.
# target_compatible_with pins these to windows/x86_64, so they can never
# shadow the zig cc toolchains on linux (or the host Xcode toolchain on mac).
_MSVC_EXEC_HOSTS = {
"linux-x64": ["@platforms//os:linux", "@platforms//cpu:x86_64"],
"linux-arm64": ["@platforms//os:linux", "@platforms//cpu:aarch64"],
"darwin-arm64": ["@platforms//os:osx", "@platforms//cpu:aarch64"],
"darwin-x64": ["@platforms//os:osx", "@platforms//cpu:x86_64"],
}
[
toolchain(
name = "msvc-cc-from-" + name,
exec_compatible_with = exec_cv,
target_compatible_with = [
"@platforms//os:windows",
"@platforms//cpu:x86_64",
],
toolchain = "@msvc_cc//:cc_toolchain",
toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
)
for name, exec_cv in _MSVC_EXEC_HOSTS.items()
]
+5
View File
@@ -0,0 +1,5 @@
# Hermetic clang-cl + lld-link + xwin (MSVC CRT/SDK) cross toolchain for
# x86_64-pc-windows-msvc, replacing cargo-xwin. The repository rules live in
# llvm.bzl / sysroot.bzl / cc.bzl (instantiated from MODULE.bazel); the
# toolchain() registrations live in //bazel/toolchains. See NOTES.md for the
# knobs and what still needs validation on can.internal.
+139
View File
@@ -0,0 +1,139 @@
# msvc cross toolchain — knobs & validation notes
Hermetic clang-cl + lld-link + xwin (MSVC CRT/SDK) cc toolchain for
`x86_64-pc-windows-msvc`, cross-linking from linux-x64 (CI) and darwin (dev)
exec hosts. Replaces cargo-xwin.
## Layout
| Piece | Where | Why separate |
| --- | --- | --- |
| `@llvm_msvc_tools` | `llvm.bzl` | LLVM 20.1.7 release archive for the fetching host, pruned to clang-cl/lld-link/llvm-lib/llvm-rc/llvm-mt + `lib/clang/*/include`. Downloads (~2 GiB) are sha256-pinned → Bazel repository cache. |
| `@xwin_sysroot` | `sysroot.bzl` | xwin 0.6.5 (pinned per-host sha256) runs `splat` in the repo rule. The ~1 GiB CRT/SDK payload comes from the Microsoft CDN via xwin itself and is **not** in Bazel's repo cache — a cold output base re-downloads it. Keep `sysroot.bzl` stable. |
| `@msvc_cc` | `cc.bzl` | Wrapper scripts + `cc_toolchain` + MSVC feature config (copied from the resolved rules_cc, like `@local_config_cc`). Cheap to regenerate — iterate flags here. |
| `toolchain()`s | `//bazel/toolchains` (`msvc-cc-from-*`) | One per exec host (linux-x64/arm64, darwin-arm64/x64), all pointing at `@msvc_cc//:cc_toolchain`; only the local host's variant can resolve. `target_compatible_with = [windows, x86_64]` ⇒ can never shadow zig on linux. |
| MODULE.bazel | `# --- msvc cross toolchain ---` section | `rules_cc` 0.2.17 (= Bazel 9.2's builtin pin) + the three `use_repo_rule` instantiations. Plus one target-suffixed env key inside the existing `audiopus_sys` annotation (see below). |
## Design decisions
- **No toolchains_llvm**: it wants to register full host cc toolchains, which
risks shadowing the zig linux toolchains. Direct LLVM release fetch instead.
- **Wrappers self-locate from `$0`** (execroot-relative sibling repos), so they
work from Bazel actions (cwd = execroot) *and* from build scripts, where
rules_rust `${pwd}`-expands `CC`/`AR` to absolute paths and cc-rs/cmake spawn
tools from other cwds.
- **CRT: dynamic `/MD`** (rules_cc's msvc branch default outside `dbg` without
the `static_link_msvcrt` feature) — matches what napi/cc-rs produced under
cargo-xwin (rust msvc targets default to dynamic CRT without `+crt-static`).
- **SSE floor in the wrapper, not annotations**: `-msse4.1 -msse4.2` live in the
clang-cl wrapper, which only ever targets win32-x64 (baseline = x86-64-v2 ⊇
SSE4.2). This is the old build-native.ts CFLAGS hack, windows-only by
construction.
- **cmake generator via target-suffixed env**: `crate_universe` cannot select()
annotations per platform, and a second `crate.annotation` for the same crate
hard-fails the extension (`_insert_annotation` dupe check; `annotation_select`
is unused/broken in rules_rust 0.71.3). Instead the existing `audiopus_sys`
annotation carries `CMAKE_GENERATOR_x86_64_pc_windows_msvc=Ninja` — cmake-rs
reads `VAR_<triple>` before `VAR`, so the key is inert for all other targets.
cmake-rs sets `CMAKE_SYSTEM_NAME=Windows` itself when target ≠ host.
- **cmake tool discovery**: wrappers are named bare `clang-cl`, `lld-link`,
`llvm-lib`, `llvm-rc`, `llvm-mt` (no `.sh`) because CMake's
`CMakeFindBinUtils`/`find_program` probes for those names next to
`CMAKE_C_COMPILER`, and cc-rs sniffs the MSVC/clang-cl tool family from the
basename. The clang-cl wrapper also exports link.exe-style `LIB` and passes
`-fuse-ld=lld-link` so compiler-driver links (cmake `try_compile` ABI checks)
resolve CRT import libs without a toolchain file.
- **ring 0.17.14 needs no perl/nasm**: verified in its build.rs — crates.io
tarballs use `pregenerated/*-nasm.o` objects directly for windows-msvc
(`use_nasm()` path only shells out during the maintainer packaging step).
The .o files flow through `cc::Build.object()` into llvm-lib.
## Reproducibility / cache implications
- First fetch per host: ~2 GiB LLVM (repo-cache backed) + ~15 MiB xwin +
~1 GiB MS CDN splat (not repo-cache backed). Splat repo ends up ~800 MiB.
- `--manifest-version 17` pins the VS2022 channel, but Microsoft advances the
channel payload over time → splat is stable day-to-day, not bit-reproducible
forever (same property cargo-xwin had). Action keys only depend on the files
actually read, so remote-cache hit rates degrade gracefully after an MS bump.
- Toolchain binaries differ per exec host (linux vs mac clang) → win32 link
actions do not share remote-cache entries across host OSes. CI is
linux-x64-only for this target, so this only affects dev machines.
## Already verified (darwin-arm64 dev host, 2026-07-27)
- `bazel build --nobuild //:natives-win32-x64-baseline` analyzes clean;
`cquery deps(...)` confirms `@msvc_cc//:cc_toolchain` (not the host Xcode
toolchain) resolved for the windows target. Full fetch + splat took ~2.5 min
on a fast link. Repin (`bun run bazel:repin`) already run for the
`CMAKE_GENERATOR_x86_64_pc_windows_msvc` annotation key.
- Wrapper smoke test outside Bazel: `clang-cl /MD` compiled a windows.h +
smmintrin.h SSE4.1 program and driver-linked it via `-fuse-ld=lld-link` +
`LIB` into a valid PE32+ exe; the standalone `lld-link` wrapper (rustc's
`-Clinker` path) and `llvm-lib` also produced a PE exe / ar archive.
- xwin's `10.0.26100 -> .` self-referential version symlinks broke Bazel's
glob ("too many levels of symbolic links"); `sysroot.bzl` now prunes any
readdir entry whose realpath equals its parent, post-splat.
- blake3 MASM (`ml64.exe` from cc-rs on non-windows hosts): `bin/ml64.exe` /
`bin/ml64` shims exec `llvm-ml -m64`. All four blake3 1.8.5
`blake3_*_x86-64_windows_msvc.asm` files assemble to valid amd64 COFF
objects through the shim (invoked cc-rs-style via PATH with joined `/Fo`).
cc-rs finds the shim through the blake3 crate.annotation, which prepends
`$${pwd}/external/+msvc_cc_repository+msvc_cc/bin` to the build-script PATH
(`$$` because annotation env runs through Bazel make-var expansion; the
rules_rust runner then substitutes `${pwd}` → exec root). The wrapper dir
reaches the sandbox via the cc toolchain's `all_files`. NOTE: the PATH entry
hardcodes @msvc_cc's canonical repo name — keep in sync if the repo rule or
repo name changes. Repin for this annotation already run.
- audiopus_sys/opus cmake exe links (can.internal finding #2): cmake's
`vs_link_exe` demands rc/mt tools that `find_program` can't locate on a
linux/mac PATH. @msvc_cc now generates `toolchain.cmake` (self-locating via
`CMAKE_CURRENT_LIST_DIR`: compiler/linker/rc/mt = the wrappers) handed to
cmake-rs through `CMAKE_TOOLCHAIN_FILE_x86_64_pc_windows_msvc` in the
audiopus_sys annotation (same `$${pwd}` + canonical-repo-path mechanism as
the blake3 shim). Second failure mode fixed in the same file: `try_compile`
defaults to the Debug config → `/MDd` → `msvcrtd.lib`, which the lean splat
(like cargo-xwin's) does not carry; toolchain.cmake pins
`CMAKE_TRY_COMPILE_CONFIGURATION=Release`, `CMAKE_POLICY_DEFAULT_CMP0091=NEW`
and `CMAKE_MSVC_RUNTIME_LIBRARY=MultiThreadedDLL` (/MD everywhere).
Verified on darwin: scratch `project(C)` + `add_executable` configures with
"Clang 20.1.7 with MSVC-like command-line" and links a valid PE32+ exe
through vs_link_exe with the wrapper rc/mt/linker. Repin already run.
## What to verify on can.internal (linux-x64)
1. `bazel build //:natives-win32-x64-baseline` end-to-end link; check the
produced `pi_natives.win32-x64-baseline.node` imports (dumpbin/llvm-readobj:
expect VCRUNTIME140/api-ms-win-crt-* → `/MD`, no static CRT).
2. LLVM 20.1.7 Linux-X64 binaries are built on a newish Ubuntu: confirm the
kata runner image's glibc is ≥ 2.35-ish and has `libtinfo6`/`libstdc++6`
(usual LLVM release-binary runtime deps).
3. `ninja` + `cmake` must be on the audiopus_sys build-script PATH
(`/usr/local/bin:/usr/bin:/bin`) on the kata image — same requirement the
old ensure-cmake action satisfied for cargo-xwin.
4. audiopus_sys configure: cmake should report
"Clang with MSVC-like command-line", take `toolchain.cmake` (log shows the
vs_link_exe --rc/--mt pointing into the wrapper dir), and produce opus.lib
with /MD objects. If mt is ever asked to actually merge manifests, note
the official LLVM llvm-mt lacks libxml2 and would error — not hit today.
5. tree-sitter grammar compiles via cc-rs: wrapper is picked up as `CC`
(family detection needs the basename to contain `clang-cl` — it does).
6. ring: no `nasm`/`perl` spawns in the build-script log; archive step uses
the `llvm-lib` wrapper.
7. blake3: build-script log should show `ml64.exe` resolving to the shim (no
"failed to find tool" error); spot-check the assembled objects land in the
rlib.
8. Repo fetch time/disk on the pods (first fetch ~3 GiB, ~25 min worst case);
consider pre-warming the bazel output base or a persistent
`--repository_cache` volume if it hurts.
## Knobs
- LLVM version/sha256s: `llvm.bzl` (`_LLVM_VERSION`, `_LLVM_DISTS`). 20.1.7 is
the newest release with archives for all four host tuples.
- xwin version + manifest channel: `sysroot.bzl` (`_XWIN_VERSION` 0.6.5 — last
release with darwin binaries; `_XWIN_MANIFEST_VERSION` "17").
- Compile/link flags, include/libpath set, CRT choice: wrapper templates and
`cc_toolchain_config` attrs in `cc.bzl`.
- Static CRT if ever needed: build with the standard `static_link_msvcrt`
feature (`--features=static_link_msvcrt`) instead of editing flags.
+279
View File
@@ -0,0 +1,279 @@
"""Repository rule generating the hermetic clang-cl + xwin MSVC cc toolchain.
The @msvc_cc repo holds only cheap generated files — wrapper shell scripts and
the cc_toolchain/cc_toolchain_config BUILD — so iterating on flags here never
invalidates the big @llvm_msvc_tools / @xwin_sysroot downloads (their rules
live in llvm.bzl / sysroot.bzl on purpose).
Wrappers derive every path from $0 (execroot-relative sibling repos), so they
work from Bazel actions (cwd = execroot) and from build scripts, where
rules_rust ${pwd}-expands CC/AR to absolute paths and cc-rs/cmake spawn the
tools from other working directories:
bin/clang-cl --target=x86_64-pc-windows-msvc, /imsvc CRT+SDK includes,
-msse4.1 -msse4.2 (win32-x64 baseline floor; clang-cl
enforces per-function target features, real MSVC does not),
-fuse-ld=lld-link + exported link.exe-style LIB so driver
links (cmake try_compile) resolve the CRT import libs.
bin/lld-link /libpath for CRT + SDK libs, then pass-through; rustc uses
it via -Clinker for the msvc linker flavor.
bin/llvm-lib archiver (lib.exe replacement, cc-rs AR + cmake CMAKE_AR).
bin/llvm-rc resource compiler (cmake finds it next to the compiler).
bin/llvm-mt manifest tool (cmake CMAKE_MT probe).
bin/ml64.exe MASM shim → llvm-ml -m64 (also bare `ml64`): cc-rs looks
bin/ml64 up `ml64.exe` on PATH for x64 msvc .asm (blake3); the
blake3 crate.annotation prepends this dir to PATH.
The MSVC-flavored feature/action config (dynamic CRT /MD by default — matching
what napi/cc-rs produced under cargo-xwin; /MT only via the standard
static_link_msvcrt feature) comes from rules_cc's own
windows_cc_toolchain_config.bzl, copied into the repo exactly like
@local_config_cc does, so it always matches the resolved rules_cc version.
"""
_CLANG_CL_WRAPPER = """\
#!/bin/sh
# Generated by //bazel/toolchains/msvc:cc.bzl. clang-cl driver for
# x86_64-pc-windows-msvc against the @xwin_sysroot MSVC CRT + Windows SDK.
set -eu
execroot="$(cd "$(dirname "$0")/../../.." && pwd)"
llvm="$execroot/external/{llvm}"
splat="$execroot/external/{xwin}/splat"
# lld-link (spawned through -fuse-ld for compiler-driver links, e.g. cmake
# try_compile) resolves CRT/SDK import libs via the link.exe-style LIB env.
LIB="$splat/crt/lib/x86_64;$splat/sdk/lib/um/x86_64;$splat/sdk/lib/ucrt/x86_64"
export LIB
# -msse4.1/-msse4.2: clang-cl enforces per-function target features (real MSVC
# does not); opus' silk/x86 SSE4.1 units fail without the feature enabled
# globally. The win32-x64 addon floor is x86-64-v2 (SSE4.2 inclusive), so this
# is safe for every C dep — same flags the cargo-xwin pipeline exported.
exec "$llvm/bin/clang-cl" \\
--target=x86_64-pc-windows-msvc \\
-fuse-ld=lld-link \\
-msse4.1 \\
-msse4.2 \\
-Wno-unused-command-line-argument \\
"/imsvc$splat/crt/include" \\
"/imsvc$splat/sdk/include/ucrt" \\
"/imsvc$splat/sdk/include/um" \\
"/imsvc$splat/sdk/include/shared" \\
"/imsvc$splat/sdk/include/winrt" \\
"/imsvc$splat/sdk/include/cppwinrt" \\
"$@"
"""
_LLD_LINK_WRAPPER = """\
#!/bin/sh
# Generated by //bazel/toolchains/msvc:cc.bzl. lld-link with the @xwin_sysroot
# CRT + SDK libpaths; rustc invokes it via -Clinker (msvc linker flavor).
set -eu
execroot="$(cd "$(dirname "$0")/../../.." && pwd)"
llvm="$execroot/external/{llvm}"
splat="$execroot/external/{xwin}/splat"
# rustc addresses lld in generic multi-flavor style ("-flavor link" first);
# the single-flavor lld-link binary would treat "link" as an input file.
if [ "${{1:-}}" = "-flavor" ]; then shift 2; fi
exec "$llvm/bin/lld-link" \\
"/libpath:$splat/crt/lib/x86_64" \\
"/libpath:$splat/sdk/lib/um/x86_64" \\
"/libpath:$splat/sdk/lib/ucrt/x86_64" \\
"$@"
"""
_PASSTHROUGH_WRAPPER = """\
#!/bin/sh
# Generated by //bazel/toolchains/msvc:cc.bzl.
set -eu
execroot="$(cd "$(dirname "$0")/../../.." && pwd)"
exec "$execroot/external/{llvm}/bin/{tool}" "$@"
"""
_ML64_WRAPPER = """\
#!/bin/sh
# Generated by //bazel/toolchains/msvc:cc.bzl. MASM shim: cc-rs assembles .asm
# for x64 msvc targets (blake3's blake3_*_x86-64_windows_msvc.asm) by invoking
# `ml64.exe` from PATH on non-windows hosts; llvm-ml is a MASM-compatible
# replacement — same shim cargo-xwin installed. The blake3 crate.annotation in
# MODULE.bazel prepends this bin/ dir to the build script PATH.
set -eu
execroot="$(cd "$(dirname "$0")/../../.." && pwd)"
exec "$execroot/external/{llvm}/bin/llvm-ml" -m64 "$@"
"""
_NOP_WRAPPER = """\
#!/bin/sh
# Generated by //bazel/toolchains/msvc:cc.bzl. Placeholder for tools the MSVC
# toolchain does not have (gcov/nm/objcopy/objdump/strip).
exit 0
"""
# CMake toolchain file for the `cmake` crate (audiopus_sys' bundled opus).
# cmake's vs_link_exe helper insists on rc/mt tools for MSVC-ABI exe links
# (try_compile links a test exe), and CMake's own find_program would only look
# for `rc`/`mt` on PATH. CMAKE_CURRENT_LIST_DIR makes the file self-locating —
# no canonical repo names involved. Handed to build scripts via the
# CMAKE_TOOLCHAIN_FILE_x86_64_pc_windows_msvc annotation env in MODULE.bazel.
_TOOLCHAIN_CMAKE = """\
# Generated by //bazel/toolchains/msvc:cc.bzl — clang-cl + lld-link + xwin
# CRT/SDK cross toolchain for x86_64-pc-windows-msvc (mirrors the toolchain
# file cargo-xwin used to generate).
set(CMAKE_SYSTEM_NAME Windows)
set(CMAKE_SYSTEM_PROCESSOR AMD64)
set(CMAKE_C_COMPILER "${CMAKE_CURRENT_LIST_DIR}/bin/clang-cl")
set(CMAKE_CXX_COMPILER "${CMAKE_CURRENT_LIST_DIR}/bin/clang-cl")
set(CMAKE_LINKER "${CMAKE_CURRENT_LIST_DIR}/bin/lld-link")
set(CMAKE_RC_COMPILER "${CMAKE_CURRENT_LIST_DIR}/bin/llvm-rc")
set(CMAKE_MT "${CMAKE_CURRENT_LIST_DIR}/bin/llvm-mt")
# The xwin splat carries release CRT import libs only (msvcrt.lib, no
# msvcrtd.lib — same as cargo-xwin). try_compile defaults to the Debug
# configuration, whose /MDd would demand the debug CRT; pin try_compile to
# Release and the runtime library to dynamic release /MD for every config
# (CMP0091 NEW makes CMAKE_MSVC_RUNTIME_LIBRARY authoritative even for
# projects with ancient cmake_minimum_required, e.g. bundled opus).
set(CMAKE_TRY_COMPILE_CONFIGURATION Release)
set(CMAKE_POLICY_DEFAULT_CMP0091 NEW)
set(CMAKE_MSVC_RUNTIME_LIBRARY MultiThreadedDLL)
"""
_BUILD = """\
# Generated by //bazel/toolchains/msvc:cc.bzl — hermetic clang-cl + lld-link +
# xwin CRT/SDK cc toolchain for x86_64-pc-windows-msvc. The toolchain() targets
# registering this live in //bazel/toolchains (one per supported exec host).
load("@rules_cc//cc/toolchains:cc_toolchain.bzl", "cc_toolchain")
load(":windows_cc_toolchain_config.bzl", "cc_toolchain_config")
package(default_visibility = ["//visibility:public"])
filegroup(name = "empty")
filegroup(
name = "wrappers",
srcs = glob(["bin/*"]) + ["toolchain.cmake"],
)
filegroup(
name = "all_files",
srcs = [
":wrappers",
"@llvm_msvc_tools//:all",
"@xwin_sysroot//:sysroot",
],
)
cc_toolchain_config(
name = "clang_cl_xwin_config",
abi_libc_version = "local",
abi_version = "local",
archiver_flags = ["/MACHINE:X64"],
compiler = "clang-cl",
cpu = "x64_windows",
dbg_mode_debug_flag = "/DEBUG",
default_link_flags = ["/MACHINE:X64"],
fastbuild_mode_debug_flag = "/DEBUG",
host_system_name = "local",
msvc_cl_path = "bin/clang-cl",
msvc_env_include = "{env_include}",
msvc_env_lib = "{env_lib}",
msvc_env_path = "/usr/bin:/bin",
msvc_env_tmp = "/tmp",
msvc_lib_path = "bin/llvm-lib",
msvc_link_path = "bin/lld-link",
msvc_ml_path = "bin/ml64.exe",
supports_parse_showincludes = False,
target_libc = "msvcrt",
target_system_name = "x86_64-pc-windows-msvc",
tool_paths = {{
"ar": "bin/llvm-lib",
"cpp": "bin/clang-cl",
"gcc": "bin/clang-cl",
"gcov": "bin/msvc-nop",
"ld": "bin/lld-link",
"ml": "bin/ml64.exe",
"nm": "bin/msvc-nop",
"objcopy": "bin/msvc-nop",
"objdump": "bin/msvc-nop",
"strip": "bin/msvc-nop",
}},
toolchain_identifier = "clang_cl_xwin_x64",
)
cc_toolchain(
name = "cc_toolchain",
all_files = ":all_files",
ar_files = ":all_files",
as_files = ":all_files",
compiler_files = ":all_files",
dwp_files = ":empty",
linker_files = ":all_files",
objcopy_files = ":empty",
strip_files = ":empty",
supports_param_files = 1,
toolchain_config = ":clang_cl_xwin_config",
toolchain_identifier = "clang_cl_xwin_x64",
)
"""
def _msvc_cc_impl(rctx):
llvm = rctx.attr.llvm_repo.repo_name
xwin = rctx.attr.xwin_repo.repo_name
splat = "external/{}/splat".format(xwin)
rctx.file("bin/clang-cl", _CLANG_CL_WRAPPER.format(llvm = llvm, xwin = xwin), executable = True)
rctx.file("bin/lld-link", _LLD_LINK_WRAPPER.format(llvm = llvm, xwin = xwin), executable = True)
for tool in ("llvm-lib", "llvm-rc", "llvm-mt"):
rctx.file("bin/" + tool, _PASSTHROUGH_WRAPPER.format(llvm = llvm, tool = tool), executable = True)
rctx.file("bin/msvc-nop", _NOP_WRAPPER, executable = True)
# cc-rs resolves the x64 MASM assembler as `ml64.exe` from PATH on
# non-windows hosts (blake3); ship both spellings of the shim.
for name in ("ml64.exe", "ml64"):
rctx.file("bin/" + name, _ML64_WRAPPER.format(llvm = llvm), executable = True)
# The MSVC feature/action-config machinery, verbatim from the resolved
# rules_cc (same mechanism @local_config_cc uses on real Windows hosts).
rctx.template("windows_cc_toolchain_config.bzl", rctx.attr._config_bzl, executable = False)
# CMake toolchain file for the cmake crate (no placeholders — it
# self-locates via CMAKE_CURRENT_LIST_DIR, so no .format here).
rctx.file("toolchain.cmake", _TOOLCHAIN_CMAKE, executable = False)
# INCLUDE/LIB for raw cc_* compile/link actions (cwd = execroot, so the
# execroot-relative entries resolve). The rust graph routes everything
# through the wrappers, which pass /imsvc and /libpath themselves.
env_include = ";".join([
splat + "/crt/include",
splat + "/sdk/include/ucrt",
splat + "/sdk/include/um",
splat + "/sdk/include/shared",
splat + "/sdk/include/winrt",
splat + "/sdk/include/cppwinrt",
])
env_lib = ";".join([
splat + "/crt/lib/x86_64",
splat + "/sdk/lib/um/x86_64",
splat + "/sdk/lib/ucrt/x86_64",
])
rctx.file(
"BUILD.bazel",
_BUILD.format(env_include = env_include, env_lib = env_lib),
executable = False,
)
msvc_cc_repository = repository_rule(
implementation = _msvc_cc_impl,
doc = "clang-cl/lld-link wrapper scripts + MSVC-flavored cc_toolchain for x86_64-pc-windows-msvc.",
attrs = {
"llvm_repo": attr.label(
default = "@llvm_msvc_tools//:BUILD.bazel",
doc = "Anchor into the pruned LLVM tools repo (canonical name source; not fetched here).",
),
"xwin_repo": attr.label(
default = "@xwin_sysroot//:BUILD.bazel",
doc = "Anchor into the xwin CRT/SDK sysroot repo (canonical name source; not fetched here).",
),
"_config_bzl": attr.label(
default = "@rules_cc//cc/private/toolchain:windows_cc_toolchain_config.bzl",
doc = "rules_cc's Windows cc_toolchain_config implementation, copied into this repo.",
),
},
)
+126
View File
@@ -0,0 +1,126 @@
"""Repository rule fetching the LLVM binaries used by the msvc cross toolchain.
Downloads the official LLVM release archive for the host that fetches the repo
(linux-x64 CI pods, darwin dev hosts) and prunes it down to the clang-cl /
lld-link / llvm-lib / llvm-rc slice plus the clang builtin headers
(lib/clang/<major>/include — immintrin.h & co, required for the SSE units in
bundled opus). The pruned tree is ~300 MiB instead of ~10 GiB.
The archive download (~1.5-2 GiB) goes through repository_ctx.download_and_extract
with a pinned sha256, so it lands in Bazel's content-addressed repository cache:
re-fetches after `bazel clean --expunge` or a .bzl edit only pay extraction.
Checksums are the official llvm-project release assets, cross-checked against
bazel-contrib/toolchains_llvm's distribution table.
"""
_LLVM_VERSION = "20.1.7"
# host key -> (release asset suffix, sha256)
_LLVM_DISTS = {
"linux-arm64": ("Linux-ARM64", "832f2802a29457dc758f56e26e98558c6cd0e45fcd07186f540cb6e7f4e59385"),
"linux-x64": ("Linux-X64", "8494c98a774051a40bfe1187a2d6442f4bc107598998bbe1673d9bb1572cfd6f"),
"macos-arm64": ("macOS-ARM64", "6aa75de00575ad0663183b00f00f39992ded611b5136e57649ace1e6a53c0d16"),
"macos-x64": ("macOS-X64", "ccf82ffe7e136ee49659cb57157856a7963d0950fac3d05aabba0db75bfba26f"),
}
# bin/ entries to keep. Symlink chains (clang-cl -> clang -> clang-20,
# llvm-lib -> llvm-ar, lld-link -> lld) are closed over at fetch time by
# resolving realpaths, so version-suffixed real binaries need no hardcoding.
_KEEP_BINS = [
"clang",
"clang-cl",
"lld",
"lld-link",
"llvm-ar",
"llvm-lib",
"llvm-ml",
"llvm-mt",
"llvm-rc",
]
def _host_key(rctx):
os_name = rctx.os.name.lower()
arch = rctx.os.arch.lower()
if os_name.startswith("linux"):
host_os = "linux"
elif os_name.startswith("mac") or os_name.startswith("darwin"):
host_os = "macos"
else:
fail("bazel/toolchains/msvc: unsupported exec host OS for the msvc cross toolchain: " + rctx.os.name)
if arch in ("amd64", "x86_64", "x64"):
host_cpu = "x64"
elif arch in ("aarch64", "arm64"):
host_cpu = "arm64"
else:
fail("bazel/toolchains/msvc: unsupported exec host CPU for the msvc cross toolchain: " + rctx.os.arch)
return host_os + "-" + host_cpu
_BUILD = """\
# Generated by //bazel/toolchains/msvc:llvm.bzl — pruned LLVM {version} for the
# msvc cross toolchain ({host} exec host). Consumed by @msvc_cc wrappers.
package(default_visibility = ["//visibility:public"])
filegroup(
name = "bin",
srcs = glob(["bin/*"]),
)
filegroup(
name = "builtin_headers",
srcs = glob(["lib/clang/*/include/**"]),
)
filegroup(
name = "all",
srcs = [
":bin",
":builtin_headers",
],
)
"""
def _llvm_msvc_tools_impl(rctx):
key = _host_key(rctx)
if key not in _LLVM_DISTS:
fail("bazel/toolchains/msvc: no pinned LLVM release archive for host " + key)
suffix, sha256 = _LLVM_DISTS[key]
prefix = "LLVM-{}-{}".format(_LLVM_VERSION, suffix)
rctx.report_progress("Downloading LLVM {} ({}, ~2 GiB, repository-cache backed)".format(_LLVM_VERSION, suffix))
rctx.download_and_extract(
url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-{}/{}.tar.xz".format(_LLVM_VERSION, prefix),
sha256 = sha256,
stripPrefix = prefix,
)
# Close the keep-set over symlink targets, then prune bin/.
keep = {name: None for name in _KEEP_BINS}
bin_dir = rctx.path("bin")
for name in _KEEP_BINS:
tool = bin_dir.get_child(name)
if tool.exists:
keep[tool.realpath.basename] = None
for entry in bin_dir.readdir():
if entry.basename not in keep:
rctx.delete(entry)
# Prune everything outside bin/ and lib/clang/<ver>/include.
for entry in rctx.path(".").readdir():
if entry.basename not in ("bin", "lib"):
rctx.delete(entry)
lib_dir = rctx.path("lib")
for entry in lib_dir.readdir():
if entry.basename != "clang":
rctx.delete(entry)
for verdir in lib_dir.get_child("clang").readdir():
for entry in verdir.readdir():
if entry.basename != "include":
rctx.delete(entry)
rctx.file("BUILD.bazel", _BUILD.format(version = _LLVM_VERSION, host = key), executable = False)
llvm_msvc_tools_repository = repository_rule(
implementation = _llvm_msvc_tools_impl,
doc = "Pruned LLVM release binaries (clang-cl/lld-link/llvm-lib/llvm-rc) for the exec host.",
)
+156
View File
@@ -0,0 +1,156 @@
"""Repository rule materializing the MSVC CRT + Windows SDK sysroot via xwin.
Downloads a pinned xwin release binary (github.com/Jake-Shadle/xwin) for the
host that fetches the repo and runs `xwin --accept-license splat`, producing:
splat/crt/include VC toolset headers
splat/crt/lib/x86_64 VC toolset libs (msvcrt.lib & co)
splat/sdk/include/{ucrt,um,shared,winrt,cppwinrt}
splat/sdk/lib/{ucrt,um}/x86_64
Cache implications: only the small xwin binary tarball goes through Bazel's
repository cache. The CRT/SDK payload (~1 GiB) is downloaded from the
Microsoft CDN by xwin itself inside this rule, so a cold fetch (clean
--expunge, sysroot.bzl edit, new output base) re-downloads it. The xwin
download cache is deleted after splatting to keep the repo at ~800 MiB.
Keep this file stable; wrapper/toolchain iteration lives in cc.bzl precisely
so it never invalidates this repo.
Reproducibility: --manifest-version pins the VS channel (17 = VS2022), but
Microsoft advances the channel's payload over time, so the splat is stable
day-to-day, not bit-reproducible forever — same property the cargo-xwin
pipeline had.
xwin release binaries stop shipping darwin builds after 0.6.5; 0.6.5 is the
newest version covering linux-musl + darwin hosts, which is why it is pinned.
"""
_XWIN_VERSION = "0.6.5"
_XWIN_MANIFEST_VERSION = "17"
# host key -> (release triple, sha256), from the published .sha256 assets.
_XWIN_DISTS = {
"linux-arm64": ("aarch64-unknown-linux-musl", "5e131007fad7c5f30d2f41090b49937fb8f16a787e5a95b4b3140e88d174dab2"),
"linux-x64": ("x86_64-unknown-linux-musl", "9fd53950b064d067f42428a69453b927656cae68dbd7f8d3f86dcb81c80dd22d"),
"macos-arm64": ("aarch64-apple-darwin", "21acd1e35d23b72efc8c47cbeda5028989f98089174b8c87074f892b65adbc01"),
"macos-x64": ("x86_64-apple-darwin", "ecb2b19b30fa3786749fae600ad60b034b0c1c6a604ecf9f35f682c23a40e54b"),
}
def _host_key(rctx):
os_name = rctx.os.name.lower()
arch = rctx.os.arch.lower()
if os_name.startswith("linux"):
host_os = "linux"
elif os_name.startswith("mac") or os_name.startswith("darwin"):
host_os = "macos"
else:
fail("bazel/toolchains/msvc: unsupported exec host OS for xwin: " + rctx.os.name)
if arch in ("amd64", "x86_64", "x64"):
host_cpu = "x64"
elif arch in ("aarch64", "arm64"):
host_cpu = "arm64"
else:
fail("bazel/toolchains/msvc: unsupported exec host CPU for xwin: " + rctx.os.arch)
return host_os + "-" + host_cpu
_BUILD = """\
# Generated by //bazel/toolchains/msvc:sysroot.bzl — MSVC CRT + Windows SDK
# splatted by xwin {version} (manifest-version {manifest}). Consumed by the
# @msvc_cc wrappers via /imsvc and /libpath.
package(default_visibility = ["//visibility:public"])
filegroup(
name = "crt_includes",
srcs = glob(["splat/crt/include/**"]),
)
filegroup(
name = "crt_libs",
srcs = glob(["splat/crt/lib/**"]),
)
filegroup(
name = "sdk_includes",
srcs = glob(["splat/sdk/include/**"]),
)
filegroup(
name = "sdk_libs",
srcs = glob(["splat/sdk/lib/**"]),
)
filegroup(
name = "sysroot",
srcs = [
":crt_includes",
":crt_libs",
":sdk_includes",
":sdk_libs",
],
)
"""
def _xwin_sysroot_impl(rctx):
key = _host_key(rctx)
if key not in _XWIN_DISTS:
fail("bazel/toolchains/msvc: no pinned xwin release binary for host " + key)
triple, sha256 = _XWIN_DISTS[key]
prefix = "xwin-{}-{}".format(_XWIN_VERSION, triple)
rctx.download_and_extract(
url = "https://github.com/Jake-Shadle/xwin/releases/download/{}/{}.tar.gz".format(_XWIN_VERSION, prefix),
sha256 = sha256,
stripPrefix = prefix,
)
rctx.report_progress("Splatting MSVC CRT + Windows SDK via xwin (first fetch ~1 GiB from the Microsoft CDN)")
result = rctx.execute(
[
rctx.path("xwin"),
"--accept-license",
"--arch",
"x86_64",
"--variant",
"desktop",
"--manifest-version",
_XWIN_MANIFEST_VERSION,
"--cache-dir",
".xwin-cache",
"splat",
"--copy",
"--output",
"splat",
],
timeout = 3600,
)
if result.return_code != 0:
fail("bazel/toolchains/msvc: xwin splat failed (exit {}):\n{}\n{}".format(
result.return_code,
result.stdout,
result.stderr,
))
# Drop the download cache (the splat is a --copy, not links into it).
rctx.delete(".xwin-cache")
# xwin drops `<sdk-version> -> .` alias symlinks (e.g. sdk/lib/10.0.26100)
# so version-qualified include/lib paths resolve. They are self-referential
# directory cycles, which Bazel's glob refuses to traverse — and nothing in
# this toolchain uses version-qualified paths, so drop them.
for dirname in ("splat/sdk/include", "splat/sdk/lib", "splat/crt/lib", "splat/crt/include"):
dirpath = rctx.path(dirname)
if not dirpath.exists:
continue
for entry in dirpath.readdir():
if entry.realpath == dirpath.realpath:
rctx.delete(entry)
rctx.file(
"BUILD.bazel",
_BUILD.format(version = _XWIN_VERSION, manifest = _XWIN_MANIFEST_VERSION),
executable = False,
)
xwin_sysroot_repository = repository_rule(
implementation = _xwin_sysroot_impl,
doc = "MSVC CRT + Windows SDK sysroot splatted by a pinned xwin release.",
)
+99
View File
@@ -0,0 +1,99 @@
# Rust target-triple config_settings for crate_universe's rendered selects
# (MODULE.bazel sets platforms_template = "@@//bazel/triples:{triple}").
#
# rules_rust's builtin @rules_rust//rust/platform settings can't express musl:
# gnu and musl triples share (os, cpu), so the libc axis rides on
# @zig_sdk//libc. The gnu settings match both the zig gnu.2.17 platforms and
# libc-unconstrained platforms (host builds, GH runners); musl requires the
# explicit constraint carried by //bazel/platforms:linux-musl-*.
load("@bazel_skylib//lib:selects.bzl", "selects")
package(default_visibility = ["//visibility:public"])
_LINUX_CPUS = {
"x86_64": "x86_64",
"aarch64": "aarch64",
}
[
config_setting(
name = "_linux-{}-libc-default".format(cpu),
constraint_values = [
"@platforms//os:linux",
"@platforms//cpu:" + cv,
"@zig_sdk//libc:unconstrained",
],
)
for cpu, cv in _LINUX_CPUS.items()
]
[
config_setting(
name = "_linux-{}-libc-gnu217".format(cpu),
constraint_values = [
"@platforms//os:linux",
"@platforms//cpu:" + cv,
"@zig_sdk//libc:gnu.2.17",
],
)
for cpu, cv in _LINUX_CPUS.items()
]
selects.config_setting_group(
name = "x86_64-unknown-linux-gnu",
match_any = [
":_linux-x86_64-libc-default",
":_linux-x86_64-libc-gnu217",
],
)
selects.config_setting_group(
name = "aarch64-unknown-linux-gnu",
match_any = [
":_linux-aarch64-libc-default",
":_linux-aarch64-libc-gnu217",
],
)
config_setting(
name = "x86_64-unknown-linux-musl",
constraint_values = [
"@platforms//os:linux",
"@platforms//cpu:x86_64",
"@zig_sdk//libc:musl",
],
)
config_setting(
name = "aarch64-unknown-linux-musl",
constraint_values = [
"@platforms//os:linux",
"@platforms//cpu:aarch64",
"@zig_sdk//libc:musl",
],
)
config_setting(
name = "x86_64-apple-darwin",
constraint_values = [
"@platforms//os:macos",
"@platforms//cpu:x86_64",
],
)
config_setting(
name = "aarch64-apple-darwin",
constraint_values = [
"@platforms//os:macos",
"@platforms//cpu:arm64",
],
)
config_setting(
name = "x86_64-pc-windows-msvc",
constraint_values = [
"@platforms//os:windows",
"@platforms//cpu:x86_64",
],
)
+26
View File
@@ -0,0 +1,26 @@
# x64 ISA variant axis for shipped addons: `baseline` (x86-64-v2) runs on any
# 2010+ CPU, `modern` (x86-64-v3) needs AVX2. Non-x64 targets use `default`.
# The constraint rides on //bazel/platforms:* and drives -Ctarget-cpu selects
# in //crates/pi-natives.
package(default_visibility = ["//visibility:public"])
constraint_setting(
name = "cpu_variant",
default_constraint_value = ":default",
)
constraint_value(
name = "default",
constraint_setting = ":cpu_variant",
)
constraint_value(
name = "baseline",
constraint_setting = ":cpu_variant",
)
constraint_value(
name = "modern",
constraint_setting = ":cpu_variant",
)