iOS(シミュレーターとiPhone 7 Plus実機)でmrubyを動かす

Androidより苦労しないだろうと思ってたけど、予想通りそうでした。
(Web上に情報が多い)

mrubyのbuildまで

まずはプロジェクトを作成。
(ここではプロジェクト名をHelloMrubyとする)

プロジェクトのディレクトリにmrubyをcloneしてくる。

$ cd ~/path/to/HelloMruby
$ git clone --depth 1 https://github.com/mruby/mruby.git -b 2.1.2 mruby-2.1.2

https://github.com/cinderella-project/mruby/blob/for-imast/build_config.rb を参考にcustom_build_config.rbを作成。

MRuby::Build.new do |conf|
  conf.toolchain :clang
  conf.gem core: 'mruby-bin-mrbc'
end

MRuby::CrossBuild.new('iphonesimulator') do |conf|
  toolchain :clang

  conf.cc do |cc|
    cc.command = "xcrun"
    cc.flags = %W(-sdk iphonesimulator clang -fembed-bitcode-marker)
  end

  conf.linker do |linker|
    linker.command = "xcrun"
    linker.flags = %W(-sdk iphonesimulator clang -fembed-bitcode-marker)
  end

  Dir.glob("#{root}/mrbgems/mruby-*/mrbgem.rake") do |x|
    g = File.basename File.dirname x
    conf.gem :core => g unless g =~ /^mruby-(test|bin-.*)$/
  end
end

MRuby::CrossBuild.new('iphoneos') do |conf|
  toolchain :clang

  conf.cc do |cc|
    cc.command = "xcrun"
    cc.flags = %W(-sdk iphoneos clang -arch arm64 -arch arm64e -arch armv7 -arch armv7s -fembed-bitcode-marker)
  end

  conf.linker do |linker|
    linker.command = "xcrun"
    linker.flags = %W(-sdk iphoneos clang -arch arm64 -arch arm64e -arch armv7 -arch armv7s -fembed-bitcode-marker)
  end

  Dir.glob("#{root}/mrbgems/mruby-*/mrbgem.rake") do |x|
    g = File.basename File.dirname x
    conf.gem :core => g unless g =~ /^mruby-(test|bin-.*)$/
  end
end

buildした後、lipoでシミュレーターと実機用のlibmruby.aを1つのファイルにする。

$ cd mruby-2.1.2
$ rake MRUBY_CONFIG=../custom_build_config.rb

$ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/lipo  build/iphoneos/lib/libmruby.a build/iphonesimulator/lib/libmruby.a -create -output build/libmruby.a

lipoについては http://akisute.com/2011/03/lipo-universal-binary.html を参考にしました。

Xcodeプロジェクトの設定

以下の記事ほぼそのままで行ける。

yamshing.hatenablog.com

  • Header Search Pathsに mruby-2.1.2/include を追加(non-recursive)
  • Link Binary With Librariesから mruby-2.1.2/build/libmruby.a を追加(Library Search Pathsは自動で追加される)
  • ブリッジングヘッダーを作成
    • 空のObjective-Cファイルを作れば自動作成される。Objective-Cファイルはすぐ消す。
    • 中身は以下
#include <mruby.h>
#include <mruby/compile.h>
#include <mruby/string.h>

これでmrubyがプロジェクトに追加される。

mrubyを呼び出す

ViewControllerから呼び出します。

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        runRuby("'a * 1")
        runRuby("'hello! ' * 3")
    }
    
    func runRuby(_ source: String) {
        let mrb = mrb_open()
        
        let result = mrb_load_string(mrb, source)
        let output: String
        if let exc = mrb?.pointee.exc {
            output = String(cString: mrb_string_cstr(mrb, mrb_inspect(mrb, mrb_obj_value(exc))))
        } else {
            output = String(cString: mrb_string_cstr(mrb, result))
        }
        print(output)
    }
}

シミュレーターでも実機でもコンソールに以下の内容が出力されました。

line 1:6: unterminated string meets end of file
syntax error (SyntaxError)
hello! hello! hello! 

これでiOSアプリにも導入できそう(具体的なアイディアはまだない)