Skip to content

Commit ac57eed

Browse files
authored
Add Linux and macOS Compatibility to OCRAN
- Add Linux support: build and run self-extracting ELF executables on Linux. The stub compiles and runs natively on Linux using POSIX APIs. - Add macOS support: build and run self-extracting Mach-O executables on macOS. - Add `--output-dir` option: output all files to a directory with a platform-appropriate launch script (`.sh` on Linux/macOS, `.bat` on Windows) instead of a single executable. - Add `--output-zip` option: same as `--output-dir` but packages the result into a zip archive. - Add `--macosx-bundle` option: wrap the macOS executable in a `.app` bundle with a generated `Info.plist`, suitable for Finder, the Dock, and Authenticode-style code signing with `codesign` and `xcrun notarytool`. Use `--bundle-id` to set `CFBundleIdentifier` and `--icon` (`.icns`) to set the bundle icon. - Use symlinks for shared library aliases on POSIX (e.g. `libruby.so → libruby.so.4.0`) instead of copying files, matching the layout Ruby expects at runtime. - Fix crash on cleanup when a symlink target does not exist: `DeleteRecursively` now uses `lstat` instead of `stat` so dangling symlinks are removed correctly. - Publish platform-specific gems for Linux, macOS (ARM and Intel), and Windows so `gem install ocran` selects the right pre-built stub automatically. - Publish a source gem (`ruby` platform) with `ext/extconf.rb` so users on unlisted platforms can install by compiling the stub from source. Falls back to plain `make` if `ridk exec make` is unavailable on Windows. - CI: add GitHub Actions workflow to build and publish per-platform gems on tag push. - CI: run the packed Linux executable inside a Debian Docker container to verify cross-distro portability (no Ruby required on target). - CI: test against Ruby 3.2, 3.3, 3.4, and 4.0 on Linux, macOS (ARM and Intel), and Windows.
2 parents b8c79bf + f4c69c2 commit ac57eed

39 files changed

+2329
-673
lines changed

.github/workflows/gem-release.yml

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
name: Build and Release Gem
2+
3+
on:
4+
push:
5+
tags:
6+
- '*'
7+
8+
jobs:
9+
build:
10+
strategy:
11+
fail-fast: false
12+
matrix:
13+
include:
14+
- os: windows-latest # x64-mingw-ucrt
15+
- os: ubuntu-latest # x86_64-linux
16+
- os: macos-14 # arm64-darwin (Apple Silicon)
17+
- os: macos-15-intel # x86_64-darwin (Intel)
18+
19+
runs-on: ${{ matrix.os }}
20+
21+
steps:
22+
- uses: actions/checkout@v4
23+
24+
- uses: ruby/setup-ruby@v1
25+
with:
26+
ruby-version: '4.0'
27+
bundler-cache: true
28+
29+
- name: Install Linux build dependencies
30+
if: runner.os == 'Linux'
31+
run: sudo apt-get install -y xz-utils gcc
32+
33+
- name: Install macOS build dependencies
34+
if: runner.os == 'macOS'
35+
run: brew install xz
36+
37+
- name: Build stubs and run tests
38+
run: |
39+
bundle exec rake build
40+
bundle exec rake test
41+
42+
- name: Build platform gem
43+
run: gem build ocran.gemspec
44+
45+
- name: Upload gem artifact
46+
uses: actions/upload-artifact@v4
47+
with:
48+
name: gem-${{ matrix.os }}
49+
path: '*.gem'
50+
51+
build-source-gem:
52+
runs-on: ubuntu-latest
53+
steps:
54+
- uses: actions/checkout@v4
55+
56+
- uses: ruby/setup-ruby@v1
57+
with:
58+
ruby-version: '4.0'
59+
bundler-cache: true
60+
61+
- name: Build source gem
62+
run: gem build ocran-source.gemspec
63+
64+
- name: Upload gem artifact
65+
uses: actions/upload-artifact@v4
66+
with:
67+
name: gem-source
68+
path: '*.gem'
69+
70+
release:
71+
needs: [build, build-source-gem]
72+
runs-on: ubuntu-latest
73+
environment: production
74+
permissions:
75+
contents: write
76+
77+
steps:
78+
- name: Download all gem artifacts
79+
uses: actions/download-artifact@v4
80+
with:
81+
pattern: gem-*
82+
merge-multiple: true
83+
84+
- name: Create GitHub Release and upload gems
85+
env:
86+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
87+
run: |
88+
gh release create "${{ github.ref_name }}" \
89+
--repo "${{ github.repository }}" \
90+
--title "Release ${{ github.ref_name }}" \
91+
*.gem
92+
93+
- name: Push gems to RubyGems
94+
env:
95+
GEM_HOST_API_KEY: ${{ secrets.RUBYGEMS_API_KEY }}
96+
run: |
97+
for gem in *.gem; do
98+
gem push "$gem"
99+
done

