本文简单的介绍了golang和rust语言在openwrt系统、mips架构下的交叉编译。
环境
主机 | 系统 | 内核 | 架构 |
---|---|---|---|
host主机 | Centos 7.2 | linux 3.10.0-327 | x86_64 |
target主机 | openwrt 14.07 | linux 3.10.14 | mipsel |
我们要在host主机上编译target主机上运行的二进制程序。由于我们团队有现有的路由宝产品,所以使用现有openwrt环境、并在真机路由器上做测试。如果想亲自动手实验,可以考虑使用QEMU等虚拟机软件模拟相应环境。
工具链
获取openwrt工具链有两种方式:
文档介绍的比较详细,以下简单列出一些步骤和问题。
- 进入源码目录,make menuconfig配置相应平台和其他选项等。
- make menuconfig终端可能显示乱码。解决:export TERM=screen
- make -j8
- 可以使用-j8 选项加快编译速度。
- make时会下载依赖源码包,由于众所周知的网络原因,可能有些包无法下载。
解决:可以使用make V=s 打印编译详细信息,查看卡在哪个下载,根据url自行想办法,然后把下载到到包放到dl目录。
- 编译完成后会在staging_dir目录下生产工具链。
验证工具链
第1步. 设置STAGING_DIR环境变量为上面工具链目录。
$ export STAGING_DIR=staging_dir目录
第2步. 写一个hello world程序hello.c。
#include <stdio.h>
int main() {
printf("Hello, c!\n");
}
第3步. 使用工具链编译该文件。
$ $STAGING_DIR/toolchain-mipsel_24kec+dsp_gcc-4.8-linaro_uClibc-0.9.33.2/bin/mipsel-openwrt-linux-gcc -o hello-c hello.c
$ ls -l
-rwxr-xr-x 1 wanglei01 users 5933 Jan 31 11:09 hello-c
第4步. 把hello-c弄到路由上,测试。
[root@Youku-router]./hello-c
Hello, c!
rust交叉编译
第1步. 安装rust。curl https://sh.rustup.rs -sSf | sh
第2步. 创建rust项目,编写main.rs文件,并配置一些优化选项。
$ cargo new --bin hello-rust
$ cd hello-rust
$ ls -al
-rw-r--r-- 1 wanglei01 users 205 Jan 31 11:20 Cargo.toml
drwxr-xr-x 2 wanglei01 users 4096 Jan 31 11:37 src
$ cat src/main.rs
fn main() {
println!("Hello, rust!");
}
$ cat Cargo.toml
[package]
name = "hello-rust"
version = "0.1.0"
authors = ["you"]
[dependencies]
[profile.release]
lto = true
panic = "abort"
第3步. rust交叉编译需要一些nightly特性,所以需要安装nightly版本,并设置当前目录编译工具。
$ rustup install nightly
$ rustup override set nightly
第4步. 安装rust源码,供交叉编译rust std。
$ rustup component add rust-src
第5步. 安装xargo工具,该工具方便rust进行交叉编译。
cargo install xargo
第6步. 进行一些交叉编译的配置。以下直接列出配置项:
$ cat .cargo/config
[build]
target = "mipsel-unknown-linux-uclibc"
[target.mipsel-unknown-linux-uclibc]
linker = "$STAGING_DIR/bin/mipsel-openwrt-linux-gcc"
$ cat Xargo.toml
[target.mips-unknown-linux-uclibc.dependencies.std]
features = []
第7步. 编译。
$ xargo build --release
$ tree -L 4
.
├── Cargo.lock
├── Cargo.toml
├── src
│ └── main.rs
├── target
│ ├── mipsel-unknown-linux-uclibc
│ │ ├── debug
│ │ └── release
│ │ ├── hello-rust 可执行文件
└── Xargo.toml
第8步. 放到路由宝上验证。
[root@Youku-router]./hello-rust
Hello, rust!
golang交叉编译
相比与rust,golang的交叉编译就简单多了。
golang 在1.8版本以后,可以直接使用gc Go编译MIPS(LE)架构的linux二进制程序。所以我们可以直接安装host主机的go,而不用c交叉工具链。如果要使用gccgo编译,或是使用cgo的话是需要的。gc与gccgo区别
安装golang
安装golang有两种方式:
编译golang
package main
import "fmt"
func main() {
fmt.Println("hello golang!")
}
- 使用-ldflags '-w -s’编译选项,去掉一些符号信息,减少二进制体积。具体可以查看go tool link -h
$ GOOS=linux GOARCH=mipsle go build -o hello-go-symbol
$ GOOS=linux GOARCH=mipsle go build -o hello-go -ldflags '-w -s'
$ ls -l
-rwxr-xr-x 1 wanglei01 users 1384448 Jan 31 10:58 hello-go
-rwxr-xr-x 1 wanglei01 users 1956182 Jan 31 11:02 hello-go-symbol
运行
把它弄到路由上跑一下。
[root@router]./hello-go
hello golang!
总结
我们只是简单的布置了开发环境,只是写了一个简单的hello world程序,没有使用第三方库,也没有动态连接其他动态库。
- 开发环境golang是非常的简单的,应该也是因为go强大的运行时库,不需要依赖第三方的原因。
- 也正是因为golang运行时库的优势,也造成了他的劣势,二进制体积过大。
下面列出经过strip后的文件列表:
-rwxr-xr-x 1 wanglei01 users 5931 Jan 31 20:04 hello-c
-rwxr-xr-x 1 wanglei01 users 3580 Jan 31 11:09 hello-c-strip
-rwxr-xr-x 1 wanglei01 users 1956182 Jan 31 11:02 hello-go-symbol
-rwxr-xr-x 1 wanglei01 users 1384448 Jan 31 10:58 hello-go
-rwxr-xr-x 1 wanglei01 users 1385068 Jan 31 11:11 hello-go-strip
-rwxr-xr-x 1 wanglei01 users 149824 Jan 31 11:06 hello-rust
-rwxr-xr-x 1 wanglei01 users 111084 Jan 31 11:11 hello-rust-strip
-rwxr-xr-x 1 wanglei01 users 79440 Jan 31 20:40 hello-rust-release
-rwxr-xr-x 1 wanglei01 users 79440 Jan 31 20:41 hello-rust-release-strip
- 不知为何,golagn strip后反而变大了。。。
- rust-release是经过优化后的。参考 。