Skip to content

Instantly share code, notes, and snippets.

@dm0-
Created December 20, 2023 21:51
Show Gist options
  • Save dm0-/4fa598940ca6bc6c451a007458c7b89e to your computer and use it in GitHub Desktop.
Save dm0-/4fa598940ca6bc6c451a007458c7b89e to your computer and use it in GitHub Desktop.
Notes on using Fedora to cross-compile Rust projects

Cross-compile Rust on Fedora

These notes will set up a cross-compiling environment for Rust projects using only prebuilt Fedora RPMs with no emulation. While this works, it is unsupported and will leave the system RPM database in an odd state that could result in packages getting out of sync. It should only be used as a temporary measure if at all.

The example commands use aarch64 as the target architecure.

Install a cross-compiling environment for GNU C

Rust uses the C toolchain in various places, so install that first. Fedora packages a basic cross-compiler.

sudo dnf -y install gcc-c++-aarch64-linux-gnu

This allows compiling simple code, but it doesn't include the GNU C library for building normal programs. The toolchain packages' empty directory /usr/aarch64-linux-gnu/sys-root can be used for installing libraries for the target architecture. Install the glibc development files, but note that this creates a different RPM root which effectively means everything under this directory is unpackaged from the host's point of view.

sudo dnf --forcearch=aarch64 --installroot=/usr/aarch64-linux-gnu/sys-root --releasever=$(. /etc/os-release ; echo $VERSION_ID) -y install glibc-devel

Package scriptlets execute in the target chroot which would usually require emulation to run the foreign script interpreters, utilities, etc. Luckily the core packages' scriptlets are implemented in Lua to eliminate dependencies for bootstrapping, so they will run in the native RPM process's Lua interpreter allowing cross-installation. If additional packages are installed later, they might require configuring a binfmt handler or ignoring failing scriptlets.

One final piece is missing--Fedora's cross-compiler package doesn't include libgcc_s.so. It's normally in the GCC libdir, but write it under the sysroot with the other "unpackaged" stuff for cleanliness.

sudo tee /usr/aarch64-linux-gnu/sys-root/usr/lib64/libgcc_s.so << 'EOF' > /dev/null
OUTPUT_FORMAT(elf64-littleaarch64)
GROUP ( /lib64/libgcc_s.so.1 libgcc.a )
EOF

Install the Rust target standard libraries

Get the native Rust compiler if it's not installed. It's backed by LLVM, and Fedora enables support for all architectures in LLVM, so it can cross-compile already.

sudo dnf -y install cargo

Normal Rust projects need its standard libraries built for the target, though. Most of these targets are fairly self-contained under /usr/lib/rustlib, so the foreign target RPM can be installed directly on the host. Unfortunately, it declares an architecture-specific dependency on glibc which conflicts with the native one. Install it without dependencies as a workaround since its glibc is provided by the sysroot, but note this will leave an unsatisfied entry in the RPM database.

dnf --forcearch=aarch64 download rust-std-static
sudo rpm --ignorearch --nodeps -i rust-std-static-*.aarch64.rpm
rm -f rust-std-static-*.aarch64.rpm

Run a build

With the target libraries installed, Rust can specify the --target option to use it. The only catch is that it defaults to the native GCC for the linker, so builds must also specify the cross-linker. For example:

git clone --branch=0.0.21 --depth=1 https://github.com/uutils/coreutils.git
cd coreutils
cargo build --target=aarch64-unknown-linux-gnu --config='target.aarch64-unknown-linux-gnu.linker="aarch64-linux-gnu-gcc"'

If the qemu-user-static-aarch64 package is installed, the cross-compiled binary can be executed via emulation to verify it works. It just needs to be pointed at the sysroot for its dynamic libraries.

qemu-aarch64-static -L /usr/aarch64-linux-gnu/sys-root target/aarch64-unknown-linux-gnu/debug/coreutils --help

Some Rust crates have build processes with complicated library dependencies on the host. Their development packages for the target architecture would normally be installed under the sysroot, but there is no consistent way to specify their location to the build systems. Each crate's build process needs to be reviewed and addressed individually as they are encountered (usually by setting some environment variables).

Clean up everything

For a complete uninstall, delete the unpackaged files and remove the cross-packages.

sudo rm -fr /usr/aarch64-linux-gnu/sys-root
sudo dnf -y remove gcc-c++-aarch64-linux-gnu rust-std-static.aarch64
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment