P/ECEでmrubyを動かす
前文
mruby(軽量Ruby)というものを知って、組み込み環境で使えるぐらい消費メモリが削減されているそうなので、P/ECEでも動かせるんじゃね? という実験をしてみたら、コンパイラの古さに泣きそうになった話。
mrubyリポジトリ
P/ECE向けにクロスコンパイルするための設定を入れたfork
https://github.com/zurachu/mruby/tree/cross_build_for_piece
P/ECE仕様(今回キモになるところだけ抜粋)
CPU EPSON S1C33209 24MHz(32ビットRISC)
SRAM 256KB
アプリケーション開発ツール(C言語)付属
アプリケーション開発ツールはEPSONのS1C33向けGCCがベースになっていて、なんとGCCのバージョンは2.7.2(うーんこの)
mrubyのコンパイルにはC99が要求されるそうなので、コンパイルエラーが出た箇所をなんとかやっつけていきます。
ビルド
これのやり方は色々な方が書かれているので、ここでは手短に。
必要環境(括弧内は私が使用したバージョン)
- Visual Studio(Community 2017)
- Ruby(RubyInstaller 2.5.0-1)
- Bison for Windows(2.4.1)
- P/ECE開発環境
手順
「すべてのプログラム」→「Visual Studio 2017」→「Developer Command Prompt for VS 2017」を開き、以下を実行すると、Windows用の各種実行ファイル&ライブラリ、P/ECE用のライブラリが出力されます。
> cd [リポジトリをチェックアウトしたパス]
> make
サンプルプログラム
examples/targets/PIECE に簡単なサンプルプログラムを用意しています。
ライブラリビルド後に、以下コマンドで実行できます。
> cd [リポジトリをチェックアウトしたパス]\examples\targets\PIECE
> make
> run
mrubyスクリプト
def prime?(n)
(2...n).each do |i|
return false if n % i == 0
end
true
end
def puts(x)
Pce::Font::put_str "#{x}\n"
end
a = (2..100).select {|n| prime?(n) }
puts a
実行結果
画面表示されるまで、だいぶ時間かかります。
また、関数名の後ろに書いてるのが実行後のヒープ残量なのですが、VMの初期化(mrb_open_allocf())が終わった時点で4KBしかないというギリギリさw
本当に動かせただけというレベル。
P/ECE用に対応したところ
ビルド環境編
pcc33がサブディレクトリ以下のファイルのコンパイルに失敗する
コンパイラドライバーであるpcc33がカレントディレクトリでの実行しか想定されておらず、また出力先を指定する-oオプションが無いので、そのままではビルドに使えない。
これを実現するためのラッパーをRubyで書いて、それをconf.cc.commandに与える。
ライブラリ編
stdint.h, inttypes.hが無い
C99じゃないので。
こちらのファイルを改変して使用。
https://github.com/chemeris/msinttypes
構造体メンバのサイズ不明配列がincomplete typeになる
struct mrb_pool_page {
struct mrb_pool_page *next;
size_t offset;
size_t len;
void *last;
char page[];
};
これもC99?
使われ方を見ていると、メンバ(上記page
)自体のサイズはゼロにしつつ、構造体が格納されている次のメモリ領域を指すポインタとして扱っているもよう(こういうことできるの知らなかった)
当該メンバを削除してメンバ参照箇所は構造体のポインタをchar*にキャスト後sizeof(struct mrb_pool_page)を加算するコードに書き換え。
stddef.hとstdlib.hでwchar_tのtypedefが競合
P/ECE開発環境のヘッダファイルで定義済みを表すマクロ文字列が違っているため。コメントの感じから、stddef.hがEPSONのS1C33コンパイラセットに含まれるものではないっぽくて、それを作った人がミスってる気がする。
#ifndef _WCHART
#define _WCHART
typedef unsigned short _Wchart;
typedef _Wchart wchar_t;
#endif
#ifndef _WCHAR_T
#define _WCHAR_T
typedef unsigned short wchar_t; /* wide character type */
#endif
開発環境に手をつけて良いなら、stddef.h側のマクロを書き換えるのが安いけど、あまりシステムインクルードパスの中身を書き換えたくないので、マクロの定義状態を見て、うまいこと細工する。
#ifdef PIECE
#if defined(_WCHAR_T) && !defined(_WCHART)
#define _WCHART
#endif
#endif
#include <stdint.h>
#include <stddef.h>
無名共用体が使えない
#ifdef MRB_METHOD_TABLE_INLINE
typedef uintptr_t mrb_method_t;
#else
typedef struct {
mrb_bool func_p;
union {
struct RProc *proc;
mrb_func_t func;
};
} mrb_method_t;
#endif
こちらの共用体へのアクセスがエラーになる。
union { ... } u;と名前を付けて、呼び出し箇所(proc.hのマクロ)にも名前を付けるでも良いが、MRB_METHOD_TABLE_INLINEマクロを定義しても回避できるし、そちらの方がメモリ消費量が少なく済んだので、後者を採用。
浮動小数点演算をカット
NAN, INFINITY, isinf(), isfinite() など、C99 math.h で実装されているものが未定義で、src/numeric.cのコンパイルが失敗するため。
頑張って実装したところでメモリが足りなさそうなので、MRB_WITHOUT_FLOATマクロを定義して、あきらめる。
標準入出力をカット
stdin/out などがないため、MRB_DISABLE_STDIOマクロを定義。(ライブラリ作成時点では警告止まりで、リンク時にエラー)
ターゲットプログラム編(リンカエラーへの対処など)
64ビット整数演算の実装が無い
Warning: Unresolved external symbol '__muldi3'.
Warning: Unresolved external symbol '__adddi3'.
こちらのファイルをリンクする。
http://www.piece-me.org/piece-lab/piece-lab-2002.txt
- Sun Oct 13 10:03:00 JST 2002 Naoyuki Sawa
- 64ビット整数演算ライブラリ
exit(),_exit()が無い
Warning: Unresolved external symbol '_exit'.
Warning: Unresolved external symbol '_exit'.
exit()だけじゃなくて_exit()も要ることが分かりにくいエラーメッセージ…。
while(1);で適当に実装する。
ただ、P/ECEのアプリの終了はpceAppReqExit()を呼んでpceAppExit()が呼び出されるという流れをふまないといけないので、そもそもこいつらが呼ばれるような事態があっては困る。
それでいうと、真面目に液晶にエラー出力するようなコードを書いた方が良いかも。
errnoが無い
Warning: Unresolved external symbol 'errno'.
定義したら良い。
独自のアロケータを渡す
mrb_open()ではなくmrb_open_allocf()を使い、独自のアロケータを渡す。
static void* allocf(mrb_state* mrb, void* p, size_t size, void* ud)
{
void* ret;
if(size == 0)
{
if(p)
{
pceHeapFree(p);
}
return NULL;
}
ret = pceHeapAlloc(size);
if(p)
{
memcpy(ret, p, size);
pceHeapFree(p);
}
return ret;
}
pceHeapRealloc()の仕様がrealloc()と若干異なる(しかもバグあり)ので、pceHeapAlloc()/pceHeapFree()のみで実装する。
今後の課題
- mrubyから呼び出せるP/ECE開発環境のAPIを増やす(メモリ残量が‥)
- gem使ってみる(同上)
- なんとかしてメモリを浮かせる。ただ、マクロでの設定は相当切り詰めているので、他の要素を探さないと。
おまけ
ビルド環境編で詰まっていた時にMatzさんからリプライが飛んできてビビったという話。
コンパイル後のオブジェクトファイルをムーブするシェルスクリプトをCCに指定する手があります。
— Yukihiro Matsumoto (@yukihiro_matz) 2018年2月7日
参考文献
Author And Source
この問題について(P/ECEでmrubyを動かす), 我々は、より多くの情報をここで見つけました https://qiita.com/zurachu/items/b73c1466525b8410e305著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .