RISC-V/GHC: Difference between revisions

From NixOS Wiki
Add nix-output-monitor and xmonad to the package list. Add "see also" link to the PR that enables cross-building GHC.
Fgaz (talk | contribs)
Reformat
Line 1: Line 1:
{{RISC-V/breadcrumb}}
{{RISC-V/breadcrumb}}
<span id="ghc"></span>
=== GHC ===


<code>cannot bootstrap GHC on this platform ('riscv64-linux' with libc 'defaultLibc')</code> see:
== Current status ==
* https://gitlab.haskell.org/ghc/ghc/-/issues/23179
* https://gitlab.haskell.org/ghc/ghc/-/issues/16783
* https://gitlab.haskell.org/ghc/ghc/-/issues/14903
* https://gitlab.haskell.org/ghc/ghc/-/commit/31e265c1df948d1bcc82d08affe995fd1d1c1438
* '''https://gitlab.haskell.org/ghc/ghc/-/issues/23519''' ← we need this one - https://gitlab.haskell.org/ghc/ghc/-/issues/23957


* ☐ nix-tree
<code>cannot bootstrap GHC on this platform ('riscv64-linux' with libc 'defaultLibc')</code>
* ☐ nixfmt
* ☐ hledger
* ☐ hledger-ui
* ☐ hledger-web
* ☐ exa
* ☐ pandoc
* ☐ nix-output-monitor
* ☐ xmonad
* does cross-compile though when building unregisterised


