Skip to content

Conversation

@cgrindel
Copy link
Member

@cgrindel cgrindel commented Jan 2, 2026

Summary

  • Add support for installing prebuilt Ruby binaries from rv-ruby.
  • Add checksums attribute to ruby.toolchain() for platform-specific SHA256 verification
  • Add excluded_gems attribute to ruby.bundle_fetch() to skip downloading default gems bundled with Ruby

Usage

ruby.toolchain(
    name = "ruby",
    rv_checksums = {
        "linux-arm64": "0c08c35a99f10817643d548f98012268c5433ae25a737ab4d6751336108a941d",
        "linux-x86_64": "f36cef10365d370e0867f0c3ac36e457a26ab04f3cfbbd7edb227a18e6e9b3c3",
        "macos-arm64": "cd9d7a1428076bfcc6c2ca3c0eb69b8e671e9b48afb4c351fa4a84927841ffef",
        "macos-x86_64": "e9da39082d1dd8502d322c850924d929bc45b7a1e35da593a5606c00673218d4",
    },
    rv_version = "20251225",
    version_file = "//:.ruby-version",
)

ruby.bundle_fetch(
    name = "bundle",
    excluded_gems = ["psych"],  # Skip gems bundled with Ruby
    gemfile = "//:Gemfile",
    gemfile_lock = "//:Gemfile.lock",
)

Performance Comparison

To evaluate the performance benefits of this change, the following command was run from the examples/rails directory five times:

clear && bazel clean --expunge && time bazel test //...

The results were averaged and a percent diff was calcuated.

Description Run 1 Run 2 Run 3 Run 4 Run 5 Average Diff % Diff
main branch using MRI 0:01:53 0:01:50 0:01:47 0:01:45 0:01:49 0:01:49
rv-ruby 0:00:17 0:00:16 0:00:17 0:00:16 0:00:16 0:00:17 -0:01:32 -84.84%

Note

For each test case (i.e., row in the table), the first execution of the test command was discarded. The intention of the tests was to measure the performance with the repository cache and disk cache being populated.

Commentary

There are several wins by using rv-provided Ruby binaries vs building them using ruby build.

  • Eliminates the time to build Ruby.
  • The cachability of the Ruby binary in the repository cache. There is no download of the Ruby binary if you are using the repository cache.
  • The cachability of the Ruby targets in the build graph. When downloading Ruby from rv, any build/test actions that depend on the toolchain are valid on subsequent runs. In other words, rebuilding Ruby from source invalidates the build graph.

🤖 Generated with Claude Code

Related Slack thread.

Blocked by #281.

@cgrindel cgrindel self-assigned this Jan 2, 2026
@cgrindel cgrindel changed the base branch from main to main_perf January 2, 2026 20:56
@cgrindel cgrindel marked this pull request as ready for review January 2, 2026 21:47
@cgrindel cgrindel requested a review from p0deje January 2, 2026 21:47
Base automatically changed from main_perf to main January 3, 2026 03:54
Copy link
Member

@p0deje p0deje left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for working on this. It's amazing to finally see the precompiled Rubies land in rules_ruby. The code looks great to me overall, and I'll be happy to merge it as-is, especially since it's opt-in. I only have a few questions to clarify:

  1. How much effort would it take to make toolchains work for different platforms? E.g., make the same rb_download automatically download Ruby for the target platform. This would be handy in remote builds where the host can be macOS, while the target is Linux.
  2. Would it be possible to fetch all prebuilt Ruby checksums and put them in a file (like ruby/private/bundler_checksums.bzl)? This could be a first step to make prebuilt Rubies be used by default. We should, of course, keep rv_checksums and rv_version attributes for anyone who needed fresh/custom versions of Ruby.
  3. What happens when we try to install prebuilt gems (e.g., date) on prebuilt Ruby? Does it error?
  4. If we really should skip installing prebuilt gems, do you think we should create excluded_gems.bzl that keeps a map of Ruby version to prebuilt gems list? This can be automatically picked up by rb_bundle_fetch() so that users don't have to think twice about configuring the excluded_gems attribute.

