DEV Community

Paweł Świątkowski
Paweł Świątkowski

Posted on • Originally published at katafrakt.me

Portable mruby binaries with Cosmopolitan

One of my main interests with mruby is its ability to create standalone executables. As explored in this post, this is absolutely possible and works well. However, there is a classic issue of most standalone binaries: they can only be run on the same, or very similar, system as the one they were built on.

For example, if I take an executable from my mruby Hello World project, built on amd64 Linux, it won't work on Silicon Mac:

$ ./hello
exec: Failed to execute process: './hello' the file could not be run by the operating system.
exec: Maybe the interpreter directive (#! line) is broken?
Enter fullscreen mode Exit fullscreen mode

Mruby does have some cross-compilation capabilities, but I'll be honest: it always felt intimidating, complected and I never actually got it working from Linux to MacOS. So, are we doomed here? Is it possible to build standalone binaries for MacOS without a MacOS docker image or something?

While reading the changelog of mruby I noticed one entry there that got me curious:

New Platform: Cosmopolitan Libc

I never heard about Cosmopolitan, but a quick search revealed that it is what might address the issue mentioned above. From the project's website:

Cosmopolitan Libc makes C a build-anywhere run-anywhere language, like Java, except it doesn't need an interpreter or virtual machine. Instead, it reconfigures stock GCC and Clang to output a POSIX-approved polyglot format that runs natively on Linux + Mac + Windows + FreeBSD + OpenBSD + NetBSD + BIOS on AMD64 and ARM64 with the best possible performance.

Alright, let's give it a try then!

Building an mruby project with Cosmopolitan

The regular steps to build a standalone binary are as shown in the Rakefile:

  1. Build mruby
  2. Generate bytecode from the Ruby code, using mrbc built in step 1
  3. Compile the binary using a C entry file and the bytecode generated in step 2

For Cosmopolitan, it's simple, but we need some initial setup.

First, let's download the Cosmopolitan toolkit from https://cosmo.zip/pub/cosmocc/. I extracted it to ~/Downloads/cosmocc for the purpose of this article.

Then we can build mruby using it:

COSMO_ROOT=~/Downloads/cosmocc rake MRUBY_CONFIG=cosmopolitan
Enter fullscreen mode Exit fullscreen mode

NOTE: At the time of writing, I needed to remove mirb (this line) from the config, because it failed to compile with Cosmopolitan.

Then we can generate the bytecode. Note the different executable name:

./mruby/bin/mrbc.com -Bhello_world hello.rb
Enter fullscreen mode Exit fullscreen mode

Finally, compile the entry file:

~/Downloads/cosmocc/bin/cosmocc -std=c99 -Imruby/include main.c -o hello mruby/build/host/lib/libmruby.a -lm
Enter fullscreen mode Exit fullscreen mode

After that we get a binary hello. And if I copy it over to my Mac, it just works there! The binary size is larger, of course, which is the understandable price. But if it is fine for the project you are working on, for sure this is a simpler way than providing multiple binaries targeting different platforms.

Top comments (0)