Build truly portable Ruby executables that run on Linux, macOS, Windows, FreeBSD, OpenBSD, and NetBSD from a single binary.
# Install
gem install portable_mruby
# Create a Ruby program
mkdir myapp
echo 'puts "Hello from #{RUBY_ENGINE}!"' > myapp/hello.rb
# Build portable executable
portable-mruby build -d myapp -o hello.com
# Run it (works on Linux, macOS, Windows, FreeBSD, OpenBSD, NetBSD)
./hello.comportable_mruby uses mruby (embedded Ruby) compiled with Cosmopolitan Libc to create "Actually Portable Executables" (APE). These are single binaries that run natively on multiple operating systems and CPU architectures without any dependencies.
A single binary runs on:
- Linux (x86_64, ARM64)
- macOS (x86_64, ARM64)
- Windows (x86_64)
- FreeBSD (x86_64)
- OpenBSD (x86_64)
- NetBSD (x86_64)
gem install portable_mrubyOn first build, the Cosmopolitan toolchain (~60MB) will be automatically downloaded to ~/.portable-mruby/cosmocc/.
# Build all .rb files in a directory
portable-mruby build -d src/ -o myapp.com
# Run on any supported platform
./myapp.comAll .rb files in the directory (recursively) are compiled and executed in sorted order.
When you have multiple files and need a specific file to run last (e.g., your main program that uses classes defined in other files):
# Specify an entry file (runs last, after all other files)
portable-mruby build -d src/ -e main.rb -o myapp.comImportant: The -e (entry) path is relative to the -d (directory) path. In the example above, it looks for src/main.rb.
Usage: portable-mruby build [options]
Options:
-d, --dir DIR Source directory containing .rb files (required)
-e, --entry FILE Entry point Ruby file, relative to -d (runs last)
-o, --output FILE Output binary name (default: app.com)
--mruby-source DIR Build mruby from custom source directory
-v, --verbose Verbose output
-h, --help Show help
Environment Variables:
COSMO_ROOT Path to cosmocc toolchain (auto-downloaded if not set)
If you need custom mruby gems or configuration, you can build from source:
# Clone mruby with your customizations
git clone https://github.com/mruby/mruby.git ~/mruby
# Build using your custom mruby
portable-mruby build -d src/ --mruby-source ~/mruby -o myapp.comCreate a simple Ruby program:
mkdir hello
cat > hello/main.rb << 'EOF'
name = ARGV[0] || 'World'
puts "Hello, #{name}!"
puts "Running on: #{RUBY_ENGINE} #{RUBY_VERSION}"
puts "Time: #{Time.now}"
EOFBuild it:
portable-mruby build -d hello -o hello.comRun it anywhere:
$ ./hello.com Alice
Hello, Alice!
Running on: mruby 3.4
Time: 2025-12-09 12:00:00 +0000myapp/
lib/
greeter.rb
main.rb
# myapp/lib/greeter.rb
class Greeter
def initialize(name)
@name = name
end
def greet
"Hello, #{@name}!"
end
end# myapp/main.rb
greeter = Greeter.new(ARGV[0] || 'World')
puts greeter.greet# Build with main.rb as entry point (runs last, after lib/greeter.rb)
portable-mruby build -d myapp -e main.rb -o greeter.com
./greeter.com Ruby # => Hello, Ruby!Files are loaded in sorted order (lib/greeter.rb before main.rb), but -e main.rb ensures it runs last regardless of sort order.
- Ruby source files are compiled to mruby bytecode using
mrbc - Bytecode is embedded in a C source file as byte arrays
- A minimal C runtime initializes mruby and loads the bytecode
- Everything is compiled with Cosmopolitan's
cosmocccompiler - The result is an APE binary - a polyglot that runs on all platforms
The gem installation may be corrupted. Reinstall:
gem uninstall portable_mruby
gem install portable_mrubyEnsure you have enough disk space (~60MB for cosmocc download, ~200MB extracted). You can also manually install cosmocc:
mkdir -p ~/.portable-mruby/cosmocc
cd ~/.portable-mruby/cosmocc
wget https://cosmo.zip/pub/cosmocc/cosmocc.zip
unzip cosmocc.zipexport COSMO_ROOT=/path/to/cosmocc
portable-mruby build -d src/ -o app.comMIT License