浦島太郎と辿るここ数年のmruby

Techc, Japanese, mruby, Ruby

こんにちは、kishimaと申します。

2020年以降数年の身の周りの変化や、私事で色々バタバタしていて、mrubyもぜんぜん触れてなかったのですが、少しは落ち着いてきたので、久しぶりにmrubyを使って色々やってみたいという気持ちを込めて、mrubyファミリーアドベントカレンダーにトライしてみます。

https://qiita.com/advent-calendar/2023/mruby-family

とはいえ触っていないうちにメジャーバージョンも2から3に上がり、だいぶ変化があるようです。

浦島太郎な自分のためにも、どんな進化の道をたどってきたのか、追いかけて来年に備えていきたいと思います。

リリースの履歴

私が最後に利用していたのが2020年頃で、その時の最新はv2.1.0でした。そこから現在に至るまで3回のリリースがあったことになります。

リリース履歴

各バージョンから気になるポイントをピックアップ

自分が最後によく使っていたv2.0.0から辿りながら、リリースノート上で気になるポイントをピックアップしていきましょう。

パッチバージョンでも結構機能が増えたりしているので、一つ一つ見ていきます。

リリースノートは以下のサイトから見られますが、

https://mruby.org/

英語なので、日本語で読みたい方は軽量RubyフォーラムのDownloadページから翻訳したものが見られます。(サイトがhttpなので、https対応してほしいですね。)

http://forum.mruby.org/download/index32.html

v2.0.0

メモリ削減

リソースが限られた環境で使うことを想定しているmrubyではメモリの使用量は重要な要素です。その改善のための実装が入っています。

バイトコードの改定

mrubyはRubyのコードを一度バイトコードにコンパイルして、それをVMが実行します。そのバイトコードの仕様が大きく変わって、過去のバイトコードが実行できなくなっています。これまで固定長で表現していた命令が可変長になり、バイトコードの長さもより最適になりました。

バージョンは0005に更新。

メタプログラミング機能のmrbgem化

methodsなどメタプログラミングで使われる機能がmrbgemとして分離されたので、メタプログラミング機能が必要ない場合はVMのサイズが小さくなるかと思います。

v2.0.1

文字列リテラルの連結

コード書く際にはありがたいですね。

Ruby2.6からの機能追加

Enumerator::Chain などの追加。

https://docs.ruby-lang.org/ja/latest/class/Enumerator=3a=3aChain.html

ProcとMethodにFunction Composition opearator<< と>>が追加

省メモリ対応

mrb_state構造体から、symbol ハッシュテーブルを削除して、メモリ削減。ハッシュテーブルを使わないため、シンボルの検索が遅くなるが、mrubyのユースケースでは無視できる範囲だろう、という判断とのことです。

5文字未満の英数字シンボルはbase64の32bit整数にパックされるということです。コーディング時は短いシンボルもよく使うかと思うので、そういうときに地味に効いてくるものかと思います。

バイナリフォーマットの更新

バージョン0006に更新

C API:RRangeAPIの追加

Boxingに関連してるので、RRangeの要素にアクセスする場合は以下のメソッドを利用する必要がある。

  • mrb_range_beg
  • mrb_range_end
  • mrb_range_excl_p

v2.1.0

Rational/Complex リテラルのサポート

有理数、複素数の対応。1/3、1.23i のような書き方。Ruby2.1あたりで入っていたんですね。

Ruby2.7、Ruby2.6の機能サポート

Array#intersection、Enumerable#filter_mapなどなど

記法に関するもの

メソッドコールの間に改行、コメントを入れられるようになった。

行頭に&.が来ることが許されるようになった。

$/の削除。Perlライクなグローバル変数は推奨しない方向なので。

ビルドに関するもの

lockファイルに対応。色々な環境で動かすことを考えると必要な機能ですね。

リファクタリングでC APIのメソッド名なども結構変わっているようなので、C拡張を書いているとバージョンアップに追従していくのはなかなか大変そうです。

v2.1.1

記法に関するもの

Ruby2.7から、ブロックで番号の変数を取る機能が入りました。

[1, 2, 3].map { _1 + 3 }
=> [4, 5, 6]

RationalとComplexのリテラルが常に有効に。

ビルドに関するもの

minirakeではなくて、rakeを使用するようになった。

MRB_INT16 オプションの削除。32bit環境で利用が前提になった、ということですかね。

v2.1.2

記法に関するもの

Arguments Forwardingの対応。 def foo(…)

バイトコードの改定

mrubyバイナリから、エンディアンの情報が削除。固定されたということなのかな?

0007になった。

コアライブラリ

rational, complexに加えて、mruby-evalがデフォルトでライブラリに含まれるようになった。evalは元々コアにはなかったものですが、公式になったんですね。

ビルドに関するもの

bisonが不要になった。

github actionsに対応して、以下のCIが走るようになった。

  • Ubuntu 16.04
  • Ubuntu 18.04 (gcc)
  • Ubuntu 18.04 (clang)
  • macOS
  • Windows (MinGW)
  • Windows (Cygwin)
  • Windows (MSVC)

