Luaをスクリプトエンジン部に使うのはちょっと苦労しますが十分に使えることが前回までに確認できました。
で、今回はなぜかRubyの組み込みを使って動かしてみることを考えてみることにしました。RubyもC言語(C++)から読み込むことが可能ですので似たようなことが出来るかな~と思っていました。
が、そんな甘い物ではありませんでした。甘くなかった理由が・・・
そもそもライブラリがうまくコンパイルできない
Luaで試したときは単純にプロジェクトを作ってコンパイルするだけで良かったのですが・・・。
Rubyの場合はWindowsの場合はnmake経由でコンパイルしないとコンパイルがとても複雑になってしまうところにあります。
これはRubyの場合は付属するライブラリ群(サブルーチンや文字コード変換など)が外付けのライブラリ扱いなのでこれも同時にコンパイルしなければならないので
それを行うためにnmake経由になっています。コンパイルされているバイナリの場合、configのチェックに引っかかることがあるので使わない方がいいと思います。
で、そのための前段階がややこしことややこしいこと・・・。
しかも(後述もしますが)Ruby1.9系とRuby2.0系では私の環境ではいろいろと問題が出て
- Ruby1.9系:コンパイル時に(本体側に実行可能な)Rubyが必要と言うことを言われてそれ以上コンパイルが進まない
- Ruby2.0系:コンパイルオプションを変更してみたがC言語側に組み込んでの実行時にSegmentFaultによるメモリエラーでうまく動かない(Ruby本体は一応動く)
と言う事態となり、やむなくRuby1.8系でのテストとなりました。
ライブラリの作成手順そのものはRuby1.8系だろうがRuby1.9系だろうがRuby2.0系だろうがだいたい同じです。
なお、コンパイルにはVisualStudio2005を使用していますのでこれでないときはちょっと動作が違うかもしれません。
(もしかすると新しいVisualStudioを使うとRuby2.0系のメモリエラーが無くなるかも)
1.Rubyのソースコードをダウンロード
Rubyのページよりコードをダウンロードします。
安定版のコードであれば問題ないと思います。今回のテストにはRuby1.8.7-p371(もしくはRuby2.0.0-p0)をダウンロードします。
2.Rubyのソースコードを展開
自分の環境にコードを展開します。C:\hogeにRuby1.8系とRuby2.0系を両方とも展開したとき(一段目しか書きませんが)
C:\hoge ├─ruby-1.8.7-p371 │ ├─bcc32 │ ├─bin │ ├─cygwin │ ├─djgpp │ ├─doc │ ├─ext │ ├─lib │ ├─misc │ ├─missing │ ├─sample │ ├─test │ ├─vms │ ├─win32 │ ├─wince │ └─x68 └─ruby-2.0.0-p0 ├─bcc32 ├─benchmark ├─bin ├─bootstraptest ├─cygwin ├─defs ├─doc ├─enc ├─ext ├─include ├─lib ├─man ├─misc ├─missing ├─nacl ├─sample ├─spec ├─symbian ├─template ├─test ├─tool └─win32
のようになります。
3. コンパイルされたファイルの置き場所を生成
これを作らないとコンパイル時にオブジェクトファイルの状態がおかしくなってしまうことがあるようです。(Ruby2.0系で確認)
とりあえずC:\hogeに適当にディレクトリを作成します。今回はmakerubyとします。
4. win32用のconfigureを実行
以降の実行はVisualStudioのコマンドプロンプト内(VisualStudioのコンパイラなどにパスが通ったコマンドプロンプト)で行います。
configureの実行についてはREADMEにも書いてありますが、基本的にはそのまま
C:\hoge\makeruby>C:\hoge\ruby-1.8.7-p371\win32\configure
と実行すれば問題ありません。
64bit版をコンパイルするときは–targetにより
C:\hoge\makeruby>C:\hoge\ruby-1.8.7-p371\win32\configure --target=x64-mswin64
を指定しておくことを忘れずに。Rubyのバージョン違いの場合は指定するディレクトリが変わるだけでオプションは変える必要はありません。
微妙に違うオプションを指定することも出来るので気になる人はconfigureから状態を見てみるといいかもしれません。
5. nmakeでバイナリを作成
ちなみに、そのままnmakeを行うと対象のVisualStudioのバージョンに応じたランタイムDLLを使用するようになります。
これは作成されるライブラリ(DLL,Lib)以外にもrubyの実行ファイルもランタイムDLLを使うようになります。それで問題ないのであれば
C:\hoge\makeruby>nmake
と簡潔に書きます。ランタイムを静的リンクさせたい場合は
C:\hoge\makeruby>nmake RUNTIMEFLAG=-MT
とします。後は終了を待つだけです。
6. 実行に必要なデータを拾ってくる
インストールさせずに必要なファイルだけ作成されたファイルをコピーします。対象は以下の通り。
表記中の*.hは対象のディレクトリにある.hがつくすべてファイルと言う意味です。
[Ruby1.8系の場合]
組み込みRuby実行用DLL C:\hoge\makeruby\msvcr80-ruby18.dll 組み込みRuby実行用DLLのライブラリ C:\hoge\makeruby\msvcr80-ruby18.lib 組み込みRuby実行用ライブラリ(静的リンク) C:\hoge\makeruby\msvcr80-ruby18-static.lib インクルードファイル(本体部) C:\hoge\ruby-1.8.7-p371\*.h インクルードファイル(Win32定義部) C:\hoge\ruby-1.8.7-p371\win32\win32.h インクルードファイル(生成時設定部) C:\hoge\makeruby\config.h インクルードファイルを配置すると
└─include │ config.h │ defines.h │ dln.h │ env.h │ intern.h │ missing.h │ node.h │ re.h │ regex.h │ ruby.h │ rubyio.h │ rubysig.h │ st.h │ util.h │ version.h │ └─win32 win32.hとなります。
[Ruby2.0系の場合]
組み込みRuby実行用DLL C:\hoge\makeruby\msvcr80-ruby200.dll 組み込みRuby実行用DLLのライブラリ C:\hoge\makeruby\msvcr80-ruby200.lib 組み込みRuby実行用ライブラリ(静的リンク) C:\hoge\makeruby\msvcr80-ruby200-static.lib インクルードファイル(本体部) C:\hoge\ruby-2.0.0-p0\include 以下すべてのファイル インクルードファイル(生成時設定部) C:\hoge\makeruby\.ext\include\mswin32_80\ruby\config.h インクルードファイルを配置すると
└─include │ ruby.h │ └─ruby │ debug.h │ defines.h │ digest.h │ dl.h │ encoding.h │ intern.h │ io.h │ missing.h │ oniguruma.h │ re.h │ regex.h │ ruby.h │ st.h │ subst.h │ thread.h │ util.h │ version.h │ vm.h │ win32.h │ ├─backward │ classext.h │ rubyio.h │ rubysig.h │ st.h │ util.h │ └─ruby config.hとなります。
組み込みを使用するテストルーチン
こんな感じですか。
#include <stdio.h> #include "include/ruby.h" #pragma comment(lib,"ruby187-static.lib") #pragma comment(lib,"ws2_32.lib") //#pragma comment(lib,"imagehlp.lib") //#pragma comment(lib,"shlwapi.lib") int main(void) { ruby_init(); ruby_init_loadpath(); //rb_load(rb_str_new2("test.rb"), 0); rb_eval_string("puts 'Hello World'"); ruby_finalize(); //ruby_cleanup(0); return 0; }
いくつかコメントアウトがかかっていますが、pragmaの方はRuby2.0系用のライブラリの連結指示です。
rb_loadのコメントアウトは直接実行テストとファイルからの読み込みテストを分けた物です。
これが正常に実行できればとりあえず正常に生成できた、と言うことで・・・。
なお、Ruby2.0系の場合、私の環境で構築した場合はこのルーチンのruby_finalize()でメモリアクセスエラーを起こした、と言う報告が入り以降解決法が分からず、と言うことになっています。
ファイル側のテストでもファイルのロードを抜ける前にエラーが起きていますのでエンジンの実行部のコンパイルに何か問題があったのかもしれません。
調べてみるとADVエンジンでは使いにくいような気が
そもそも、Ruby本体は内部にGPLのコードを持っている関係上、基本的にGPL汚染が起こりますので公開する気がないのであれば使えませんね。
一般のゲームで組み込みが中にあることが発覚した時点で大変なことになりますね~。その部分だけ分離、と言うのも難しそうですし。
また、あまりC言語本体との連結が良くないようでその意味では使いづらいようです。
ルーチン本体もプログラムとかなりくっついていてRuby内部からWinAPIなどを呼び出す分にはそれなりですが。
ライブラリの作成がかなり手順を踏まないとうまく作成出来ないのがかなりマイナス点ですね。
Ruby自体はとてもいい言語なんですが・・・。
結局ADVエンジンとしてのスクリプト言語としてはLuaの時と同様の問題点を持ちますので
使う場合はそれも考えて使えるかどうかを判定していく必要がありそうですね・・・。
そういう目的では、mrubyもどうでしょうか?と言っても、私も使ったことないのですが、指向性としては向いているような気がします。