在 iOS 上構(gòu)建和部署 Rust 庫

首先沾歪,我們必須安裝 Xcode潘酗,然后設(shè)置 Xcode 構(gòu)建工具贮配。如果您已經(jīng)安裝了構(gòu)建工具并且它們是最新的,則可以跳過此步驟弟疆。

xcode-select --install
xcode-select --install

接下來盒揉,我們需要確保安裝了 Rust,并且我們可以交叉編譯到 iOS 架構(gòu)榆俺。為此售躁,我們將使用rustup。如果你已經(jīng)安裝了 rustup茴晋,你可以跳過這一步陪捷。Rustup 從官方發(fā)布渠道安裝 Rust,使您能夠輕松地在不同的發(fā)布版本之間切換诺擅。它對你未來所有的 Rust 開發(fā)都有用市袖,而不僅僅是在這里。

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

將 iOS 架構(gòu)添加到 rustup,以便我們可以在交叉編譯期間使用它們苍碟。
這里列出了所有支持的架構(gòu): Rust Cross-compilation Platform Support

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

當(dāng)你安裝 Rust 時酒觅,它也安裝了 cargo,這是一個類似于 pip微峰、gems 等的包管理器∠系ぃ現(xiàn)在我們將使用 cargo 來安裝cargo-lipo。這是一個 cargo 子命令蜓肆,它自動創(chuàng)建一個用于 iOS 的通用庫颜凯。沒有這個箱子,交叉編譯 Rust 以在 iOS 上工作將變得非常困難仗扬。

cargo install cargo-lipo

現(xiàn)在我們都準(zhǔn)備好了症概,可以開始了。讓我們創(chuàng)建項目目錄早芭。

mkdir greetings
cd greetings
cargo new cargo
mkdir iOS

cargo new cargo建立一個全新的 Rust 項目彼城,其默認(rèn)文件和目錄位于名為cargo. 在這個目錄中有一個名為 的文件Cargo.toml,它是包管理器描述符文件退个,還有一個子目錄募壕,src其中包含一個名為lib.rs. 這將包含我們將要執(zhí)行的 Rust 代碼。

我們這里的 Rust 項目是一個超級簡單的 Hello World 庫语盈。它包含一個函數(shù)rust_greeting司抱,該函數(shù)接受一個字符串參數(shù)并返回一個字符串問候該參數(shù)。因此黎烈,如果參數(shù)是“world”,則返回的字符串是“Hello world”匀谣。

打開cargo/src/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)
    };
}

讓我們來看看這里發(fā)生了什么。

由于我們將從非 Rust 代碼調(diào)用這個庫武翎,我們實際上將通過 C 橋調(diào)用它烈炭。#[no_mangle]告訴編譯器不要像默認(rèn)情況下那樣破壞函數(shù)名,確保我們的函數(shù)名被導(dǎo)出宝恶,就像它是用 C 語言編寫的一樣符隙。

extern告訴 Rust 編譯器這個函數(shù)將從 Rust 外部調(diào)用,因此確保它是使用 C 調(diào)用約定編譯的垫毙。

接受的字符串rust_greeting是指向 C 字符數(shù)組的指針霹疫。然后我們必須將字符串從 C 字符串轉(zhuǎn)換為 Rust 字符串str。CStr首先我們從指針創(chuàng)建一個對象综芥。然后我們將其轉(zhuǎn)換為 astr并檢查結(jié)果丽蝎。如果發(fā)生錯誤,則沒有提供 arg 并且我們替換there膀藐,否則我們使用提供的字符串的值屠阻。然后我們將提供的字符串附加到我們的問候字符串的末尾以創(chuàng)建我們的返回字符串红省。然后將返回字符串轉(zhuǎn)換為 aCString并傳遞回 C 代碼。

使用CString并返回原始表示將字符串保留在內(nèi)存中并防止它在函數(shù)結(jié)束時被釋放国觉。如果要釋放內(nèi)存吧恃,返回給調(diào)用者的指針現(xiàn)在將指向空內(nèi)存——或者可能完全指向其他東西。但是麻诀,通過確保字符串在函數(shù)執(zhí)行完成后仍然存在痕寓,我們已經(jīng)分配了內(nèi)存并且不再有任何句柄。這是內(nèi)存泄漏的一個秘訣针饥,因此我們必須提供第二個函數(shù)rust_greeting_free厂抽,它接受一個指向 C 字符串的指針并釋放該內(nèi)存。我們必須記住rust_greeting_free從我們的 iOS 代碼調(diào)用以確保我們不會遇到問題丁眼。

