Repository navigation
Publish precompiled native gems on tag (x86_64-linux, aarch64-linux, arm64-darwin) - #109
Merged
Merged
Conversation
…arm64-darwin)
red-candle has only ever shipped a source ("ruby" platform) gem, so every
consumer compiles the full Candle/Rust extension at `bundle install` time:
rb_sys bootstraps rustup via `curl | sh` and builds from scratch on any cache
miss. This adds a tag-triggered release pipeline that publishes precompiled fat
gems so consumers install with no Rust toolchain.
- lib/candle.rb: load the extension from a Ruby-ABI-versioned subdir
(lib/candle/<minor>/candle.{so,bundle}) first, falling back to the flat path,
so a fat gem can carry one binary per Ruby version. require_spec updated to
assert the versioned-first-with-fallback form.
- candle.gemspec: RED_CANDLE_PLATFORM_GEM gate that, for the manually-assembled
darwin fat gem, sets the platform, clears spec.extensions (no recompile on
install) and packs the per-ABI bundles.
- .github/workflows/release.yml: on a version tag, build + push the source gem
plus x86_64-linux & aarch64-linux (oxidize-rb cross-gem; aarch64 native on
ubuntu-24.04-arm, no QEMU) and a native Metal+Accelerate arm64-darwin fat gem
(matrix compile on macos-26 -> merge). ABIs 3.1-4.0. Actions SHA-pinned latest.
- build.yml: bump deprecated actions/checkout@v3.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Allow X.Y.Z.preN / .rcN tags (RubyGems dot form) to drive the pipeline so the full tag -> rubygems.org flow can be exercised with e.g. 1.8.0.pre1 — which normal requirements (rx's `~> 1`, plain `gem install`) ignore. The prepare job now derives a prerelease flag (Gem::Version#prerelease?) and the GitHub Release is marked --prerelease accordingly. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
xrl
added a commit
that referenced
this pull request
Jun 18, 2026
End-to-end test of the precompiled-native-gem release pipeline (#109) all the way to rubygems.org. Prereleases are ignored by normal requirements (rx's `~> 1`, plain `gem install`), so this is non-disruptive. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
red-candlehas only ever published a source-only gem — all 30 versions (incl. 1.7.1) are platformruby. So every consumer compiles the full Candle/Rust extension atbundle install:rb_sysbootstraps a toolchain viacurl https://sh.rustup.rs | shand builds from scratch on any cache miss. That's slow, network-fragile, and an unpinnedcurl|shon the build path.This wires up the cross-compile scaffolding the
Rakefilealready declares (butrelease.ymlnever invoked) so a git tag publishes precompiled fat gems and consumers install with no Rust toolchain:red-candle-<v>.gem(ruby)ubuntu-24.04…-x86_64-linux.gemubuntu-24.04…-aarch64-linux.gemubuntu-24.04-arm…-arm64-darwin.gemmacos-26Each fat gem carries one binary per Ruby ABI: 3.1, 3.2, 3.3, 3.4, 4.0.
How it works
lib/candle.rb— loads the extension from the ABI-versioned subdir (lib/candle/<major.minor>/candle.{so,bundle}) first, falling back to the flat path. Without this, a fat gemLoadErrors.spec/require_spec.rbupdated (the existing substring guards still hold).candle.gemspec—RED_CANDLE_PLATFORM_GEMgate: for the manually-assembled darwin fat gem it sets the platform, clearsspec.extensions(else RubyGems recompiles on install) and packs the per-ABI bundles. The linux gems are assembled by rake-compiler/rb_sys, which clears extensions itself; the source gem path is unchanged.release.yml—on: push: tags:; apreparejob guards that the tag matchesversion.rb. Pushes are per-platform and idempotent so a darwin flake can't block the linux gems and the source gem always ships.Why
arm64-darwinis a native job (and a win, not a regression)A darwin gem cross-compiled from Linux is CPU-only (Metal frameworks can't link under osxcross) — that would silently strip Metal from Mac devs. Built natively on
macos-26,extconf.rbauto-enablesmetal+accelerate, and since candle 0.9.2 compiles its Metal shaders at runtime (newLibraryWithSource; nobuild.rs, nometallib), the build needs only base CLT — no Metal Toolchain download, no full-Xcode select. Metal/Accelerate are system frameworks, so the binary is portable across Apple Silicon Macs (unlike CUDA, which pins a driver). We publish the genericarm64-darwinplatform because RubyGems doesn't fall back across darwin majors. CI has no GPU, so the release gate is anotool -Llink check, not a runtime Metal test.Versions
All actions SHA-pinned to current latest (June 2026):
checkoutv6.0.3,upload-artifactv7.0.1,download-artifactv8.0.1,setup-rubyv1.313.0,oxidize-rb/actions/*v1.4.4. Ruststable(1.96). Also bumpsbuild.ymloff the deprecatedcheckout@v3.Release procedure
The tag (not CI) drives it — a CI-created tag wouldn't re-trigger:
Verification
Local:
ruby -c, gemspec evaluates correctly in both modes (platform=ruby/extensions set vsplatform=arm64-darwin/extensions cleared + bundles packed),require_specassertions pass, both workflowsactionlint-clean. The cross-compile feasibility, gem size (~17 MB stripped/ABI, far under the ~500 MB cap), and Metal build-vs-runtime questions were each verified with adversarial review; the heavy aarch64/darwin compiles themselves are first exercised by this workflow on the first tagged release.Follow-ups (not in this PR)
rx: bump red-candle to the first tag built here, thenbundle lock --add-platform aarch64-linux(theCandle::RerankerAPI is byte-identical 1.2.2→1.7.x).benchmateoff its git-fork pin.🤖 Generated with Claude Code