I found a guide for cross-compiling Rust which basically involves
configuring it with a --target
option. The target needs to include the
cross-compile target and the host target.
$ wget https://static.rust-lang.org/dist/rustc-1.5.0-src.tar.gz
$ tar xf rustc-1.5.0-src.tar.gz
$ ./configure --target=arm-unknown-linux-gnueabi,x86_64-unknown-linux-gnu --prefix "$(PWD)"/../bin
$ make -j$(nproc) install
This didn't work with my target arm-unknown-linux-gneabi
as at some point in
the build it started trying to use arm-linux-gneabi-gcc
and
arm-linux-gneabi-ar
, which didn't work as they are called
arm-unknown-linux-gneabi-gcc
and arm-unknown-linux-gneabi-gcc
. I guess this
is a problem with the build script, but I couldn't easily work out a fix, so I
just created some symlinks with the names it was expecting. This worked well.
$ export LD_LIBRARY_PATH=~/projects/arm-rust-cross-compiler/bin/lib/
$ export PATH=$PATH:~/projects/arm-rust-cross-compiler/bin/bin/
$ bin/bin/rustc --version
rustc 1.5.0-dev
Cargo can also be built from source. I don't think Cargo needs to be cross-compiled as it supports compiling for different targets and I don't actually want to run Cargo on the target machine.
$ git clone https://github.com/rust-lang/cargo
$ cd cargo
$ git submodule update --init
$ python -B src/etc/install-deps.py
$ ./configure --local-rust-root="$PWD"/../bin --prefix "$(PWD)"/../bin
$ make
$ make install
To cross-compile with Cargo, a linker needs to be specified for the target. In my case:
$ cat > ~/.cargo/config << EOF
[target.arm-unknown-linux-gnueabi]
linker = "arm-unknown-linux-gnueabi-gcc-5.2.0"
EOF
Now Cargo can be used to create a new project and build a binary for an ARM target.
$ cargo new --bin hello-rust
$ cd hello
$ cargo build --target=arm-unknown-linux-gnueabi
$ file target/arm-unknown-linux-gnueabi/debug/hello-rust
target/arm-unknown-linux-gnueabi/debug/hello: ELF 32-bit LSB shared object,
ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter
/lib/ld-linux.so.3, for GNU/Linux 4.3.0, not stripped
I was pretty confident at this point, until I tried to run it in my emulator and the program immediately terminated with the message "Illegal instruction". So far, my cross-compiler toolchain and emulator had worked well. Why is now generating illegal instructions?
I eventually found that I wasn't specifying a CPU type and qemu
was using the
default ARM926 processor on the Versatile board. This can be fixed by adding
--cpu arm1176
(which is the CPU on the first generation Raspberry Pi which I
am trying to emulate). However, now the Kernel doesn't boot as it was built for
an ARM926 processor as specified by versatile_defconfig
.
The Linux ARM Versatile config restricts the possible CPU targets to CPUs that
can actually fit in the board. Fortunately I found this patch which removes
this restriction. Now make ARCH=arm versatile_defconfig && make ARCH=arm
menuconfig
allows the System Type -> Support ARM V6 processor
option to be
selected.
Finally, after rebuilding the Kernel and adding the Rust built hello
binary to
the filesystem, the program can run in the emulator.
qemu-system-arm -M versatilepb -cpu arm1176 -m 128M -kernel zImage -initrd ./rootfs.img.gz -append "root=/dev/ram rdinit=/sbin/init"
Comments
There are no comments