我們還需要創(chuàng)建我們的 C 橋筷凤。cargo/src在名為greetings.h. 在該文件中,讓我們定義 C 接口的外觀苞七。我們需要確保我們想要從 iOS 調(diào)用的每個 Rust 函數(shù)都在這里定義藐守。

#include <stdint.h>

const char* rust_greeting(const char* to);
void rust_greeting_free(char *);

讓我們構(gòu)建我們的代碼以確保它有效。為此蹂风,我們必須完成我們的Cargo.toml文件卢厂。這將告訴 cargo 為我們的代碼創(chuàng)建靜態(tài)庫和 C 動態(tài)庫。

[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"]

我們需要使用cargo-lipo. 的構(gòu)建工件將放置在cargo/target/. 我們感興趣的通用 iOS 庫可以在cargo/target/universal/release/libgreetings.a.

cd cargo
cargo lipo --release

這就是我們的 Rust 庫惠啄。讓我們把它與一個 iOS 項目聯(lián)系起來慎恒。

打開 Xcode 并創(chuàng)建一個新項目。轉(zhuǎn)到File\New\Project…并選擇iOS\Application\Single View Application模板撵渡。此模板盡可能接近默認(rèn)的 iOS 應(yīng)用程序融柬。點擊Next。

image.png

調(diào)用該項目Greetings趋距,使其成為 Swift 項目粒氧。單擊Next以選擇位置。我們正在使用之前創(chuàng)建的 ios 目錄节腐。如果您選擇另一個位置外盯,您將不得不修改我們稍后設(shè)置的一些路徑。點擊Create翼雀。

image.png

從項目導(dǎo)航器中選擇 Greetings 項目饱苟,然后確保選擇了 Greetings 目標(biāo)。打開General選項卡锅纺。向下滾動到該Linked Frameworks and Libraries部分掷空。

image.png

通過從 finder 中拖入您的libgreetings.a庫,或單擊列表底部的 +,單擊“添加其他...”并導(dǎo)航至 來導(dǎo)入您的庫cargo/target/universal/release/坦弟。選擇libgreetings.a然后單擊Open护锤。

鏈接libresolv.tbd。單擊 Linked Frameworks 列表底部的 +酿傍,然后在搜索框中鍵入 libresolv烙懦。選擇libresolv.tbd然后“添加”。

image.png

iOS 將需要一個橋接標(biāo)頭來訪問我們創(chuàng)建的 C 標(biāo)頭赤炒。首先氯析,讓我們導(dǎo)入greetings.h到我們的 Xcode 項目中,以便我們可以鏈接到它莺褒。轉(zhuǎn)到File\Add files to "Greetings"...導(dǎo)航到greetings.h并選擇Add掩缓。

要創(chuàng)建我們的橋接頭,請轉(zhuǎn)到File\New\File...遵岩。iOS\Source\Header File從提供的選項中選擇并選擇Next你辣。命名文件Greetings-Bridging-Header.h并選擇Create.

image.png

打開橋接頭并將其修改為如下所示:

#ifndef Greetings_Bridging_Header_h
#define Greetings_Bridging_Header_h

#import "greetings.h"

#endif

我們需要將橋接標(biāo)頭告知 Xcode。從項目導(dǎo)航器中選擇 Greetings 項目尘执,然后確保選擇了 Greetings 目標(biāo)并打開 Build Settings 選項卡舍哄。將Objective-C Bridging Header選項值設(shè)置為$(PROJECT_DIR)/Greetings/Greetings-Bridging-Header.h

image.png

我們還需要告訴 Xcode 在哪里尋找我們的鏈接庫。在同一個 Build Settings 窗格中誊锭,將Library Search Paths選項值修改為$(PROJECT_DIR)/../../cargo/target/universal/release

image.png

構(gòu)建你的 xcode 項目表悬,一切都應(yīng)該編譯。

所以丧靡,現(xiàn)在我們已經(jīng)將 Rust 庫導(dǎo)入到我們的 iOS 項目中并成功鏈接到它蟆沫。但是我們?nèi)匀恍枰{(diào)用它。去File\New\File...温治。iOS\Source\Swift File從提供的選項中選擇并選擇Next饥追。命名命名它RustGreetings。

image.png

添加以下代碼:

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
    }
}

