Setting up NixOS to run RISC-V binaries
Since most RISC-V boards are quite slow, it is often useful to do initial development and testing on a fast x86-64 or ARM64 machine. QEMU user mode emulation has you covered here – it can run binaries for another CPU using emulation without setting up a complete VM.
Running QEMU user mode emulation by hand gets a bit tedious over time, but you can set up linux binfmt_misc to register QEMU as a handler for RISC-V binaries. In NixOS, you can enable this by adding this line to your system configuration:
boot.binfmt.emulatedSystems = [ "riscv64-linux" ];Then you go from:
$ nix run nixpkgs#pkgsCross.riscv64.hello
error: unable to execute '/nix/store/2476cpnkgbl5cdhrln3mlbhl9dslad97-hello-riscv64-unknown-linux-gnu-2.12.2/bin/hello': Exec format errorto
$ nix run nixpkgs#pkgsCross.riscv64.hello
Hello, world!after switching to the new system configuration.
Cross-compilation
You can easily create a cross-compiler with nixpkgs using the crossSystem option. The nicest way to do this is to create a flake that creates a cross-compilation environment as a development shell:
{
description = "RISC-V cross-compiler";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs =
{
self,
nixpkgs,
flake-utils,
}:
flake-utils.lib.eachDefaultSystem (
system:
let
cross = import nixpkgs {
crossSystem = {
config = "riscv64-unknown-linux-gnu";
# Or if you want to build against MUSL:
# config = "riscv64-unknown-linux-musl";
};
inherit system;
};
in
{
devShells.default =
with cross; mkShell {
# RISC-V dependencies if you need them.
buildInputs = [ zlib ];
};
}
);
}You can then cross-compile your C or C++ programs in the development shell:
$ nix develop
$ riscv64-unknown-linux-gnu-gcc -o hello hello.c ; file hello ; ./hello
hello: ELF 64-bit LSB pie executable, UCB RISC-V, RVC, double-float ABI, version 1 (SYSV), dynamically linked, interpreter /nix/store/vggr947f2zwmzvnjv9ikkk5kcsqhpgml-glibc-riscv64-unknown-linux-gnu-2.40-66/lib/ld-linux-riscv64-lp64d.so.1, for GNU/Linux 4.15.0, not stripped
Hello world!If you need any additional C/C++ dependencies, you can add them to buildInputs.