diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 868d9a5..ec2760b 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -40,7 +40,6 @@ jobs: platform: - x86_64-linux - aarch64-linux - - arm64-darwin steps: - uses: actions/checkout@v6 @@ -57,8 +56,77 @@ jobs: path: pkg/*.gem if-no-files-found: error + # arm64-darwin cannot use rb-sys-dock: BoringSSL cross-compilation fails because + # CMake picks up /usr/bin/ld (ELF) instead of the osxcross Mach-O linker. + # No upstream project (wreq, rnet, boring) cross-compiles BoringSSL for Darwin. + native-darwin: + name: Build native gem (arm64-darwin) + runs-on: macos-latest + steps: + - uses: actions/checkout@v6 + + - uses: dtolnay/rust-toolchain@stable + + - uses: Swatinem/rust-cache@v2 + with: + prefix-key: macos-arm64 + shared-key: release + + # Compile per-Ruby-version binaries (matching rb-sys-dock behavior on Linux). + # BoringSSL is compiled once and cached; only rb-sys/magnus rebuild per version. + - uses: ruby/setup-ruby@v1 + with: + ruby-version: "3.3" + bundler-cache: true + + - name: Compile for Ruby 3.3 + env: + RB_SYS_CARGO_PROFILE: release + run: | + cargo clean -p rb-sys -p magnus -p serde_magnus -p wreq-ruby --release 2>/dev/null || true + bundle exec rake compile + mkdir -p lib/wreq_ruby/3.3 + cp lib/wreq_ruby/wreq_ruby.bundle lib/wreq_ruby/3.3/ + + - uses: ruby/setup-ruby@v1 + with: + ruby-version: "3.4" + bundler-cache: true + + - name: Compile for Ruby 3.4 + env: + RB_SYS_CARGO_PROFILE: release + run: | + cargo clean -p rb-sys -p magnus -p serde_magnus -p wreq-ruby --release + bundle exec rake compile + mkdir -p lib/wreq_ruby/3.4 + cp lib/wreq_ruby/wreq_ruby.bundle lib/wreq_ruby/3.4/ + + - uses: ruby/setup-ruby@v1 + with: + ruby-version: "4.0" + bundler-cache: true + + - name: Compile for Ruby 4.0 + env: + RB_SYS_CARGO_PROFILE: release + run: | + cargo clean -p rb-sys -p magnus -p serde_magnus -p wreq-ruby --release + bundle exec rake compile + mkdir -p lib/wreq_ruby/4.0 + cp lib/wreq_ruby/wreq_ruby.bundle lib/wreq_ruby/4.0/ + + - name: Build platform gem + run: ruby script/build_platform_gem.rb arm64-darwin + + - uses: actions/upload-artifact@v4 + with: + name: native-gem-arm64-darwin + path: pkg/*arm64-darwin*.gem + if-no-files-found: error + smoke-test: - name: Smoke test (Ruby ${{ matrix.ruby }}) + name: Smoke test Linux (Ruby ${{ matrix.ruby }}) needs: [cross-compile] runs-on: ubuntu-latest strategy: @@ -81,9 +149,33 @@ jobs: - name: Verify gem loads and prints version run: ruby -rwreq -e "puts Wreq::VERSION" + smoke-test-darwin: + name: Smoke test macOS (Ruby ${{ matrix.ruby }}) + needs: [native-darwin] + runs-on: macos-latest + strategy: + fail-fast: false + matrix: + ruby: ["3.3", "3.4", "4.0"] + steps: + - uses: ruby/setup-ruby@v1 + with: + ruby-version: ${{ matrix.ruby }} + + - uses: actions/download-artifact@v4 + with: + name: native-gem-arm64-darwin + path: pkg/ + + - name: Install native gem + run: gem install pkg/wreq-*-arm64-darwin.gem + + - name: Verify gem loads and prints version + run: ruby -rwreq -e "puts Wreq::VERSION" + release: name: Release - needs: [source-gem, cross-compile, smoke-test] + needs: [source-gem, cross-compile, native-darwin, smoke-test, smoke-test-darwin] runs-on: ubuntu-latest if: startsWith(github.ref, 'refs/tags/v') permissions: @@ -102,7 +194,7 @@ jobs: - uses: actions/download-artifact@v4 with: path: pkg/ - pattern: "{cross-gem-*,source-gem}" + pattern: "{cross-gem-*,native-gem-*,source-gem}" merge-multiple: true - name: List gems diff --git a/Rakefile b/Rakefile index 8477cb2..e4e61eb 100644 --- a/Rakefile +++ b/Rakefile @@ -18,10 +18,10 @@ RbSys::ExtensionTask.new(CRATE_PACKAGE_NAME, GEMSPEC) do |ext| ext.ext_dir = "." ext.lib_dir = "lib/wreq_ruby" ext.cross_compile = true + # arm64-darwin is built natively on macOS (see .github/workflows/release.yml) ext.cross_platform = %w[ x86_64-linux aarch64-linux - arm64-darwin ] # Override Ruby version for native gems (keep in sync with wreq.gemspec) diff --git a/script/build_platform_gem.rb b/script/build_platform_gem.rb new file mode 100644 index 0000000..579d28f --- /dev/null +++ b/script/build_platform_gem.rb @@ -0,0 +1,34 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# Build a platform-specific gem with pre-compiled native extensions. +# +# Usage: ruby script/build_platform_gem.rb PLATFORM +# Example: ruby script/build_platform_gem.rb arm64-darwin +# +# Expects compiled .bundle/.so files in version-specific directories: +# lib/wreq_ruby/3.3/wreq_ruby.bundle +# lib/wreq_ruby/3.4/wreq_ruby.bundle +# lib/wreq_ruby/4.0/wreq_ruby.bundle + +require "rubygems/package" +require "fileutils" + +platform = ARGV.fetch(0) { abort "Usage: #{$0} PLATFORM" } + +spec = Gem::Specification.load("wreq.gemspec") +spec.platform = Gem::Platform.new(platform) +spec.extensions = [] +# Keep in sync with Rakefile cross_compiling block +spec.required_ruby_version = Gem::Requirement.new(">= 3.3", "< 4.1.dev") + +# Add version-specific compiled extensions +binaries = Dir.glob("lib/wreq_ruby/[0-9]*/*.{bundle,so}") +abort "No compiled binaries found in lib/wreq_ruby/*/. Did compilation succeed?" if binaries.empty? +spec.files += binaries + +FileUtils.mkdir_p("pkg") +gem_file = Gem::Package.build(spec) +FileUtils.mv(gem_file, "pkg/") + +puts "Built: pkg/#{File.basename(gem_file)}"