首页 > 代码库 > MIPS平台OpenWrt路由器系统内的Rust应用程序开发

MIPS平台OpenWrt路由器系统内的Rust应用程序开发

目标

使用 Rust 语言,交叉编译开发 MIPS(el) + OpenWrt 路由器平台下的应用软件。


编译rustc

首先自行编译Rust编译器源代码,生成支持 mipsel-linux 平台的交叉编译器rustc

[plain] view plaincopy在CODE上查看代码片派生到我的代码片
  1. ./configure --target=mipsel-linux && make && make install  

注意编译过程中会调用 MIPS(el) + OpenWrt 平台的开发包SDK,具体来说就是 mipsel-linux-gcc 和 mipsel-linux-ar。但是SDK内的工具命名格式是 mipsel-openwrt-linux-uclibc-gcc/ar,跟Rust编译脚本说要求的不同。一个简单的做法是,创建符号链接文件:

[plain] view plaincopy在CODE上查看代码片派生到我的代码片
  1. cd /path/to/openwrt/sdk/toolchain  
  2. ln -s mipsel-openwrt-linux-uclibc-gcc mipsel-linux-gcc  
  3. ln -s mipsel-openwrt-linux-uclibc-ar mipsel-linux-ar  


使用Rust标准库std

编写源文件 histd.rs:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. fn main() {  
  2.     println!("Hi Rust! (uses std crate)");  
  3. }  

编译 histd:

[plain] view plaincopy在CODE上查看代码片派生到我的代码片
  1. rustc --target=mipsel-linux -C linker=mipsel-linux-gcc histd.rs  

将生成目标平台下的可执行文件histd,文件尺寸是 1,389,884 字节,约 1.32 MB,相当的大!对于路由器设备而言,几乎是难以接受。

这是静态编译生成的可执行文件,没有额外的运行时库依赖。严格地说仅依赖目标系统内的libc.so,当然如果不需要向控制台输出文本,连libc.so也不需要。


使用Rust核心库core(不使用标准库std)

编写源文件 hicore.rs:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #![no_std]  
  2. #![feature(lang_items)]  
  3.   
  4. extern crate libc;  
  5. extern crate core;  
  6.   
  7. use libc::puts;  
  8. use core::intrinsics::transmute;  
  9.   
  10. #[start]  
  11. fn start(_argc: int, _argv: *const *const u8) -> int {  
  12.     let s = "Hi Rust! (uses core crate)\0"; // &str  
  13.     unsafe {  
  14.         let (s,_): (*const i8, uint) = transmute(s); // see core::raw::Slice  
  15.         puts(s);  
  16.     }  
  17.     return 0;  
  18. }  
  19.   
  20. #[lang = "stack_exhausted"] extern fn stack_exhausted() {}  
  21. #[lang = "eh_personality"] extern fn eh_personality() {}  
  22.   
  23. #[lang = "begin_unwind"]  
  24. extern fn begin_unwind(_args: &core::fmt::Arguments,  
  25.                         _file: &str,  
  26.                         _line: uint) -> ! {  
  27.     loop {}  
  28. }  

编译 hicore.rs:

[plain] view plaincopy在CODE上查看代码片派生到我的代码片
  1. rustc --target=mipsel-linux -C linker=mipsel-linux-gcc hicore.rs  

将生成目标平台下的可执行文件hicore,文件尺寸只有 6556 字节,相当的小!

这是静态编译生成的可执行文件,没有额外的运行时库依赖。严格地说仅依赖目标系统内的libc.so,当然如果不需要向控制台输出文本,连libc.so也不需要。


不用标准库std,也不用核心库core,纯裸奔

编写源代码 hi.rs:

