From 9009fc091ace0305f35f6cccd131a9093b463162 Mon Sep 17 00:00:00 2001 From: Aleksandr Sokolovskii Date: Mon, 12 Oct 2026 11:17:18 +0200 Subject: [PATCH 1/2] Use the prebuilt x64 protoc on Windows ARM64 and release 0.3.4. protobuf publishes no Windows ARM64 protoc, so on that exec platform the proto toolchain matched no prebuilt and Bazel compiled protoc, abseil, and upb from source. bazel_utils_buf now registers a toolchain for Windows ARM64 that uses protoc-36.2-win64.zip (Windows 11 on ARM emulates it), and protoc_prefix fails instead of staging a protoc compiled from source. The sha256 equals the protobuf module's own win64 pin and the zip was downloaded and checked against it. Cross-analysis with a Windows ARM64 exec platform selects the new toolchain; without it the from-source protoc is selected. Raised every module to 0.3.4. Co-Authored-By: Claude Sonnet 5.5 Signed-off-by: Aleksandr Sokolovskii --- CHANGELOG.md | 24 ++++++++++- CLAUDE.md | 27 +++++++------ MODULE.bazel | 23 +++++------ README.md | 59 +++++++++++++++++++--------- bazel/MODULE.bazel | 4 +- buf/BUILD.bazel | 11 ++++++ buf/MODULE.bazel | 23 +++++++++-- buf/protoc_prefix.bzl | 7 +++- buf/protoc_windows_arm64.BUILD.bazel | 8 ++++ core/MODULE.bazel | 2 +- go/MODULE.bazel | 4 +- markdown/MODULE.bazel | 4 +- protoc/MODULE.bazel | 4 +- python/MODULE.bazel | 4 +- rust/MODULE.bazel | 4 +- tests/buf/BUILD.bazel | 11 ++++++ 16 files changed, 159 insertions(+), 60 deletions(-) create mode 100644 buf/protoc_windows_arm64.BUILD.bazel diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c2fac3..2d93792 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,27 @@ patch; breaking Starlark API changes bump the minor. ## [Unreleased] +## [0.3.4] - 2026-10-12 + +### Fixed + +- `bazel_utils_buf`: on a Windows ARM64 exec platform the proto toolchain + matched no prebuilt `protoc` (protobuf publishes `win32` and `win64` only), + so Bazel fell back to `@protobuf//:protoc` and compiled protoc, abseil, and + upb from source. The module now registers a toolchain for Windows ARM64 + that uses the x64 `protoc-36.2-win64.zip` (the same release and sha256 as + the `protobuf` module's win64 pin; Windows 11 on ARM emulates it). +- `protoc_prefix` fails with a clear message when the resolved `protoc` is + compiled from source instead of staging it silently. + +### Added + +- `//tests/buf:protoc_prefix` builds `protoc_prefix` on every CI platform. + +### Changed + +- Raised every language module and the aggregator to `0.3.4` (lockstep). + ## [0.3.3] - 2026-10-12 ### Added @@ -377,7 +398,8 @@ Initial tagged release. Language modules for Bazel workspaces: Pin modules with `git_override` at tag `v0.1.0`. `bazel_utils_core` is a transitive dependency, not a consumer API. -[unreleased]: https://github.com/sonalect/bazel_utils/compare/v0.3.3...HEAD +[unreleased]: https://github.com/sonalect/bazel_utils/compare/v0.3.4...HEAD +[0.3.4]: https://github.com/sonalect/bazel_utils/compare/v0.3.3...v0.3.4 [0.3.3]: https://github.com/sonalect/bazel_utils/compare/v0.3.2...v0.3.3 [0.3.2]: https://github.com/sonalect/bazel_utils/compare/v0.3.1...v0.3.2 [0.3.1]: https://github.com/sonalect/bazel_utils/compare/v0.3.0...v0.3.1 diff --git a/CLAUDE.md b/CLAUDE.md index 7d7862a..13ba19b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -40,19 +40,20 @@ aggregator that pulls them in with `local_path_override`; consumers use Where pins live: -| Tool | File | -| -------------- | ------------------------------------------------------------------------------ | -| Buf CLI | `buf/registry.bzl` (+ fallback in `buf/MODULE.bazel`) | -| protoc plugins | `protoc/plugins//registry.bzl` (+ fallback pin in `protoc/MODULE.bazel`) | -| buildifier | `bazel/buildifier.MODULE.bazel` | -| golangci-lint | `go/golangci.MODULE.bazel` | -| govulncheck | `go/go.mod` | -| ruff | `python/ruff.MODULE.bazel` | -| uv | `python/uv.MODULE.bazel` | -| cargo-audit | `rust/cargo_audit.MODULE.bazel` | -| Node, pnpm | `markdown/MODULE.bazel` + `markdown/package.json` `packageManager` | -| busybox-w32 | `core/MODULE.bazel` | -| bazelisk (CI) | `.github/workflows/ci.yml` matrix | +| Tool | File | +| --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Buf CLI | `buf/registry.bzl` (+ fallback in `buf/MODULE.bazel`) | +| protoc plugins | `protoc/plugins//registry.bzl` (+ fallback pin in `protoc/MODULE.bazel`) | +| protoc (Windows ARM64 only) | `buf/MODULE.bazel` `protoc_windows_arm64`: the `win64` zip of the same release as the `protobuf` `bazel_dep`; sha256 from protobuf's `tool_integrity.bzl` | +| buildifier | `bazel/buildifier.MODULE.bazel` | +| golangci-lint | `go/golangci.MODULE.bazel` | +| govulncheck | `go/go.mod` | +| ruff | `python/ruff.MODULE.bazel` | +| uv | `python/uv.MODULE.bazel` | +| cargo-audit | `rust/cargo_audit.MODULE.bazel` | +| Node, pnpm | `markdown/MODULE.bazel` + `markdown/package.json` `packageManager` | +| busybox-w32 | `core/MODULE.bazel` | +| bazelisk (CI) | `.github/workflows/ci.yml` matrix | When a version is newer than a rule set's built-in catalog, pin it ourselves: Node uses `node_repositories` with the sha256s from `SHASUMS256.txt`, and pnpm diff --git a/MODULE.bazel b/MODULE.bazel index 52cdc68..4fe4f76 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -2,17 +2,18 @@ module( name = "bazel_utils", - version = "0.3.3", -) - -bazel_dep(name = "bazel_utils_bazel", version = "0.3.3") -bazel_dep(name = "bazel_utils_buf", version = "0.3.3") -bazel_dep(name = "bazel_utils_core", version = "0.3.3") -bazel_dep(name = "bazel_utils_go", version = "0.3.3") -bazel_dep(name = "bazel_utils_md", version = "0.3.3") -bazel_dep(name = "bazel_utils_protoc", version = "0.3.3") -bazel_dep(name = "bazel_utils_python", version = "0.3.3") -bazel_dep(name = "bazel_utils_rust", version = "0.3.3") + version = "0.3.4", +) + +bazel_dep(name = "bazel_utils_bazel", version = "0.3.4") +bazel_dep(name = "bazel_utils_buf", version = "0.3.4") +bazel_dep(name = "bazel_utils_core", version = "0.3.4") +bazel_dep(name = "bazel_utils_go", version = "0.3.4") +bazel_dep(name = "bazel_utils_md", version = "0.3.4") +bazel_dep(name = "bazel_utils_protoc", version = "0.3.4") +bazel_dep(name = "bazel_utils_python", version = "0.3.4") +bazel_dep(name = "bazel_utils_rust", version = "0.3.4") +bazel_dep(name = "protobuf", version = "36.2") local_path_override( module_name = "bazel_utils_bazel", diff --git a/README.md b/README.md index 136cdbf..25ae286 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Starlark helpers for Bazel workspaces. Each language is a **separate Bazel modul `bazel_utils_core` is pulled in transitively. The root module `bazel_utils` in this repository is an aggregator for development, not a consumer dependency. -Current module version: **0.3.3**. See [CHANGELOG.md](CHANGELOG.md) for release notes. +Current module version: **0.3.4**. See [CHANGELOG.md](CHANGELOG.md) for release notes. | Module | Load | Public API | | ------------------------------------------- | -------------------------------------- | ------------------------------------------------------------------------------------- | @@ -22,16 +22,16 @@ Pass `buildifier` / `golangci` / `govulncheck` / `buf` / `ruff` / `uv` / `cargo_ Windows needs no host bash (Git Bash, MSYS2) or Python. `bazel_utils_core` downloads [busybox-w32](https://frippery.org/busybox/) (amd64, arm64): the `*_test` and `*_format` wrappers run through a `.bat` launcher with `busybox sh`, and `buf_module` / `buf_generate` actions run with it too. Linux and macOS use the system bash. Prebuilt binaries have a `.exe` output on Windows. `markdownlint_test` on Windows needs `build:windows --enable_runfiles` (with `common --enable_platform_specific_config`): rules_js's `js_binary` needs a runfiles tree. `protoc.plugin` zip releases are extracted at build time with the hermetic bsdtar from [tar.bzl](https://registry.bazel.build/modules/tar.bzl); no host Python or unzip is used. -Modules live in subdirectories of [sonalect/bazel_utils](https://github.com/sonalect/bazel_utils.git). Pin each language module with `git_override` at tag `v0.3.3` and `strip_prefix` matching that directory. Language modules depend on `bazel_utils_core` (no public macros, not on the Bazel Central Registry), so add this once: +Modules live in subdirectories of [sonalect/bazel_utils](https://github.com/sonalect/bazel_utils.git). Pin each language module with `git_override` at tag `v0.3.4` and `strip_prefix` matching that directory. Language modules depend on `bazel_utils_core` (no public macros, not on the Bazel Central Registry), so add this once: ```starlark -bazel_dep(name = "bazel_utils_core", version = "0.3.3") +bazel_dep(name = "bazel_utils_core", version = "0.3.4") git_override( module_name = "bazel_utils_core", remote = "https://github.com/sonalect/bazel_utils.git", strip_prefix = "core", - tag = "v0.3.3", + tag = "v0.3.4", ) ``` @@ -45,13 +45,13 @@ Prebuilt [buildifier](https://github.com/bazelbuild/buildtools) (GitHub release, ```starlark # MODULE.bazel -bazel_dep(name = "bazel_utils_bazel", version = "0.3.3") +bazel_dep(name = "bazel_utils_bazel", version = "0.3.4") git_override( module_name = "bazel_utils_bazel", remote = "https://github.com/sonalect/bazel_utils.git", strip_prefix = "bazel", - tag = "v0.3.3", + tag = "v0.3.4", ) ``` @@ -128,13 +128,13 @@ The action sandbox does not inherit the user shell. Without this, buf runs anony ```starlark # MODULE.bazel -bazel_dep(name = "bazel_utils_buf", version = "0.3.3") +bazel_dep(name = "bazel_utils_buf", version = "0.3.4") git_override( module_name = "bazel_utils_buf", remote = "https://github.com/sonalect/bazel_utils.git", strip_prefix = "buf", - tag = "v0.3.3", + tag = "v0.3.4", ) buf = use_extension("@bazel_utils_buf//:extensions.bzl", "buf") @@ -281,6 +281,29 @@ plugins: out: rust/api/gen/my_thing ``` +### `protoc_prefix` + +Stages the **prebuilt** `protoc` of the resolved proto toolchain (`@protobuf//bazel/private:proto_toolchain_type`) with the well-known-type `.proto` files as a Unix-layout directory: `bin/protoc` and `include/google/protobuf/…`. Use it where a tool needs a `protoc` path, such as a Cargo `build.rs` (`PROTOC=$(execpath :protoc_prefix)/bin/protoc`). Never depend on `@protobuf//:protoc`: that target compiles protoc from source, and the rule fails if the toolchain resolves to such a build. + +protobuf publishes no Windows ARM64 `protoc`. `bazel_utils_buf` registers a toolchain for that exec platform that uses the x64 `protoc--win64.zip` of the same release as the `protobuf` module (Windows 11 on ARM emulates it), so Windows ARM64 never compiles protoc. + +| Name | Type | Required | Default | Description | +| ------ | ------------ | -------- | ------- | --------------------------------------------------------------- | +| `name` | `string` | yes | — | Target name; the output directory has the same name. | +| `wkts` | `label_list` | yes | — | `.proto` filegroups, e.g. `@protobuf//:well_known_type_protos`. | + +```starlark +load("@bazel_utils_buf//:protoc_prefix.bzl", "protoc_prefix") + +protoc_prefix( + name = "protoc_prefix", + wkts = [ + "@protobuf//:descriptor_proto_srcs", + "@protobuf//:well_known_type_protos", + ], +) +``` + ### `buf_lint_test` `bazel test`: `buf lint` on a staged `buf_module`. Fetches `buf.yaml` `deps` from the BSR. @@ -333,13 +356,13 @@ Canonical labels: `@bazel_utils_protoc//plugins/…`. [`bazel_utils_buf`](#bazel ```starlark # MODULE.bazel -bazel_dep(name = "bazel_utils_protoc", version = "0.3.3") +bazel_dep(name = "bazel_utils_protoc", version = "0.3.4") git_override( module_name = "bazel_utils_protoc", remote = "https://github.com/sonalect/bazel_utils.git", strip_prefix = "protoc", - tag = "v0.3.3", + tag = "v0.3.4", ) protoc = use_extension("@bazel_utils_protoc//:extensions.bzl", "protoc") @@ -416,13 +439,13 @@ Both tools run in the `manifest` (`go.mod`) directory, so `go.mod` may be below ```starlark # MODULE.bazel -bazel_dep(name = "bazel_utils_go", version = "0.3.3") +bazel_dep(name = "bazel_utils_go", version = "0.3.4") git_override( module_name = "bazel_utils_go", remote = "https://github.com/sonalect/bazel_utils.git", strip_prefix = "go", - tag = "v0.3.3", + tag = "v0.3.4", ) ``` @@ -490,13 +513,13 @@ Prebuilt [ruff](https://github.com/astral-sh/ruff) and [uv](https://github.com/a ```starlark # MODULE.bazel -bazel_dep(name = "bazel_utils_python", version = "0.3.3") +bazel_dep(name = "bazel_utils_python", version = "0.3.4") git_override( module_name = "bazel_utils_python", remote = "https://github.com/sonalect/bazel_utils.git", strip_prefix = "python", - tag = "v0.3.3", + tag = "v0.3.4", ) ``` @@ -580,13 +603,13 @@ Prebuilt [cargo-audit](https://github.com/rustsec/rustsec/tree/main/cargo-audit) ```starlark # MODULE.bazel -bazel_dep(name = "bazel_utils_rust", version = "0.3.3") +bazel_dep(name = "bazel_utils_rust", version = "0.3.4") git_override( module_name = "bazel_utils_rust", remote = "https://github.com/sonalect/bazel_utils.git", strip_prefix = "rust", - tag = "v0.3.3", + tag = "v0.3.4", ) ``` @@ -627,13 +650,13 @@ cargo_audit_test( ```starlark # MODULE.bazel -bazel_dep(name = "bazel_utils_md", version = "0.3.3") +bazel_dep(name = "bazel_utils_md", version = "0.3.4") git_override( module_name = "bazel_utils_md", remote = "https://github.com/sonalect/bazel_utils.git", strip_prefix = "markdown", - tag = "v0.3.3", + tag = "v0.3.4", ) ``` diff --git a/bazel/MODULE.bazel b/bazel/MODULE.bazel index 6bbc467..f5e3e11 100644 --- a/bazel/MODULE.bazel +++ b/bazel/MODULE.bazel @@ -2,10 +2,10 @@ module( name = "bazel_utils_bazel", - version = "0.3.3", + version = "0.3.4", ) bazel_dep(name = "bazel_skylib", version = "1.9.2") -bazel_dep(name = "bazel_utils_core", version = "0.3.3") +bazel_dep(name = "bazel_utils_core", version = "0.3.4") include("//:buildifier.MODULE.bazel") diff --git a/buf/BUILD.bazel b/buf/BUILD.bazel index 530745b..10364b0 100644 --- a/buf/BUILD.bazel +++ b/buf/BUILD.bazel @@ -3,6 +3,17 @@ load(":generate_path_test.bzl", "dep_import_path_test", "repo_rel_from_short_pat package(default_visibility = ["//visibility:public"]) +# The x64 protoc for a Windows ARM64 exec platform (see MODULE.bazel). +toolchain( + name = "protoc_windows_arm64_toolchain", + exec_compatible_with = [ + "@platforms//cpu:aarch64", + "@platforms//os:windows", + ], + toolchain = "@protoc_windows_arm64//:toolchain", + toolchain_type = "@protobuf//bazel/private:proto_toolchain_type", +) + bzl_library( name = "plugin_bzl", srcs = ["plugin.bzl"], diff --git a/buf/MODULE.bazel b/buf/MODULE.bazel index f054061..9b778ec 100644 --- a/buf/MODULE.bazel +++ b/buf/MODULE.bazel @@ -2,12 +2,12 @@ module( name = "bazel_utils_buf", - version = "0.3.3", + version = "0.3.4", ) bazel_dep(name = "bazel_skylib", version = "1.9.2") -bazel_dep(name = "bazel_utils_core", version = "0.3.3") -bazel_dep(name = "bazel_utils_protoc", version = "0.3.3") +bazel_dep(name = "bazel_utils_core", version = "0.3.4") +bazel_dep(name = "bazel_utils_protoc", version = "0.3.4") bazel_dep(name = "platforms", version = "1.1.0") bazel_dep(name = "protobuf", version = "36.2") @@ -20,3 +20,20 @@ use_repo(buf, "buf") # Root-module `protoc.plugin` labels for buf_generate PATH (`ROOT_PLUGIN_LABELS`). protoc = use_extension("@bazel_utils_protoc//:extensions.bzl", "protoc") use_repo(protoc, "protoc_root_plugins") + +# protobuf publishes no Windows ARM64 protoc, so its prebuilt toolchains match +# no Windows ARM64 exec platform and Bazel falls back to compiling protoc from +# source (a large C++ build). Windows 11 on ARM runs the x64 build, so register +# that one for this exec platform. Same release and sha256 as the protobuf +# module's own win64 pin (`bazel/private/oss/toolchains/prebuilt/ +# tool_integrity.bzl`); move it with the `protobuf` bazel_dep. +http_archive = use_repo_rule("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") + +http_archive( + name = "protoc_windows_arm64", + build_file = "//:protoc_windows_arm64.BUILD.bazel", + sha256 = "f0c128dc0d8492eceece83bb459a4c0e316764b929ffbf1aa416357fd644edd3", + url = "https://github.com/protocolbuffers/protobuf/releases/download/v36.2/protoc-36.2-win64.zip", +) + +register_toolchains("//:protoc_windows_arm64_toolchain") diff --git a/buf/protoc_prefix.bzl b/buf/protoc_prefix.bzl index ca10fed..8c0373d 100644 --- a/buf/protoc_prefix.bzl +++ b/buf/protoc_prefix.bzl @@ -3,7 +3,9 @@ Never depend on @protobuf//:protoc — that cc_binary compiles protoc from source. Protobuf 33.4+ registers a GitHub prebuilt on @protobuf//bazel/private:proto_toolchain_type when prefer_prebuilt_protoc is -true (the default). +true (the default). protobuf publishes no Windows ARM64 protoc; for that exec +platform this module registers the x64 build (`MODULE.bazel`), which Windows 11 +on ARM emulates. """ _PROTO_TOOLCHAIN_TYPE = "@protobuf//bazel/private:proto_toolchain_type" @@ -16,6 +18,9 @@ def _protoc_prefix_impl(ctx): protoc = compiler.executable if not protoc: fail("{}: proto toolchain has no proto_compiler".format(ctx.label)) + if not protoc.is_source: + fail(("{}: the proto toolchain resolved to a protoc compiled from source ({}). " + + "No prebuilt protoc matches this exec platform.").format(ctx.label, protoc.path)) out = ctx.actions.declare_directory(ctx.label.name) copies = [ diff --git a/buf/protoc_windows_arm64.BUILD.bazel b/buf/protoc_windows_arm64.BUILD.bazel new file mode 100644 index 0000000..c563393 --- /dev/null +++ b/buf/protoc_windows_arm64.BUILD.bazel @@ -0,0 +1,8 @@ +load("@protobuf//bazel/toolchains:proto_toolchain.bzl", "proto_toolchain") + +package(default_visibility = ["//visibility:public"]) + +proto_toolchain( + name = "toolchain", + proto_compiler = "bin/protoc.exe", +) diff --git a/core/MODULE.bazel b/core/MODULE.bazel index 42f7d06..5954799 100644 --- a/core/MODULE.bazel +++ b/core/MODULE.bazel @@ -2,7 +2,7 @@ module( name = "bazel_utils_core", - version = "0.3.3", + version = "0.3.4", ) bazel_dep(name = "bazel_lib", version = "3.7.2") diff --git a/go/MODULE.bazel b/go/MODULE.bazel index d3641ac..b7f0faa 100644 --- a/go/MODULE.bazel +++ b/go/MODULE.bazel @@ -2,11 +2,11 @@ module( name = "bazel_utils_go", - version = "0.3.3", + version = "0.3.4", ) bazel_dep(name = "bazel_skylib", version = "1.9.2") -bazel_dep(name = "bazel_utils_core", version = "0.3.3") +bazel_dep(name = "bazel_utils_core", version = "0.3.4") bazel_dep(name = "gazelle", version = "0.54.0") bazel_dep(name = "rules_go", version = "0.64.2") diff --git a/markdown/MODULE.bazel b/markdown/MODULE.bazel index abebb36..5d55e00 100644 --- a/markdown/MODULE.bazel +++ b/markdown/MODULE.bazel @@ -2,12 +2,12 @@ module( name = "bazel_utils_md", - version = "0.3.3", + version = "0.3.4", ) bazel_dep(name = "aspect_rules_js", version = "3.5.1") bazel_dep(name = "bazel_skylib", version = "1.9.2") -bazel_dep(name = "bazel_utils_core", version = "0.3.3") +bazel_dep(name = "bazel_utils_core", version = "0.3.4") bazel_dep(name = "rules_nodejs", version = "6.7.6") # Newer than rules_nodejs 6.7.6's catalog, so the sha256s come from diff --git a/protoc/MODULE.bazel b/protoc/MODULE.bazel index 3ac5a55..834dd8b 100644 --- a/protoc/MODULE.bazel +++ b/protoc/MODULE.bazel @@ -2,11 +2,11 @@ module( name = "bazel_utils_protoc", - version = "0.3.3", + version = "0.3.4", ) bazel_dep(name = "bazel_skylib", version = "1.9.2") -bazel_dep(name = "bazel_utils_core", version = "0.3.3") +bazel_dep(name = "bazel_utils_core", version = "0.3.4") # Hermetic bsdtar extracts zip releases (//plugins:unzip.bzl). bazel_dep(name = "tar.bzl", version = "0.10.9") diff --git a/python/MODULE.bazel b/python/MODULE.bazel index 7fac393..28a8c49 100644 --- a/python/MODULE.bazel +++ b/python/MODULE.bazel @@ -2,11 +2,11 @@ module( name = "bazel_utils_python", - version = "0.3.3", + version = "0.3.4", ) bazel_dep(name = "bazel_skylib", version = "1.9.2") -bazel_dep(name = "bazel_utils_core", version = "0.3.3") +bazel_dep(name = "bazel_utils_core", version = "0.3.4") include("//:ruff.MODULE.bazel") include("//:uv.MODULE.bazel") diff --git a/rust/MODULE.bazel b/rust/MODULE.bazel index 2d07a07..138638f 100644 --- a/rust/MODULE.bazel +++ b/rust/MODULE.bazel @@ -2,11 +2,11 @@ module( name = "bazel_utils_rust", - version = "0.3.3", + version = "0.3.4", ) bazel_dep(name = "bazel_skylib", version = "1.9.2") -bazel_dep(name = "bazel_utils_core", version = "0.3.3") +bazel_dep(name = "bazel_utils_core", version = "0.3.4") bazel_dep(name = "rules_rust", version = "0.74.0") include("//:cargo_audit.MODULE.bazel") diff --git a/tests/buf/BUILD.bazel b/tests/buf/BUILD.bazel index 36c1283..6994ad2 100644 --- a/tests/buf/BUILD.bazel +++ b/tests/buf/BUILD.bazel @@ -1,4 +1,5 @@ load("@bazel_utils_buf//:buf.bzl", "buf_format", "buf_generate", "buf_lint_test", "buf_module", "buf_plugin") +load("@bazel_utils_buf//:protoc_prefix.bzl", "protoc_prefix") load(":layout.bzl", "generate_layout_check") # Smoke tests for the buf rules and every prebuilt plugin on each CI platform. @@ -63,3 +64,13 @@ buf_format( name = "format", module = ":module", ) + +# The protoc of the proto toolchain must be a prebuilt one on every exec +# platform, Windows ARM64 included (protoc_prefix fails on a from-source protoc). +protoc_prefix( + name = "protoc_prefix", + wkts = [ + "@protobuf//:descriptor_proto_srcs", + "@protobuf//:well_known_type_protos", + ], +) From fdd851228dff1172ef6f6df18ca042c353a83be7 Mon Sep 17 00:00:00 2001 From: Aleksandr Sokolovskii Date: Mon, 12 Oct 2026 11:25:20 +0200 Subject: [PATCH 2/2] Stage protoc_prefix through run_shell_action so it works without a host bash. The Windows CI job runs without a host bash, and protoc_prefix used ctx.actions.run_shell, so //tests/buf:protoc_prefix failed there. The rule now takes SHELL_ACTION_ATTRS and runs the script with busybox on Windows, and stages bin/protoc.exe next to bin/protoc when the compiler is an .exe. Co-Authored-By: Claude Sonnet 5.5 Signed-off-by: Aleksandr Sokolovskii --- CHANGELOG.md | 4 ++++ buf/protoc_prefix.bzl | 11 +++++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d93792..465950a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,10 @@ patch; breaking Starlark API changes bump the minor. the `protobuf` module's win64 pin; Windows 11 on ARM emulates it). - `protoc_prefix` fails with a clear message when the resolved `protoc` is compiled from source instead of staging it silently. +- `protoc_prefix` staged the prefix with the host bash (`run_shell`), which + does not exist on a Windows runner without Git Bash. It now runs through + `run_shell_action`, like the other rules (busybox on Windows), and also + stages `bin/protoc.exe` next to `bin/protoc` when the compiler is an `.exe`. ### Added diff --git a/buf/protoc_prefix.bzl b/buf/protoc_prefix.bzl index 8c0373d..e473c5b 100644 --- a/buf/protoc_prefix.bzl +++ b/buf/protoc_prefix.bzl @@ -8,6 +8,8 @@ platform this module registers the x64 build (`MODULE.bazel`), which Windows 11 on ARM emulates. """ +load("@bazel_utils_core//internal:launcher.bzl", "SHELL_ACTION_ATTRS", "run_shell_action") + _PROTO_TOOLCHAIN_TYPE = "@protobuf//bazel/private:proto_toolchain_type" def _protoc_prefix_impl(ctx): @@ -27,17 +29,18 @@ def _protoc_prefix_impl(ctx): 'cp "{}" "$OUT/include/google/protobuf/{}"'.format(src.path, src.basename) for src in ctx.files.wkts ] - ctx.actions.run_shell( + run_shell_action( + ctx, outputs = [out], inputs = depset(direct = [protoc] + ctx.files.wkts), tools = [compiler], command = "\n".join([ - "set -euo pipefail", + "set -eu", 'OUT="{}"'.format(out.path), 'mkdir -p "$OUT/bin" "$OUT/include/google/protobuf"', 'cp "{}" "$OUT/bin/protoc"'.format(protoc.path), "chmod +x \"$OUT/bin/protoc\"", - ] + copies), + ] + (['cp "{}" "$OUT/bin/protoc.exe"'.format(protoc.path)] if protoc.extension == "exe" else []) + copies), mnemonic = "ProtocPrefix", progress_message = "Staging prebuilt protoc prefix %{label}", ) @@ -51,6 +54,6 @@ protoc_prefix = rule( mandatory = True, doc = "google.protobuf WKT .proto files (filegroups, not compiled C++).", ), - }, + } | SHELL_ACTION_ATTRS, toolchains = [_PROTO_TOOLCHAIN_TYPE], )