MIPS平臺OpenWrt路由器系統內的Rust應用程序開發

作者:Liigo(莊曉立)

日期:2014年9月17日 (9月29日更新,11月19日再次更新,更新內容詳見文末)

原創鏈接:http://blog.csdn.net/liigo/article/details/39347541

版權所有,轉載請註明出處:http://blog.csdn.net/liigo


目標

使用 Rust 語言,交叉編譯開發 MIPS(el) + OpenWrt 路由器平臺(MT7620A CPU)下的應用軟件。


編譯rustc

首先自行編譯Rust編譯器源代碼,生成支持 mipsel-unknown-linux-gnu 平臺的交叉編譯器rustc

./configure --target=mipsel-unknown-linux-gnu && make && make install

注意編譯過程中會調用 MIPS(el) + OpenWrt 平臺的開發包SDK,具體來說就是 mipsel-unknown-linux-gnu-gcc 和 mipsel-unknown-linux-gnu-ar。但是SDK內的工具命名格式是 mipsel-openwrt-linux-uclibc-gcc/ar,跟Rust編譯腳本所要求的不同。一個簡單的做法是,創建符號鏈接文件:

cd <openwrt>/staging_dir/toolchain-mipsel_r2_gcc-4.7-linaro_uClibc-0.9.33.2/bin
ln -s mipsel-openwrt-linux-uclibc-gcc mipsel-unknown-linux-gnu-gcc
ln -s mipsel-openwrt-linux-uclibc-ar  mipsel-unknown-linux-gnu-ar


使用Rust標準庫std

編寫源文件 histd.rs:

fn main() {
	println!("Hi Rust! (uses std crate)");
}
編譯 histd:

rustc --target=mipsel-unknown-linux-gnu -C linker=mipsel-unknown-linux-gnu-gcc -C target-cpu=mips32r2 histd.rs

將生成目標平臺下的可執行文件histd,文件尺寸是 1,389,884 字節,約 1.32 MB (11月19日Liigo用最新Rust編譯後更新) 932013 字節,約 930 KB,相當的大!對於路由器設備而言,幾乎是難以接受。

這是靜態編譯生成的可執行文件,沒有額外的運行時庫依賴。嚴格地說僅依賴目標系統內的libc.so,當然如果不需要向控制檯輸出文本,連libc.so也不需要。


使用Rust核心庫core(不使用標準庫std)

編寫源文件 hicore.rs:

#![no_std]
#![feature(lang_items)]

extern crate libc;
extern crate core;

use libc::puts;
use core::str::StrPrelude; // &str::as_prt()

#[start]
fn start(_argc: int, _argv: *const *const u8) -> int {
    unsafe {
        puts("Hi Rust! (uses core crate)\0".as_ptr() as *const i8);
    }
    return 0;
}

#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
#[lang = "eh_personality"] extern fn eh_personality() {}

#[lang = "panic_fmt"]
extern fn panic_fmt(_args: &core::fmt::Arguments,
                   _file: &str,
                   _line: uint) -> ! {
    loop {}
}

編譯 hicore.rs:

rustc --target=mipsel-unknown-linux-gnu -C linker=mipsel-unknown-linux-gnu-gcc -C target-cpu=mips32r2 hicore.rs

將生成目標平臺下的可執行文件hicore,文件尺寸只有 7419 字節,約 7KB,相當的小!

這是靜態編譯生成的可執行文件,沒有額外的運行時庫依賴。嚴格地說僅依賴目標系統內的libc.so,當然如果不需要向控制檯輸出文本,連libc.so也不需要。


不用標準庫std,也不用核心庫core,純裸奔

編寫源代碼 hi.rs:

#![no_std]
#![feature(lang_items)]
#![feature(intrinsics)]

#[link(name = "c")]
extern {
    fn puts(s: *const u8);
}

#[start]
fn start(_argc: int, _argv: *const *const u8) -> int {
    let s = "Hi Rust!\0"; // &str
    unsafe {
        let (s,_): (*const u8, uint) = transmute(s); // see core::raw::Slice
        puts(s);
    }
    return 0;
}

#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
#[lang = "eh_personality"] extern fn eh_personality() {}

#[lang="sized"] trait Sized {}

extern "rust-intrinsic" {
    fn transmute<T, U>(x: T) -> U;
}

編譯 hi.rs:

rustc --target=mipsel-unknown-linux-gnu -C linker=mipsel-unknown-linux-gnu-gcc -C target-cpu=mips32r2 hi.rs
將生成目標平臺下的可執行文件hi,文件尺寸只有 6552 字節,約 6KB,相當的小!比使用核心庫core的hicore還要小,但相差不大。

這是靜態編譯生成的可執行文件,沒有額外的運行時庫依賴。嚴格地說僅依賴目標系統內的libc.so,當然如果不需要向控制檯輸出文本,連libc.so也不需要。


可執行文件尺寸對比

使用Rust標準庫std編譯生成的histd,使用Rust核心庫core編譯生成的的hicore,和不用標準庫也不用核心庫編譯生成的hi,這三者的可執行文件尺寸對比如下:

-rwxr-xr-x 1 liigo liigo 932013  11月 19 20:20 histd
-rwxr-xr-x 1 liigo liigo   7419  11月 19 20:19 hicore
-rwxr-xr-x 1 liigo liigo   6552  11月 19 20:19 hi
使用標準庫std編譯出來的程序histd太大,不適合嵌入式設備,首先被淘汰;使用核心庫core編譯出來的程序hicore很小,跟不使用任何庫的hi不相上下。既然用不用核心庫core,在文件尺寸上沒有多大變化,而核心庫core還能帶來很多編碼上的便利,故推薦在嵌入式平臺內使用核心庫core。

以上是 mipsel-unknown-linux-gnu 平臺的情況。下面作爲對比,我們再看一下 x86_64-unknown-linux-gnu 平臺:

-rwxr-xr-x 1 liigo liigo 668621  9月 17 20:16 histd
-rwxr-xr-x 1 liigo liigo   8920  9月 17 20:16 hicore
-rwxr-xr-x 1 liigo liigo   8159  9月 17 20:16 hi

對比後發現,x86_64 平臺下的可執行文件總體上比 mipsel 平臺略大,但差距不大,情況也類似。

11月19日Liigo注:跟兩個月前最初發表本文時相比,mipsel 平臺和 windows 平臺的 histd 尺寸分別縮小了 450KB 和 320KB,體現了標準庫的優化結果(例如 RFC #230);但 hicore 和 hi 的尺寸變化很小。


Rust支持的主流交叉編譯平臺 (target triples)

信息來源:https://github.com/rust-lang/rust/tree/master/mk/cfg

arm-apple-ios
arm-linux-androideabi
arm-unknown-linux-gnueabi
arm-unknown-linux-gnueabihf
i386-apple-ios
i686-apple-darwin
i686-pc-windows-gnu
i686-unknown-linux-gnu
mipsel-unknown-linux-gnu
mips-unknown-linux-gnu
x86_64-apple-darwin
x86_64-pc-windows-gnu
x86_64-unknown-dragonfly
x86_64-unknown-freebsd
x86_64-unknown-linux-gnu

使用方法:

編譯Rust本身:./configure --target=triple1,triple2 && make && make install

編譯Rust程序:rustc --target=triple -C linker=triple-gcc

必要時創建對應交叉編譯平臺SDK編譯工具的符號鏈接文件 triple-gcc、triple-ar 等。


本文涉及到多個源代碼文件已上傳到Github:https://github.com/liigo/hirust ,作者Liigo。


Liigo 20140929 更新內容

1、修正 lang_item `sized` 和 `fail_fmt`,與當前最新 rustc 編譯器改動同步;

2、增加編譯參數 `-C target-cpu=mips32r2`,針對測試所用CPU,消除編譯警告信息;

3、註明測試採用的硬件路由器CPU型號`MT7620A CPU`。


Liigo 20141119 更新內容

1、修正目標平臺爲 mipsel-unknown-linux-gnu (原 mipsel-linux 已廢棄);

2、更新Rust支持的主流交叉編譯平臺列表(triples);

3、更新文中Rust示例代碼(與 https://github.com/liigo/hirust 同步);

4、採用今日最新Rust源代碼重新交叉編譯並更新文中相關數據。


發佈了275 篇原創文章 · 獲贊 442 · 訪問量 244萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章