.github/workflows/test-on-push.yml

Lines changed: 151 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,127 @@ on:
44
branches:
55
- '*'
66
jobs:
7-
run-tests:
7+
run-tests-linux:
8+
strategy:
9+
fail-fast: false
10+
matrix:
11+
ruby: [ '3.2', '3.3', '3.4', '4.0' ]
12+
runs-on: ubuntu-latest
13+
steps:
14+
- uses: actions/checkout@v4
15+
16+
- uses: ruby/setup-ruby@v1
17+
with:
18+
ruby-version: ${{ matrix.ruby }}
19+
bundler-cache: true
20+
21+
- name: Install dependencies
22+
run: sudo apt-get install -y xz-utils gcc
23+
24+
- name: Build stub and run tests
25+
env:
26+
OCRAN_DEBUG: "1"
27+
run: |
28+
bundle exec rake build
29+
bundle exec rake test
30+
31+
- name: Build zlib fixture for cross-distro test
32+
env:
33+
OCRAN_DEBUG: "1"
34+
run: ruby -Ilib exe/ocran test/fixtures/zlib/zlib.rb --output /tmp/zlib_packed
35+
36+
- name: Run packed executable on Debian (no Ruby installed)
37+
run: docker run --rm -e OCRAN_DEBUG=1 -v /tmp:/mnt debian:stable-slim /mnt/zlib_packed
38+
39+
run-tests-macos:
40+
strategy:
41+
fail-fast: false
42+
matrix:
43+
os: [macos-14, macos-15-intel]
44+
ruby: ['3.2', '3.3', '3.4', '4.0']
45+
runs-on: ${{ matrix.os }}
46+
steps:
47+
- uses: actions/checkout@v4
48+
49+
- uses: ruby/setup-ruby@v1
50+
with:
51+
ruby-version: ${{ matrix.ruby }}
52+
bundler-cache: true
53+
54+
- name: Install dependencies
55+
run: brew install xz
56+
57+
- name: Build stub and run tests
58+
run: |
59+
bundle exec rake build
60+
bundle exec rake test
61+
62+
- name: Build zlib fixture for cross-system test
63+
run: ruby -Ilib exe/ocran test/fixtures/zlib/zlib.rb --output zlib_packed
64+
65+
- name: Upload packed binary
66+
uses: actions/upload-artifact@v4
67+
with:
68+
name: zlib-macos-${{ matrix.os }}-${{ matrix.ruby }}
69+
path: zlib_packed
70+
retention-days: 1
71+
72+
test-macos-portability:
73+
needs: run-tests-macos
74+
strategy:
75+
fail-fast: false
76+
matrix:
77+
os: [ macos-14, macos-15-intel ]
78+
ruby: [ '3.2', '3.3', '3.4', '4.0' ]
79+
runs-on: ${{ matrix.os }}
80+
steps:
81+
- name: Download packed binary
82+
uses: actions/download-artifact@v4
83+
with:
84+
name: zlib-macos-${{ matrix.os }}-${{ matrix.ruby }}
85+
86+
- name: Run packed executable
87+
run: |
88+
chmod +x zlib_packed
89+
./zlib_packed
90+
91+
test-source-gem-install:
92+
strategy:
93+
fail-fast: false
94+
matrix:
95+
include:
96+
- os: ubuntu-24.04-arm
97+
- os: windows-11-arm
98+
runs-on: ${{ matrix.os }}
99+
steps:
100+
- uses: actions/checkout@v4
101+
102+
- uses: ruby/setup-ruby@v1
103+
with:
104+
ruby-version: '4.0'
105+
106+
- name: Install build dependencies
107+
if: runner.os == 'Linux'
108+
run: sudo apt-get install -y xz-utils gcc make
109+
110+
- name: Build and install source gem
111+
run: |
112+
gem build ocran-source.gemspec
113+
gem install --local ocran-*.gem
114+
115+
- name: Build zlib executable and run portability test (Linux)
116+
if: runner.os == 'Linux'
117+
run: |
118+
ocran test/fixtures/zlib/zlib.rb --output /tmp/zlib_from_source_gem
119+
docker run --rm -v /tmp:/mnt debian:stable-slim /mnt/zlib_from_source_gem
120+
121+
- name: Build and run zlib executable (Windows)
122+
if: runner.os == 'Windows'
123+
run: |
124+
ocran test/fixtures/zlib/zlib.rb --no-lzma --output zlib_from_source_gem.exe
125+
.\zlib_from_source_gem.exe
126+
127+
run-tests-windows:
8128
strategy:
9129
fail-fast: false
10130
matrix:
@@ -57,10 +177,37 @@ jobs:
57177
# shell: pwsh
58178
# run: ridk exec pacman -S --noconfirm mingw-w64-ucrt-x86_64-tcl mingw-w64-ucrt-x86_64-tk
59179

