As a SW/Ops/DB Engineer

riywo’s technology memo

Mruby on MIPS in PQI Air Pen

moyashi さんの記事を読んで以来、ずっと欲しかったPQI Airシリーズなんですが、USのAmazonでは売ってなかったり無駄に高かったりして二の足を踏んでました。ある日、郵便局を使うと数百円で荷物が送れることが分かったので、日本のAmazonで買って実家に発送して送ってもらうことでついにゲットしました。

ただ、Cardの方を動かせるmicroSDを持ってなかったので、今はPenでちょっと遊んでみただけです。何をやったかというと、mrubyを動かしてみました。CRubyはちょっと動かせる自信なかったですが、最初から組み込み向けのmrubyなら簡単かなぁと思ってやってみたら簡単でした。

Cross Compile

PQI AirのハードウェアはCPUがMIPSで、使い慣れているx86/x86_64とは違います。ので単にいつもLinuxで使ってるバイナリをコピーしてもダメです。

# cat /proc/cpuinfo
system type             : Atheros AR9330 (Hornet)
processor               : 0
cpu model               : MIPS 24Kc V7.4
BogoMIPS                : 232.96
wait instruction        : yes
microsecond timers      : yes
tlb_entries             : 16
extra interrupt vector  : yes
hardware watchpoint     : yes, count: 4, address/irw mask: [0x0000, 0x0c68, 0x0ff8, 0x0393]
ASEs implemented        : mips16
shadow register sets    : 1
core                    : 0
VCED exceptions         : not available
VCEI exceptions         : not available

さすがにここでコンパイルするのは、その環境を準備するところで挫折しそうなのでクロスコンパイル(別のアーキテクチャ用のバイナリをコンパイルする)をしました。

やり方はmoyashiさんが紹介されているSourcery CodeBenchというツールチェインを使って静的リンクでコンパイルしただけです。楽チン。

Macで動かすにはこれ自体をセルフビルドする必要があったので萎えて、Vagrantで適当に32bit Linuxを起動して、インストール。適当にPATHを通しておきます。以下はVagrantfileの例。

$ cat Vagrantfile
Vagrant.configure("2") do |config|
  config.vm.box = "precise32"
  config.vm.box_url = "http://files.vagrantup.com/precise32.box"
  config.vm.provision :shell, :inline => "apt-get install build-essential -y"
end
$ vagrant up
$ vagrant ssh

mrubyは最近ビルド方法が変わったらしく、rubyが必要なのでこれも適当に。Vagrantのboxだと大抵入ってるかな。あと必要なパッケージも適当に。Vagrantfileに書いといてもいいね。

$ sudo apt-get install bison git

これで適当にクロスコンパイルの準備ができました。

make mruby

とりあえずコード取ってきます。

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

mrubybuild_config.rbというファイルでコンパイルの方法を色々変えられます(多分)。今回は以下を追加してみました。意味は簡単でMIPS用のgccarが先ほどのSoucery CodeBenchに入ってるので、それを適当なオプションとともに指定してるだけです。

MRuby::CrossBuild.new('pqi-air') do |conf|
  toolchain :gcc

  conf.gembox 'default'
  conf.cc.command = "mips-linux-gnu-gcc"
  conf.cc.flags << %w(-g -O2 -Wall -static -march=24kc)
  conf.linker.command = "mips-linux-gnu-gcc"
  conf.linker.flags << %w(-s -static)
  conf.archiver.command = "mips-linux-gnu-ar"
end

もともとあるMRuby::Buildの方を消すとundefined method 'build_dir' for nil:NilClassなるエラーになってしまうのでそれも残しておきます(何かやり方間違ってる気が。。。)

あとはmakeしたらできあがり。

$ make
ruby ./minirake
(in /home/vagrant/mruby)

Build summary:

================================================
      Config Name: pqi-air
 Output Directory: build/pqi-air
         Binaries: mrbc
    Included Gems:
             mruby-sprintf
             mruby-print
             mruby-math
             mruby-time
             mruby-struct
             mruby-enum-ext
             mruby-string-ext
             mruby-numeric-ext
             mruby-array-ext
             mruby-hash-ext
             mruby-range-ext
             mruby-proc-ext
             mruby-symbol-ext
             mruby-random
             mruby-bin-mirb
               - Binaries: mirb
             mruby-bin-mruby
               - Binaries: mruby
================================================

$ file build/pqi-air/bin/*
build/pqi-air/bin/mirb:  ELF 32-bit MSB executable, MIPS, MIPS32 rel2 version 1, statically linked, for GNU/Linux 2.6.12, with unknown capability 0x41000000 = 0xf676e75, with unknown capability 0x10000 = 0x70401, stripped
build/pqi-air/bin/mrbc:  ELF 32-bit MSB executable, MIPS, MIPS32 rel2 version 1, statically linked, for GNU/Linux 2.6.12, with unknown capability 0x41000000 = 0xf676e75, with unknown capability 0x10000 = 0x70401, stripped
build/pqi-air/bin/mruby: ELF 32-bit MSB executable, MIPS, MIPS32 rel2 version 1, statically linked, for GNU/Linux 2.6.12, with unknown capability 0x41000000 = 0xf676e75, with unknown capability 0x10000 = 0x70401, stripped

実行!

あとは出来上がったフォルダ一式(と言いつつ静的リンクした実行ファイルしか試してませんが。。。)をPQI Air Penに挿したSDカードにコピーしたら実行!

# ./mruby -e 'p 1+1'
2
# ./mirb
mirb - Embeddable Interactive Ruby Shell

This is a very early version, please test and report errors.
Thanks :)

> a = {:foo => 1, :bar => 2}
 => {:foo=>1, :bar=>2}
> a.each { |k,v| p "#{k} => #{v}" }
"foo => 1"
"bar => 2"
 => {:foo=>1, :bar=>2}

感動的ですね、こんなちっこいマシンの上でrubyが動くなんて。mirbreadlineがないせいか、カーソルキー効かなくて不便ですが。。。

mrubyのことは実はさっぱり分かってないのですが、色々楽しめそうです。興味ある方はぜひ遊んでみて下さい or 遊び方教えて下さい。

Comments