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
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ See [toolshed/README.md](toolshed/README.md) for build instructions and

| tag | Python | GCC (native) | GCC (arm-none-eabi) | Clang (native) | Cmake | Host Platforms | Other Utilities |
|----------|--------|--------------|---------------------|----------------|-------|----------------|-----------------|
| [ts26.4.3](https://github.com/OpenCyphal/docker_toolchains/pkgs/container/toolshed) | 3.14 | 15.2.0 | 14.2.rel1 | 22.1.2 | 4.2.3 | <ul><li>linux/amd64</li><li>linux/arm64</li></ul> | <ul><li>Rust 1.93.1</li><li>Go 1.26</li><li>Node.js 22.22.1</li><li>TypeScript 5.2.2</li><li>Emscripten SDK 6.0.2</li><li>LLVM 22.1.2</li><li>MLIR 22.1.2</li><li>JLink V816</li><li>cppcheck</li><li>yakut</li><li>libpcap0.8-dev</li><li>network-tools</li><li>can-utils</li><li>doxygen 1.13.2</li><li>tox</li><li>nox</li><li>gcovr</li><li>lit</li><li>Dafny 4.11.0</li><li>.NET SDK 10.0</li><li>z3 4.13.3</li><li>Bazel 9.2.0 (bazelisk 1.29.0)</li><li>gcc-multilib (amd64 only)</li></ul> |
| [ts26.4.2](https://github.com/OpenCyphal/docker_toolchains/pkgs/container/toolshed) | 3.14 | 15.2.0 | 14.2.rel1 | 22.1.2 | 4.2.3 | <ul><li>linux/amd64</li><li>linux/arm64</li></ul> | <ul><li>Rust 1.93.1</li><li>Go 1.26</li><li>Node.js 22.22.1</li><li>TypeScript 5.2.2</li><li>Emscripten SDK 6.0.2</li><li>LLVM 22.1.2</li><li>MLIR 22.1.2</li><li>JLink V816</li><li>cppcheck</li><li>yakut</li><li>libpcap0.8-dev</li><li>network-tools</li><li>can-utils</li><li>doxygen 1.13.2</li><li>tox</li><li>nox</li><li>gcovr</li><li>lit</li><li>Dafny 4.11.0</li><li>.NET SDK 10.0</li><li>z3 4.13.3</li><li>gcc-multilib (amd64 only)</li></ul> |
| [ts26.4.1](https://github.com/OpenCyphal/docker_toolchains/pkgs/container/toolshed) | 3.14 | 15.2.0 | 14.2.rel1 | 22.1.2 | 4.2.3 | <ul><li>linux/amd64</li><li>linux/arm64</li></ul> | <ul><li>Rust 1.93.1</li><li>Go 1.26</li><li>Node.js 22.22.1</li><li>TypeScript 5.2.2</li><li>Emscripten SDK 6.0.2</li><li>LLVM 22.1.2</li><li>MLIR 22.1.2</li><li>JLink V816</li><li>cppcheck</li><li>yakut</li><li>libpcap0.8-dev</li><li>network-tools</li><li>can-utils</li><li>doxygen 1.13.2</li><li>tox</li><li>nox</li><li>gcovr</li><li>lit</li><li>gcc-multilib (amd64 only)</li></ul> |
| [ts24.4.3](https://github.com/OpenCyphal/docker_toolchains/pkgs/container/toolshed) | <ul><li>3.12</li><li>3.10</li></ul> | <ul><li>13.3.0</li><li>12.3.0</li><li>11.4.0</li><li>10.5.0</li><li>7.5.0</li></ul>| 13.3.1 | <ul><li>19.1.7</li><li>18.1.8</li></ul> | 3.31.5 | <ul><li>linux/amd64</li><li>linux/arm64</li></ul> | <ul><li>JLink V816</li><li>cppcheck-2.13</li><li>yakut 0.13.0</li><li>libpcap0.8-dev</li><li>network-tools</li><li>can-utils</li><li>doxygen 1.13.2</li><li>tox</li><li>nox</li><li>govr</li><li>gcc-multilib (amd64 only)</li></ul> |
Expand All @@ -48,7 +49,7 @@ You can use this in your workflow yaml like this:
jobs:
my-job:
runs-on: ubuntu-latest
container: ghcr.io/opencyphal/toolshed:ts26.4.2
container: ghcr.io/opencyphal/toolshed:ts26.4.3
```


Expand Down
52 changes: 52 additions & 0 deletions toolshed/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,58 @@
Per-release notes for the `ghcr.io/opencyphal/toolshed` image. The summary table of
every published tag lives in the [top-level README](../README.md#opencyphaltoolshedts).

## ts26.4.3

Adds:

- Bazel, via bazelisk 1.29.0, on both `linux/amd64` and `linux/arm64`
- Bazel 9.2.0, unpacked into the image rather than fetched on first use

`bazel` on `PATH` is bazelisk, not a Bazel release binary. Bazel's own apt
repository publishes `amd64` only while this image ships both architectures — the
same constraint that decided how Dafny is installed in ts26.4.2 — and bazelisk
publishes both. Installing the launcher rather than a fixed binary is also what
lets a project pin its own Bazel through `.bazelversion`.

`BAZELISK_HOME` is `/opt/bazelisk`, world-readable, rather than the default under
`$HOME`. The default is invisible to any other user the container runs as, which
CI routinely does; this is the trap `dotnet tool install --tool-path` avoids for
Dafny.

**`USE_BAZEL_VERSION` is deliberately not set.** It takes precedence over a
project's `.bazelversion` — measured, not assumed — so setting it here would
silently build every project with 9.2.0 whatever that project pinned. A project
that wants the pre-warmed toolchain writes `9.2.0` into its own `.bazelversion`,
which is where that decision belongs; a project pinning anything else downloads it
on first use.

### Bazel builds in this image are not offline

Worth stating plainly, because it is the first thing anyone reaching for Bazel
will assume otherwise.

Bazel's hermeticity guarantees cover action *execution* — sandboxed actions,
declared inputs, no leakage from the host. They have never covered the fetch
phase. Under bzlmod that phase is unavoidable: a module declaring **no**
dependencies at all still resolves `bazel_tools`' transitive deps
(`apple_support`, `protobuf`, `rules_java`, `rules_python`, `platforms`,
`rules_cc`, `bazel_skylib`, and more) from `bcr.bazel.build` before analysis
begins. `--noenable_bzlmod` does not escape it on Bazel 9.

None of the obvious mitigations move this, all measured against a cold cache:
a warmed `--repository_cache` holds archives rather than registry metadata; a
committed `MODULE.bazel.lock` records the resolution but still fetches the module
files; and `bazel vendor --vendor_dir` does not cover registry access either. What
does work is a warm per-user `$HOME/.cache/bazel`, which is no help to CI running
as an arbitrary uid.

A project that needs offline or air-gapped builds points Bazel at its own registry
mirror (`--registry=file:///...`) or vendors into its own workspace. Those are
per-project decisions — which modules you need is a function of your dependency
graph — so this image deliberately does not pin `--registry`, ship a partial
mirror that would go stale at every Bazel bump, or otherwise get in the way. It
supplies the toolchain; the dependency policy stays with the project.

## ts26.4.2

Adds:
Expand Down
79 changes: 78 additions & 1 deletion toolshed/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,83 @@ RUN printf 'method Smoke(x: int) requires x > 0 ensures x + 1 > 1 { }\n' > /tmp/
&& dafny verify /tmp/smoke.dfy \
&& rm /tmp/smoke.dfy

# +---------------------------------------------------------------------------+# LEAVE THE WORKDIR AS /repo
# +---------------------------------------------------------------------------+
# | INSTALL BAZEL
# +---------------------------------------------------------------------------+
# bazelisk rather than a Bazel release binary, and from GitHub rather than from
# apt. Bazel's own apt repository publishes amd64 only, and this image ships both
# architectures -- the same constraint that decided Dafny above. bazelisk
# publishes linux/amd64 and linux/arm64, so it is the one route that serves both.
#
# Installing bazelisk as `bazel` is also what lets a project pin its own Bazel:
# bazelisk reads .bazelversion from the workspace root and fetches that version.
FROM dafny AS bazel
WORKDIR /tmp
COPY cached-download.sh .

ARG BAZELISK_VERSION=1.29.0
# The version pre-warmed into the image below. A project pinning this one gets it
# without a download; any other version is fetched on first use.
ARG BAZEL_VERSION=9.2.0

# BAZELISK_HOME defaults to $HOME/.cache/bazelisk, which is invisible to any other
# user the container runs as -- and CI routinely runs as one. A shared path, made
# world-readable below, is what lets all of them use the pre-warmed Bazel. This is
# the same trap `dotnet tool install --tool-path` avoids for Dafny.
ENV BAZELISK_HOME=/opt/bazelisk

ARG BAZELISK_CHECKSUM_FILE=bazelisk-${BAZELISK_VERSION}-linux-${TARGETARCH}.sha256
COPY ${BAZELISK_CHECKSUM_FILE} .
RUN --mount=type=cache,target=/bazelisk-download \
./cached-download.sh \
--cache-target "/bazelisk-download" \
--download-url "https://github.com/bazelbuild/bazelisk/releases/download/v${BAZELISK_VERSION}/bazelisk-linux-${TARGETARCH}" \
--download-to-file "/bazelisk-download/bazelisk-linux-${TARGETARCH}" \
--checksums "/tmp/${BAZELISK_CHECKSUM_FILE}" \
--algorithm 256 \
&& install -m 0755 "/bazelisk-download/bazelisk-linux-${TARGETARCH}" /usr/local/bin/bazel

# Bazel itself is unpacked into BAZELISK_HOME here rather than on first use. The
# throwaway workspace is what makes that happen: bazelisk honours .bazelversion
# only at a workspace root, and with no workspace it resolves "latest" over the
# network instead.
#
# Deliberately NOT setting USE_BAZEL_VERSION. That variable takes precedence over
# a project's .bazelversion -- measured, not assumed -- so an image setting it
# would silently build every project with this version whatever the project
# pinned. A project that wants the pre-warmed Bazel commits `9.2.0` to its own
# .bazelversion, which is where that decision belongs.
RUN mkdir -p /tmp/bazel-warm \
&& cd /tmp/bazel-warm \
&& printf 'module(name = "warm", version = "0.0.1")\n' > MODULE.bazel \
&& touch BUILD.bazel \
&& echo "${BAZEL_VERSION}" > .bazelversion \
&& bazel --version \
&& bazel shutdown \
&& cd /tmp \
&& rm -rf /tmp/bazel-warm \
&& chmod -R a+rwX "${BAZELISK_HOME}" \
&& chmod 1777 "${BAZELISK_HOME}"

# Build something rather than just running --version. Launching proves bazelisk
# resolved a binary; building additionally proves that binary can execute an
# action and write an output, which is the part that silently goes missing.
#
# This step needs network, and so will any real Bazel build: Bazel resolves even
# its built-in module dependencies through the Bazel Central Registry, exactly as
# npm, cargo, and pip in this image fetch theirs. The image supplies the
# toolchain, not a hermetic dependency cache.
RUN mkdir -p /tmp/bazel-smoke \
&& cd /tmp/bazel-smoke \
&& printf 'module(name = "smoke", version = "0.0.1")\n' > MODULE.bazel \
&& printf 'genrule(name = "g", outs = ["o.txt"], cmd = "echo built > $@")\n' > BUILD.bazel \
&& echo "${BAZEL_VERSION}" > .bazelversion \
&& bazel build //:g \
&& grep -q built bazel-bin/o.txt \
&& bazel shutdown \
&& cd /tmp \
&& rm -rf /tmp/bazel-smoke

# +---------------------------------------------------------------------------+
# LEAVE THE WORKDIR AS /repo
WORKDIR /repo
1 change: 1 addition & 0 deletions toolshed/bazelisk-1.29.0-linux-amd64.sha256
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
5a408715e932c0250d28bd84555f12edbf70117de42f9181691c736eacc4a992 bazelisk-linux-amd64
1 change: 1 addition & 0 deletions toolshed/bazelisk-1.29.0-linux-arm64.sha256
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
e20e8b0f4f240091b7a55bf17b9398bd4f40ee70ae0208dff95dd4c445fb4010 bazelisk-linux-arm64