60-
# - name: Install tk gem
61-
# run: gem install tk -v 0.5.1 -- --without-X11 --with-cflags="-std=gnu99 -Wno-incompatible-pointer-types"
62-
63180
- name: Build stub and run tests
64181
run: |
65182
bundle exec rake build
66183
bundle exec rake test
184+
185+
- name: Build zlib fixture for portability test
186+
run: bundle exec ruby -Ilib exe/ocran test/fixtures/zlib/zlib.rb --output zlib_packed.exe
187+
188+
- name: Upload packed binary
189+
uses: actions/upload-artifact@v4
190+
with:
191+
name: zlib-windows-${{ matrix.ruby }}
192+
path: zlib_packed.exe
193+
retention-days: 1
194+
195+
test-windows-portability:
196+
needs: run-tests-windows
197+
strategy:
198+
fail-fast: false
199+
matrix:
200+
os: [ windows-latest ]
201+
ruby: [ '3.2', '3.3', '3.4', '4.0' ]
202+
runs-on: ${{ matrix.os }}
203+
steps:
204+
- name: Download packed binary
205+
uses: actions/download-artifact@v4
206+
with:
207+
name: zlib-windows-${{ matrix.ruby }}
208+
209+
- name: Run packed executable
210+
shell: pwsh
211+
run: |
212+
$env:PATH = "C:\Windows\system32;C:\Windows"
213+
.\zlib_packed.exe

.github/workflows/windows-gem-release.yml

Lines changed: 0 additions & 55 deletions
This file was deleted.

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,5 @@ pkg
66
README.txt
77
*.tmp
88
*.res
9+
share/ocran/stub
10+
src/stub

CHANGELOG.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
=== 1.4.0
2+
- Add Linux support: build and run self-extracting ELF executables on Linux. The stub compiles and runs natively on Linux using POSIX APIs.
3+
- Add macOS support: build and run self-extracting Mach-O executables on macOS.
4+
- Add `--output-dir` option: output all files to a directory with a platform-appropriate launch script (`.sh` on Linux/macOS, `.bat` on Windows) instead of a single executable.
5+
- Add `--output-zip` option: same as `--output-dir` but packages the result into a zip archive.
6+
- Add `--macosx-bundle` option: wrap the macOS executable in a `.app` bundle with a generated `Info.plist`, suitable for Finder, the Dock, and Authenticode-style code signing with `codesign` and `xcrun notarytool`. Use `--bundle-id` to set `CFBundleIdentifier` and `--icon` (`.icns`) to set the bundle icon.
7+
- Use symlinks for shared library aliases on POSIX (e.g. `libruby.so → libruby.so.4.0`) instead of copying files, matching the layout Ruby expects at runtime.
8+
- Fix crash on cleanup when a symlink target does not exist: `DeleteRecursively` now uses `lstat` instead of `stat` so dangling symlinks are removed correctly.
9+
- Publish platform-specific gems for Linux, macOS (ARM and Intel), and Windows so `gem install ocran` selects the right pre-built stub automatically.
10+
- Publish a source gem (`ruby` platform) with `ext/extconf.rb` so users on unlisted platforms can install by compiling the stub from source. Falls back to plain `make` if `ridk exec make` is unavailable on Windows.
11+
- CI: add GitHub Actions workflow to build and publish per-platform gems on tag push.
12+
- CI: run the packed Linux executable inside a Debian Docker container to verify cross-distro portability (no Ruby required on target).
13+
- CI: test against Ruby 3.2, 3.3, 3.4, and 4.0 on Linux, macOS (ARM and Intel), and Windows.
14+
115
=== 1.3.18
216
- Support shipping IRB as .exe File
317
- Fix SxS error 14001 when loading native extensions (e.g. openssl.so, date_core.so) at runtime. Each .so file may have a companion *.so-assembly.manifest in archdir defining its private SxS assembly; these manifests are now included alongside the .so files. All files in ruby_builtin_dlls/ (DLLs and manifest) are now included rather than the manifest alone.

Gemfile.lock

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,9 @@ GEM
3030
hoe (4.6.1)
3131
rake (~> 13.0)
3232
libui (0.1.2)
33+
libui (0.1.2-arm64-darwin)
3334
libui (0.1.2-x64-mingw)
35+
libui (0.1.2-x86_64-darwin)
3436
logger (1.7.0)
3537
matrix (0.4.3)
3638
method_source (1.1.0)
@@ -66,8 +68,11 @@ GEM
6668
wisper (2.0.1)
6769

6870
PLATFORMS
71+
arm64-darwin-23
6972
x64-mingw-ucrt
7073
x64-mingw32
74+
x86_64-darwin-22
75+
x86_64-darwin-24
7176
x86_64-linux
7277

7378
DEPENDENCIES

0 commit comments

Comments
 (0)