Compiling Rust for the Raspberry Pi
juillet 20th, 2014
Far far far from VCS coding, time for some higher level stuff… but not that much !
Since a few months, I’m looking at what « new » languages can bring, I’m still very fond of C, C++ and even Java but when I need to be efficient and code little tools especially to check something, those languages usually divert me from my original goal and I spent more time on the code design itself than on the functional aspect of my program.
But on the other hand I simply hate Python, Ruby, Javascript (even if I must admit I like node.js, but not due to the language choice…).
So I coded a few things in Go… Funny, especially the error management, a lot of opensource framework…. but somewhat not that new. And I failed make it working on embedded platforms (it was not clear one year ago if it could work or not), Go’s memory management simply doesn’t fit.
And recently I took time to look at Mozilla’s Rust and I must admit it seems to solve most of my issues : one language for embedded dev up to webdev, a large community, and new paradigms really interesting. I won’t go much in details, a lot of smarter people gave their opinions, just DuckDuckGo for it :)
Consequently, as I’dd like my little tools to run on my Raspberry Pis, I tried to cross-compile the Rust Compiler (rustc) for the Rpi so that I can directly code and execute. Currently there is no official port of the rustc for Rpi, so with the help of kwantam who already ported if to the Nexus7, I modified his script to compile it for the Rpi… and it works :)
Basically, the « only » changes is to used the prebuilt gcc gnueabihf toolchain for the Rpi (DON’T use the one provided in Ubuntu packages) and define the good target/options.
This was tested with an Ubuntu Server 14.04 LTS x64, and gcc/g++ 4.8, compiled for the Rasbpian (Debian Wheezy June 2014).
Note that you will need also to install gcc 4-8 on the Rpi to make it working.
Here is the result :
echo "-------------------------------"
echo "setup linux env"
echo "-------------------------------"
sudo apt-get update
sudo apt-get -y install apt-utils git gcc g++ perl python2.7 curl make unzip nano
echo "-------------------------------"
echo "download rpi toolchain"
echo "-------------------------------"
wget https://github.com/raspberrypi/tools/archive/master.zip
unzip master.zip
export PATH=$PWD/tools-master/arm-bcm2708/gcc-linaro-arm-linux-gnueabihf-raspbian-x64/bin:$PATH
echo "-------------------------------"
echo "First steps"
echo "-------------------------------"
mkdir -p $HOME/toolchains/src
cd $HOME/toolchains/src
git clone https://github.com/mozilla/rust.git
cd rust
git submodule update --init
echo "-------------------------------"
echo "Configuring Rust"
echo "-------------------------------"
cd $HOME/toolchains/src/rust
mkdir build
cd build
mkdir -p $HOME/toolchains/var/lib
mkdir $HOME/toolchains/etc
$PWD/../configure --prefix=$HOME/toolchains \
--host=x86_64-unknown-linux-gnu --disable-llvm-assertions \
--target=x86_64-unknown-linux-gnu,arm-unknown-linux-gnueabihf \
--localstatedir=$HOME/toolchains/var/lib \
--sysconfdir=$HOME/toolchains/etc
cd x86_64-unknown-linux-gnu
find . -type d -exec mkdir -p ../arm-unknown-linux-gnueabihf/\{\} \;
echo "-------------------------------"
echo "Building cross LLVM"
echo "-------------------------------"
cd $HOME/toolchains/src/rust/build/x86_64-unknown-linux-gnu/llvm
$HOME/toolchains/src/rust/src/llvm/configure --enable-target=x86,x86_64,arm,mips \
--enable-optimized --disable-assertions --disable-docs --enable-bindings=none \
--disable-terminfo --disable-zlib --disable-libffi \
--with-python=/usr/bin/python2.7
make -j$(nproc)
cd $HOME/toolchains/src/rust/build/arm-unknown-linux-gnueabihf/llvm
$HOME/toolchains/src/rust/src/llvm/configure --enable-target=x86,x86_64,arm,mips \
--enable-optimized --disable-assertions --disable-docs --enable-bindings=none \
--disable-terminfo --disable-zlib --disable-libffi \
--with-python=/usr/bin/python2.7 --build=x86_64-unknown-linux-gnu \
--host=arm-linux-gnueabihf --target=arm-linux-gnueabihf
make -j$(nproc)
echo "-------------------------------"
echo "Enable llvm-config for the cross LLVM build"
echo "-------------------------------"
cd $HOME/toolchains/src/rust/build/arm-unknown-linux-gnueabihf/llvm/Release/bin
mv llvm-config llvm-config-arm
ln -s ../../BuildTools/Release/bin/llvm-config .
# (Now test to be sure this works.)
./llvm-config --cxxflags
# (You should see some CXX flags printed out here!)
echo "-------------------------------"
echo "Making RBS use our LLVM builds"
echo "-------------------------------"
cd $HOME/toolchains/src/rust/build/
chmod 0644 config.mk
grep 'CFG_LLVM_[BI]' config.mk | \
sed 's/x86_64\(.\)unknown.linux.gnu/arm\1unknown\1linux\1gnueabihf/g' \
>> config.mk
cd $HOME/toolchains/src/rust
sed -i.bak 's/\([\t]*\)\(.*\$(MAKE).*\)/\1#\2/' mk/llvm.mk
echo "-------------------------------"
echo "Building a working librustc for the cross architecture"
echo "-------------------------------"
cd $HOME/toolchains/src/rust
sed -i.bak \
's/^CRATES := .*/TARGET_CRATES += $(HOST_CRATES)\nCRATES := $(TARGET_CRATES)/' \
mk/crates.mk
sed -i.bak \
's/\(.*call DEF_LLVM_VARS.*\)/\1\n$(eval $(call DEF_LLVM_VARS,arm-unknown-linux-gnueabihf))/' \
mk/main.mk
sed -i.bak 's/foreach host,$(CFG_HOST)/foreach host,$(CFG_TARGET)/' mk/rustllvm.mk
cd $HOME/toolchains/src/rust
sed -i.bak 's/.*target_arch = .*//' src/etc/mklldeps.py
cd $HOME/toolchains/src/rust/build
arm-unknown-linux-gnueabihf/llvm/Release/bin/llvm-config --libs \
| tr '-' '\n' | sort > arm
x86_64-unknown-linux-gnu/llvm/Release/bin/llvm-config --libs \
| tr '-' '\n' | sort > x86
diff arm x86
echo "-------------------------------"
echo "Build it, part 1"
echo "-------------------------------"
cd $HOME/toolchains/src/rust/build
make -j$(nproc)
echo "-------------------------------"
echo "Build it, part 2"
echo "-------------------------------"
cd $HOME/toolchains/src/rust/build
LD_LIBRARY_PATH=$PWD/x86_64-unknown-linux-gnu/stage2/lib/rustlib/x86_64-unknown-linux-gnueabihf/lib:$LD_LIBRARY_PATH \
./x86_64-unknown-linux-gnu/stage2/bin/rustc --cfg stage2 -O --cfg rtopt \
-C linker=arm-linux-gnueabihf-g++ -C ar=arm-linux-gnueabihf-ar \
-C target-feature=+vfp2,-neon -C target-cpu=arm1176jzf-s \
--cfg debug -C prefer-dynamic --target=arm-unknown-linux-gnueabihf \
-o x86_64-unknown-linux-gnu/stage2/lib/rustlib/arm-unknown-linux-gnueabihf/bin/rustc --cfg rustc \
$PWD/../src/driver/driver.rs
LD_LIBRARY_PATH=$PWD/x86_64-unknown-linux-gnu/stage2/lib/rustlib/x86_64-unknown-linux-gnueabihf/lib:$LD_LIBRARY_PATH \
./x86_64-unknown-linux-gnu/stage2/bin/rustc --cfg stage2 -O --cfg rtopt \
-C linker=arm-linux-gnueabihf-g++ -C ar=arm-linux-gnueabihf-ar \
-C target-feature=+vfp2,-neon -C target-cpu=arm1176jzf-s \
--cfg debug -C prefer-dynamic --target=arm-unknown-linux-gnueabihf \
-o x86_64-unknown-linux-gnu/stage2/lib/rustlib/arm-unknown-linux-gnueabihf/bin/rustdoc --cfg rustdoc \
$PWD/../src/driver/driver.rs
echo "-------------------------------"
echo "Package"
echo "-------------------------------"
cd $HOME/toolchains/src/rust/build/
mkdir -p cross-dist/lib/rustlib/arm-unknown-linux-gnueabihf
cd cross-dist
cp -R ../x86_64-unknown-linux-gnu/stage2/lib/rustlib/arm-unknown-linux-gnueabihf/* \
lib/rustlib/arm-unknown-linux-gnueabihf
mv lib/rustlib/arm-unknown-linux-gnueabihf/bin .
cd lib
for i in rustlib/arm-unknown-linux-gnueabihf/lib/*.so; do ln -s $i .; done
cd ../
tar cjf ../rust_arm-unknown-linux-gnueabihf_dist.tbz2 .
Oh, last point, please consider watching a good movie or going outside, it takes a while to compile :)