RISC-V/GHC: Difference between revisions

From NixOS Wiki
0x4A6F (talk | contribs)
Created page with "{{RISC-V/breadcrumb}} <span id="ghc"></span> === GHC === <code>cannot bootstrap GHC on this platform ('riscv64-linux' with libc 'defaultLibc')</code> see: * 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..."
 
Add nix-output-monitor and xmonad to the package list. Add "see also" link to the PR that enables cross-building GHC.
Line 17: Line 17:
* ☐ exa
* ☐ exa
* ☐ pandoc
* ☐ pandoc
* ☐ nix-output-monitor
* ☐ xmonad
* does cross-compile though when building unregisterised
* does cross-compile though when building unregisterised


Line 155: Line 157:


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.
== See also ==
* [https://github.com/NixOS/nixpkgs/pull/243619 Nixpkgs PR 243619 (fix cross-built native GHC)]

Revision as of 18:11, 3 April 2024

GHC

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

  • ☐ 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