Webアプリケーションエンジニアによる初めての組み込みをmrubyで

こんばんは、久保田です。

今回は話題のmrubyを取り上げたいと思います。

mruby?

mrubyとは、Rubyのパパ、Matzが作っている組み込み向けに作られた軽量Ruby処理系です。

これはぜひ習得しなくては、と思ったのですが、 正直今までLinux上でRubyやらPythonを使ってwebアプリしか作ってこなかったプログラミング2年目のペーペーの僕からしたら、まず、 組み込み という事自体がよくわからなく。。。 ラズパイやarduinoなどのマイコンを動かすためのものなのかなと思えば、 apacheやNginxなどのアプリケーションに組み込んだなどという話もでていますし、、、 完全に混乱していたので、色々と調べ、触ってみました。

組み込み?

組み込みとはそもそも何なのかと言いますと、

「 組み込みシステム(くみこみシステム)あるいはエンベデッドシステム (Embedded system) とは、 特定の機能を実現するために家電製品や機械等に組み込まれるコンピュータシステムのこと。(by wikipedia) 」

らしいです。 ものすごく噛み砕いてしまうと、組み込み = 「家電や機械の中にあるシステム」と言えそうです。 僕のようなアプリケーションエンジニアがやっているようなLinux上でサーバーを立てて、Rubyを動かしネットワークからリクエストを受け取って、、、 DBを立てて、、、 などとは違う環境で動くシステムのようですね。

確かに、今暮らしの中で当たり前のように使っている家電なども考えたらプログラムが動いているはず。 例えば電子レンジであったら、ユーザーからの温め時間や温度などの入力を受け取り、温めるという処理を行うとか。 スイカをタッチしたら残額によってユーザーが改札を通れるようにする、とか。

こういった制御をするソフトウェアを作るための言語が組み込み向けの言語、ということになります。

ではなぜこんな言語が必要なのかというと、主にリソースの問題が大きいようです。

このような家電などは、PCのような汎用的な機械とは違い、WindowsやMacOSなどのようなリソースをたくさん使うOSは動きません。 そんなリッチなCPUやメモリは搭載しないということです。(必要がない上に高いからですね) そんな限られたリソースでプログラムを動かすには、RubyやPythonなどの汎用言語は動かすのは厳しいようです。

なぜmrubyか

じゃあ何でmrubyなのか、軽い言語が必要ならばアセンブラやCでいいじゃないか、と思うかもしれません。 ここにポイントがあると思います。 CはRubyやpythonなどに比べて、難しいです。 アセンブラなんて僕は書けません。

この事が組み込みをやること自体が僕のようなエンジニアにはハードルが高いのではないかな、と思います。

Cで文字列を表示するとなると、

#include<stdio.h>

int main(void)
{
  char str[] = "hello world!";
  printf("%s\n", str);
  return 0;
}

と書いて、

$ gcc hello.c
$ ./a.out

を実行して、やっと

hello world!

と表示されます。

ですが、Rubyだと、

puts 'hello world!'

と書いて、

$ ruby hello.rb

hello world!

簡単ですね!

$ ruby -e "puts 'hello world!'"

でもいけますね。 いやぁ、楽しい。

このRubyの良さを組み込みにも!という事で作られたのがmrubyなのです。 確かにこれなら楽しくできそう!と思いました。

アプリケーションへの組み込み

家電などの組み込みの他に、apacheやNginxにも組み込んだという話をよく聞きます。 これは一体どういう事なのでしょうか。 簡単に言ってしまうと、既にある既存のアプリケーションからmrubyを使う事で機能を拡張する、という事だと解釈しています。

apacheやNginxは、サーバーのアプリケーションですね。 ここにmrubyを組み込む事で、独自の拡張を作る事ができるわけです! これも先ほどと同じで、基本的に場所を選ばないCとかが主流だったところを、mrubyを使って気持ちよく書く事ができます。 さらに軽量なので、処理も重くならない、というわけですね。 夢が広がります。

この辺はmatsumoto-rさんの なぜApacheにmrubyを組み込もうと思ったか が非常に分かりやすかったです。

Cに組み込んで使ってみる。

かなり長めになりましたが、実際にmrubyを使ってみます。 ラズパイで、とか行きたいところですが、最初からハードルが高いので(間に合わなかった)まずはCのアプリケーションに組み込んでみます。 と言ってもものすごく簡単な事をやりたいので、自分で作ったCのプログラムからmrubyを使うだけにします。

mrubyをcのプログラムに組み込んで使うには、

  • mrubyをインストール
  • mrubyをコンパイル
  • cからmrubyを使うように書く

という流れになります。

mrubyをインストール

まずはmrubyをインストールします。

$ git clone https://github.com/mruby/mruby.git

build

rake

これで./bin以下にmrubyや、REPLであるmirb、rubyのコードをバイナリーにするコンパイラmrbcが作られます。 (bisonなどが必要になります。) (mrbcは、.rbファイルを.mrbにコンパイルしてくれます。こうする事でさらに軽くできるらしいです。)

ちなみに、gemとかを使うときは、build_config.rbに設定してからbuildする必要があります。 CRubyとは違い、requireで動的にファイルを読む機能はないため、mrubyに組み込んでおくのです。

実装

ではまずはcを書いていきます。 mrubyを使う側のアプリケーションですね。

とりあえずHello World!を。

#hello_world.c


#include "mruby.h"
#include "mruby/compile.h"

int main(void)
{
  FILE *f;
  // ここでmruby仮想マシンの作成
  mrb_state *mrb = mrb_open();
  // file読み込み
  f = fopen("hello_world.rb", "r");
  // 実行
  mrb_load_file(mrb, f);
  // 仮想マシン閉じる。
  mrb_close(mrb);
  return 0;
}

次にrubyのプログラムを書きます。

#hello_world.rb

p "hello world!"

コンパイル & 実行

gcc -I ./mruby/include -I ./mruby/include/mruby hello_world.c ./mruby/build/host/lib/libmruby.a -lm -o hello_world
./hello_world

#=> "hello world!"

できましたね!これでcからmrubyを使う事ができています。

調べたらかなり面白そうだったので、しばらく触ってみようと思います。 では、また。