RISC-V cross compilation on aarch64-darwin

Hello,

I would like to create a flake that creates an environment where I can cross compile simple C code to risc32 or risc64 on an aarch64-darwin machine.

I currently have this flake:

{
  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/release-23.11";
    flake-utils.url = "github:numtide/flake-utils";
  };

  outputs = {
    nixpkgs,
    flake-utils,
    ...
  }:
    flake-utils.lib.eachDefaultSystem (system: let
      pkgs = import nixpkgs {inherit system;};
      riscv64Pkgs =
        (import nixpkgs {
          inherit system;
          crossSystem.config = "riscv32-linux-gnu";
        })
        .buildPackages;
    in {
      devShells.default = pkgs.mkShell {
        buildInputs = with riscv64Pkgs; [
          gcc
        ];
      };
    });
}

The problem is that, gcc seems to be getting a flag that is macOS only.

$ riscv32-linux-gnu-gcc main.c
riscv32-linux-gnu-gcc: error: unrecognized command-line option ‘-iframework’

Is there a way for me to turn this flag off ? Where is it defined ?

Thank you for your time !

Update:

I’ve done some research on where the iframework comes from:

I cloned the nixpkgs repo and did a quick regex search, I found that in pkgs/build-support/cc-wrapper/setup-hook.sh, there’s this section:

Is there a way that I can turn this off with an override of some sort ? This is definitely correct in the general case, but the riscv32 gcc doesn’t like this option.

Thank you for your time !

Hello !

you have a problem with gcc because you have two different gcc in your shell: the one that comes from stdenv (through mkShell, which is a rather thin wrapper around stdenv.mkDerivation) and which is correctly setup, and the one that comes from buildInputs, which is half-broken because buildInputs is for libs, not compilers.

You should only keep the gcc from stdenv: instead of pkgs.mkShell { buildInputs = [ pkgs.gcc ]; } use pkgs.stdenv.mkDerivation { /* no buildInputs */ }. To obtain a cross gcc, then you need a cross stdenv:

let
      riscv64Pkgs =
        import nixpkgs {
          inherit system;
          crossSystem.config = "riscv32-linux-gnu";
        };
in
    riscv64Pkgs.stdenv.mkDerivation { name = "whatever"; }

Notice how I removed .buildPackage: stdenv is a bit special in that pkgs.stdenv is the stdenv to build pkgs, so riscv64Pkgs.buildPackages.stdenv builds packages to build packages for riscv.

For more complex stuff, please mind that you need to use callPackage for splicing. See How do I cross compile my own package (rather than something in nix-pkgs) for another example.

2 Likes

Thanks for the explanation ! It worked perfectly.