這將創(chuàng)建一個新類罐盔,我們將使用它作為調(diào)用我們的 Rust 庫的接口。這將使我們能夠從應(yīng)用程序的主要代碼中抽象出細(xì)微差別救崔,包括從 C 字符串到 Swift 字符串的轉(zhuǎn)換惶看,并確保我們不會忘記調(diào)用我們的自由函數(shù)并無意中引入內(nèi)存泄漏!

打開ViewController.swift六孵。在函數(shù)內(nèi)部viewDidLoad添加以下代碼:

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

現(xiàn)在構(gòu)建您的項目并運行纬黎。模擬器將打開并開始運行您的應(yīng)用程序。當(dāng)視圖加載時劫窒,“Hello world”將在 Xcode 的控制臺窗口中輸出本今。

你可以在Github上找到這個代碼

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子冠息,更是在濱河造成了極大的恐慌挪凑,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,591評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件逛艰,死亡現(xiàn)場離奇詭異躏碳,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)散怖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評論 3 392
  • 文/潘曉璐 我一進(jìn)店門菇绵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人镇眷,你說我怎么就攤上這事咬最。” “怎么了欠动?”我有些...
    開封第一講書人閱讀 162,823評論 0 353
  • 文/不壞的土叔 我叫張陵永乌,是天一觀的道長。 經(jīng)常有香客問我翁垂,道長铆遭,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,204評論 1 292
  • 正文 為了忘掉前任沿猜,我火速辦了婚禮枚荣,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘啼肩。我一直安慰自己橄妆,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,228評論 6 388
  • 文/花漫 我一把揭開白布祈坠。 她就那樣靜靜地躺著害碾,像睡著了一般。 火紅的嫁衣襯著肌膚如雪赦拘。 梳的紋絲不亂的頭發(fā)上慌随,一...
    開封第一講書人閱讀 51,190評論 1 299
  • 那天,我揣著相機(jī)與錄音躺同,去河邊找鬼阁猜。 笑死,一個胖子當(dāng)著我的面吹牛蹋艺,可吹牛的內(nèi)容都是我干的剃袍。 我是一名探鬼主播,決...
    沈念sama閱讀 40,078評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼捎谨,長吁一口氣:“原來是場噩夢啊……” “哼民效!你這毒婦竟也來了憔维?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,923評論 0 274
  • 序言:老撾萬榮一對情侶失蹤畏邢,失蹤者是張志新(化名)和其女友劉穎业扒,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體棵红,經(jīng)...
    沈念sama閱讀 45,334評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡凶赁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,550評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了逆甜。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片虱肄。...
    茶點故事閱讀 39,727評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖交煞,靈堂內(nèi)的尸體忽然破棺而出咏窿,到底是詐尸還是另有隱情,我是刑警寧澤素征,帶...
    沈念sama閱讀 35,428評論 5 343
  • 正文 年R本政府宣布集嵌,位于F島的核電站,受9級特大地震影響御毅,放射性物質(zhì)發(fā)生泄漏根欧。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,022評論 3 326
  • 文/蒙蒙 一端蛆、第九天 我趴在偏房一處隱蔽的房頂上張望凤粗。 院中可真熱鬧,春花似錦今豆、人聲如沸嫌拣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽异逐。三九已至,卻和暖如春插掂,著一層夾襖步出監(jiān)牢的瞬間灰瞻,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評論 1 269
  • 我被黑心中介騙來泰國打工辅甥, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留箩祥,地道東北人。 一個月前我還...
    沈念sama閱讀 47,734評論 2 368
  • 正文 我出身青樓肆氓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親底瓣。 傳聞我的和親對象是個殘疾皇子谢揪,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,619評論 2 354

推薦閱讀更多精彩內(nèi)容