iOSでは、Objective-C（C++も書ける）、Swift しか使えません

が、C++の 異言語間インタフェース FFIを使えば、Objectibe-CやSwiftから C++を通して Rustを実行出来ます

そのための環境構築

とりあえず xcodeでのビルドを行う

Rustのインストール

Rust自体は パッケージマネージャから出来るが、その場合だと Rustのバージョン管理などが不便なので

もしインストールしている場合は 一旦削除し、Rustupをインストールする

環境構築は下記参照

Building and Deploying a Rust library on iOS

書いてる通り実行すれば出来るけど一応簡単に

xcode build toolのインストール

xcode-select --install

にて、xcodeのインストール

rustupのインストール

curl https://sh.rustup.rs -sSf | sh

rustupをインストールする

ios、iosシミュレータ用のToolChainのインストール

rustup target add aarch64-apple-ios armv7-apple-ios armv7s-apple-ios x86_64-apple-ios i386-apple-ios

iosだけでなく、iosシミュレータも入れておくと開発が楽

Cargoのインストール

cargo install cargo-lipo

パッケージマネージャ＆ビルドツールのCargoは是非入れておくべきだ

bash_profile 等に cargoのパスの設定が入るので、sourceして環境変数を読み込み直す

source ~/.bash_profile

サンプル

これまた、上記URLのとおりにすればよい

Rustファイル作成

lib.rs

use std :: os :: raw :: {c_char}; use std :: ffi :: {CString, CStr}; #[no_mangle] pub extern fn rust_greeting (to: *const c_char) -> *mut c_char { let c_str = unsafe { CStr :: from_ptr (to) }; let recipient = match c_str. to_str () { Err (_) => "there" , Ok (string) => string, }; CString :: new ( "Hello " . to_owned () + recipient). unwrap (). into_raw () } #[no_mangle] pub extern fn rust_greeting_free (s: *mut c_char) { unsafe { if s. is_null () { return } CString :: from_raw (s) }; }

Rustの文法は今回は省略

rust_greeting関数は 引数に文字列を受け取り "Hello " を頭につけて返す

rust_greeting_freeは 作成した文字列を開放する

FFI用ヘッダ

greetings.h

#include <stdint.h> const char * rust_greeting( const char * to); void rust_greeting_free( char *);

上記のRust関数を呼び出すためのヘッダである

toml

Rustのビルドのしかたを教えなければならない

Cargo.toml

[package] name = "greetings" version = "0.1.1" authors = ["fluffyemily <fluffyemily@mozilla.com>"] description = "Example static library project built for iOS" publish = false [lib] name = "greetings" crate-type = ["staticlib", "cdylib"]

今回は、ライブラリを作成するので、create-typeは スタティックライブラリとダイナミックライブラリを指定した

rustのビルド

cargo lipo --release

lipoを使うと便利である

今はToolChainに iOS関連をいれているので、それらがビルドされる

また、Universalライブラリという、全てのToolChainのライブラリがまとまったものが作成されるので

それを指定すれば、エミュレータでも実機でも、32bitでも64bitでも 設定変更不要で便利だ

xcodeでプロジェクト作成

とりあえずSinglePageプロジェクトを作成し

先程の作成した Universalライブラリと、libresolvをリンクする

また、リンクパスに Universalの場所を指定する

Swift Bridgeファイル

RustからC++へのブリッジは 上記 ライブラリ作成でC++とアクセス可能だ

Objective-CはC++と互換性があり そのまま実行できる

SwiftとC++を相互呼び出しするために Bridgeを作る

#ifndef Greetings_Bridging_Header_h #define Greetings_Bridging_Header_h #import "greetings.h" #endif

この、greetings.hは 先程作った Rust関数のC言語ヘッダである

importで怒られると思うが、ヘッダのSearchPathを追加すれば良い

Swiftコード作成

RustGreetings.swift

class RustGreetings { func sayHello (to : String ) -> String { let result = rust_greeting(to) let swift_result = String(cString : result ! ) rust_greeting_free(UnsafeMutablePointer( mutating : result )) return swift_result } }

RustのBridgeをした関数 rust_greeting、rust_greeting_free を呼び出すWrapクラス

多少面倒だが、こうやって呼び出すことが出来る

これを実行するために ViewControllerの viewDidLoadedに 上記を呼び出すコードを書く

let rustGreetings = RustGreetings() print( " \(rustGreetings.sayHello(to: "world") )" )

実行

実行すると Hello World とコンソールに出るはずだ