0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

一次Rust重寫基礎軟件的實踐

jf_wN0SrCdH ? 來源:Rust語言中文社區(qū) ? 2024-01-25 11:21 ? 次閱讀

前言

受到2022年“谷歌使用Rust重寫Android系統(tǒng)且所有Rust代碼的內存安全漏洞為零” [1] 的啟發(fā),最近筆者懷著濃厚的興趣也順應Rust 的潮流,嘗試著將一款C語言開發(fā)的基礎軟件轉化為 Rust 語言。本文的主要目的是通過記錄此次轉化過程中遇到的比較常見且有意思的問題以及解決此問題的方法與大家一起做相關的技術交流和討論。

問題描述

本文將記錄轉化過程中遇到的另外一個問題。該問題是由已經轉化完成的 Rust 代碼使用到軟件中引入的第三方軟件包和鏈接庫所導致的。設想這樣一個場景:Rust 項目中完成某一個功能點需要用到一個或多個第三方軟件包和鏈接庫。這顯然是很常見的用戶場景,但是由于用戶環(huán)境不同,用戶安裝的第三方軟件包和鏈接庫的版本不同,使得轉化后的 Rust 代碼必須要做適當的兼容處理。

這里所說的用戶的環(huán)境不同,可以理解為芯片指令集的平臺不同,如 Intel x86 以及國產的 ARM 麒麟服務器。當然更常見的情形是芯片平臺相同,但是存在操作系統(tǒng)層面第三方軟件包和鏈接庫安裝的差異,如 x86 下的 Ubuntu 和 CentOS 中用戶安裝了不同版本的第三方軟件包和鏈接庫等。

事實上,即使排除所有平臺和系統(tǒng)層面的差異,由于用戶安裝了該基礎軟件所依賴的不同版本的第三方軟件包和鏈接庫,然而這些第三方軟件包或者鏈接庫由于自身的演進導致不同版本之間存在較大差異(可能實現相同功能的函數和函數簽名都有千差萬別),這給我重寫該軟件的工作帶來了一些挑戰(zhàn)?;谏鲜稣f明,在完成重寫該基礎軟件的過程中如何使得轉化后的 Rust 代碼能兼容該基礎軟件所依賴的主流第三方軟件包和鏈接庫則是我遇到的最大挑戰(zhàn)。需要說明的是這里的第三方軟件包和鏈接庫可能是基于 Rust 語言開發(fā)的,也可能是基于 C 語言開發(fā)的。

解決方案

對于此問題的解決方案需要使用 Rust FFI(Foreign Function Interface) [1],這基本上是沒有太大爭議的。因為在本次軟件重寫過程中我遇到的場景是:對于不同版本的鏈接庫使用哪個版本的函數取決于用戶的安裝運行時環(huán)境,所以除了 Rust FFI,在代碼適配上我還考慮了使用 Rust features [2] 機制。

下面我簡化了一下場景和解決方案,同時我把樣本代碼放到了我的 github [3] 里,歡迎大家一起交流。如樣本代碼所示,my-rust-bin 文件夾中的一段業(yè)務代碼需要調用到靜態(tài)鏈接庫 my_rust_lib 中的函數,該鏈接庫有兩個版本 v1(在文件夾 my-rust-lib-v1 中) 和 v2(在文件夾 my-rust-lib-v2 中), 且不同版本的庫其函數不一樣。

my-rust-lib-v1 對應的業(yè)務函數為:pub fn my_rust_lib_v1(left: usize, right: usize) -> usize

my-rust-lib-v2 對應的業(yè)務函數為:pub fn my_rust_lib_v2(left: usize, right: usize) -> usize

另外一個 lib 文件夾的目的其實是為了模擬用戶本地安裝的鏈接庫。可以分別編譯不同版本的靜態(tài)鏈接庫,然后把生成的庫文件(在本例中是)libmy_rust_lib.a, 然后把不同版本的庫文件拷貝到此文件夾下,以此來模擬用戶環(huán)境中安裝的不同版本的鏈接庫。解決方案中的關鍵點在于 my-rust-bin 中,

首先在 my-rust-bin 的 Cargo.toml 中有定義對應的 features,如下所示:

[features]
v1=[]
v2=[]

其次在 my-rust-bin 的 src/main.rs 下的代碼如下:

#[cfg(feature="v1")]
modbindingmylib{
extern"C"{
pubfnmy_rust_lib_v1(left:usize,right:usize)->usize;
}
}

#[cfg(feature="v2")]
modbindingmylib{
extern"C"{
pubfnmy_rust_lib_v2(left:usize,right:usize)->usize;
}
}

