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)
m →‎Current status: Restore error message
 
(4 intermediate revisions by 2 users not shown)
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
We can cross-compile ([https://github.com/NixOS/nixpkgs/pull/305392 #305392]) but we are missing bootstrap tarballs for native builds.
* ☐ 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>
<code>cannot bootstrap GHC on this platform ('riscv64-linux' with libc 'defaultLibc')</code>
==== Booting GHC via cross-compilation ====
 
* [https://gitlab.haskell.org/ghc/ghc/-/issues/?label_name%5B%5D=RISC-V RISC-V Label]
* [https://gitlab.haskell.org/ghc/ghc/-/issues/16783 Main issue] ✅
* [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]'''
 
Some popular affected packages are:
 
* nix-tree
* nixfmt
* hledger
* hledger-ui
* hledger-web
* exa
* pandoc
* nix-output-monitor
* xmonad
 
== 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>):
Line 154: Line 157:
For newer GHCs, refer to the GHC documentation or the Nixpkgs source to find which version of GHC and LLVM is needed for compilation.
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 &gt;=9.2 is unable to boot any version of GHC when cross-compiled. GHC &gt;=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.
GHC &gt;=9.2 is unable to boot 9.2 and 9.4. GHC &gt;=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 https://github.com/AlexandreTunstall/nixos-riscv for an example of a pure flake that uses this trick to compile Haskell programs for RISC-V.
Line 161: Line 164:


* [https://github.com/NixOS/nixpkgs/pull/243619 Nixpkgs PR 243619 (fix cross-built native GHC)]
* [https://github.com/NixOS/nixpkgs/pull/243619 Nixpkgs PR 243619 (fix cross-built native GHC)]
* [https://github.com/NixOS/nixpkgs/pull/305392 Nixpkgs PR 305392 (fix cross-built native GHC, version 2)]

Latest revision as of 13:16, 20 September 2024

Current status

We can cross-compile (#305392) but we are missing bootstrap tarballs for native builds.

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

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 9.2 and 9.4. 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