To cross compile a rust project using oxalica/rust-overlay, run the following in a fresh directory:

nix flake init -t github:ipetkov/crane#cross-rust-overlay

Alternatively, if you have an existing project already, copy and paste the following flake.nix:

{ description = "Cross compiling a rust program using rust-overlay"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; crane.url = "github:ipetkov/crane"; flake-utils.url = "github:numtide/flake-utils"; rust-overlay = { url = "github:oxalica/rust-overlay"; inputs.nixpkgs.follows = "nixpkgs"; }; }; outputs = { nixpkgs, crane, flake-utils, rust-overlay, ... }: flake-utils.lib.eachDefaultSystem (localSystem: let # Replace with the system you want to build for crossSystem = "aarch64-linux"; pkgs = import nixpkgs { inherit crossSystem localSystem; overlays = [ (import rust-overlay) ]; }; craneLib = (crane.mkLib pkgs).overrideToolchain (p: p.rust-bin.stable.latest.default); # Note: we have to use the `callPackage` approach here so that Nix # can "splice" the packages in such a way that dependencies are # compiled for the appropriate targets. If we did not do this, we # would have to manually specify things like # `nativeBuildInputs = with pkgs.pkgsBuildHost; [ someDep ];` or # `buildInputs = with pkgs.pkgsHostHost; [ anotherDep ];`. # # Normally you can stick this function into its own file and pass # its path to `callPackage`. crateExpression = { openssl , libiconv , lib , pkg-config , stdenv }: craneLib.buildPackage { src = craneLib.cleanCargoSource ./.; strictDeps = true; # Dependencies which need to be build for the current platform # on which we are doing the cross compilation. In this case, # pkg-config needs to run on the build platform so that the build # script can find the location of openssl. Note that we don't # need to specify the rustToolchain here since it was already # overridden above. nativeBuildInputs = [ pkg-config ] ++ lib.optionals stdenv.buildPlatform.isDarwin [ libiconv ]; # Dependencies which need to be built for the platform on which # the binary will run. In this case, we need to compile openssl # so that it can be linked with our executable. buildInputs = [ # Add additional build inputs here openssl ]; }; # Assuming the above expression was in a file called myCrate.nix # this would be defined as: # my-crate = pkgs.callPackage ./myCrate.nix { }; my-crate = pkgs.callPackage crateExpression { }; in { checks = { inherit my-crate; }; packages.default = my-crate; apps.default = flake-utils.lib.mkApp { drv = pkgs.writeScriptBin "my-app" '' ${pkgs.pkgsBuildBuild.qemu}/bin/qemu-aarch64 ${my-crate}/bin/cross-rust-overlay ''; }; }); }