Flake build for a Rust Wasm32 library

I have a web application that involves a Typeshare GUI with a Rust logic engine. I discovered that it’s not all that hard, through a bunch of manual steps, to connect that gui to a WASM32 build of Rust.

But I don’t want to stick to manual steps. I want to have a single command to build the app and its dependencies. Since nix build .kifu-gtk (a GTK GUI for the same core library) already works, nix build .#kifu-pwa seems like a good command to run.

In order to constrain my build times, I’m using buildRustCrate so that I get the crate-level caching. That actually helps me quite a lot since one of my crates is rust-gtk, which has a huge number of dependencies and leads to 10+ minute builds on my machine.

So my question becomes, how can I direct buildRustCrate to pass --target wasm32-unknown-unknown to rustc? The only prior art I’ve found on something like this was an article Tom Houle wrote, but that article is still using Cargo. I haven’t figured out how to adapt it to a Cargoless world.

Here’s what I have right now, and this would work if I were targeting my host platform:

kifu/kifu-wasm/default.nix:

{ pkgs, typeshare, wasm-pack }:
let
  customBuildInfo = pkgs: pkgs.buildRustCrate.override {
    defaultCrateOverrides = pkgs.defaultCrateOverrides // {
      kifu-wasm = attrs: {
        buildInputs = [
          typeshare
        ];
      };
    };
  };
in (import ./Cargo.nix {
  inherit pkgs;
  buildRustCrateForPkgs = customBuildInfo;
  release = true;
}).rootCrate.build

flake.nix:

        packages."x86_64-linux" = {
            kifu-gtk = import ./kifu/kifu-gtk {
              inherit pkgs;
              typeshare = typeshare.packages."x86_64-linux".default;
            };

            kifu-wasm = import ./kifu/kifu-wasm {
              inherit pkgs;
              typeshare = typeshare.packages."x86_64-linux".default;
              wasm-pack = pkgs.wasm-pack;
            };

You can find these, including the full context, on my branch as long as it lives….

I would appreciate any help in getting this working, even if it means that I have to rearchitect my nix expressions. The actual goal is to build kifu-pwa, bundling kifu-wasm in. The only requirement is that I very much want to keep the crate-level dependency caching.

extraRustcOpts = [ " --target wasm32-unknown-unknown" ]; as an argument to buildRustCrate ?

Note that:

      # A list of extra options to pass to rustc.
      #
      # Example: [ "-Z debuginfo=2" ]
      # Default: []
    , extraRustcOpts
      # A list of extra options to pass to rustc when building a build.rs.
      #
      # Example: [ "-Z debuginfo=2" ]
      # Default: []
    , extraRustcOptsForBuildRs
      # Whether to enable building tests.
      # Use true to enable.
      # Default: false

(in the source code of buildRustCrate)

facepalm

I don’t know why these things are so hard for me to see.

(I read the source code FWIW, rg buildRustCrate, opened it, grepped for rustc or extra options and found it. If that can help you for the next time! And no worries, it happens to everyone. :slight_smile:)

I read the source, too. Somehow still didn’t see it.

However, it looks like I still have to figure out how to get the wasm32 target installed.

Unfortunately, I wasn’t able to get this working. I could see at one point that I was installing the necessary toolchain, but then I started getting build errors in libraries much deeper than where I’m working. I pushed all of the code up, but for now I’m using Makefiles so that I can keep the project moving forward.

Apologies, for the target, you need to use the cross-compilation infrastructure.

let cross = import <nixpkgs> {
   crossSystem = lib.systems.examples.wasi32 // { rustc.config = "wasm32-unknown-unknown"; };
};

then use that cross nixpkgs to build your packages. Also, it should be a good idea to upstream the fact that wasi32 has rustc.config = ... so you don’t need my //.

Don’t hesitate to come ask for questions on this in https://matrix.to/#/#cross-compiling:nixos.org for this. :slight_smile:

An alternative is to use GitHub - oxalica/rust-overlay: Pure and reproducible nix overlay of binary distributed rust toolchains or GitHub - nix-community/fenix: Rust toolchains and rust-analyzer nightly for Nix [maintainer=@figsoda] which have proper support for cross compiling AFAIK.

1 Like

I’ll check out the cross-compile channel in a few days.

Where is this documented?

  • if you want a cross-compiler, run this command
  • this is the list of keys command will return and what those keys mean
  • when you want to inject the compiler into [buildRustCrate|buildRustPackage|crane|whatever], this is the interface that the compiler derivation must conform to

Most of it is documented here: Nixpkgs 23.11 manual | Nix & NixOS
And the Rust part is documented: Nixpkgs 23.11 manual | Nix & NixOS (subsection on cross compiling)

I admit that I have no idea on how to evaluate our documentation on this, those are usually hard subjects anyway…