ちゃんと確認できてませんが、armにも対応してるのかな?mrubyの用途だとarm環境で動くことも大切なはず。最近仕事でarm64とamd64でのqemu使ったCIとか覚えたので、試してみたい。

C APIに関して

mrb_run()がC APIから削除。どういう経緯なんだろうか?

v3.0.0

メモリの削減

100kB程度のメモリで動くようになったとのこと。自分の記憶では200KB程度はないと最低限の動作も厳しかったはずなので、大きな進歩だと思います。

シンボルを静的メモリ領域に与えることでメモリを削減。私もmruby/cを無理やりArduinoで動かすときにやってみた組み込みソフトの手法です。以前から議論されているのは知ってましたが、ここでマージされたのですね。ぜひコードも追ってみたいです。

https://github.com/mruby/mruby/blob/master/doc/guides/symbol.md

記法に関するもの

  • Ruby3.0より
    • 右代入のサポート。ローカル変数のみ対応。
    • エンドレスメソッド定義
  • Ruby2.3より
    • Squiggly heredocsサポート。インデントを汚くしないで、ヒアドキュメント書けるやつ。(リリースノート誤字ですね)

ビルドに関するもの

これまではbuild_config.rbでまとめて書いていたものが、build_config以下のファイルから構成されるようになったそうです。Rubyとは違って、mrubyではmrbgemを取り込むにもmrubyのビルドが必要で、クロスコンパイルなども行うケースも考えると、より見通しが良くなったのではと思いました。

開発ツールに関するもの

  • mrubyインタプリタの引数で、rbとmrbファイルを混在して実行可能に。mrbはどこかから持ってきたものを使っている場合などに助かりますね。
  • mrbcでirepのC構造体を-Sオプションで出力できるように。irepはプログラムの実行情報を持っている構造体ですが、これを使うと実行状態のスナップショット取るような使い方できるのでしょうか?どんなものか試してみたいです。

バイトコードに関するもの

下位互換性がなくなり、バイナリバージョンが、0200に。

Integerの見直し

CRubyとmrubyで動きが大きくことなるポイントでしたが、これがCRuby準拠になったそうです。これも影響は大きそうですが、混乱の元にもなりやすいポイントだったと思うので、良かったのではないかと思います。

  • FixnumとIntegerの統合
  • Integral廃止
  • 整数同士の除算は整数に

v3.1.0

記法に関するもの

Ruby3.0互換のキーワード引数対応。

ビルドに関するもの

ビルドコンフィグファイルが色々追加。

  • cross-mingw-winetest.rb
  • cross-mingw.rb
  • nintendo_switch.rb
  • serenity.rb
  • minimal: minimal configuration
  • host-f32: compiles with mrb_float as 32 bit float
  • host-nofloat: compiles with no float configuration
  • android_arm64_v8a.rb: renamed from android_arm64-v8a.rb

nitendo_switch.rb !?

以前のRuby会議でSwitch向けのゲームでmruby使っている発表ありましたが、その流れでしょうか?どなたがコミットしたものなのか気になります。

バイトコードに関するもの

下位互換性がなくなり、バイナリバージョンが、0300に。

消えるバイトコードの命令も複数。命令の仕様も色々変化しています。

  • OP_LOADL16
  • OP_LOADSYM16
  • OP_STRING16
  • OP_LAMBDA16
  • OP_BLOCK16
  • OP_METHOD16
  • OP_EXEC16

メモリ効率に関するもの

Boxingについてもアップデートが入っています。中身はまだ良く理解できてません。

コンパイラに関するもの

定数畳み込み(Constant Folding)という最適化技法に対応。定数の計算をそのままバイトコードに落とすのではなくて、コンパイル時点で計算して、その計算結果をバイトコードにする、という機能かと思います。

その他、CVEへの対応も色々入っているようなので、やはり最新のものを使うのがよいですね。

v3.2.0

記法に関するもの

多倍長整数に対応。

ビルドに関するもの

mrbc に –no-optimize オプション追加。逆に考えると、今後もさらにコンパイル最適化の機能も増えていくことを期待できそうです。

C APIに関するもの

mrb_vm_run()はブロックから参照されるトップレベルのローカル変数を切り離す可能性がある。

これはmrubyプログラムの実行を細かく制御するようなアプリを作っている人は注意しないといけない内容ですね。詳細は説明をちゃんと読みましょう>自分。

感想

こうして変化の流れを追ってみると、色々試してみたい機能や、期待していた消費メモリの削減など、大きな進化を感じられました。互換性がなくなる変更も結構入っているので、ここは一つ最新版で自分のプロジェクトも作り直さねば、というモチベーションが湧きました。

今後の抱負

とりあえず、最新の環境をキャッチアップしつつ、Family mrubyのハードウェアとファームウェアを更新したい気持ちです。

お仕事では最近ROSでロボットを制御したり、クラウドサービスとつながるエッジデバイス環境を整備したりといろいろやってます。言語はC++、Python、Rustなどを使ってますが、mrubyが刺さりそうな場面もあるような気がしているので、そういうユースケース見つけて、試してみたいなと思ってます。

https://silentworlds.info/family_mruby/