[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #![no_std]  
  2. #![feature(lang_items)]  
  3. #![feature(intrinsics)]  
  4.   
  5. #[link(name = "c")]  
  6. extern {  
  7.     fn puts(s: *const u8);  
  8. }  
  9.   
  10. #[start]  
  11. fn start(_argc: int, _argv: *const *const u8) -> int {  
  12.     let s = "Hi Rust!\0"; // &str  
  13.     unsafe {  
  14.         let (s,_): (*const u8, uint) = transmute(s); // see core::raw::Slice  
  15.         puts(s);  
  16.     }  
  17.     return 0;  
  18. }  
  19.   
  20. #[lang = "stack_exhausted"] extern fn stack_exhausted() {}  
  21. #[lang = "eh_personality"] extern fn eh_personality() {}  
  22.   
  23. extern "rust-intrinsic" {  
  24.     fn transmute<T, U>(x: T) -> U;  
  25. }  

编译 hi.rs:

[plain] view plaincopy在CODE上查看代码片派生到我的代码片
  1. rustc --target=mipsel-linux -C linker=mipsel-linux-gcc hi.rs  

将生成目标平台下的可执行文件hi,文件尺寸只有 6504 字节,相当的小!比使用核心库core的hicore还要小,但相差不大。

这是静态编译生成的可执行文件,没有额外的运行时库依赖。严格地说仅依赖目标系统内的libc.so,当然如果不需要向控制台输出文本,连libc.so也不需要。


可执行文件尺寸对比

使用Rust标准库std编译生成的histd,使用Rust核心库core编译生成的的hicore,和不用标准库也不用核心库编译生成的hi,这三者的可执行文件尺寸对比如下:

[plain] view plaincopy在CODE上查看代码片派生到我的代码片
  1. -rwxr-xr-x 1 liigo liigo 1389884  9月 17 20:20 histd  
  2. -rwxr-xr-x 1 liigo liigo    6556  9月 17 20:19 hicore  
  3. -rwxr-xr-x 1 liigo liigo    6504  9月 17 20:19 hi  

使用标准库std编译出来的程序histd太大,不适合嵌入式设备,首先被淘汰;使用核心库core编译出来的程序hicore很小,跟不使用任何库的hi不相上下。既然用不用核心库core,在文件尺寸上没有多大变化,而核心库core还能带来很多编码上的便利,故推荐在嵌入式平台内使用核心库core。

以上是 mipsel-linux 平台的情况。下面作为对比,我们再看一下 x86_64-unknown-linux-gnu 平台:

[plain] view plaincopy在CODE上查看代码片派生到我的代码片
  1. -rwxr-xr-x 1 liigo liigo 1004136  9月 17 20:16 histd  
  2. -rwxr-xr-x 1 liigo liigo    8203  9月 17 20:16 hicore  
  3. -rwxr-xr-x 1 liigo liigo    8159  9月 17 20:16 hi  

对比后发现,x86_64 平台下的可执行文件总体上比 mipsel 平台略大,但差距也不大,情况也类似。


Rust支持的主流交叉编译平台 (target triples)

信息来源:https://github.com/rust-lang/rust/blob/master/mk/platform.mk

[plain] view plaincopy在CODE上查看代码片派生到我的代码片
  1. x86_64-unknown-linux-gnu  
  2. i686-unknown-linux-gnu  
  3. arm-apple-ios  
  4. i386-apple-ios  
  5. x86_64-apple-darwin  
  6. i686-apple-darwin  
  7. arm-linux-androideabi  
  8. arm-unknown-linux-gnueabihf  
  9. arm-unknown-linux-gnueabi  
  10. mipsel-linux  
  11. mips-unknown-linux-gnu  
  12. i586-mingw32msvc  
  13. i686-w64-mingw32  
  14. x86_64-w64-mingw32  
  15. x86_64-unknown-freebsd  
  16. x86_64-pc-dragonfly-elf  

使用方法:

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

编译Rust程序:rustc --target=triple -C linker=triple-gcc 

必要时创建对应交叉编译平台SDK编译工具的符号链接文件 triple-gcc/triple-ar 等。

MIPS平台OpenWrt路由器系统内的Rust应用程序开发