#[cfg(not(any(feature="v1",feature="v2")))]
compile_error!("Pleasespecifyeither'v1'or'v2'feature");

pubfnmy_rust_lib(left:usize,right:usize)->usize{
#[cfg(feature="v1")]
unsafe{
returnbindingmylib::my_rust_lib_v1(left,right);
}

#[cfg(feature="v2")]
unsafe{
returnbindingmylib::my_rust_lib_v2(left,right);
}
}

fnmain(){
letr_value:usize=my_rust_lib(3,5);
println!("Thereturnvalueofmy_rust_libis[{}]",r_value);
}

現在我來解讀一下這段代碼。代碼先分別定義一個相同的模塊 bindingmylib,然后根據 features 分別引入的依賴,使用的不同的靜態(tài)鏈接庫函數(my_rust_lib_v1 和 my_rust_lib_v2), 同時通過 compile_error! 定義一個沒有設置 v1 和 v2 features 的編譯錯誤(防止編譯時忘記設置 features選項,下面在編譯環(huán)節(jié)的時候有用)。最后將兩個有差異的函數統(tǒng)一為函數 my_rust_lib,并在該函數中根據 features 定義分別調用不同的函數并返回相應的值。

最后是在 my-rust-bin 中編譯二進制文件:

編譯并運行 v1 的二進制文件

#編譯v1版本的my-rust-bin
$cdmy-rust-bin
$cargobuild--features="v1"

#運行v1版本的my-rust-bin
$target/debug/my-rust-bin
my_rust_lib_v1:8
Thereturnvalueofmy_rust_libis[8]

編譯并運行 v2 的二進制文件

#編譯v2版本的my-rust-bin
$cdmy-rust-bin
$cargobuild--features="v2"

#運行v2版本的my-rust-bin
$target/debug/my-rust-bin
my_rust_lib_v2:8
Thereturnvalueofmy_rust_libis[8]

備注:如果編譯的時候沒有設置 --features 則會有如下輸出:

$cargobuild
error:Pleasespecifyeither'v1'or'v2'feature
-->src/main.rs1
|
16|compile_error!("Pleasespecifyeither'v1'or'v2'feature");
|^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

至此,用戶在編譯好該基礎軟件之后,就可以無感知的通過統(tǒng)一的函數入口調用不同版本的相同鏈接庫中的不同函數了。

總結

本文主要是在簡化了問題的實際場景以后,解決不同版本的同一軟件包或者鏈接庫中,函數及其函數簽名不同導致的調用問題。之所以說簡化,主要是本文所描述的場景中,my-rust-bin 和其依賴的外部鏈接庫均是 Rust 編寫。而在我的實際場景中則會更復雜一些,存在著 Rust 代碼依賴 C 編寫的外部鏈接庫,同時存在混合的原來 C 代碼部分依賴新改寫的 Rust 外部鏈接庫的情況。但是無論哪種情況,萬變不離其宗,我們都可以從這種最簡單的場景出發(fā)去解決遇到的問題。

關于作者

張懷龍曾就職于阿爾卡特朗訊,百度,IBM等企業(yè)從事云計算研發(fā)相關的工作。目前就職于 Intel 中國,擔任云原生開發(fā)工程師并致力于云原生、服務網格等技術領域研究實踐,也是Istio 的maintainer的開發(fā)者。曾多次在 KubeCon、ServiceMeshCon、IstioCon、GOTC 和 InfoQ/QCon 等大會上發(fā)表演講。

審核編輯:湯梓紅

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • 操作系統(tǒng)

    關注

    37

    文章

    6603

    瀏覽量

    123019
  • C語言
    +關注

    關注

    180

    文章

    7581

    瀏覽量

    135540
  • 代碼
    +關注

    關注

    30

    文章

    4694

    瀏覽量

    68075
  • Rust
    +關注

    關注

    1

    文章

    228

    瀏覽量

    6524

原文標題:一次Rust重寫基礎軟件的實踐(二)

文章出處:【微信號:Rust語言中文社區(qū),微信公眾號:Rust語言中文社區(qū)】歡迎添加關注!文章轉載請注明出處。