<span id="booting-ghc-via-cross-compilation"></span>
* [https://gitlab.haskell.org/ghc/ghc/-/issues/16783 Main issue]
==== Booting GHC via cross-compilation ====
* [https://gitlab.haskell.org/ghc/ghc/-/issues/23179 NCG]
* [https://gitlab.haskell.org/ghc/ghc/-/commit/31e265c1df948d1bcc82d08affe995fd1d1c1438 LLVM backend]
* '''[https://gitlab.haskell.org/ghc/ghc/-/issues/23519 Binary tarballs] (needed for bootstrap)'''
* [https://gitlab.haskell.org/ghc/ghc/-/issues/?label_name%5B%5D=RISC-V RISC-V Label]
 
Some popular affected packages are:
 
* nix-tree
* nixfmt
* hledger
* hledger-ui
* hledger-web
* exa
* pandoc
* nix-output-monitor
* xmonad
** does cross-compile though when building unregisterised
 
== Booting GHC via cross-compilation ==


On a platform where Nixpkgs supports compiling GHC (e.g. <code>x86_64-linux</code>):
On a platform where Nixpkgs supports compiling GHC (e.g. <code>x86_64-linux</code>):

Revision as of 09:09, 4 April 2024

Current status

cannot bootstrap GHC on this platform ('riscv64-linux' with libc 'defaultLibc')

Some popular affected packages are:

  • nix-tree
  • nixfmt
  • hledger
  • hledger-ui
  • hledger-web
  • exa
  • pandoc
  • nix-output-monitor
  • xmonad
    • does cross-compile though when building unregisterised

Booting GHC via cross-compilation

On a platform where Nixpkgs supports compiling GHC (e.g. x86_64-linux):

nix copy --to ssh://root@$riscv_host --no-check-sigs \
  'github:alexandretunstall/nixpkgs/ghc-cross-usable#pkgsCross.riscv64.haskell.compiler.integer-simple.ghc8107'

(You don’t need to SSH as root if you copy it via a trusted user.)

Then you’ll want to pin the copied path so that the GC never deletes it. On the RISC-V host:

nix-store --realise --indirect --add-root $root_path $cross_ghc_path

Finally, create the GHC configuration on the RISC-V host so that native builds use the cross-compiled GHC.

The configuration below assumes that there is a symbolic link to the previously built GHC at ../boot/ghc-8.10.7.

The configuration should work with any modern version of Nixpkgs.

{ config, lib, pkgs, ... }:

let
  mkBootCompiler = { version, outPath, llvmPackages }: let
    passthru = {
      targetPrefix = "";
      enableShared = false;
      hasHaddock = false;
      hasThreadedRuntime = false;

      inherit llvmPackages;

      haskellCompilerName = "ghc-${version}";
    };
  in passthru // {
    inherit version outPath passthru;

    meta = {
      license = lib.licenses.bsd3;
      platforms = [ "riscv64-linux" ];
    };
  };

  mkBootPackages = { base, ghc }: let
    buildHaskellPackages = base.override (old: {
      inherit buildHaskellPackages ghc;

      overrides = bootOverrides;
    });
  in buildHaskellPackages;

  hsLib = pkgs.haskell.lib.compose;

  # Overrides that are needed to boot a native GHC
  bootOverrides = self: super: {
    mkDerivation = args: super.mkDerivation ({
      enableLibraryProfiling = false;
    } // args);

    alex = hsLib.dontCheck super.alex;
    data-array-byte = hsLib.dontCheck super.data-array-byte;
    doctest = hsLib.dontCheck super.doctest;
    hashable = hsLib.dontCheck super.hashable;
    optparse-applicative = hsLib.dontCheck super.optparse-applicative;
    QuickCheck = hsLib.dontCheck super.QuickCheck;
    temporary = hsLib.dontCheck super.temporary;
    vector = hsLib.dontCheck super.vector;
  };

  # If a package fails to build, try disabling checks here.
  # Since RISC-V has to use an unregisterised GHC, many test suites fail.
  unregOverrides = self: super: {
    # Example: lens fails without this override
    lens = hsLib.dontCheck super.lens;
  };

in {
  nixpkgs.overlays = [
    (self: super: {
      # If you need to change the default GHC, uncomment these lines.
      # Using the Nixpkgs default is better as it can build more packages than
      # other versions of GHC.
      #ghc = self.haskell.compiler.ghc94;
      #haskellPackages = self.haskell.packages.ghc94;

      haskell = super.haskell // {
        compiler = {
          ghc8107Boot = mkBootCompiler {
            version = "8.10.7";
            outPath = builtins.storePath ../boot/ghc-8.10.7;
            llvmPackages = pkgs.llvmPackages_12;
          };

          ghc928 = (super.haskell.compiler.ghc928.override (old: {
            bootPkgs = self.pkgsBuildBuild.haskell.packages.ghc8107Boot;
          })).overrideAttrs ({ configureFlags ? [], ... }: {
            # Registerised RV64 produces programs that segfault
            configureFlags = configureFlags ++ [ "--enable-unregisterised" ];
          });
          
          ghc92 = self.haskell.compiler.ghc928;
          
          ghc964 = (super.haskell.compiler.ghc964.override (old: {
            bootPkgs = self.pkgsBuildBuild.haskell.packages.ghc928;
          }).overrideAttrs ({ configureFlags ? [], ... }: {
            configureFlags = configureFlags ++ [ "--enable-unregisterised" ];
          });
          
          ghc96 = self.haskell.compiler.ghc964;
        };

        packages = {
          ghc928 = super.haskell.packages.ghc928.override (old: {
            overrides = unregOverrides;
          });
          
          ghc92 = self.haskell.packages.ghc928;
          
          ghc964 = super.haskell.packages.ghc964.override (old: {
            overrides = unregOverrides;
          });
          
          ghc96 = self.haskell.packages.ghc96;

          ghc8107Boot = mkBootPackages {
            base = super.haskell.packages.ghc8107;
            ghc = self.pkgsBuildHost.haskell.compiler.ghc8107Boot;
          };
        };
      };
    })
  ];
}

For newer GHCs, refer to the GHC documentation or the Nixpkgs source to find which version of GHC and LLVM is needed for compilation.

GHC >=9.2 is unable to boot any version of GHC when cross-compiled. GHC >=9.6 cannot be cross-compiled at all due to issues with Hadrian. Newer GHCs can be booted using natively compiled versions of GHC instead.

See https://github.com/AlexandreTunstall/nixos-riscv for an example of a pure flake that uses this trick to compile Haskell programs for RISC-V.

See also