ocran 1.4.6 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.txt +82 -0
- data/README.md +519 -15
- data/ext/extconf.rb +5 -1
- data/lib/ocran/aot_toolchain.rb +154 -0
- data/lib/ocran/build_helper.rb +7 -0
- data/lib/ocran/command_output.rb +8 -1
- data/lib/ocran/compatibility_scan.rb +414 -0
- data/lib/ocran/cosmo_toolchain.rb +29 -7
- data/lib/ocran/dir_builder.rb +88 -38
- data/lib/ocran/direction.rb +292 -44
- data/lib/ocran/ed_resource.rb +113 -0
- data/lib/ocran/ed_resource_builder.rb +199 -0
- data/lib/ocran/env_hook.rb +98 -0
- data/lib/ocran/file_path_set.rb +9 -5
- data/lib/ocran/gem_spec_queryable.rb +13 -5
- data/lib/ocran/host_config_helper.rb +11 -1
- data/lib/ocran/inno_setup_script_builder.rb +24 -14
- data/lib/ocran/launcher_batch_builder.rb +8 -11
- data/lib/ocran/npm_package.rb +106 -0
- data/lib/ocran/option.rb +465 -35
- data/lib/ocran/pe_imports.rb +96 -0
- data/lib/ocran/pe_resources.rb +226 -0
- data/lib/ocran/refine_pathname.rb +29 -32
- data/lib/ocran/roundhouse_builder.rb +316 -0
- data/lib/ocran/runner.rb +52 -11
- data/lib/ocran/runtime_sdk.rb +259 -0
- data/lib/ocran/spinel_builder.rb +183 -0
- data/lib/ocran/spinel_compatibility.rb +149 -0
- data/lib/ocran/static_runtime/boot.rb +443 -0
- data/lib/ocran/static_runtime/build_static_ext.rb +86 -0
- data/lib/ocran/static_runtime_builder.rb +814 -0
- data/lib/ocran/stub_builder.rb +70 -25
- data/lib/ocran/version.rb +1 -1
- data/lib/ocran/wasm_builder.rb +570 -0
- data/lib/ocran/wasm_compatibility.rb +198 -0
- data/lib/ocran/windows_command_escaping.rb +21 -0
- data/lib/ocran/zip_payload_builder.rb +18 -9
- data/lib/ocran/zip_writer.rb +48 -9
- data/src/Makefile +18 -2
- data/src/Makefile.mswin +65 -0
- data/src/inst_dir.c +34 -6
- data/src/path_utils.c +144 -0
- data/src/script_info.c +5 -0
- data/src/stub.c +77 -19
- data/src/stub.rc +1 -1
- data/src/system_utils.c +276 -155
- data/src/system_utils.h +46 -3
- data/src/system_utils_posix.c +243 -148
- data/src/unpack.c +9 -0
- metadata +25 -4
data/README.md
CHANGED
|
@@ -1,12 +1,29 @@
|
|
|
1
|
-
# OCRAN
|
|
1
|
+
# OCRAN — turn Ruby scripts into standalone executables (.exe) for Windows, Linux and macOS
|
|
2
2
|
|
|
3
|
-

|
|
3
|
+

