こんばんは。最近mgemを作成する機会があり、何から始めたらいいのかわからなくて困ったので、一連の流れをまとめて備忘録にしたいと思います。 本作業はMacOSX Siera上で実施しています。 誤った記述があれば突っ込んでいただけると・・・
mgemとは?
非常にざっくりいうとCRubyの gem
のmruby版が mgem
CRubyのように gem install hoge
するわけではなく、mgemでは依存ライブラリとして指定したうえで
mruby自身のコンパイル時に組み込み、 hoge mgemを組み込んだmrubyバイナリ
を作ることになる。
さっそく作る
1. matsumotory/mruby-mrbgem-template
を使用してmgemの雛形を作成する
詳細は http://blog.matsumoto-r.jp/?p=3923 など参照 基本的にリポジトリのREADME通りにやればOK
# リポジトリもってくる tahira at mac in ~/work ❯ git clone git@github.com:matsumotory/mruby-mrbgem-template.git 23:57 Cloning into 'mruby-mrbgem-template'... remote: Counting objects: 126, done. remote: Total 126 (delta 0), reused 0 (delta 0), pack-reused 126 Receiving objects: 100% (126/126), 20.05 KiB | 0 bytes/s, done. Resolving deltas: 100% (59/59), done. tahira at mac in ~/work ❯ cd mruby-mrbgem-template/ 3s 106ms # template_config.rbを編集する tahira at mac in ~/work/mruby-mrbgem-template on master ❯ vi template_config.rb tahira at mac in ~/work/mruby-mrbgem-template on master ❯ cat -n template_config.rb 29s 69ms 1 params = { 2 :mrbgem_name => 'mruby-example', 3 :license => 'MIT', 4 :github_user => 'tap1ra', 5 :mrbgem_prefix => File.expand_path('.'), 6 :class_name => 'Example', 7 :author => 'tap1ra', 8 } 9 10 c = MrbgemTemplate.new params 11 c.create # rake実行 いろいろ走って mruby-example が作成される # 完了するとその後叩くコマンドも全部出力される tahira at mac in ~/work/mruby-mrbgem-template on master [?] ❯ rake cd /Users/tahira/work/mruby-mrbgem-template/mruby-example # ★これがmgemを作成していくリポジトリ git init git add . git commit -m "first commit" git remote add origin git@github.com:tap1ra/mruby-example.git git push -u origin master > finally, pull-request mruby-example.gem to mgem-list https://github.com/bovi/mgem-list # あらかじめ自身のGithubアカウントに mruby-example リポジトリを作成し、上記コマンドを実行していく tahira at mac in ~/work/mruby-mrbgem-template on master [?] ❯ cd /Users/tahira/work/mruby-mrbgem-template/mruby-example 33s 125ms tahira at mac in ~/work/mruby-mrbgem-template/mruby-example on master [?] ❯ git init 00:03 Initialized empty Git repository in /Users/tahira/work/mruby-mrbgem-template/mruby-example/.git/ tahira at mac in ~/work/mruby-mrbgem-template/mruby-example on master [?] ❯ git add . 00:03 tahira at mac in ~/work/mruby-mrbgem-template/mruby-example on master [+] ❯ git commit -m "first commit" 00:03 [master (root-commit) 451b629] first commit 10 files changed, 188 insertions(+) create mode 100644 .travis.yml create mode 100644 .travis_build_config.rb create mode 100644 LICENSE create mode 100644 README.md create mode 100644 mrbgem.rake create mode 100644 mrblib/mrb_example.rb create mode 100644 mruby-example.gem create mode 100644 src/mrb_example.c create mode 100644 src/mrb_example.h create mode 100644 test/mrb_example.rb tahira at mac in ~/work/mruby-mrbgem-template/mruby-example on master ❯ git remote add origin git@github.com:tap1ra/mruby-example.git 00:03 tahira at mac in ~/work/mruby-mrbgem-template/mruby-example on master ❯ git push -u origin master # これでmgemの雛形がリポジトリにpushされた
2. 雛形のなかみ
# 何も手を加えていない状態が以下 tahira at mac in ~/work/mruby-mrbgem-template/mruby-example on master ❯ ls -la 00:24 total 48 drwxr-xr-x 12 tahira 2033490572 408 5 19 00:03 . drwxr-xr-x 18 tahira 2033490572 612 5 19 00:00 .. drwxr-xr-x 12 tahira 2033490572 408 5 19 00:24 .git -rw-r--r-- 1 tahira 2033490572 329 5 19 00:00 .travis.yml -rw-r--r-- 1 tahira 2033490572 121 5 19 00:00 .travis_build_config.rb -rw-r--r-- 1 tahira 2033490572 1135 5 19 00:00 LICENSE -rw-r--r-- 1 tahira 2033490572 504 5 19 00:00 README.md -rw-r--r-- 1 tahira 2033490572 110 5 19 00:00 mrbgem.rake # 作成するmgemが依存する他のmgemの情報を記載するファイル drwxr-xr-x 3 tahira 2033490572 102 5 19 00:00 mrblib # この下に作成するmgemのmrubyソースコードを配置 -rw-r--r-- 1 tahira 2033490572 181 5 19 00:00 mruby-example.gem drwxr-xr-x 4 tahira 2033490572 136 5 19 00:00 src # この下に作成するmgemのCソースコードを配置 drwxr-xr-x 3 tahira 2033490572 102 5 19 00:00 test
3. 手元でビルドできるようRakefileを作成する
# .travis_build_config.rb と [https://github.com/pyama86/mruby-acme-client/blob/master/build_config.rb] などを真似して自身を組み込んだmrubyをビルドできるようbuild_config.rbを作成する # 多少違うかもしれないけど以下のようになっているはず ❯ cat .travis_build_config.rb 00:10 MRuby::Build.new do |conf| toolchain :gcc conf.gembox 'default' conf.gem '../mruby-example' conf.enable_test end # 「conf.gem '../mruby-mrbgem-template'」この行で依存gemとして自分自身を読ませている(認識違ったら突っ込んで…) # よって以下のようなbuild_config.rbを書く tahira at mac in ~/work/mruby-mrbgem-template/mruby-example on master [?] ❯ cat -n build_config.rb 9s 854ms 1 MRuby::Build.new do |conf| 2 toolchain :gcc 3 conf.gembox 'default' 4 conf.gem File.expand_path(File.dirname(__FILE__)) 5 conf.enable_test 6 end # その上で「build_config.rbに↑で作成したものを利用してmrubyをビルドする」タスクの定義をおこなう tahira at mac in ~/work/mruby-mrbgem-template/mruby-example on master [?] ❯ cat -n Rakefile 00:33 1 MRUBY_CONFIG=File.expand_path("build_config.rb") 2 MRUBY_VERSION="master" 3 desc "mrubyをビルドするタスク" 4 file :mruby do 5 sh "git clone --depth=1 git://github.com/mruby/mruby.git" 6 Dir.chdir("./mruby") do 7 sh "git checkout #{MRUBY_VERSION} || true" 8 end 9 end 10 11 desc "build_config.rbを指定して(指定しないとmruby標準のものが利用されるので)ビルドするタスク" 12 task :compile => :mruby do 13 sh "cd mruby && MRUBY_CONFIG=#{MRUBY_CONFIG} rake all" 14 end
4. ここまでやるとmruby-exampleを組み込んだmrubyのビルドができるのでタスクを実行する
tahira at mac in ~/work/mruby-mrbgem-template/mruby-example on master [?] ❯ rake compile 209ms git clone --depth=1 git://github.com/mruby/mruby.git Cloning into 'mruby'... remote: Counting objects: 468, done. remote: Compressing objects: 100% (377/377), done. remote: Total 468 (delta 35), reused 216 (delta 13), pack-reused 0 Receiving objects: 100% (468/468), 474.67 KiB | 68.00 KiB/s, done. Resolving deltas: 100% (35/35), done. git checkout master|| true Already on 'master' Your branch is up-to-date with 'origin/master'. cd mruby && MRUBY_CONFIG=build_config.rb rake all ・・・(中略) ビルド完了 tahira at mac in ~/work/mruby-mrbgem-template/mruby-example on master [?] ❯ ll mruby/bin/mruby 00:36 -rwxr-xr-x 1 tahira 2033490572 920760 5 19 00:35 mruby/bin/mruby # mruby-exampleで定義されたクラスは以下のようになっている tahira at mac in ~/work/mruby-mrbgem-template/mruby-example on master [?] ❯ cat mrblib/mrb_example.rb 00:36 class Example def bye self.hello + " bye" end end # 以下のようなテストファイルを用意して作成したmrubyバイナリで実行すると、mrubyバイナリにmruby-exampleが組み込まれていれば結果が出力される tahira at mac in ~/work/mruby-mrbgem-template/mruby-example on master [?] ❯ cat -n example.rb 10:30 1 example = Example.new('hoge') 2 p example.bye tahira at mac in ~/work/mruby-mrbgem-template/mruby-example on master [?] ❯ mruby/bin/mruby example.rb 10:30 "hoge bye" # mruby-exampleが組み込まれていなければ以下のようにclass定義がみつからずエラーになる tahira at mac in ~/work/mruby-mrbgem-template/mruby-example on master [?] ❯ mruby/bin/mruby example.rb 1m 7s 814ms trace: [0] example.rb:1 example.rb:1:uninitialized constant Example (NameError)
5. Linux上で実行できるバイナリを作るため、Dockerでビルドさせる
今回Mac上で作業したので、アーキテクチャが異なるため(?)Linux上では実行することができません (同様にLinux上でビルドしたものはMac上で実行しようとすると「cannot execute binary file」のように怒られます)
# 以下のようなDockerfileを作成します # centos latestを使用し、ビルドに必要なライブラリをインストールしているだけのきれいな環境 tahira at mac in ~/work/mruby-mrbgem-template/mruby-example on master [?] ❯ cat -n Dockerfile 13s 155ms 1 FROM centos:latest 2 3 RUN yum install -y \ 4 epel-release \ 5 gcc \ 6 git \ 7 openssl-devel \ 8 ca-certificates \ 9 rubygems \ 10 curl \ 11 bison 12 13 RUN gem install \ 14 mgem \ 15 rake # Rakefileに以下のようにdockerでビルドするためのタスクの定義をおこないます # 1. ↑で作成したDockerfileを使用してexample:mrubyコンテナを作成 # 2. mruby-example作業ディレクトリをdockerコンテナ上にバインドマウントさせ、あとはMac上で行うときと同様にrake compileタスクを実行しています tahira at mac in ~/work/mruby-mrbgem-template/mruby-example on master [?] ❯ cat -n Rakefile | tail -4 20s 100ms 16 task :build do 17 sh "docker build -t example:mruby ." 18 sh "docker run -v `pwd`:/tmp -w /tmp -t example:mruby rake compile" 19 end # rake buildタスクを実行すると無事mrubyバイナリが作成されました tahira at mac in ~/work/mruby-mrbgem-template/mruby-example on master [?] ❯ rake build 10:39 docker build -t example:mruby . Sending build context to Docker daemon 23.23 MB Step 1/3 : FROM centos:latest # 今ビルドしたものをMac上で実行すると、おこられます ❯ mruby/bin/mruby example.rb 54s 699ms Failed to execute process 'mruby/bin/mruby'. Reason: exec: Exec format error The file 'mruby/bin/mruby' is marked as an executable but could not be run by the operating system.
今回はmgem自身の実装は全く触れていませんが、とりあえず開発ができる準備ができました。 おしまい
(便利情報)
local_buildみたいなオプションでRakefileも作ってくれる。あとmrubyはクロスコンパイル出来る。RT:mgemテンプレート作成からDocker上でビルドまで - カメニッキ https://t.co/JzrO708vo6
— P山 (@pyama86) 2017年5月19日