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
68 changes: 65 additions & 3 deletions .github/actions/rust-setup/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,12 @@ description: >-

inputs:
toolchain:
description: "Rust toolchain (e.g. stable, 1.86.0)."
default: stable
description: >-
Rust toolchain to install. Leave empty (the default) to use the channel
from `rust-toolchain.toml`, which is the single source of truth for the
project toolchain — set it there, not here. Only pass a value to install
something deliberately different from the project pin.
default: ""
targets:
description: "Comma-separated extra rustup targets (e.g. wasm32-unknown-unknown)."
default: ""
Expand Down Expand Up @@ -37,6 +41,64 @@ inputs:
runs:
using: composite
steps:
# Resolve the toolchain from `rust-toolchain.toml` unless the caller asked
# for a specific one. This keeps ONE version literal in the repo: bumping
# the project toolchain is a single edit to `rust-toolchain.toml` and every
# workflow follows, with no chance of a call site drifting behind.
#
# This used to default to `stable`, which was misleading rather than wrong:
# `rust-toolchain.toml` is a directory override and outranks the `rustup
# default` this action performs, so every job was ALREADY compiling on the
# pinned channel (rustup logs "toolchain '<channel>' is currently in use
# (overridden by .../rust-toolchain.toml)"). The only effect of the
# `stable` default was to download a second toolchain that nothing then
# used — and to make the workflows read as though they tested on latest
# stable, which they never did.
#
# Extraction is scoped to the `[toolchain]` TABLE, not "the first `channel`
# key in the file". A bare `channel = ...` match would take the wrong value
# if any other table ever gained a `channel` key ahead of `[toolchain]` —
# silently installing whatever that said, which is exactly the kind of
# guess the fail-closed design exists to prevent.
#
# Only TOML basic (double-quoted) strings are accepted. A literal
# single-quoted channel is valid TOML but is not used here, and failing
# loudly on one beats guessing at its value.
#
# Fail-closed: an unparseable `rust-toolchain.toml` aborts the job rather
# than silently falling back to some other channel.
- name: Resolve Rust toolchain
id: resolve
shell: bash
env:
REQUESTED: ${{ inputs.toolchain }}
run: |
set -euo pipefail
if [ -n "$REQUESTED" ]; then
resolved="$REQUESTED"
echo "Toolchain requested explicitly by the caller: ${resolved}"
else
resolved="$(awk '
/^[[:space:]]*\[/ {
in_toolchain = /^[[:space:]]*\[toolchain\][[:space:]]*$/
next
}
in_toolchain && match($0, /^[[:space:]]*channel[[:space:]]*=[[:space:]]*"[^"]*"/) {
v = substr($0, RSTART, RLENGTH)
sub(/^[^"]*"/, "", v)
sub(/"$/, "", v)
print v
exit
}
' rust-toolchain.toml)"
if [ -z "$resolved" ]; then
echo "::error::Could not parse [toolchain].channel (as a double-quoted string) from rust-toolchain.toml"
exit 1
fi
echo "Toolchain resolved from rust-toolchain.toml: ${resolved}"
fi
echo "toolchain=${resolved}" >> "$GITHUB_OUTPUT"

# Pinned to a commit SHA, not `@master`. Every other action in this repo is
# referenced by a `@vN` tag, which is not expected to move; `@master` is a
# BRANCH that advances on every upstream commit, so each run silently
Expand All @@ -55,7 +117,7 @@ runs:
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@e97e2d8cc328f1b50210efc529dca0028893a2d9 # v1
with:
toolchain: ${{ inputs.toolchain }}
toolchain: ${{ steps.resolve.outputs.toolchain }}
targets: ${{ inputs.targets }}
components: ${{ inputs.components }}

Expand Down
12 changes: 3 additions & 9 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,6 @@ jobs:
persist-credentials: false
- uses: ./.github/actions/rust-setup
with:
toolchain: 1.96.0
components: rustfmt,clippy
- name: rustfmt
run: cargo fmt --all -- --check
Expand Down Expand Up @@ -367,16 +366,11 @@ jobs:
- uses: actions/checkout@v7
with:
persist-credentials: false
# Pinned to the project toolchain like the `lint` job, rather than the
# action's `stable` default. Not a correctness fix — `rust-toolchain.toml`
# already wins over the action's `rustup default stable` (rustup logs
# "toolchain '1.96.0' is currently in use (overridden by
# .../rust-toolchain.toml)"), so this job was always building on 1.96.0.
# It avoids installing a `stable` toolchain that nothing then uses, and
# makes the toolchain this job rehearses explicit at the call site.
# No `toolchain:` input anywhere in this repo: `rust-setup` resolves it
# from `rust-toolchain.toml`, so this job rehearses the buildbot on the
# exact channel the buildbot uses.
- uses: ./.github/actions/rust-setup
with:
toolchain: 1.96.0
apt: "false"
cache-key: libretro-${{ matrix.target }}
# Point bindgen at the NDK sysroot, which is what `cargo ndk` does for us
Expand Down
2 changes: 0 additions & 2 deletions .github/workflows/pgo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ jobs:
# full `rustynes-frontend` binary).
- uses: ./.github/actions/rust-setup
with:
toolchain: 1.96.0
components: llvm-tools-preview
cache-key: pgo

Expand Down Expand Up @@ -199,7 +198,6 @@ jobs:
persist-credentials: false
- uses: ./.github/actions/rust-setup
with:
toolchain: 1.96.0
components: llvm-tools-preview
cache-key: pgo-bolt
- name: Install cargo-pgo
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ jobs:
persist-credentials: false
- uses: ./.github/actions/rust-setup
with:
toolchain: 1.96.0
components: clippy
cache-key: security-clippy
# The main CI `lint` job already runs `clippy -D warnings` on the DEFAULT
Expand Down
87 changes: 47 additions & 40 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -191,55 +191,62 @@ libretro-build-ios-arm64:

# tvOS
#
# The tvOS template overrides `script` with
# `cargo +nightly build -Zbuild-std --target aarch64-apple-tvos --release`
# (aarch64-apple-tvos needs build-std). That explicit `+nightly` outranks
# BOTH `rust-toolchain.toml` and `RUSTUP_TOOLCHAIN`, so this is the one job
# that does not run on our pinned 1.96.0 — and the image's pre-installed
# nightly is 1.94.0-nightly, which trips cargo's MSRV gate against the
# workspace's `rust-version = "1.96"` before compilation even starts:
# Unlike the other three Apple jobs, the upstream tvOS template also overrides
# `script`, replacing the shared Apple build line with
#
# error: rustc 1.94.0-nightly is not supported by the following packages:
# rustynes-core@2.2.1 requires rustc 1.96 (+ apu/cpu/libretro/mappers/ppu)
# cargo +nightly build -Zbuild-std --target aarch64-apple-tvos --release
#
# Refreshing the nightly channel is the surgical fix. Lowering `rust-version`
# on those six crates would also silence it, but `.cargo/config.toml` sets
# `[resolver] incompatible-rust-versions = "fallback"`, which keys off the
# LOWEST workspace-member MSRV — so that route risks silently downgrading
# dependencies workspace-wide on the next `cargo update`. Not worth it for
# one job.
# That dates from when `aarch64-apple-tvos` was a tier-3 target with no
# distributed `rust-std`, making `-Zbuild-std` — and therefore nightly — the
# only way to build it. The target has since been promoted and rustup now
# ships a complete prebuilt std for it, `panic_abort` included, so the
# override is obsolete. Verified against the pinned 1.96.0:
# `rustup target add aarch64-apple-tvos` installs 26 rlibs (`panic_abort`
# among them) and `cargo check --release -p rustynes-libretro --target
# aarch64-apple-tvos` compiles the entire graph, bindgen included.
#
# Uninstall-then-install rather than `rustup update nightly`: a stale extra
# component carried by the image's nightly may not be published for the new
# nightly date, which aborts an in-place update. `rust-src` is required by
# `-Zbuild-std`. The container is ephemeral, so this is job-local.
# Restoring the shared script puts tvOS on the same pinned 1.96.0 as every
# other job, and dissolves three separate workarounds this job used to need
# rather than accumulating a fourth:
#
# Refreshing the nightly then exposes a SECOND tvOS-only blocker. A bare
# `-Zbuild-std` builds `std` but NOT `panic_abort`, and this workspace sets
# `[profile.release] panic = "abort"`, so linking the cdylib fails with
# `E0463: can't find crate for panic_abort`. The usual fix is
# `-Zbuild-std=std,panic_abort` — but the flag is hardcoded in the template's
# `script`, and `CARGO_UNSTABLE_BUILD_STD` does NOT help (verified: the CLI
# `-Z` flag wins over the config/env form, so the crate list stays the
# default). Overriding the profile's panic strategy for this job is the
# remaining lever, and it uses the same `CARGO_PROFILE_RELEASE_*` mechanism
# the template itself already uses for `CARGO_PROFILE_RELEASE_DEBUG`.
# 1. MSRV. `+nightly` outranks BOTH `rust-toolchain.toml` and
# `RUSTUP_TOOLCHAIN`, pinning the job to the image's stale
# 1.94.0-nightly — below the workspace's `rust-version = "1.96"`, so
# cargo's MSRV gate failed before compiling anything. The job had to
# uninstall and reinstall the nightly channel to get past it.
# 2. `panic_abort`. A bare `-Zbuild-std` builds `std` but NOT
# `panic_abort`, which `[profile.release] panic = "abort"` requires, so
# the cdylib failed to link with `E0463`. The crate list is hardcoded in
# the template and `CARGO_UNSTABLE_BUILD_STD` cannot override it (the
# CLI `-Z` flag wins), so the job had to force `panic = "unwind"` via
# `CARGO_PROFILE_RELEASE_PANIC`. The prebuilt std ships `panic_abort`,
# so the profile is now honoured as written and tvOS matches every
# other platform.
# 3. `-C ar`. Refreshing to a current nightly then failed with
# `error: `-C ar`: this option has been removed`. The build image
# injects `-Car=<path>,Clink-arg=...` into every Apple job, and that
# long-deprecated no-op became a hard error in Rust 1.97 (bisected:
# 1.96.1 warns, 1.97.1 errors). On the pinned 1.96.0 it is still only a
# warning — exactly as it already was for the three Apple jobs that
# were green throughout.
#
# `unwind` is safe here: since Rust 1.81 a panic that reaches an `extern "C"`
# boundary aborts rather than unwinding into C frames, so a libretro core
# behaves the same on a panic either way — this costs only slightly larger
# code and unwind tables, on tvOS alone. Every other platform keeps
# `panic = "abort"` untouched.
# `!reference [.libretro-rust-apple-base, script]` pulls in the generic Apple
# build/package steps instead of duplicating them here, so upstream fixes to
# that script keep reaching this job. It drives off `TARGET_ARCH`, which the
# tvOS template already sets to `aarch64-apple-tvos`, and honours the same
# `STRIP_CORE_LIB` / `DSYM_CORE_LIB` flags the template sets.
#
# GitLab concatenates `before_script` and `script` into ONE shell invocation
# (that is how the template's own `export SDKROOT=...` reaches its cargo
# call), so exporting here does reach the build.
# NOTE: `-C ar` is still a latent hazard for ALL FOUR Apple jobs, now
# including this one. Read `rust-toolchain.toml` before bumping `channel` to
# 1.97 or newer.
libretro-build-tvos-arm64:
extends:
- .libretro-rust-tvos-arm64-default
- .core-defs
variables:
RUST_TARGET: aarch64-apple-tvos
before_script:
- !reference [.libretro-rust-tvos-arm64-default, before_script]
- rustup toolchain uninstall nightly || true
- rustup toolchain install nightly --profile minimal --component rust-src
- export CARGO_PROFILE_RELEASE_PANIC=unwind
- rustup target add ${RUST_TARGET}
script:
- !reference [.libretro-rust-apple-base, script]
Loading