From 0837a06e998500f89447379e37cb59ed924e58c9 Mon Sep 17 00:00:00 2001 From: Edouard CHIN Date: Wed, 3 Dec 2025 22:52:54 +0100 Subject: [PATCH] Allow to ship this gem with precompiled binaries TL;DR I'd like to propose releasing the json gem with precompiled binaries built for different platforms and different ABI version (fat gem). I'm currently working on a tool to help the Ruby community ship gems with precompiled binaries with the intent to make `bundle install` much faster for everyone. The main bottleneck when installing gems in a project is the compilation of native extensions. [cibuildgem](https://github.com/Shopify/cibuildgem) modestly tries to follow the same approach as what the python community did with [cibuildwheel](https://cibuildwheel.pypa.io/en/stable/). It works with a native compilation using CI runners (GitHub it the only supported vendor for now) and tries to be as easy to setup as possible. This gem already relies on Rake Compiler for development purposes, and because cibuildgem piggyback on top of Rake Compiler, there is no extra configuration required. The CI workflow in this commit was generated with the cibuildgem CLI which reads the gemspec and determine what ruby versions needs to be compiled and tested agains. The tool is very new and I did many tests internally to make sure that it create binaries that can be ported to other environment. For instance, I used it to precompile almost all gems that a new Rails application depends on and pushed them under a "namespaced" name on my [RubyGems](https://rubygems.org/profiles/edouardchin), I then confirmed that the rails application was bootable using all those gems (I'm on MacOS). --- .github/workflows/cibuildgem.yaml | 86 +++++++++++++++++++++++++++++++ lib/stack_frames.rb | 8 ++- 2 files changed, 93 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/cibuildgem.yaml diff --git a/.github/workflows/cibuildgem.yaml b/.github/workflows/cibuildgem.yaml new file mode 100644 index 0000000..562d17d --- /dev/null +++ b/.github/workflows/cibuildgem.yaml @@ -0,0 +1,86 @@ +name: "Package and release gems with precompiled binaries" +on: + workflow_dispatch: + inputs: + release: + description: "If the whole build passes on all platforms, release the gems on RubyGems.org" + required: false + type: boolean + default: false +jobs: + compile: + timeout-minutes: 20 + name: "Cross compile the gem on different ruby versions" + strategy: + matrix: + os: ["macos-latest", "ubuntu-22.04"] + runs-on: "${{ matrix.os }}" + steps: + - name: "Checkout code" + uses: "actions/checkout@v5" + - name: "Setup Ruby" + uses: "ruby/setup-ruby@v1" + with: + ruby-version: "3.1.7" + bundler-cache: true + - name: "Run cibuildgem" + uses: "shopify/cibuildgem/.github/actions/cibuildgem@main" + with: + step: "compile" + test: + timeout-minutes: 20 + name: "Run the test suite" + needs: compile + strategy: + matrix: + os: ["macos-latest", "ubuntu-22.04"] + rubies: ["3.1", "3.2", "3.3", "3.4"] + type: ["cross", "native"] + runs-on: "${{ matrix.os }}" + steps: + - name: "Checkout code" + uses: "actions/checkout@v5" + - name: "Setup Ruby" + uses: "ruby/setup-ruby@v1" + with: + ruby-version: "${{ matrix.rubies }}" + bundler-cache: true + - name: "Run cibuildgem" + uses: "shopify/cibuildgem/.github/actions/cibuildgem@main" + with: + step: "test_${{ matrix.type }}" + install: + timeout-minutes: 5 + name: "Verify the gem can be installed" + needs: test + strategy: + matrix: + os: ["macos-latest", "ubuntu-22.04"] + runs-on: "${{ matrix.os }}" + steps: + - name: "Setup Ruby" + uses: "ruby/setup-ruby@v1" + with: + ruby-version: "3.4.7" + - name: "Run cibuildgem" + uses: "shopify/cibuildgem/.github/actions/cibuildgem@main" + with: + step: "install" + release: + permissions: + id-token: write + contents: read + timeout-minutes: 5 + if: ${{ inputs.release }} + name: "Release all gems with RubyGems" + needs: install + runs-on: "ubuntu-latest" + steps: + - name: "Setup Ruby" + uses: "ruby/setup-ruby@v1" + with: + ruby-version: "3.4.7" + - name: "Run cibuildgem" + uses: "shopify/cibuildgem/.github/actions/cibuildgem@main" + with: + step: "release" diff --git a/lib/stack_frames.rb b/lib/stack_frames.rb index 068bf9b..f653bbc 100644 --- a/lib/stack_frames.rb +++ b/lib/stack_frames.rb @@ -1,7 +1,13 @@ # frozen_string_literal: true require 'stack_frames/version' -require 'stack_frames/stack_frames' + +begin + ruby_version = /(\d+\.\d+)/.match(RUBY_VERSION) + require "stack_frames/#{ruby_version}/stack_frames" +rescue LoadError + require "stack_frames/stack_frames" +end StackFrames::Frame.singleton_class.class_eval do private(:new)