Skip to content

Instantly share code, notes, and snippets.

@kevinmehall
Last active November 3, 2023 13:23
Show Gist options
  • Star 9 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save kevinmehall/16e8b3ea7266b048369d to your computer and use it in GitHub Desktop.
Save kevinmehall/16e8b3ea7266b048369d to your computer and use it in GitHub Desktop.
Cross-compile Rust standard library for Tessel without full bootstrap build [A work in progress]
#!/bin/bash
# THIS IS A GIANT HACK
# if you think this would be a good idea if it weren't so terrible, go read https://github.com/rust-lang/rfcs/pull/1133
set -e
# Parse args
for i in "$@"
do
case $i in
--rust-prefix=*)
RUST_PREFIX=$(readlink -f "${i#*=}")
shift
;;
--rust-git=*)
RUST_TREE=$(readlink -f "${i#*=}")
shift
;;
--target-json=*)
JSON="${i#*=}"
shift
;;
*)
# unknown option
;;
esac
done
# Sanity-check args
if [ ! -f $RUST_PREFIX/bin/rustc ]; then
echo $RUST_PREFIX/bin/rustc does not exist. Pass --rust-prefix=/usr/local
exit 1
fi
if [ ! -d $RUST_TREE/.git ]; then
echo 'Pass --rust-git=path to rust git tree (git clone https://github.com/rust-lang/rust)'
exit 1
fi
export PATH=$RUST_PREFIX/bin:$PATH
export LD_LIBRARY_PATH=$RUST_PREFIX/lib
export RUSTLIB=$RUST_PREFIX/lib/rustlib
export RUSTC=$RUST_PREFIX/bin/rustc
RUST_VERSION=$($RUSTC --version | cut -f2 -d ' ')
RUST_GIT_VERSION=$($RUSTC --version | cut -f2 -d'(' | cut -f1 -d' ')
if ($RUSTC --version | grep -q nightly); then
echo "Using a nightly rustc"
else
echo "Unlocking stable rustc to support unstable features. You get to keep both pieces when this breaks."
export RUSTC_BOOTSTRAP_KEY=$(echo -n $RUST_VERSION | md5sum | cut -c1-8)
echo "Bootstrap key is '$RUSTC_BOOTSTRAP_KEY'"
fi
export HOST=x86-64-linux-gnu
export RUST_TARGET_PATH=$(dirname $(readlink -f "$JSON"))
export TARGET=$(basename $JSON .json)
# Parse the target JSON into environment variables
source <( cat "$JSON" | python -c '
import json, sys
j = json.load(sys.stdin)
print "export ARCH=%s"%(j["arch"])
print "export CC=%s"%(j["c-compiler"])
print "export AR=%s"%(j["ar"])
print "export CFLAGS=\"%s\""%(j["c-flags"])
print "export LINKFLAGS=\"%s\""%(j["c-link-flags"])
print "export TRIPLE=%s"%(j["c-triple"])
')
export FILENAME_EXTRA=$($RUSTC --version | cut -d' ' -f 2 | tr -d $'\n' | md5sum | cut -c 1-8)
export BUILD=$(mktemp -d --suffix=-rust-cross)
DEST="${RUSTLIB}/${TARGET}/lib"
cd $RUST_TREE
git checkout $RUST_GIT_VERSION || (git fetch; git checkout $RUST_GIT_VERSION)
git submodule update --init
# Build compiler-rt
mkdir "$BUILD/comprt"
make -C "$RUST_TREE/src/compiler-rt" \
ProjSrcRoot="$RUST_TREE/src/compiler-rt" \
ProjObjRoot="$(realpath $BUILD/comprt)" \
CC="$CC" \
AR="$AR" \
RANLIB="$AR s" \
CFLAGS="$CFLAGS" \
TargetTriple=$TRIPLE \
triple-builtins
mv "$BUILD/comprt/triple/builtins/libcompiler_rt.a" "$BUILD/libcompiler-rt.a"
# Build libbacktrace
mkdir "$BUILD/libbacktrace"
(cd "$BUILD/libbacktrace" &&
CC="$CC" \
AR="$AR" \
RANLIB="$AR s" \
CFLAGS="$CFLAGS -fno-stack-protector" \
"$RUST_TREE/src/libbacktrace/configure" \
--build=$TRIPLE \
--host=$HOST
make INCDIR="$RUST_TREE/src/libbacktrace"
)
mv "$BUILD/libbacktrace/.libs/libbacktrace.a" "$BUILD"
# Build crates
# Use the rust build system to obtain the target crates in dependency order.
# TODO: use the makefile to build the C libs above
cat > "${BUILD}/hack.mk" <<'EOF'
RUSTC_OPTS = -Copt-level=2 --target=$(TARGET) \
-L $(BUILD) --out-dir=$(BUILD) -C extra-filename=-$(FILENAME_EXTRA)
define BUILD_CRATE
$(1): $$(filter-out native:%,$$(DEPS_$(1)))
$(RUSTC) $(CRATEFILE_$(1)) $(RUSTC_OPTS) $(RUSTFLAGS_$(1))
.PHONY: $(1)
endef
$(foreach crate,$(CRATES),$(eval $(call BUILD_CRATE,$(crate))))
EOF
make -f mk/util.mk -f mk/crates.mk -f "${BUILD}/hack.mk" std CFG_DISABLE_JEMALLOC=1
rm -rf "$DEST"
mkdir -p "$DEST"
mv "$BUILD"/*.rlib "$BUILD"/*.so "$BUILD"/*.a "$DEST"
rm -rf "$BUILD"
echo "Libraries are in ${DEST}."
{
"arch": "mips",
"cpu": "mips32r2",
"data-layout": "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64",
"llvm-target": "mipsel-unknown-linux-gnu",
"features": "+mips32,+soft-float",
"os": "linux",
"vendor": "openwrt",
"relocation-model": "pic",
"target-endian": "little",
"target-pointer-width": "32",
"exe-allocation-crate": "alloc_system",
"lib-allocation-crate": "alloc_system",
"linker": "mipsel-openwrt-linux-gcc",
"ar": "mipsel-openwrt-linux-ar",
"dynamic-linking": true,
"executables": true,
"c-compiler": "mipsel-openwrt-linux-gcc",
"c-flags": "-Wall -g -fPIC -mips32 -mabi=32 -O2",
"c-link-flags": "-shared -fPIC -g -mips32",
"c-triple": "mipsel-openwrt-linux"
}
# This will only work on Linux x86-64, only tested on Ubuntu 14.04
# Download rust-cross-libs.sh and tessel2.json of this gist into an empty directory
# Get OpenWRT SDK
wget https://s3.amazonaws.com/builds.tessel.io/t2/OpenWRT+SDK/OpenWrt-SDK-ramips-mt7620_gcc-4.8-linaro_uClibc-0.9.33.2.Linux-x86_64.tar.bz2
tar xf OpenWrt-SDK-ramips-mt7620_gcc-4.8-linaro_uClibc-0.9.33.2.Linux-x86_64.tar.bz2
export STAGING_DIR=$PWD/OpenWrt-SDK-ramips-mt7620_gcc-4.8-linaro_uClibc-0.9.33.2.Linux-x86_64/staging_dir
export PATH=$STAGING_DIR/toolchain-mipsel_24kec+dsp_gcc-4.8-linaro_uClibc-0.9.33.2/bin/:$PATH
# Get Rust source and binary
git clone https://github.com/rust-lang/rust
wget https://static.rust-lang.org/dist/rust-1.10.0-x86_64-unknown-linux-gnu.tar.gz
tar xf rust-1.10.0-x86_64-unknown-linux-gnu.tar.gz
rust-1.10.0-x86_64-unknown-linux-gnu/install.sh --prefix=$PWD/rust-root
# Build libs
./rust-cross-libs.sh --rust-prefix=$PWD/rust-root --rust-git=rust --target-json=tessel2.json
# Use rust from the local install dir
export PATH=$PWD/rust-root/bin:$PATH
export LD_LIBRARY_PATH=$PWD/rust-root/lib
export RUST_TARGET_PATH=$PWD
# To re-enter build environment later, re-run the `export` lines from this directory
# Build example and copy to Tessel
cargo new --bin hello
cd hello
cargo build --target=tessel2 --release
scp target/tessel2/release/test root@tessel.lan:/tmp
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment