mruby-cliを使用してmrubyでコマンドラインアプリケーションを書く
タグ: mruby / 初版公開: 2016-08-12

このエントリは、mruby-cliを使ってみて、わかったことのメモです。 mruby-cliを使うと、mrubyでスタンドアローンなコマンドラインアプリケーションを、複数のプラットフォーム向けに簡単にビルドすることができます。

対象ソフトウェア

ソフトウェア バージョン 備考
Debian stretch -
Docker 1.11.0 -
Docker Compose 1.5.2 -
mruby-cli 0.0.4 https://github.com/hone/mruby-cli/releases/tag/v0.0.4

mruby-cliの概要

mruby-cliが提供するのはmruby-cliというコマンドだけです。 mruby-cli--setupオプションで、mrubyでアプリケーションを開発するためのファイル郡を生成します。

ファイル郡には、

  • mruby本体
  • アプリケーションのソースコードの雛形
  • ビルド用のRakefiledocker-compose.yml

が含まれます。

アプリケーションのビルドはdocker-composeコマンドで、クロスプラットフォーム向けのビルド環境が整ったDockerコンテナ内で行います。 デフォルトのターゲットプラットフォームはLinux, MacOS X, Windowsで、ビルド時には全プラットフォーム向けのバイナリがそれぞれ出力されます。

ビルドにはDockerを使用するため、mruby-cliを作者の想定どおり使用するには、DockerとDocker Composeが必要です。 もちろん、ビルド環境さえ整っていればDockerとDocker Composeを使わずに、rakeでアプリケーションをビルドすることもできます。

インストール

mruby-cliのGitHubからlatest releaseをダウンロードしてくるのが良いです。 mruby-cli自体がmruby-cliで作られているため、ワンバイナリの恩恵に預かりましよう。

私が試した環境はLinuxですので、mruby-cli-0.0.4-x86_64-pc-linux-gnu.tgzをダウンロードしました。 これを展開すると、mruby-cliという実行可能ファイルが出てきます。

次のアプリケーションのファイル郡の生成は、このmruby-cliを使って行います。 必要ならパスを通しておくと良いでしょう。

アプリケーションの生成

このエントリではhellomrubyというコマンドラインアプリケーションを作ることにします。 以下のように--setupもしくは-sオプションでアプリケーション名を指定して、mruby-cliを実行します。 カレントディレクトリの下にアプリケーション名のディレクトリが作成され、ファイル郡が配置されます。

mruby-cli -s hellomruby

出力されるファイル郡は以下のとおりです。

hellomruby
├── bintest
│   └── hellomruby.rb
├── build_config.rb
├── docker-compose.yml
├── Dockerfile
├── mrbgem.rake
├── mrblib
│   ├── hellomruby
│   │   └── version.rb
│   └── hellomruby.rb
├── Rakefile
├── test
│   └── test_hellomruby.rb
└── tools
    └── hellomruby
        └── hellomruby.c

アプリケーションの実装

アプリケーションのコードの雛形はmrblib以下に出力されています。 この例ではhellomruby.rbが本体です。

def __main__(argv)
  if argv[1] == "version"
    puts "v#{Hellomruby::VERSION}"
  else
    puts "Hello World"
  end
end

mruby-cliで作成するアプリケーションは__main__メソッドが最初に実行されます。 これはtools/hellomruby.cとして生成されたC部分のコードから、__main__を呼び出す仕組みのためです。

雛形では、引数なしで実行した場合にHello Worldを出力します。 またversionオプションが指定された時に、version.rbで定義した、アプリケーションのバージョンを表示するようになっています。

お気づきかも知れませんが、__main__に渡されるargvは、argv[1]が1つ目のコマンドラインオプションです。 RubyのARGVとは勝手が違い、argv[0]にはアプリケーションのファイル名そのものが格納されているのでご注意下さい。 (ようは、C言語のmain()が受け取った第2引数が、そのまま渡される)

このままでも良いのですが、ここは遊び心で、出力するメッセージをHello mrubyに変えてみます。

def __main__(argv)
  if argv[1] == "version"
    puts "v#{Hellomruby::VERSION}"
  else
    puts "Hello mruby"
  end
end

ビルドの設定の変更

上記のファイルをビルドするだけなら、この手順は必要ありません。

build_config.rb

ビルドの設定を変更したい場合は、アプリケーション名の直下に生成されるbuild_config.rbを編集します。 内容は以下のようになっています。

def gem_config(conf)
    #conf.gembox 'default'
  
    # be sure to include this gem (the cli app)
    conf.gem File.expand_path(File.dirname(__FILE__))
end
    
MRuby::Build.new do |conf|
  toolchain :clang

  conf.enable_bintest
  conf.enable_debug
  conf.enable_test

  gem_config(conf)
end 
  
MRuby::Build.new('x86_64-pc-linux-gnu') do |conf|
  toolchain :gcc
  
  gem_config(conf)
end

# 以下省略...

ポイントは、以下の2点です。

  • クロスコンパイルするプラットフォーム毎にMRuby::Build.newが分かれている
  • 冒頭で定義されているgem_configメソッドが、すべてのMruby::Build.newのブロック内から呼び出されている
  • gem-configメソッドでは、アプリケーション自体のgemがconf.gemで追加されている

全プラットフォームで共通の設定は、gem_configメソッドを書き換えれば良く、もしプラットフォーム毎に切り替えたい部分があれば、各プラットフォームのMruby::Build.newのブロック内を書き換えれば良いということです。

また、特定のプラットフォームをクロスコンパイルの対象から除外したい場合は、そのプラットフォームのMRuby::Build.newをまるごと消してしまえばビルドされなくなります。

アプリケーション自体のgemが追加されていますので、mrbgemsの依存関係は、次に説明するmrbgems.rakeを編集することで、変更することができます。

mrbgems.rakeの変更

mrbgems.rakeのデフォルトの内容は以下のとおりです。 mrbgemsの依存関係がある場合はadd_dependencyで依存関係を追加すれば良いです。

MRuby::Gem::Specification.new('hellomruby') do |spec|
  spec.license = 'MIT'
  spec.author  = 'MRuby Developer'
  spec.summary = 'hellomruby'
  spec.bins    = ['hellomruby']

  spec.add_dependency 'mruby-print', :core => 'mruby-print'
  spec.add_dependency 'mruby-mtest', :mgem => 'mruby-mtest'
end

ビルド

docker-compose run compileで、Dockerを使用してコマンドラインアプリケーションを全プラットフォーム向けにクロスコンパイルできます。

docker-composeはカレントディレクトリのdocker-compose.ymlを読み込んでコンテナを起動します。 このためアプリケーションのルートディレクトリで実行して下さい。

docker-compose run compile

ビルドしたバイナリの出力先はmruby/buildのプラットフォーム名のディレクトリ以下になります。

mruby/build/host/bin/hellomruby
mruby/build/i686-pc-linux-gnu/bin/hellomruby
mruby/build/i386-apple-darwin14/bin/hellomruby
mruby/build/x86_64-pc-linux-gnu/bin/hellomruby
mruby/build/x86_64-apple-darwin14/bin/hellomruby

実行

自分のプラットフォーム向けのバイナリを実行してみましょう。

mruby/build/x86_64-pc-linux-gnu/bin/hellomruby

出力は以下のとおりです。

Hello mruby

ちゃんと動きましたね!

補足:mrub-cliの使用する Dockerfile / docker-compose.yml について

Dockerfileはこれだけです。

FROM hone/mruby-cli

DockerHubのhone/mruby-cliイメージを落としてくるだけの内容です。 DockerHub上ではlatestのサイズは575MBと、結構なサイズがあります。

このDockerイメージは、Githubへのリンクが設定されていませんが、以下のDockerfileをビルドしたもののようです。 ubuntu-debootstrap:14.04ベースで、Rubyとクロスコンパイルに必要なビルド環境をインストールしたイメージとなっています。

次にdocker-compose.ymlですが、以下のとおりで、compileがデフォルトです。 volumesが多少怖いですが、カレントディレクトリがコンテナ内で/home/mruby/codeにマウントされます。

compileではbuild: .Dockerfileをビルドし、起動時にはrake compileを実行するようになっています。 特にREADME.mdに解説は無いですがtestbintestなど、compile以外の操作も、コンテナ内で実行できるように書かれていることがわかります。

compile: &defaults
  build: .
  volumes:
    - .:/home/mruby/code:rw
  command: rake compile
test:
  <<: *defaults
  command: rake test
bintest:
  <<: *defaults
  command: rake test:bintest
mtest:
  <<: *defaults
  command: rake test:mtest
clean:
  <<: *defaults
  command: rake clean
shell:
  <<: *defaults
  command: bash

補足:Dockerを使わないビルド

上記のとおりdocker-compose run compileは、ビルド環境が整ったコンテナ内でrakeしているだけです。 このため、mruby-cliのアプリケーションを、Dockerを使わずにrakeでビルドすることもできます。 もちろん、この場合は全ターゲットプラットフォーム向けのビルド環境を、予め準備しておく必要があります。

rake

ビルド環境が整ったコンテナを使ってビルドするのがmruby-cliの良いところですので、あまりオススメできません。