Upgrade to Pro — share decks privately, control downloads, hide ads and more …

It’s about time to pack Ruby and Ruby scripts in one binary

It’s about time to pack Ruby and Ruby scripts in one binary

ahogappa

May 16, 2024
Tweet

Other Decks in Programming

Transcript

  1. It’s about time to pack Ruby and Ruby scripts in

    one binary RubyKaigi 2024 ahogappa
  2. Why one binary in Ruby? 💻 a.rb a.rb a.rb a.rb

    💻 Ruby 3.3.0 Sinatra 4.0.0 Sqlite3 2.0.1 developer user 10
  3. Why one binary in Ruby? 💻 a.rb a.rb a.rb a.rb

    💻🚫 Ruby 3.3.0 Sinatra 4.0.0 Sqlite3 2.0.1 Ruby 3.0.0 Sinatra 3.2.0 Sqlite3 Not installed developer user 11
  4. Why one binary in Ruby? 💻 💻 Ruby 3.3.0 Sinatra

    4.0.0 Sqlite3 2.0.1 developer user 12 Ruby 3.0.0 Sinatra 3.2.0 Sqlite3 Not installed
  5. Why one binary in Ruby? 💻 💻 one binary developer

    user Ruby 3.3.0 Sinatra 4.0.0 Sqlite3 2.0.1 13 Ruby 3.0.0 Sinatra 3.2.0 Sqlite3 Not installed
  6. Why one binary in Ruby? 💻 💻✔ one binary Ruby

    3.3.1 Sinatra 4.0.0 Sqlite3 2.0.1 a.rb a.rb a.rb a.rb developer user Ruby 3.3.1 Sinatra 4.0.0 Sqlite3 2.0.1 14 Ruby 3.0.0 Sinatra 3.2.0 Sqlite3 Not installed
  7. Existing tools look good and useful, but • No support

    for 3.0+ • Patches Ruby • Windows only • Write temporary files 18
  8. Kompo • 梱包(こんぽう) ◦ Means packaging, packing • A word

    play on “compo” ◦ compose ◦ component ◦ composite ◦ etc… 22 https://github.com/ahogappa0613/kompo
  9. Features • Monkey patch only, not patching Ruby • No

    write temporary files • Supports Gemfile • Reads local file as a fallback when failing to read from vfs 25
  10. How kompo works • Ruby scripts are embedded • Patch

    methods that read Ruby scripts ◦ Kernel#require ◦ Kernel#require_relative ◦ Kernel#load ◦ Kernel#autoload, Module#autoload • Native extensions are statically linked 28
  11. main.c 31 libruby-static.a native extensions void Init_gems(void) { ruby_init_ext( "puma/puma_http11.so",

    Init_puma_http11 ); ruby_init_ext( "sqlite3/sqlite3_native.so", Init_sqlite3_native ); } int main(int argc, char **argv) { ruby_sysinit(&argc, &argv); ruby_init(); Init_gems(); Init_kompo_fs(); … return ruby_run_node(node); }
  12. 33 class Kompo def get_file(abs_path) # return the ruby script

    from kompofs(.o) end … end main.c libruby-static.a native extensions kompofs.o +patches libkompo.a
  13. Patches Ruby main.rb b.rb 🪡Kernel#require 🪡Kernel#require_relative c.o d.rb a.rb one

    binary libkompo.a 40 module Kernel def require(path) eval(Kompo.get_file(path)) rescue => LoadError original_require(path) main.c kompofs.o
  14. Patches Ruby main.rb b.rb 🪡Kernel#require 🪡Kernel#require_relative c.o d.rb a.rb one

    binary require ‘a’ require_relative ‘./b’ require ‘c’ require ‘d’ libkompo.a 41 module Kernel def require(path) eval(Kompo.get_file(path)) rescue => LoadError original_require(path) main.c kompofs.o
  15. Patches Ruby main.rb b.rb 🪡Kernel#require 🪡Kernel#require_relative c.o d.rb a.rb one

    binary libkompo.a 42 module Kernel def require(path) eval(Kompo.get_file(path)) rescue => LoadError original_require(path) kompofs.o require ‘a’ require_relative ‘./b’ require ‘c’ require ‘d’ main.c
  16. Future Works • Support ways for users to access kompofs

    freely • Cross-compilation • File compression 44