鍍金池/ 教程/ Java/ 將Rust編譯成庫
標(biāo)準(zhǔn)輸入與輸出
消息傳遞
循環(huán)
注釋
Rust for Mac OS
幾種智能指針
Cell, RefCell
trait對(duì)象 (trait object)
rust web 開發(fā)
Unsafe、原始指針
Macro
迭代器
函數(shù)
Borrow, BorrowMut, ToOwned
快速上手
二叉樹
編輯器
測(cè)試與評(píng)測(cè)
Deref
安裝Rust
哈希表 HashMap
原生類型
17.錯(cuò)誤處理
VS Code 安裝配置
動(dòng)態(tài)數(shù)組Vec
模式匹配
操作符和格式化字符串
Rust for Linux
函數(shù)參數(shù)
Visual Studio
vim/GVim安裝配置
閉包作為參數(shù)和返回值
安全(Safety)
Cow
生命周期( Lifetime )
閉包的實(shí)現(xiàn)
所有權(quán)(Ownership)
Atom
將Rust編譯成庫
類型、運(yùn)算符和字符串
類型系統(tǒng)中的幾個(gè)常見 trait
特性
屬性和編譯器參數(shù)
Spacemacs
集合類型
Rust json處理
Heap & Stack
并行
標(biāo)準(zhǔn)庫示例
基本程序結(jié)構(gòu)
鏈表
trait 和 trait對(duì)象
前期準(zhǔn)備
代碼風(fēng)格
編譯器參數(shù)
基于語義化版本的項(xiàng)目版本聲明與管理
Rust 版本管理工具: rustup
引用&借用(References&Borrowing)
注釋與文檔
10.1 trait關(guān)鍵字
模式
調(diào)用ffi函數(shù)
unsafe
并發(fā),并行,多線程編程
AsRef 和 AsMut
Rust旅程
Rust for Windows
結(jié)構(gòu)體與枚舉
條件分支
附錄I-術(shù)語表
變量綁定與原生類型
Mutex 與 RwLock
泛型
裸指針
常用數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)
系統(tǒng)命令:調(diào)用grep
Into/From 及其在 String 和 &str 互轉(zhuǎn)上的應(yīng)用
共享內(nèi)存
Sublime
網(wǎng)絡(luò)模塊:W貓的回音
函數(shù)返回值
包和模塊
高階函數(shù)
函數(shù)與方法
match關(guān)鍵字
隊(duì)列
目錄操作:簡(jiǎn)單grep
語句和表達(dá)式
并發(fā)編程
閉包
測(cè)試
閉包的語法
同步
迭代器
String
Send 和 Sync
Rc 和 Arc
屬性
Emacs
優(yōu)先隊(duì)列
Prelude
cargo簡(jiǎn)介
控制流(control flow)
數(shù)組、動(dòng)態(tài)數(shù)組和字符串
FFI
模塊和包系統(tǒng)、Prelude
實(shí)戰(zhàn)篇
Rust 是一門系統(tǒng)級(jí)編程語言,被設(shè)計(jì)為保證內(nèi)存和線程安全,并防止段錯(cuò)誤。作為系統(tǒng)級(jí)編程語言,它的基本理念是 “零開銷抽象”。理
運(yùn)算符重載
Any和反射
rust數(shù)據(jù)庫操作
輸入輸出流
復(fù)合類型
性能測(cè)試

將Rust編譯成庫

上一章講述了如何從rust中調(diào)用c庫,這一章我們講如何把rust編譯成庫讓別的語言通過cffi調(diào)用。

調(diào)用約定和mangle

正如上一章講述的,為了能讓rust的函數(shù)通過ffi被調(diào)用,需要加上extern "C"對(duì)函數(shù)進(jìn)行修飾。

但由于rust支持重載,所以函數(shù)名會(huì)被編譯器進(jìn)行混淆,就像c++一樣。因此當(dāng)你的函數(shù)被編譯完畢后,函數(shù)名會(huì)帶上一串表明函數(shù)簽名的字符串。

