2018/03/16(金) [n年前の日記]
#1 [ruby][mruby] Cで書いたプログラムからmrubyを呼び出せるか実験
SDLを使ったCのプログラムに、mrubyを組み込んで使う事例を、DXRuby作者様が昔公開してくれていたので、それのSDL2版を書いて試そうとしていたのだけど。
_SDL_imageとmrubyを使ってみた - mirichiの日記
そもそも、ビルドの仕方が分からない…。ので、まずはシンプルな形でビルドの仕方を確認しようと。以下の記事を参考にしつつ作業。
_手探りでおぼえるmruby その1:クラスを定義する、メソッドを定義する - エンジニアのソフトウェア的愛情
_mrubyで書いたコードをC言語内で読み出す方法 - Bye Bye Moore
_Hello World - mruby/mruby Wiki
環境は、Windows10 x64 + MSYS2。
_SDL_imageとmrubyを使ってみた - mirichiの日記
そもそも、ビルドの仕方が分からない…。ので、まずはシンプルな形でビルドの仕方を確認しようと。以下の記事を参考にしつつ作業。
_手探りでおぼえるmruby その1:クラスを定義する、メソッドを定義する - エンジニアのソフトウェア的愛情
_mrubyで書いたコードをC言語内で読み出す方法 - Bye Bye Moore
_Hello World - mruby/mruby Wiki
環境は、Windows10 x64 + MSYS2。
◎ ディレクトリ構成。 :
以下のような構成にしてみたり。
~/prg/mruby/mruby/ の中に、 _mruby 1.4.0 のファイル一式を置いた。
MSYS2 のシェルを起動。スタートメニュー内の、MSYS2 MinGW 32-bit (32bit) を実行。
カレントディレクトリを変更して、makeを実行してビルド。
ビルドが成功すると、以下のような状態になる。
mruby はビルドできたので、callmruby/ の中で、CソースやMakefileを用意して、mruby を組み込めそうか実験していく。
~/prg | +---- mruby | +---- callmruby | +---- mruby
~/prg/mruby/mruby/ の中に、 _mruby 1.4.0 のファイル一式を置いた。
MSYS2 のシェルを起動。スタートメニュー内の、MSYS2 MinGW 32-bit (32bit) を実行。
カレントディレクトリを変更して、makeを実行してビルド。
cd ~/prg/mruby/mruby/ make
ビルドが成功すると、以下のような状態になる。
- ~/prg/mruby/mruby/include/ 内に *.h ファイルが入ってる。(mrubyをDL・解凍した時点で既に入ってる)
- ~/prg/mruby/mruby/build/host/lib/ 内に、libmruby.a ファイルが出来上がる。この .a ファイルを、Cで書いたプログラムのビルド時にリンクする。
mruby はビルドできたので、callmruby/ の中で、CソースやMakefileを用意して、mruby を組み込めそうか実験していく。
◎ mrubyを呼び出すだけのCプログラムを書いてみる。 :
callmruby/ の中に、callmruby.c というファイル名でCソースを用意。
_callmruby.c
上記ソースは、main.rb を読み込んで実行するので、main.rb も用意する。
_main.rb
Makefile も作る。Makefile てのは、make を実行した際にどんな処理をするのか、ルールを記述するファイル。
_Makefile
ビルドする。
もし、上手く行かなかったら、以下を実行することで、作業ファイル・出力ファイルを全部消すことができる。
出来上がった .exe を実行してみる。
これで、mruby をCプログラムの中に組み込んでビルドすることはできた。ここまでは、なんとかなった…。
_callmruby.c
#include "mruby.h" #include "mruby/compile.h" #include "mruby/proc.h" #include <stdio.h> int main(int argc, char *argv[]) { // open mruby state mrb_state *mrb = mrb_open(); if (mrb == 0) { printf("cannot open mruby state.\n"); return -2; } // file open FILE *fp = fopen("main.rb", "r"); // run mruby script mrb_load_file(mrb, fp); // file close fclose(fp); // close mruby state mrb_close(mrb); return 0; }
上記ソースは、main.rb を読み込んで実行するので、main.rb も用意する。
_main.rb
puts "Hello, I am mruby." puts "Ok. mruby, your number is 7. instrument recorder on." puts "Permission to sortie." puts "Permission granted. GOOD LUCK, mruby."
Makefile も作る。Makefile てのは、make を実行した際にどんな処理をするのか、ルールを記述するファイル。
_Makefile
TARGETS = callmruby all: $(TARGETS) SDL_PREFIX = /mingw32 # SDL_PREFIX = /mingw MRB_HEAD = ../mruby/include MRB_LIBS = ../mruby/build/host/lib # CG_LIBS = CROSS_COMPILE = $(SDL_PREFIX)/bin/ CC = $(CROSS_COMPILE)gcc CXX = $(CROSS_COMPILE)g++ CFLAGS = -g -Wall -I$(MRB_HEAD) CXXFLAGS = -g -Wall -I$(MRB_HEAD) LIBS = -L$(MRB_LIBS) -lmruby -lpthread -lm LDFLAGS = -Wl,-rpath -static -static-libgcc -static-libstdc++ clean: rm -f *.o *.a *~ $(TARGETS) $(TARGETS): $(TARGETS).o $(CXX) -o $@ $^ $(LIBS) $(LDFLAGS)
- mruby の includeフォルダ、libフォルダは、相対パスで指定してる。
- LIBS に、-L$(MRB_LIBS) -lmruby を記述して、mruby をリンクするように指定してる。
- MSYS2 でビルドしたプログラムは libwinpthread-1.dll を要求するので、-lpthread と -static を記述して、スタティックリンクをするように指定してる。
ビルドする。
$ cd ~/prg/mruby/callmruby/ $ make /mingw32/bin/gcc -g -Wall -I../mruby/include -c -o callmruby.o callmruby.c /mingw32/bin/g++ -o callmruby callmruby.o -L../mruby/build/host/lib -lmruby -lpthread -Wl,-rpath -static -static-libgcc -static-libstdc++
もし、上手く行かなかったら、以下を実行することで、作業ファイル・出力ファイルを全部消すことができる。
make clean
出来上がった .exe を実行してみる。
$ ./callmruby.exe Hello, I am mruby. Ok. mruby, your number is 7. instrument recorder on. Permission to sortie. Permission granted. GOOD LUCK, mruby.Cで書いたプログラムを実行したはずなのに、main.rb に書かれた処理が実行されて、メッセージが出力された。
これで、mruby をCプログラムの中に組み込んでビルドすることはできた。ここまでは、なんとかなった…。
◎ 少し説明。 :
Cプログラムから mruby を使うときは、
_mrb_state 解説(必ずしも徹底ではない) - Qiita
mrubyスクリプトが書かれたファイルを読み込んで実行するだけなら、以下を使うのだろう。
Cにおいて、開いた何かしらは、えてして閉じないといけない。mruby も開いたのだから、閉じる。
#include "mruby.h" #include "mruby/compile.h" #include "mruby/proc.h"を書いて…。
mrb_state *mrb = mrb_open();で、mrubyの何かを開く、のかな。mrb_state ってなんだか分からんけど、コレを使って mruby のスクリプトを動かすのだろう…。
_mrb_state 解説(必ずしも徹底ではない) - Qiita
mrubyスクリプトが書かれたファイルを読み込んで実行するだけなら、以下を使うのだろう。
FILE *fp = fopen("main.rb", "r"); mrb_load_file(mrb, fp); fclose(fp);fopen()、fclose() はCのソレで、ファイルを開いたり閉じたりする。mrb_load_file() で、開いたファイルを mruby に渡して、実行。なのかな。
Cにおいて、開いた何かしらは、えてして閉じないといけない。mruby も開いたのだから、閉じる。
mrb_close(mrb);
[ ツッコむ ]
以上です。