|
|
4
4
|
|
|
5
|
-
[
|
|
5
|
+
[](https://rubygems.org/gems/ocran)
|
|
6
|
+
|
|
7
|
+
**OCRAN (One-Click Ruby Application Next) is a Ruby-to-executable packager:
|
|
8
|
+
`ocran app.rb` turns a Ruby script into a single `.exe` (Windows) or native
|
|
9
|
+
binary (Linux, macOS) that runs on machines without Ruby installed.** It is
|
|
10
|
+
the maintained successor of [OCRA](https://github.com/larsch/ocra) for
|
|
11
|
+
Ruby 3.3 and newer.
|
|
12
|
+
|
|
13
|
+
[OCRAN](https://github.com/largo/ocran) packages Ruby applications for
|
|
6
14
|
distribution. It bundles your script, the Ruby interpreter, gems, and native
|
|
7
15
|
libraries into a single self-contained artifact that runs without requiring
|
|
8
16
|
Ruby to be installed on the target machine.
|
|
9
17
|
|
|
18
|
+
Quick start:
|
|
19
|
+
|
|
20
|
+
```
|
|
21
|
+
gem install ocran
|
|
22
|
+
ocran app.rb # → app.exe on Windows, ./app on Linux/macOS
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
See the [FAQ](#faq) and the [comparison with other Ruby packagers](#comparison-with-other-ruby-packagers).
|
|
26
|
+
|
|
10
27
|
OCRAN supports four output formats, all cross-platform:
|
|
11
28
|
|
|
12
29
|
* **Self-extracting executable** — bundles everything into a single binary that unpacks and runs transparently, with no Ruby installation required. Produces a `.exe` on Windows, and a native executable on Linux and macOS.
|
|
@@ -15,7 +32,7 @@ OCRAN supports four output formats, all cross-platform:
|
|
|
15
32
|
* **Zip archive** (`--output-zip`) — same as directory output, packed into a `.zip`.
|
|
16
33
|
|
|
17
34
|
OCRAN is a fork of [OCRA](https://github.com/larsch/ocra) maintained for
|
|
18
|
-
Ruby 3.
|
|
35
|
+
Ruby 3.3+ compatibility.
|
|
19
36
|
|
|
20
37
|
If you run into errors while using OCRAN, please check the [OCRAN issues](https://github.com/largo/ocran/issues) first.
|
|
21
38
|
|
|
@@ -76,7 +93,7 @@ This repository includes `lzma.exe` from the
|
|
|
76
93
|
[official ip7z/7zip release](https://github.com/ip7z/7zip/releases)
|
|
77
94
|
(version 22.01, from `lzma2201.7z`), used to compress Windows executables.
|
|
78
95
|
|
|
79
|
-
`stub.exe`, `stubw.exe
|
|
96
|
+
`stub.exe`, `stubw.exe` and the Linux/macOS `stub` are compiled from source in this
|
|
80
97
|
repository.
|
|
81
98
|
|
|
82
99
|
## Installation
|
|
@@ -153,7 +170,7 @@ These options control which files from included gems are added to the output.
|
|
|
153
170
|
* `--gem-guess[=gem1,..]`: Include loaded scripts and a best guess of other needed files (DEFAULT).
|
|
154
171
|
* `--gem-all[=gem1,..]`: Include all scripts and important files from the gem.
|
|
155
172
|
* `--gem-full[=gem1,..]`: Include every file in the gem directory.
|
|
156
|
-
* `--gem-spec[=gem1,..]`: Include files listed in the gemspec
|
|
173
|
+
* `--gem-spec[=gem1,..]`: Include the files listed in the gemspec.
|
|
157
174
|
|
|
158
175
|
Fine-tuning flags:
|
|
159
176
|
|
|
@@ -163,7 +180,7 @@ Fine-tuning flags:
|
|
|
163
180
|
|
|
164
181
|
#### Auto-detection options:
|
|
165
182
|
|
|
166
|
-
* `--no-dep-run`: Skip running the script to detect dependencies. Use this if your script has side effects during load or if you are manually specifying all dependencies.
|
|
183
|
+
* `--no-dep-run`: Skip running the script to detect dependencies. Use this if your script has side effects during load or if you are manually specifying all dependencies. Nothing the script loads is detected then, so you usually need `--add-all-core` for the standard library and `--gemfile` with `--gem-full` (or `--gem-all`) for gems; OCRAN warns when they are missing.
|
|
167
184
|
* `--no-autoload`: Do not attempt to load `autoload`ed constants.
|
|
168
185
|
* `--no-autodll`: Disable automatic detection of runtime DLL dependencies.
|
|
169
186
|
|
|
@@ -188,8 +205,126 @@ Fine-tuning flags:
|
|
|
188
205
|
* `--debug`: Enable verbose output when the generated executable runs.
|
|
189
206
|
* `--debug-extract`: Unpack to a local directory and do not delete after execution (useful for troubleshooting).
|
|
190
207
|
|
|
208
|
+
#### Windows resource options:
|
|
209
|
+
|
|
210
|
+
These set the PE resources of the generated executable, with the same names
|
|
211
|
+
as [rcedit](https://github.com/electron/rcedit). They apply to the
|
|
212
|
+
self-extracting `.exe` and to the wrapper `.exe` of `--output-dir`,
|
|
213
|
+
`--output-zip` and `--innosetup`. All are opt-in: without them the
|
|
214
|
+
executable is built as before. (Windows only)
|
|
215
|
+
|
|
216
|
+
* `--set-version-string <key> <value>` (alias `--version-string`): Add a `StringFileInfo` entry such as `CompanyName`, `ProductName`, `FileDescription` or `LegalCopyright`. Repeat for each key.
|
|
217
|
+
* `--set-file-version <x.y.z.w>` (alias `--file-version`): Set the numeric and string file version.
|
|
218
|
+
* `--set-product-version <x.y.z.w>` (alias `--product-version`): Set the numeric and string product version.
|
|
219
|
+
* `--set-resource-string <id> <value>` (alias `--resource-string`): Set an entry of the `RT_STRING` table by its numeric id.
|
|
220
|
+
* `--set-requested-execution-level <level>` (alias `--uac-level`): Set the UAC level in the manifest: `asInvoker` (the default), `highestAvailable` or `requireAdministrator`.
|
|
221
|
+
* `--application-manifest <file>` (alias `--manifest`): Replace the built-in application manifest with the given file. `--set-requested-execution-level` still applies to it.
|
|
222
|
+
|
|
223
|
+
```
|
|
224
|
+
ocran app.rb --set-version-string CompanyName "Example Ltd" \
|
|
225
|
+
--set-version-string ProductName "Example App" \
|
|
226
|
+
--set-version-string FileDescription "Example App" \
|
|
227
|
+
--set-file-version 1.2.0.0 --set-product-version 1.2.0.0
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
An unsigned executable with no version information, which extracts files
|
|
231
|
+
to `%TEMP%` and runs them, is what antivirus and EDR heuristics expect of a
|
|
232
|
+
malware packer. Version information, an icon and a code signature give it
|
|
233
|
+
an identity instead. [docs/av-edr-false-positives.md](docs/av-edr-false-positives.md)
|
|
234
|
+
goes through these steps in order of impact.
|
|
235
|
+
|
|
191
236
|
#### Experimental options:
|
|
192
237
|
|
|
238
|
+
* `--static-runtime <runtime-dir>`: Build a single executable for Windows,
|
|
239
|
+
Linux or macOS that runs the application **without extracting anything**:
|
|
240
|
+
no temporary directory, no DLLs or shared libraries written to disk. The
|
|
241
|
+
executable is a statically linked Ruby (the *static runtime*) with the
|
|
242
|
+
application as a plain ZIP archive: appended on Windows and Linux, in a
|
|
243
|
+
section of its own on macOS (`__OCRAN,__zip`), where appended data would
|
|
244
|
+
break the code signature. The Linux runtime is linked against musl and
|
|
245
|
+
fully static, so it runs on any x86_64 distribution.
|
|
246
|
+
|
|
247
|
+
```
|
|
248
|
+
ocran app.rb --static-runtime path/to/runtime # app.exe (Windows) or app (Linux, macOS)
|
|
249
|
+
unzip -l app.exe # lists exactly what will run (Linux: app)
|
|
250
|
+
unzip -p app.exe ocran/manifest.sha256 # SHA-256 of the runtime and every file
|
|
251
|
+
|
|
252
|
+
segedit app -extract __OCRAN __zip app.zip # macOS: the archive is a section
|
|
253
|
+
unzip -l app.zip
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
The runtime directory holds `ocran-runtime(.exe)`, its own standard
|
|
257
|
+
library and bundled gems (`lib/ruby/`) and `runtime.json`; build one with
|
|
258
|
+
`runtime/build-runtime.sh` (Windows, MinGW, on Linux), the scripts in
|
|
259
|
+
`runtime/mswin/` (Windows, Visual Studio Build Tools) or
|
|
260
|
+
`runtime/linux/build-runtime.sh` (Linux x86_64, musl) or
|
|
261
|
+
`runtime/macos/build-runtime.sh` (macOS, on a Mac). The Windows
|
|
262
|
+
runtimes import only DLLs that ship with Windows and need no VC++
|
|
263
|
+
redistributable; the Linux runtime imports nothing at all; the macOS
|
|
264
|
+
runtime links only libraries of macOS itself (libSystem, libiconv,
|
|
265
|
+
CoreFoundation). On macOS every executable is linked at packaging time,
|
|
266
|
+
with its archive, so packaging for macOS needs a Mac with clang (Xcode or
|
|
267
|
+
the Command Line Tools); the linker signs the result ad hoc, and it can
|
|
268
|
+
be signed again with `codesign`. Which system
|
|
269
|
+
the executable is for follows from the runtime, not from the build host:
|
|
270
|
+
a Linux build host can package for Windows and the other way round, as
|
|
271
|
+
long as the application does not depend on platform-specific gems. See
|
|
272
|
+
[runtime/README.md](runtime/README.md) for how it works and how it is
|
|
273
|
+
built. CI builds and tests the three runtimes and publishes each as a
|
|
274
|
+
reproducible archive (a zip for Windows, a tarball otherwise) with a
|
|
275
|
+
signed build provenance attestation
|
|
276
|
+
(`gh attestation verify <archive> -R Largo/ocran`); releases from 1.5.1
|
|
277
|
+
on have them attached.
|
|
278
|
+
|
|
279
|
+
Dependency detection runs as usual, under the build host's Ruby, which
|
|
280
|
+
must have the runtime's API version (e.g. 4.0.0). The standard library
|
|
281
|
+
and the gems the runtime ships come from the runtime, so that they match
|
|
282
|
+
its interpreter; OCRAN says when one replaces a different version on the
|
|
283
|
+
build host. C extensions are linked into the executable, since nothing
|
|
284
|
+
can be loaded from inside it: those the runtime has (openssl, psych,
|
|
285
|
+
zlib, fiddle, win32ole, bigdecimal, ...) are used as they are; any other
|
|
286
|
+
gem's extension is built from the gem's source against the runtime's
|
|
287
|
+
SDK (`sdk/` in the runtime directory) and linked into a runtime of the
|
|
288
|
+
application's own. That needs a compiler for the runtime: for a MinGW
|
|
289
|
+
runtime `x86_64-w64-mingw32ucrt-gcc` on Linux, or on Windows
|
|
290
|
+
RubyInstaller's MSYS2 GCC named with `OCRAN_RUNTIME_CC=gcc` (with
|
|
291
|
+
`ucrt64\bin` and `usr\bin` on PATH); for an mswin runtime `cl` and
|
|
292
|
+
`nmake` of Visual Studio Build Tools, from a developer prompt; for a
|
|
293
|
+
Linux runtime `musl-gcc`; for macOS clang. Gems that
|
|
294
|
+
need a C library get the one the SDK provides: nokogiri uses its
|
|
295
|
+
libxml2/libxslt, tiny_tds its FreeTDS. A precompiled platform gem is
|
|
296
|
+
built from its source gem of the same version, which OCRAN fetches from
|
|
297
|
+
the configured gem sources into `~/.cache/ocran/gems`, together with the
|
|
298
|
+
gems its build needs that are not installed (nokogiri's extconf.rb needs
|
|
299
|
+
mini_portile2), installed there for the build only. Failing that, it is
|
|
300
|
+
built from the C sources it carries, if any (`gem install <gem>
|
|
301
|
+
--platform ruby` installs the source gem).
|
|
302
|
+
|
|
303
|
+
**Licenses:** the executable is statically linked - Ruby, OpenSSL and
|
|
304
|
+
the other libraries are inside it, and their license texts are packed
|
|
305
|
+
into it as `ocran/licenses/`. Two optional libraries are under the LGPL
|
|
306
|
+
(GNU libiconv, FreeTDS: used by nokogiri and tiny_tds), which asks that
|
|
307
|
+
users can replace them; `--runtime-dll iconv,sybdb` ships them as DLLs
|
|
308
|
+
next to the executable instead. Read
|
|
309
|
+
[runtime/LICENSES.md](runtime/LICENSES.md) before distributing.
|
|
310
|
+
|
|
311
|
+
OpenSSL verifies certificates against the Windows certificate store, as
|
|
312
|
+
Windows itself does, and on Linux and macOS against the system's CA
|
|
313
|
+
bundle - no CA file is packed or needed. The application reads its own files as
|
|
314
|
+
usual (`require`, `require_relative`, `autoload`, `File.read`,
|
|
315
|
+
`Dir.glob`, `__dir__`, `DATA`); their paths lie inside the executable
|
|
316
|
+
(`C:/app/tool.exe/src/tool.rb`) and cannot be written. Files next to the
|
|
317
|
+
executable are found through `ENV["OCRAN_EXECUTABLE"]`. `--windows` makes
|
|
318
|
+
a GUI-subsystem executable; `--icon` and the version-resource options
|
|
319
|
+
work as for the stub, on any build host (OCRAN writes the resources in
|
|
320
|
+
Ruby). `--dll` and the output-directory formats do not apply.
|
|
321
|
+
Experimental.
|
|
322
|
+
|
|
323
|
+
* `--runtime-dll <lib,...>`: With `--static-runtime`, link these C libraries of the
|
|
324
|
+
runtime's SDK as DLLs shipped next to the executable rather than into it
|
|
325
|
+
(the SDK has DLL builds of `iconv` and `sybdb`, the LGPL libraries).
|
|
326
|
+
OCRAN copies them, and the DLLs they need, next to the executable.
|
|
327
|
+
|
|
193
328
|
* `--cosmo-ruby <ruby.com>`: Package a cosmopolitan-built Ruby (an APE)
|
|
194
329
|
as the bundled interpreter instead of the host Ruby. The produced
|
|
195
330
|
`.com` contains no host-native code at all and runs on Linux, Windows
|
|
@@ -256,7 +391,8 @@ Fine-tuning flags:
|
|
|
256
391
|
`__dir__` for that — it never meant "next to the exe" in either
|
|
257
392
|
mode, but here it is obviously wrong instead of subtly wrong.
|
|
258
393
|
* `--chdir-first` changes into the directory containing the
|
|
259
|
-
executable, since the application directory does not exist on disk
|
|
394
|
+
executable, since the application directory does not exist on disk;
|
|
395
|
+
`--chdir-exe-dir` does the same.
|
|
260
396
|
* The whole command line reaches `ARGV`, unchanged. The interpreter
|
|
261
397
|
claims none of it, so `app.com --version`, `app.com -v` and
|
|
262
398
|
`app.com -- x` behave exactly as they would for a natively compiled
|
|
@@ -345,6 +481,147 @@ Fine-tuning flags:
|
|
|
345
481
|
launcher stub, not to the bundled application. See
|
|
346
482
|
`docs/cosmocc-port-plan.md` for status.
|
|
347
483
|
|
|
484
|
+
#### Native compilation (experimental):
|
|
485
|
+
|
|
486
|
+
Instead of packaging the interpreter, these options compile the program
|
|
487
|
+
ahead of time with [Spinel](https://github.com/matz/spinel), Matz's Ruby
|
|
488
|
+
AOT compiler. The result is a native executable that needs no Ruby at all.
|
|
489
|
+
Spinel compiles a *subset* of Ruby (no `eval` of strings, no
|
|
490
|
+
`method_missing`, no runtime class building, only the standard library it
|
|
491
|
+
ships itself), so this works for some programs and not others. When it
|
|
492
|
+
does not, OCRAN tells you why.
|
|
493
|
+
|
|
494
|
+
* `--spinel`: Compile `script.rb` with Spinel:
|
|
495
|
+
|
|
496
|
+
```
|
|
497
|
+
ocran app.rb --spinel # -> ./app (app.exe on Windows)
|
|
498
|
+
ocran app.rb --spinel --output myapp
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
The script is not run at build time. OCRAN scans the program statically
|
|
502
|
+
(the script, the files it requires, and the source of every gem it
|
|
503
|
+
requires) and passes Spinel the `-I` roots it needs for your `lib/` and
|
|
504
|
+
for pure-Ruby gems. If Spinel cannot compile the program, OCRAN prints
|
|
505
|
+
the compiler's error, then a report of what stands in the way, grouped
|
|
506
|
+
into your code and each gem. Gems with C extensions and standard
|
|
507
|
+
libraries Spinel does not provide are named as incompatible. If
|
|
508
|
+
`spinel-doctor` is installed next to the compiler, its report is shown
|
|
509
|
+
too. If Spinel is not installed, OCRAN explains how to install it and
|
|
510
|
+
still shows the report, so you can see whether installing it is worth
|
|
511
|
+
it. Use `--spinel-opt <arg>` (repeatable) to pass flags to the compiler,
|
|
512
|
+
for example `--spinel-opt --int-overflow=promote` or
|
|
513
|
+
`--spinel-opt --defer-refusals`. With `--debug` the binary is built
|
|
514
|
+
with `-g`. Only code is compiled in; data files have to ship next to
|
|
515
|
+
the executable.
|
|
516
|
+
|
|
517
|
+
* `--roundhouse`: Compile a **Rails application** into a native server
|
|
518
|
+
binary with [Roundhouse](https://github.com/rubys/roundhouse), which
|
|
519
|
+
lowers the app to the Ruby subset Spinel compiles. OCRAN runs the
|
|
520
|
+
transpile, the generated project's asset step (`make assets`, with
|
|
521
|
+
only the Gemfile's assets group bundled) and `spin build`:
|
|
522
|
+
|
|
523
|
+
```
|
|
524
|
+
ocran --roundhouse path/to/rails/app # -> ./app-spinel/
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
The output is a directory (`<app>-spinel` by default, or `--output` /
|
|
528
|
+
`--output-dir`) that contains the binary plus the `static/`, `public/`,
|
|
529
|
+
`db/` and `config/` files it reads at run time, and a `storage/` for
|
|
530
|
+
the SQLite database. On the first build the database is created from
|
|
531
|
+
`db/seed.sql` when the `sqlite3` command is available. Rebuilding keeps
|
|
532
|
+
`storage/`. If Roundhouse does not cover the app yet, OCRAN shows the
|
|
533
|
+
useful parts of `roundhouse check --continue`: the gem census (which of
|
|
534
|
+
the app's gems Roundhouse does not model), the first errors, and the
|
|
535
|
+
list of unsupported constructs. Pass flags to Roundhouse with
|
|
536
|
+
`--roundhouse-opt <arg>`, for example
|
|
537
|
+
`--roundhouse-opt --survey --roundhouse-opt --allow-unsupported`.
|
|
538
|
+
|
|
539
|
+
**Installing the compilers.** Neither is a gem. OCRAN looks for `spinel`,
|
|
540
|
+
`spin` and `roundhouse` in the `SPINEL`, `SPIN` and `ROUNDHOUSE`
|
|
541
|
+
environment variables (the command or the directory that contains it), then
|
|
542
|
+
in `PATH`, then in their usual install locations (`~/.local/bin`,
|
|
543
|
+
`/usr/local/bin`, `~/.cargo/bin`). When one is missing, OCRAN prints how to
|
|
544
|
+
install it:
|
|
545
|
+
|
|
546
|
+
```
|
|
547
|
+
git clone https://github.com/matz/spinel && cd spinel
|
|
548
|
+
make deps && make && make install PREFIX=$HOME/.local
|
|
549
|
+
|
|
550
|
+
curl --proto '=https' --tlsv1.2 -LsSf \
|
|
551
|
+
https://github.com/rubys/roundhouse/releases/latest/download/roundhouse-installer.sh | sh
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
Apps compiled with Roundhouse also need the SQLite and jemalloc
|
|
555
|
+
development headers (`libsqlite3-dev libjemalloc-dev`, or
|
|
556
|
+
`brew install sqlite jemalloc`). OCRAN puts the directory `pkg-config`
|
|
557
|
+
reports for the allocator on `LIBRARY_PATH` for the build, so a Homebrew
|
|
558
|
+
jemalloc on Apple Silicon (under `/opt/homebrew/lib`, which the linker does
|
|
559
|
+
not search by default) links. The asset step needs Bundler, and Node.js
|
|
560
|
+
with npm when the app builds Tailwind.
|
|
561
|
+
|
|
562
|
+
**Windows.** Spinel does not build natively on Windows yet, and
|
|
563
|
+
Roundhouse's Windows build is untested. For now, run OCRAN inside WSL,
|
|
564
|
+
where both work as they do on Linux; you get a Linux binary. Nothing in
|
|
565
|
+
OCRAN is tied to a platform here: once the compilers run on Windows,
|
|
566
|
+
`--spinel` and `--roundhouse` work there as they are and produce `.exe`
|
|
567
|
+
files.
|
|
568
|
+
|
|
569
|
+
#### WebAssembly export (experimental):
|
|
570
|
+
|
|
571
|
+
`--wasm` exports the application as a web page that runs it in the browser.
|
|
572
|
+
The output is a folder (`<scriptname>-wasm` by default, or `--output-dir`)
|
|
573
|
+
or a zip archive (`--output-zip`, or an `--output` name that ends in
|
|
574
|
+
`.zip`). It contains `index.html`, the runtime and your program. The page
|
|
575
|
+
shows the program's standard output and errors. Use the `js` library to
|
|
576
|
+
work with the page itself. Browsers only load WebAssembly over HTTP, so
|
|
577
|
+
serve the folder instead of opening the file:
|
|
578
|
+
|
|
579
|
+
```
|
|
580
|
+
ocran app.rb --wasm # -> app-wasm/
|
|
581
|
+
ocran app.rb --wasm=picoruby --output app.zip
|
|
582
|
+
python3 -m http.server -d app-wasm 8000 # then open http://localhost:8000
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
There are two runtimes:
|
|
586
|
+
|
|
587
|
+
* `--wasm` (or `--wasm=ruby`): [ruby.wasm](https://github.com/ruby/ruby.wasm),
|
|
588
|
+
CRuby compiled to WebAssembly, with its whole standard library (about
|
|
589
|
+
30 MB). It needs `rbwasm` from the `ruby_wasm` gem (`gem install ruby_wasm`;
|
|
590
|
+
OCRAN also uses `RBWASM` when it is set).
|
|
591
|
+
* OCRAN packs your files into the prebuilt interpreter from npm, which
|
|
592
|
+
takes seconds. Gems must be listed in the application's Gemfile and
|
|
593
|
+
installed (`bundle install`); pure-Ruby gems are packed in beside your
|
|
594
|
+
files, at `/gems`, and put on the load path in place of
|
|
595
|
+
`bundler/setup`, so `require "bundler/setup"` in your program is fine.
|
|
596
|
+
* Only when a gem has a C extension does OCRAN run `rbwasm build`. Its
|
|
597
|
+
first run compiles CRuby and the gems for WebAssembly, which takes
|
|
598
|
+
several minutes, and is cached in `~/.cache/ocran/ruby_wasm`. The
|
|
599
|
+
extensions are cross-compiled for WASI, and the ones that link system
|
|
600
|
+
libraries usually fail.
|
|
601
|
+
* The Ruby version follows the Ruby you run OCRAN with. Use
|
|
602
|
+
`--wasm-ruby 3.4` to choose another one. Pass extra flags to
|
|
603
|
+
`rbwasm build` with `--wasm-opt <arg>`.
|
|
604
|
+
* `--wasm=picoruby` (or `--picoruby`): [PicoRuby](https://github.com/picoruby/picoruby),
|
|
605
|
+
the mruby-based Ruby for microcontrollers.
|
|
606
|
+
* Its runtime is about 2 MB, and nothing needs to be installed.
|
|
607
|
+
* PicoRuby has its own small library (`js`, `json`, `yaml`, `base64`, ...)
|
|
608
|
+
and no RubyGems. In the browser it cannot read your files, so OCRAN
|
|
609
|
+
bundles the program's files into one script, in the order they are
|
|
610
|
+
required.
|
|
611
|
+
|
|
612
|
+
In both cases the script is not run at build time. OCRAN scans the program
|
|
613
|
+
and reports what may not work on the chosen runtime, grouped into your code
|
|
614
|
+
and each gem:
|
|
615
|
+
|
|
616
|
+
* gems the runtime cannot load;
|
|
617
|
+
* threads, processes, sockets and `gets`;
|
|
618
|
+
* for PicoRuby, also CRuby standard libraries it does not have.
|
|
619
|
+
|
|
620
|
+
The build goes ahead anyway, since the program only fails if it reaches
|
|
621
|
+
those parts. The runtimes are downloaded from the npm registry once, checked
|
|
622
|
+
against the integrity hash the registry publishes, and cached in
|
|
623
|
+
`~/.cache/ocran/npm`.
|
|
624
|
+
|
|
348
625
|
### Compilation:
|
|
349
626
|
|
|
350
627
|
* OCRAN runs your script (using `Kernel#load`) and builds the output when it exits.
|
|
@@ -384,6 +661,41 @@ On Windows, run the batch file:
|
|
|
384
661
|
|
|
385
662
|
myapp\script.bat
|
|
386
663
|
|
|
664
|
+
### Running as a Windows service
|
|
665
|
+
|
|
666
|
+
The self-extracting `.exe`, the wrapper `.exe` and the launch script all
|
|
667
|
+
start the packed `ruby.exe` as a child process. The Windows service control
|
|
668
|
+
manager accepts the service dispatcher only from the process it started
|
|
669
|
+
itself, so a service registered through any of them fails with error 1063
|
|
670
|
+
("The service process could not connect to the service controller").
|
|
671
|
+
|
|
672
|
+
Build with `--output-dir` (or `--innosetup`) instead and register the packed
|
|
673
|
+
interpreter directly, e.g. with `sc create` or the
|
|
674
|
+
[win32-service](https://github.com/chef/win32-service) gem's
|
|
675
|
+
`Win32::Service.create`:
|
|
676
|
+
|
|
677
|
+
ocran service.rb --output-dir C:\MyService
|
|
678
|
+
sc create MyService binPath= "C:\MyService\bin\ruby.exe C:\MyService\src\service.rb"
|
|
679
|
+
|
|
680
|
+
That bare `ruby.exe` still gets the package's environment: OCRAN packs a
|
|
681
|
+
RubyGems startup hook (`lib/ruby/site_ruby/<version>/rubygems/defaults/operating_system.rb`)
|
|
682
|
+
that sets `GEM_HOME`, `GEM_PATH`, `RUBYLIB`, `SSL_CERT_FILE` and the other
|
|
683
|
+
variables of the launch script to the directory's actual location, unless
|
|
684
|
+
they are already set, clears those the launch script clears
|
|
685
|
+
(`BUNDLE_GEMFILE`), and then loads the Ruby installation's own one
|
|
686
|
+
(RubyInstaller's). OCRAN leaves the hook out, and warns, when the building
|
|
687
|
+
Ruby has such a file in its `site_ruby` already or keeps `site_ruby` outside
|
|
688
|
+
its installation directory; then set those variables in the service's
|
|
689
|
+
environment yourself. The hook does not change the working directory (a service
|
|
690
|
+
starts in `C:\Windows\System32`), so find your files from `__dir__`. If the
|
|
691
|
+
script the launch script runs is a generated `ocran-rubyopt-launcher.rb`
|
|
692
|
+
(`-I`/`-r` in `RUBYOPT`), register that one.
|
|
693
|
+
|
|
694
|
+
OCRAN runs the script at build time, where the service's `mainloop` cannot
|
|
695
|
+
work: skip it with `defined?(Ocran)` (see "Detecting OCRAN at build time")
|
|
696
|
+
and `require` there what the service only loads later, such as `net/http`,
|
|
697
|
+
so that it gets packed.
|
|
698
|
+
|
|
387
699
|
### Pitfalls:
|
|
388
700
|
|
|
389
701
|
* Avoid modifying load paths at runtime. Use `-I` or `RUBYLIB` if needed, but don't expect OCRAN to preserve them for runtime. OCRAN may pack sources into other directories than you
|
|
@@ -500,10 +812,10 @@ Notes:
|
|
|
500
812
|
|
|
501
813
|
## Requirements
|
|
502
814
|
|
|
503
|
-
* Ruby 3.
|
|
504
|
-
* For building Windows `.exe`: Windows with [RubyInstaller DevKit](https://rubyinstaller.org/downloads/) (mingw-w64), or Wine on Linux/macOS
|
|
815
|
+
* Ruby 3.3+
|
|
816
|
+
* For building Windows `.exe`: Windows with [RubyInstaller DevKit](https://rubyinstaller.org/downloads/) (mingw-w64), or Wine on Linux/macOS. An mswin Ruby (built with Visual C++, see [mswin Ruby](#mswin-ruby-visual-c)) works as well.
|
|
505
817
|
* For building Linux and MacOS binaries: the respective build tools
|
|
506
|
-
* For `--output-dir` / `--output-zip`: any platform with Ruby 3.
|
|
818
|
+
* For `--output-dir` / `--output-zip`: any platform with Ruby 3.3+
|
|
507
819
|
* For `--output-zip` on Linux/macOS: the `zip` command must be available
|
|
508
820
|
* For `--output-zip` on Windows: PowerShell (included in Windows 8+)
|
|
509
821
|
|
|
@@ -515,6 +827,32 @@ The architecture of the generated executable matches the Ruby interpreter used t
|
|
|
515
827
|
|
|
516
828
|
* **Windows on ARM (Windows 11 ARM)** — RubyInstaller recently started shipping ARM64 builds; Installing the ARM64 RubyInstaller on a Windows ARM machine and running OCRAN from it will produce an ARM64 `.exe`. These run on ARM Windows natively. Installing the standard x86-64 RubyInstaller on a Windows ARM machine and running OCRAN from it will (probably?) produce an x86-64 `.exe`. These run on ARM Windows via the built-in x86-64 emulation layer, so the executables work on both ARM and x86-64 Windows targets. If you use `--no-lzma`, note that `lzma.exe` (the bundled compressor) is also x86-64 and relies on the same emulation.
|
|
517
829
|
|
|
830
|
+
### mswin Ruby (Visual C++)
|
|
831
|
+
|
|
832
|
+
OCRAN also packages with an mswin Ruby (`x64-mswin64_140`), the Ruby built
|
|
833
|
+
with Microsoft Visual C++ instead of MinGW, e.g. the official builds from
|
|
834
|
+
<https://cache.ruby-lang.org/pub/ruby/binaries/mswin64/> or
|
|
835
|
+
`ruby/setup-ruby` with `ruby-version: mswin`. There is no MSYS2 devkit:
|
|
836
|
+
|
|
837
|
+
* The source gem (and `rake build` in a checkout) compiles the stubs with
|
|
838
|
+
`nmake -f src/Makefile.mswin`, so run it from a Visual Studio developer
|
|
839
|
+
prompt (`vcvars64.bat`, Build Tools with the C++ workload), as for any
|
|
840
|
+
native gem on mswin. The stubs link the C runtime statically.
|
|
841
|
+
* The Ruby DLL of an mswin Ruby links the Visual C++ runtime
|
|
842
|
+
(`vcruntime140.dll`), which is not part of Windows: without the
|
|
843
|
+
[VC++ Redistributable](https://learn.microsoft.com/cpp/windows/latest-supported-vc-redist)
|
|
844
|
+
`ruby.exe` cannot start. OCRAN bundles the VC++ runtime DLLs next to the
|
|
845
|
+
packed `ruby.exe` (app-local deployment), so the executable runs on a
|
|
846
|
+
machine without the Redistributable.
|
|
847
|
+
* The libraries an mswin Ruby uses from vcpkg (gmp, libffi, OpenSSL,
|
|
848
|
+
libyaml, zlib) live next to `ruby.exe`. OCRAN reads the import tables of
|
|
849
|
+
`ruby.exe`, the Ruby DLL and the packed extensions and bundles the DLLs
|
|
850
|
+
they need from there, even with `--no-autodll` (as it packs RubyInstaller's
|
|
851
|
+
`ruby_builtin_dlls`).
|
|
852
|
+
* If the packed interpreter still cannot load a DLL, the executable says so
|
|
853
|
+
(`The Ruby interpreter could not start: a DLL it needs was not found`)
|
|
854
|
+
instead of exiting silently with status 0xC0000135.
|
|
855
|
+
|
|
518
856
|
## Development
|
|
519
857
|
|
|
520
858
|
### Quick start
|
|
@@ -536,7 +874,7 @@ The architecture of the generated executable matches the Ruby interpreter used t
|
|
|
536
874
|
|
|
537
875
|
| Task | Purpose |
|
|
538
876
|
|--------------|------------------------------------------------------------------------|
|
|
539
|
-
| `rake build` | Compile stub(.exe) (requires
|
|
877
|
+
| `rake build` | Compile stub(.exe) (requires mingw-w64 + DevKit, MSVC with an mswin Ruby, or Unix build tools) |
|
|
540
878
|
| `rake clean` | Remove generated binaries |
|
|
541
879
|
| `rake test` | Execute all unit & integration tests |
|
|
542
880
|
|
|
@@ -1035,10 +1373,176 @@ actually encrypts stay out of reach until CosmoRuby's `openssl` grows a
|
|
|
1035
1373
|
cipher surface — mbedtls has AES, GCM and PKCS5, so it is a bounded job;
|
|
1036
1374
|
it is tracked in `PORTING-NOTES.md` in the CosmoRuby repository.
|
|
1037
1375
|
|
|
1038
|
-
##
|
|
1376
|
+
## FAQ
|
|
1377
|
+
|
|
1378
|
+
### How do I convert a Ruby script into an .exe?
|
|
1039
1379
|
|
|
1040
|
-
|
|
1041
|
-
|
|
1380
|
+
Install OCRAN on Windows and run it on your entry script:
|
|
1381
|
+
|
|
1382
|
+
gem install ocran
|
|
1383
|
+
ocran app.rb
|
|
1384
|
+
|
|
1385
|
+
The result is `app.exe`, which contains your script, the Ruby interpreter,
|
|
1386
|
+
the gems it loaded and the DLLs they need. On Linux and macOS the same
|
|
1387
|
+
command produces a native executable `./app`.
|
|
1388
|
+
|
|
1389
|
+
### Does the target machine need Ruby installed?
|
|
1390
|
+
|
|
1391
|
+
No. The executable carries its own Ruby interpreter, standard library,
|
|
1392
|
+
gems and native libraries.
|
|
1393
|
+
|
|
1394
|
+
### Can I build a Windows .exe on Linux or macOS?
|
|
1395
|
+
|
|
1396
|
+
Not with the default mode: OCRAN bundles the Ruby of the machine it runs
|
|
1397
|
+
on, so build a Windows `.exe` on Windows (for example on a GitHub Actions
|
|
1398
|
+
Windows runner, see
|
|
1399
|
+
[Building for multiple platforms](#building-for-multiple-platforms-with-github-actions)),
|
|
1400
|
+
or run a Windows Ruby and OCRAN under Wine on Linux/macOS.
|
|
1401
|
+
Two experimental modes package without the target's own Ruby:
|
|
1402
|
+
`--static-runtime` with a Windows runtime builds a Windows `.exe` on
|
|
1403
|
+
Linux (and the other way round), and `--cosmo-ruby` packages a
|
|
1404
|
+
cosmopolitan Ruby into one file that runs on Windows, Linux and macOS.
|
|
1405
|
+
|
|
1406
|
+
### What is the difference between OCRA and OCRAN?
|
|
1407
|
+
|
|
1408
|
+
OCRAN is a maintained fork of OCRA. OCRA targets Windows only and is no
|
|
1409
|
+
longer updated for current Ruby versions; OCRAN supports Ruby 3.3+, builds
|
|
1410
|
+
for Windows, Linux and macOS, and adds directory, zip, macOS `.app` and
|
|
1411
|
+
Inno Setup output. To migrate, call `ocran` instead of `ocra` and replace
|
|
1412
|
+
`OCRA_EXECUTABLE` with `OCRAN_EXECUTABLE` in your code.
|
|
1413
|
+
|
|
1414
|
+
### Which gems and native extensions are supported?
|
|
1415
|
+
|
|
1416
|
+
OCRAN runs your script once at build time and records every file that
|
|
1417
|
+
`require` and `load` pull in, including compiled extensions and the DLLs
|
|
1418
|
+
or shared libraries they link. In the default mode, gems with native extensions
|
|
1419
|
+
(for example `sqlite3`, `pg`, `nokogiri`) are packaged along with their
|
|
1420
|
+
libraries; the experimental `--cosmo-ruby` mode only supports the native
|
|
1421
|
+
extensions built into its interpreter. Use
|
|
1422
|
+
`--gemfile` to include everything from a Bundler `Gemfile`, and the
|
|
1423
|
+
[gem detection modes](#gem-content-detection-modes) to include extra files.
|
|
1424
|
+
|
|
1425
|
+
### Can I package a Rails, GUI or command-line app?
|
|
1426
|
+
|
|
1427
|
+
Yes. Command-line tools work out of the box, GUI apps can use
|
|
1428
|
+
`--windows` to hide the console on Windows, and Rails apps with SQLite are
|
|
1429
|
+
covered in [Packaging a Rails application](#packaging-a-rails-application).
|
|
1430
|
+
|
|
1431
|
+
### Why does my packaged app start slowly?
|
|
1432
|
+
|
|
1433
|
+
The default self-extracting executable unpacks Ruby to a temporary
|
|
1434
|
+
directory on every launch. Use `--output-dir`, `--output-zip` or
|
|
1435
|
+
`--innosetup` to install the files once, `--static-runtime` for a single
|
|
1436
|
+
executable that runs without extracting, or `--cosmo-ruby` with an
|
|
1437
|
+
interpreter that supports ZIP packaging (CosmoRuby `v4.0.6-cosmo3` or
|
|
1438
|
+
newer) to run without extracting; with other interpreters `--cosmo-ruby`
|
|
1439
|
+
falls back to a launcher stub that extracts on every start.
|
|
1440
|
+
|
|
1441
|
+
### My antivirus flags the generated .exe. What can I do?
|
|
1442
|
+
|
|
1443
|
+
Self-extracting executables that unpack an interpreter are a common
|
|
1444
|
+
heuristic trigger. Sign the executable (OCRAN output is code-signing
|
|
1445
|
+
compatible, e.g. with `signtool` on Windows), ship an
|
|
1446
|
+
installer built with `--innosetup`, or ship a plain directory with
|
|
1447
|
+
`--output-dir`.
|
|
1448
|
+
|
|
1449
|
+
## Comparison with other Ruby packagers
|
|
1450
|
+
|
|
1451
|
+
| Tool | Output | Platforms | Single file | Maintained for current Ruby |
|
|
1452
|
+
|------|--------|-----------|-------------|--------------------------|
|
|
1453
|
+
| **OCRAN** | `.exe` / native binary, directory, zip, macOS `.app`, Inno Setup installer | Windows, Linux, macOS | Yes | Yes |
|
|
1454
|
+
| [OCRA](https://github.com/larsch/ocra) | `.exe` | Windows only | Yes | No |
|
|
1455
|
+
| [Traveling Ruby](https://github.com/trubygems/traveling-ruby) | Prebuilt Ruby runtime you ship next to your app | Windows, Linux, macOS | No | Yes |
|
|
1456
|
+
| [Tebako](https://github.com/tamatebako/tebako) | Single binary with an embedded filesystem | Windows, Linux, macOS | Yes | Yes |
|
|
1457
|
+
| [ruby-packer](https://github.com/pmq20/ruby-packer) | Single binary with Ruby compiled from source | Windows, Linux, macOS | Yes | No |
|
|
1458
|
+
|
|
1459
|
+
OCRAN's distinguishing features are that, in its default mode, it needs no
|
|
1460
|
+
C compiler to package an app (it reuses your installed Ruby), detects dependencies by running
|
|
1461
|
+
your script, and can produce installers and macOS app bundles directly.
|
|
1462
|
+
|
|
1463
|
+
See also: [State of Ruby Packagers](https://gist.github.com/YOU54F/3775e66e6090e0371c11601e6b75c305).
|
|
1464
|
+
|
|
1465
|
+
## Security, dependencies and reproducibility
|
|
1466
|
+
|
|
1467
|
+
A packager decides which interpreter, libraries and gems end up on your
|
|
1468
|
+
users' machines, so where those come from matters as much as the
|
|
1469
|
+
packaging itself. OCRAN is built so that nothing reaches the executable
|
|
1470
|
+
that you did not install, run and test yourself, and so that you can
|
|
1471
|
+
check what went in.
|
|
1472
|
+
|
|
1473
|
+
**No hidden downloads.** In its default mode OCRAN makes no network
|
|
1474
|
+
requests: it does not fetch an interpreter, prebuilt runtime, patched
|
|
1475
|
+
Ruby source or library tarball while packaging. The executables it
|
|
1476
|
+
produces, in every mode, never download a runtime when they start. Some
|
|
1477
|
+
packaging approaches ship a small launcher that pulls the actual runtime
|
|
1478
|
+
from the internet on first launch; the app then depends on a server
|
|
1479
|
+
being reachable and trustworthy long after you released it. An OCRAN
|
|
1480
|
+
executable carries the interpreter, gems and libraries it runs; whether
|
|
1481
|
+
your app uses the network is up to your own code. The opt-in modes that
|
|
1482
|
+
do fetch say so and verify what they get:
|
|
1483
|
+
|
|
1484
|
+
* `--wasm` downloads the ruby.wasm or PicoRuby package from the npm
|
|
1485
|
+
registry once, checks it against the SHA-512 integrity the registry
|
|
1486
|
+
publishes, and caches it, so later builds run offline.
|
|
1487
|
+
* `--static-runtime` fetches the source gem of a precompiled platform gem
|
|
1488
|
+
from your configured gem sources when it has to build that gem's
|
|
1489
|
+
extension for the runtime.
|
|
1490
|
+
|
|
1491
|
+
**Your Ruby, from the source you already trust.** By default OCRAN
|
|
1492
|
+
packages the Ruby interpreter installed on the build machine —
|
|
1493
|
+
RubyInstaller, a distribution package, `ruby-build`, `ruby/setup-ruby` in
|
|
1494
|
+
CI, or your own build. It does not substitute a separately built or
|
|
1495
|
+
patched interpreter from a third party. Security fixes reach your app the
|
|
1496
|
+
same way they reach your development machine: update Ruby, rebuild.
|
|
1497
|
+
Packagers that embed their own copy of Ruby and its C libraries (OpenSSL,
|
|
1498
|
+
zlib, libyaml, libffi, ...) freeze those versions at whatever the
|
|
1499
|
+
packager last shipped, and fall behind on security fixes when the
|
|
1500
|
+
packager stops being updated. The `--static-runtime` runtimes are built
|
|
1501
|
+
by scripts in this repository (`runtime/`) that you can run yourself;
|
|
1502
|
+
OCRAN checks a runtime against the SHA-256 recorded in its
|
|
1503
|
+
`runtime.json`.
|
|
1504
|
+
|
|
1505
|
+
**Exactly the gems and libraries you tested.** Dependencies are not
|
|
1506
|
+
resolved again at packaging time. OCRAN runs your script, records the
|
|
1507
|
+
files Ruby actually loaded, and packs those files from your installed
|
|
1508
|
+
gems — the versions pinned in your `Gemfile.lock` when you build under
|
|
1509
|
+
Bundler. Native libraries are taken from the same installation your
|
|
1510
|
+
extensions were loaded from. There is no second dependency resolution
|
|
1511
|
+
that could pick a different version than the one you ran.
|
|
1512
|
+
|
|
1513
|
+
**Reproducible builds.** The bundled interpreter and dependencies are
|
|
1514
|
+
determined by three things you control: the Ruby installation (or static
|
|
1515
|
+
runtime), the installed gems (or `Gemfile.lock`) and the OCRAN version;
|
|
1516
|
+
the rest of the artifact follows from your application source and the
|
|
1517
|
+
OCRAN options you pass. Pin them — e.g. a fixed `ruby-version` in
|
|
1518
|
+
`ruby/setup-ruby` plus a committed `Gemfile.lock` — and every build
|
|
1519
|
+
packages the same interpreter, gems and libraries. OCRAN's own stubs are
|
|
1520
|
+
built reproducibly (no timestamps in the PE header), the Windows, Linux
|
|
1521
|
+
and macOS static runtimes are reproducible, and `--static-runtime`
|
|
1522
|
+
executables are byte-reproducible on all three systems; CI packages a
|
|
1523
|
+
test application twice and requires the same bytes.
|
|
1524
|
+
|
|
1525
|
+
**Inspect what went in.** Build with `--output-dir` and look at the
|
|
1526
|
+
directory, or run an executable with `--debug-extract`. A
|
|
1527
|
+
`--static-runtime` executable is a plain ZIP archive behind the runtime:
|
|
1528
|
+
`unzip -l app.exe` lists exactly what will run, and
|
|
1529
|
+
`ocran/manifest.sha256` inside it records the SHA-256 of the runtime and
|
|
1530
|
+
of every file.
|
|
1531
|
+
|
|
1532
|
+
**Verifiable OCRAN releases.** The launcher stubs (`stub.exe`,
|
|
1533
|
+
`stubw.exe` and the Linux/macOS `stub`) are about 4,000 lines of C in
|
|
1534
|
+
`src/`, compiled from this repository by GitHub Actions. Released gems
|
|
1535
|
+
and the CI-built static runtimes carry signed build provenance
|
|
1536
|
+
attestations (`gh attestation verify <file> -R Largo/ocran`); from 1.5.1
|
|
1537
|
+
on, each GitHub release has the three runtimes attached next to the gems,
|
|
1538
|
+
and gems are pushed to rubygems.org with Sigstore attestations. The only
|
|
1539
|
+
third-party binary is `lzma.exe`, taken unmodified from the official
|
|
1540
|
+
7-Zip release (see [Safety](#safety)).
|
|
1541
|
+
|
|
1542
|
+
The trade-off: keeping the bundled Ruby patched is your job, just as it
|
|
1543
|
+
is for the Ruby you develop with. The experimental `--cosmo-ruby` mode
|
|
1544
|
+
packages a cosmopolitan interpreter file you choose, such as a CosmoRuby
|
|
1545
|
+
release, as given.
|
|
1042
1546
|
|
|
1043
1547
|
## Credits
|
|
1044
1548
|
|
data/ext/extconf.rb
CHANGED
|
@@ -2,7 +2,11 @@ gem_root = File.expand_path('..', __dir__)
|
|
|
2
2
|
src_dir = File.join(gem_root, 'src')
|
|
3
3
|
stub_dir = File.join(gem_root, 'share', 'ocran')
|
|
4
4
|
|
|
5
|
-
if
|
|
5
|
+
if RUBY_PLATFORM.include?('mswin')
|
|
6
|
+
# Visual C++ (needs a Visual Studio developer prompt, as any mswin gem build)
|
|
7
|
+
Dir.chdir(src_dir) { system('nmake', '-nologo', '-f', 'Makefile.mswin', 'install') } ||
|
|
8
|
+
abort('Build failed (run from a Visual Studio developer prompt / vcvars64.bat)')
|
|
9
|
+
elsif Gem.win_platform?
|
|
6
10
|
system('ridk', 'exec', 'make', '-C', src_dir, 'install') ||
|
|
7
11
|
system('make', '-C', src_dir, 'install') ||
|
|
8
12
|
abort('Build failed')
|