この記事は Ruby Advent Calendar 2016 の 8 日目の記事です。
Windows で Ruby 製のアプリケーションを配布したいことがあります(例:デスクトップアプリケーション、ゲームなど)。
そういうときはたとえばスクリプトと一緒に Ruby の実行環境をまるごと配布する、Ocra を使って Ruby の実行環境をまるごと単体の exe にまとめるなどの方法があります。
Ruby の実行環境ごと配布する方法の場合、起動は bat ファイルになるでしょう。これはデスクトップアプリケーションやゲームのユーザにはちょっと馴染みのない実行方法になってしまいます。
Ocra を使う方法は実行するだけでアプリケーションを起動可能な exe にまとめられるという点で前者の方法よりはよいのですが、temp ディレクトリにまとめておいた Ruby の実行環境をまるごと出力してここで Ruby を実行するので、起動が遅く、ユーザ名に非 ASCII 文字が含まれている場合に実行できないなどの問題があります。
Ocra を使わないやり方
そこで、Ruby 2.0 が出るちょっと前くらい頃に、こういう方法はどうですか、という構想が提案されています。
exe の末尾にスクリプトが連結されていたらそれを読み込んで実行するようにする、というシンプルなアイデアです。
基本的にはこのパッチで実現できるのですが、埋め込んだスクリプトから require
がうまく動かなかったり、Ruby 2.2 や 2.3 では Ruby のコードが更新されていてパッチが当たらないので、そのあたりを対応したものを作りました。
このパッチを当ててビルドすれば末尾に連結されたスクリプトを読み込んで実行可能な Ruby のバイナリが得られます。
ビルド方法
ビルドすればというものの、Windows でそう簡単にビルドできたら……いいえ、Windows でもわりと簡単にビルドする方法はあります。
RubyInstaller という Windows 版 Ruby のビルド済みバイナリを配布しているサイトがあるんですが、そこが使っている Ruby ビルドキットがありまして、このリポジトリをクローンしてきて、rake ruby23
のようにバージョンを指定して rake
するだけで Ruby がビルドできます。
Ruby 2.3 なら resources/patches/ruby23
に 2.3 用のパッチを入れるとパッチを当てた状態でビルドしてくれます。
Windows でビルドって聞くとめちゃ大変そうなイメージありますが、キットを使うとコマンド叩くだけなのでとても簡単です。
実際にスクリプトを連結するには
copy
コマンドで連結できます。
copy /B ruby.exe+rubyapp.rb rubyapp.exe
配布には DLL とか拡張ライブラリとか必要だったりするので、スクリプトの連結から読み込んでるファイルをまとめてフォルダにコピーするところまでコマンドライン一発でできるといいなということを思ったので、そういうコマンドライン用のスクリプトを書きました。
この rpk をパッチ当ててビルドした Ruby の bin に入れて
rpk rubyapp.rb
ってやるとファイル一式まとめて dist というディレクトリにコピーします。
パッケージングするときにスクリプトと同じディレクトリ内に rpk.json というファイルを作っておいておくとそこに書かれたファイルを一緒にコピーします。
json の構造はこんな感じです。
{
"extra" : [
"resources"
]
}
extra というキーにコピーしたいディレクトリを配列で書くと dist にコピーされます。
ゆくゆくはほかにもオプションを記述できるようにということを考えています。
バージョンが決め打ちになってるところがあるので実行中のバージョン見るようにしたりとか、gem に対応してないので gem 経由のライブラリをうまいこと配置するようにとか、DLL が exe と同じ階層にずらっと並んでしまうので bin 配下に配置したいとか、いろいろ改善するところはありますが、とりあえずこれでコマンド叩けば配布用のファイル一式を揃えるところまでできます。
アイデアください
いまだと
- RubyInstaller のキットをクローンしてくる
- patches にパッチファイルを入れる
- ビルドする
- ビルドした Ruby の bin ディレクトリに rpk を入れる
- ビルドした Ruby にパスを通す(たとえば uru を使うとかあります)
という感じで割と手間なので、コマンド一発叩くと github からリポジトリ引っ張ってきてパッチ当ててビルドして rpk 入れてというところまでできるツールがあればなーということを思っています。
たとえば個人がビルド済みバイナリを用意して配布するとかでもいいんですが、件の RubyInstaller の中の人が今年の頭に交通事故にあって Ruby 2.3 のビルド済みバイナリの配布が遅れたという話を考えると、誰でもビルドできるようになってるほうがのぞましいなということを思います。
というわけで、アイデアを募集します。お気軽にお声かけください。
追記
"Luaのexe化ツールも同じ方法" という情報を ブコメ でいただいたので、ちょっと調べてみたんですけど srlua というのがあるみたいですね。ちょっと参考にしてみようかと思います。ちなみに sr は self-running の略だそうで。