本文主题是IOS使用Rust库。其实C/C++库操作类似,本文前半部分我将描述怎么把Rust library编译为静态/动态连接库,后半部分是怎么使用这个库。
同样的,Rust编译的库同样适用于其他平台的项目比如Android、MSVC等。
一、准备工作
我假设你已经有Xcode和Rust环境,那么还需要:
-
目标平台Rust工具链
-
C/C++ 头文件生成器
-
IOS库编译工具
Rust工具链安装
rustup target add x86_64-apple-ios aarch64-apple-ios // 其他工具链,可以根据需求安装 rustup target list三方工具安装
cargo install lipo cargo install cbindgen
二、制作FFI静态库
为什么要静态链接?IOS对依赖库限制比较多,其他平台需要解决依赖关系,但如果你的App不是对构建物大小有限制的话这就是不是问题,当然这也不是本篇讨论的重点。
下面我们以开源项目google-authenticator-rust为例子。
1.编写导出C风格函数
// 返回C风格字符串
#[cfg(feature = "clib")]
#[no_mangle]
pub extern "C" fn create_secret(len: u8) -> *const c_char {
CString::new(GA_AUTH.create_secret(len))
.expect("can't make secret.")
.into_raw()
}
#[no_mangle] 控制编译器 不要破坏C函数名,确保外部能通过 create_secret 调用到这个函数。
#[cfg(feature = "clib")] 条件编译参数,编译库时通过增加features参数确定是否编译为C/C++库。
2.编写Rust内存释放相关代码
/// # Safety
/// A function that can be used for free returnd to C string
/// `str`, the string which be passed to outside
#[cfg(feature = "clib")]
#[no_mangle]
pub unsafe extern "C" fn free_str(str: *mut c_char) {
unsafe {
let _ = CString::from_raw(str);
}
}
3.导出C/C++ Header
这个需要注意的是,默认导出的C Header file, 需要C++ header,需要配置cbindgen.tmol
导出头文件到 src/authenticator.h
cbindgen ./ -l c --output src/authenticator.h
4. 编译静态库
配置Cargo.toml
#修改[lib]
[lib]
name="authenticator"
crate-type = ["staticlib", "cdylib"] #同时编译静态和动态库
required-features = ["with-qrcode","clib"]
编译目标平台lib
# 这里需要说明的是,feature 可以根据需要增减targets, 案例中增加x86完全是为了在x86平台调试
cargo lipo --all-features --release --targets x86_64-apple-ios aarch64-apple-ios
# 编译结果文件目录如下,`.a`就是静态库
target
├── aarch64-apple-ios
│ └── build
│ ├── libauthenticator.a
│ └── libauthenticator.dylib
│
├── universal
│ └── release
└── x86_64-apple-ios
└── release
├── libauthenticator.a
└── libauthenticator.dylib
当然可以把x86和arm64两个平台库合并为一个库,合并也是测试目的,并非必要步骤,仅为x86平台调试作用。
lipo -create target/x86_64-apple-ios/release/authenticator.lib \
target/aarch64-apple-ios/release/libauthenticator.a \
-output libauthenticator.a
至此已经编译好库文件,如果你是Apple生态项目大拿或者只需要知道怎么编译Rust库就可以忽略以下内容。 下面我们将通过一个MacOS App案例介绍怎么使用静态库。
三、IOS/Mac Project 使用C库
这个案例以Swift项目为例,一步一步介绍如何使用C library
1. 添加C Library到项目
可以拖动刚才编译好的libauthenticator.a到项目,在General->Frameworks,Libraries...->Add Other添加。
添加libresolv.tdb到项目,可以直接在 General->Frameworks,Libraries...中搜索到。
2. 添加C Header到项目
xcode Add Files To '{project}'
3. 编写Objective-C Bridge Header
xcode File -> New -> File..., 选择Header File并命名为 Authenticator-Bridging-Header.h。
4. 配置项目路径
xcode TARGETS Authenticator, Build Setting
Objective-C Bridging Header增加 $(PROJECT_DIR)/Authenticator/Authenticator-Bridging-Header.h
Search Paths -> Header Search Paths 增加 $(PROJECT_DIR)/Authenticator
Search Paths -> Library Search Paths 增加 $(PROJECT_DIR)/Authenticator
修改为如下,请注意修改自己的目录
5. OC Bridging Header 引入C header
Authenticator-Bridging-Header.h
#ifndef Authenticator_Bridging_Header_h
#define Authenticator_Bridging_Header_h
#define DEFINE_QRCODE
#import "authenticator.h"
#endif /* Authenticator_Bridging_Header_h */
5. 编写swift调用类
注意这里有个要点,Rust返回的字符串需要归还Rust释放内存,其他语言同理。
free_str(UnsafeMutablePointer(mutating: encodeCode))
Authenticator.swift
import Foundation
class Authenticator {
func getCode(secret:String) -> String {
let encodeCode = get_code(secret, UInt64(NSDate().timeIntervalSince1970 / 30))
let code = String(cString: encodeCode!)
free_str(UnsafeMutablePointer(mutating: encodeCode))
return code;
}
}
至此,Swift项目调用Rust库已经配置完成。如果配置过程中遇到问题或者其他有疑惑的地方可以参照项目
更多参照
原文发布于: notes.icool.io/rust-ios-ma…