比如:fn test() {}會(huì)變成_ZN4test20hf06ae59e934e5641haaE. 這樣的函數(shù)名為ffi調(diào)用帶來了困難,因此,rust提供了#[no_mangle]屬性為函數(shù)修飾。 對(duì)于帶有#[no_mangle]屬性的函數(shù),rust編譯器不會(huì)為它進(jìn)行函數(shù)名混淆。如:

#[no_mangle]
extern "C" fn test() {}

在nm中觀察到為

...
00000000001a7820 T test
...

至此,test函數(shù)將能夠被正常的由cffi調(diào)用。

指定crate類型

rustc默認(rèn)編譯產(chǎn)生rust自用的rlib格式庫,要讓rustc產(chǎn)生動(dòng)態(tài)鏈接庫或者靜態(tài)鏈接庫,需要顯式指定。

  1. 方法1: 在文件中指定。 在文件頭加上#![crate_type = "foo"], 其中foo的可選類型有bin, lib, rlib, dylib, staticlib.分別對(duì)應(yīng)可執(zhí)行文件, 默認(rèn)(將由rustc自己決定), rlib格式,動(dòng)態(tài)鏈接庫,靜態(tài)鏈接庫。
  2. 方法2: 編譯時(shí)給rustc 傳--crate-type參數(shù)。參數(shù)內(nèi)容同上。
  3. 方法3: 使用cargo,指定crate-type = ["foo"], foo可選類型同1

小技巧: Any

由于在跨越ffi過程中,rust類型信息會(huì)丟失,比如當(dāng)用rust提供一個(gè)OpaqueStruct給別的語言時(shí):

use std::mem::transmute;

#[derive(Debug)]
struct Foo<T> {
  t: T
}

#[no_mangle]
extern "C" fn new_foo_vec() -> *const c_void {
    Box::into_raw(Box::new(Foo {t: vec![1,2,3]})) as *const c_void
}

#[no_mangle]
extern "C" fn new_foo_int() -> *const c_void {
    Box::into_raw(Box::new(Foo {t: 1})) as *const c_void
}

fn push_foo_element(t: &mut Foo<Vec<i32>>) {
    t.t.push(1);
}

#[no_mangle]
extern "C" fn push_foo_element_c(foo: *mut c_void){
    let foo2 = unsafe {
        &mut *(foo as *mut Foo<Vec<i32>>) // 這么確定是Foo<Vec<i32>>? 萬一foo是Foo<i32>怎么辦?
    };
    push_foo_element(foo3);
}

以上代碼中完全不知道foo是一個(gè)什么東西。安全也無從說起了,只能靠文檔。 因此在ffi調(diào)用時(shí)往往會(huì)喪失掉rust類型系統(tǒng)帶來的方便和安全。在這里提供一個(gè)小技巧:使用Box<Box<Any>>來包裝你的類型。

rustAny類型為rust帶來了運(yùn)行時(shí)反射的能力,使用Any跨越ffi邊界將極大提高程序安全性。

use std::any::Any;

#[derive(Debug)]
struct Foo<T> {
  t: T
}

#[no_mangle]
extern "C" fn new_foo_vec() -> *const c_void {
    Box::into_raw(Box::new(Box::new(Foo {t: vec![1,2,3]}) as Box<Any>)) as *const c_void
}

#[no_mangle]
extern "C" fn new_foo_int() -> *const c_void {
    Box::into_raw(Box::new(Box::new(Foo {t: 1}) as Box<Any>)) as *const c_void
}

fn push_foo_element(t: &mut Foo<Vec<i32>>) {
    t.t.push(1);
}

#[no_mangle]
extern "C" fn push_foo_element_c(foo: *mut c_void){
    let foo2 = unsafe {
        &mut *(foo as *mut Box<Any>)
    };
    let foo3: Option<&mut Foo<Vec<i32>>> = foo2.downcast_mut(); // 如果foo2不是*const Box<Foo<Vec<i32>>>, 則foo3將會(huì)是None
    if let Some(value) = foo3 {
      push_foo_element(value);
    }
}

這樣一來,就非常不容易出錯(cuò)了。

上一篇:Borrow, BorrowMut, ToOwned下一篇:同步