收藏 人收藏

    評論

    相關推薦

    Rust GUI實踐Rust-Qt模塊

    Rust-Qt 是 Rust 語言的個 Qt 綁定庫,它允許 Rust 開發(fā)者使用 Qt 框架來創(chuàng)建跨平臺的圖形界面應用程序。Qt 是
    的頭像 發(fā)表于 09-30 16:43 ?1460次閱讀

    步降低冰箱旋轉式壓縮機噪聲的一次實踐

    步降低冰箱旋轉式壓縮機噪聲的一次實踐
    發(fā)表于 05-20 15:19 ?646次下載

    循環(huán)充放電一次就是少一次壽命嗎?

    循環(huán)充放電一次就是少一次壽命嗎?循環(huán)就是使用,我們是在使用電池,關心的是使用的時間,為了衡量充電電池的到底可以使用多長時間這樣個性能,就規(guī)定了循環(huán)
    發(fā)表于 09-07 02:06 ?2019次閱讀

    一次電池為什么不能被充電?

    一次電池為什么不能被充電? 一次電池不能被充電再生是構成一次電池體系的本性所決定的,因為一次電池的電極反應不可逆,也就是說,放電后的放電產
    發(fā)表于 10-28 15:29 ?5748次閱讀

    循環(huán)充放電一次就是少一次壽命嗎?

    循環(huán)充放電一次就是少一次壽命嗎?     循環(huán)就是使用,我們是在使用電池,關心的是使
    發(fā)表于 11-11 13:59 ?834次閱讀

    電池循環(huán)充放電一次就是少一次壽命嗎?

    電池循環(huán)充放電一次就是少一次壽命嗎? 循環(huán)就是使用,我們是在使用電池,關心的是使用的時間,為了衡量充電電池
    發(fā)表于 09-06 11:05 ?3587次閱讀

    微軟開發(fā)基于Rust的新編程語言,將很快開源

    使用Rust重寫各種產品,因為在過去的十年里,微軟70%以上的安全補丁都提供了與內存相關的錯誤,而Rust正是解決這個問題的良藥。 而根據ZDNet的報導,近日在一次演講中,談到微軟為
    的頭像 發(fā)表于 12-03 10:36 ?3859次閱讀

    微軟正在研發(fā)基于Rust新的安全編程語言

    為提高 Windows 10 的安全性,微軟研究人員 Matthew Parkinson 在本周的一次演講中披露:微軟正基于 Rust 開發(fā)新的安全編程語言。
    的頭像 發(fā)表于 12-06 16:36 ?3138次閱讀

    電氣一次識圖基礎

    電氣一次識圖基礎
    的頭像 發(fā)表于 11-12 11:24 ?2070次閱讀

    Cloudflare用Rust重寫Nginx C模塊,構建沒有Nginx的未來

    近日,Cloudflare 工程師介紹了如何使用 Rust 重寫基于 C 語言的 Nginx 模塊。Cloudflare 工程師在博客寫道,他們用 Rust 為 Cloudflare 基礎設施中最
    的頭像 發(fā)表于 03-08 09:36 ?660次閱讀

    Rust重寫的LSP:KCL IDE 插件的功能介紹與設計解析

    在這次更新中,我們發(fā)布了全新的 KCL VS Code 插件,并且用 Rust 重寫了 LSP 的 Server 端。我們提供了 IDE 中常用的代碼輔助功能,如高亮、跳轉、補全、Outline、懸停、錯誤提示等。
    的頭像 發(fā)表于 05-11 09:39 ?897次閱讀
    <b class='flag-5'>Rust</b><b class='flag-5'>重寫</b>的LSP:KCL IDE 插件的功能介紹與設計解析

    Windows 11初嘗Rust,36000行內核代碼已重寫!

    更早些時候,微軟用 Rust 重寫了 DirectWrite Core 庫的概念驗證,它是 Windows 的 DWrite 引擎的 Windows App SDK 實現,用于文本分析、布局和渲染
    的頭像 發(fā)表于 05-19 16:39 ?949次閱讀
    Windows 11初嘗<b class='flag-5'>Rust</b>,36000行內核代碼已<b class='flag-5'>重寫</b>!

    一次電池與二電池介紹

    電池大致可分為“一次電池”和“二電池”。 “一次電池”是一次用完就處理掉的一次性電池, 而可以反復充電循環(huán)使用的電池稱為“二
    的頭像 發(fā)表于 07-05 17:24 ?4375次閱讀
    <b class='flag-5'>一次</b>電池與二<b class='flag-5'>次</b>電池介紹

    一次調頻和二調頻的概念 一次調頻可以實現無差調節(jié)?

    一次調頻和二調頻的概念 一次調頻可以實現無差調節(jié)? 、一次調頻和二調頻的概念 1.
    的頭像 發(fā)表于 10-17 16:15 ?8493次閱讀

    Rust重寫基礎軟件實踐代碼

    在項目轉化過程中我遇到了個與 CAS (Compare and Swap) [2] 操作實現相關的問題,在計算機科學中CAS 是多線程/協(xié)程中用于實現同步的原子指令。
    的頭像 發(fā)表于 01-19 10:05 ?428次閱讀