cgrindel and others added 11 commits January 3, 2026 09:28
Add support for installing prebuilt Ruby binaries from the rv-ruby
project (https://github.com/spinel-coop/rv-ruby) using a version
prefix format `rv-{release}-{ruby_version}`.

New features:
- `checksums` attribute for `ruby.toolchain()` to specify platform
  SHA256 checksums for rv-ruby downloads
- `excluded_gems` attribute for `ruby.bundle_fetch()` to skip
  downloading default gems bundled with Ruby (e.g., psych)

The rv-ruby approach provides faster, more reliable builds by using
prebuilt portable Ruby binaries instead of compiling from source
via ruby-build.

Also updates the rails example to use rv-ruby and pins minitest to
5.x for Rails 8.0.x compatibility.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Refactor rv-ruby support to use a cleaner API that maintains
compatibility with standard Ruby version files.

Changes:
- Replace `rv-{release}-{version}` version prefix with separate
  `rv_version` attribute for the rv-ruby release date
- Rename `checksums` to `rv_checksums` for clarity
- Support reading Ruby version from `.ruby-version` file, which
  remains compatible with rbenv, RuboCop, StandardRB, etc.
- Add Windows fallback: prints warning and uses RubyInstaller
  when rv_version is set on Windows

New API:
```starlark
ruby.toolchain(
    name = "ruby",
    version_file = "//:.ruby-version",  # contains "3.4.8"
    rv_version = "20251225",
    rv_checksums = { ... },
)
```

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Replace uname -m command execution with Bazel's native repository_ctx.os.arch
for more reliable and portable architecture detection in rv-ruby installation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Remove redundant OS and architecture validation checks in favor of a single
validation point against _RV_RUBY_PLATFORMS. This eliminates duplicate logic
and provides comprehensive error messages showing detected platform, raw
values, and all supported platforms when validation fails.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Document the nested directory structure of rv-ruby releases to clarify
why stripPrefix is needed and make future maintenance easier if the
tarball structure changes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Unpack registration tuple in two steps to keep all lines under 80 characters,
improving readability and conforming to code style guidelines.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
Add comprehensive documentation for rv-ruby prebuilt binaries as a faster
alternative to compiling MRI from source. Includes:

- WORKSPACE and Bzlmod configuration examples
- Critical guidance on excluding default gems with C extensions
- Platform support notes and Windows fallback behavior
- Links to stdgems.org for finding default gems per Ruby version

Also applies code formatting improvements (italics, table alignment, list style).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <[email protected]>
@cgrindel
Copy link
Member Author

cgrindel commented Jan 3, 2026

  1. How much effort would it take to make toolchains work for different platforms? E.g., make the same rb_download automatically download Ruby for the target platform. This would be handy in remote builds where the host can be macOS, while the target is Linux.

How would the Linux Ruby binaries be used in this scenario?

  1. Would it be possible to fetch all prebuilt Ruby checksums and put them in a file (like ruby/private/bundler_checksums.bzl)? This could be a first step to make prebuilt Rubies be used by default. We should, of course, keep rv_checksums and rv_version attributes for anyone who needed fresh/custom versions of Ruby.

I considered this. That would require pinning rules_ruby to an rv-ruby release. It would be convenient for the out-of-the-box experience, but could be confusing when trying to upgrade to the latest and greatest.

One thought that I considered was to implement a utility that generates the checksums for you based upon the rv-ruby version provided. I did something similar for buildifier-prebuilt. We can add this as a follow-on, if there is interest.

  1. What happens when we try to install prebuilt gems (e.g., date) on prebuilt Ruby? Does it error?

I saw version mismatch errors and I saw compilation errors.

  1. If we really should skip installing prebuilt gems, do you think we should create excluded_gems.bzl that keeps a map of Ruby version to prebuilt gems list? This can be automatically picked up by rb_bundle_fetch() so that users don't have to think twice about configuring the excluded_gems attribute.

This is a similar issue as the checksums. Perhaps, we should create a utility that generates the declarations based upon the Ruby version.

@cgrindel cgrindel merged commit 867796e into main Jan 3, 2026
99 of 100 checks passed
@cgrindel cgrindel deleted the rv_ruby_support branch January 3, 2026 16:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants