Slide 1

Slide 1 text

ahogappa kompoのその後 RubyKaigi 2024 followup 1

Slide 2

Slide 2 text

© 2020 Coiney, Inc. ● ahogappa ● STORES, Inc 自己紹介 2 2

Slide 3

Slide 3 text

© 2020 Coiney, Inc. ● RubyとRubyスクリプトをワンバイナリにする gem(kompo)を作った話 ○ モチベーション ○ デモ ○ 実装方法 ○ Future Works RubyKaigiで何を話したの 3 3

Slide 4

Slide 4 text

© 2020 Coiney, Inc. ● RubyKaigiでFuture Worksとしていた部分 ○ 内部ファイルシステムへの自由なアクセス ○ クロスコンパイル ○ ファイルの圧縮 ● STORES Tech Blogに書いた記事を元に発表資料にしてい ます ○ https://product.st.inc/entry/2024/06/25/100008 ○ この記事以降に更新があった内容も含まれています 今日話すこと 4 4

Slide 5

Slide 5 text

© 2020 Coiney, Inc. ● お手軽であること ○ 簡単にワンバイナリ化できて欲しい ○ 複雑なオプションはなるべくいらないようにしたい ● それなりに速度が出ること ○ 簡単にできても遅くなってしまうと、元のコードを チューニングする必要があったり、諦めてしまう ○ クロスコンパイルできること kompoのコンセプト 5 5

Slide 6

Slide 6 text

© 2020 Coiney, Inc. ● requireをパッチすることで、 内部ファイルシステムにアクセスしている 内部ファイルシステムへの自由なアクセス 6 6

Slide 7

Slide 7 text

© 2020 Coiney, Inc. ● requireの代わりに `eval File.read(“hoge.rb”)` を実行す るようなコードが対応できない ○ 例えばRubyGems gem ○ デモの時は誤魔化していた ● 内部ファイルにアクセスできる手段をrequire以外にも開 放する ○ 内部ファイルを取得したい!を明示的にできるような 何かを作る必要がある 内部ファイルシステムへの自由なアクセス 7 7

Slide 8

Slide 8 text

© 2020 Coiney, Inc. ● 実現するためにやらないといけないこと ● “ちゃんとした”ファイルシステムの構築 ● open, readなどの関数をパッチする => パッチした関数が呼ばれたら内部ファイルシステムに繋げる ● “ちゃんとした”ファイルシステムの構築 ○ 今はファイルの中身を巨大なバイト列として保持している ○ ディレクトリの情報や更新情報などのfile statに必要な情報を 持っていない ● open, readなどの関数をパッチする ○ ruby-packer gemはこの方法でrailsまで動かしている 内部ファイルシステムへの自由なアクセス 8 8

Slide 9

Slide 9 text

© 2020 Coiney, Inc. ● ファイルシステムとして必要な機能は基本的に読み込みだけ ○ 書き込みが要求されたら、本物のファイルシステムを使ってあげる ○ ファイルパスを与えられたらfd(のような何か)を返して、fdでアク セスされたらデータを返すような実装をすればいいはず ● FUSEも試してみた ○ macはmacfuse、windowsはそもそもない?ということで、環境差 異がありそう ○ バイナリを実行する環境にfusermountコマンドのインストールが 必要 “ちゃんとした”ファイルシステムの構築 9 9

Slide 10

Slide 10 text

© 2020 Coiney, Inc. ● 関数をパッチする方法 ○ #defineを使ってコンパイル時に関数を置き換える ○ LD_PRELOADを使ってリンクする関数を変える ○ -Wl,--wrapを使ってリンク時に関数を読み替える ● ruby-packer では#defineを使ってパッチしている ○ ruby本体に変更を加える必要がある ○ rubyの変更に追従する必要がある ● LD_PRELOADは共有ライブラリにする必要がある ○ 動的リンク時に解決 ○ パッチファイルを共有ライブラリにして配布する必要がある ● -Wl,--wrapが使えそう...? ○ rubyに変更を加える必要がない&静的リンクで解決 ○ GNU Linker限定のオプション ● 別解でIFUNCとかもありそう open, readなどの関数をパッチする 10 10

Slide 11

Slide 11 text

© 2020 Coiney, Inc. ● -Wl,--wrapってどんなことをやっているのかlldとmoldの コードを読む ● 意外とやっていることは少ない open, readなどの関数をパッチする 11 11 ref: https://github.com/rui314/mold/blob/ed4cae93542350c863eff7e10131272b4c01fe0e/src/input-files.cc#L641-L652

Slide 12

Slide 12 text

© 2020 Coiney, Inc. ● リンカの種類に依存せずにこれを実現できないか ● とはいえリンカを作るのは大変すぎる ● シンボルを読み替えればいいだけなので、コンパイル後バ イナリを編集したらできそう? ○ libstatic-ruby.aに対してバイナリ編集する ○ rubyだけで実現できれば、rustを使う必要がなくなる ○ LIEFのruby版みたいなのを作る必要がある open, readなどの関数をパッチする 12 12

Slide 13

Slide 13 text

© 2020 Coiney, Inc. ● やりたいが、全然何も考えられていない ○ 特にWindows ● 先程のバイナリ編集はELFを想定しているので、Mach-O, PEのことを考える必要があるはず クロスコンパイル 13 13

Slide 14

Slide 14 text

© 2020 Coiney, Inc. ● こちらも何も考えられていない ○ 発表した当初から変わらずzlibで固めるかな... ● そもそもどんなデータをワンバイナリに含めるか ○ minifyしたもの ○ ASTを小さく表現するほうが小さくなる? ○ boot snapのように事前コンパイルしたもののほうが速 度は出そう ● ただのminifyだったらminifyrbでいいじゃないかな ファイルの圧縮 14 14

Slide 15

Slide 15 text

© 2020 Coiney, Inc. ● 関数をパッチする方法を考えている&実装している ● ELF(などの実行形式ファイル)について調べている ● やることたくさん まとめ 15 15

Slide 16

Slide 16 text

ありがとうございました! 16

Slide 17

Slide 17 text

© 2020 Coiney, Inc. ● namespace ○ 拡張ライブラリは静的リンクしたいのでリンク時に シンボルが重なってこけそう ○ マングリングする??? ○ ワンバイナリに含めておいて、それをいい感じに参照 する??? おまけ 17 17