Unverified Commit c8680a77 authored by sternenseemann's avatar sternenseemann Committed by GitHub
Browse files

haskell.*: Bootstrap & fix on powerpc64 (#439258)

parents e1e99eca f9bee9de
Loading
Loading
Loading
Loading
+267 −0
Original line number Diff line number Diff line
{
  lib,
  stdenv,
  fetchurl,
  perl,
  gcc,
  ncurses5,
  ncurses6,
  gmp,
  libiconv,
  numactl,
  libffi,
  coreutils,
  targetPackages,
}:

# Prebuilt only does native
assert stdenv.targetPlatform == stdenv.hostPlatform;

let
  version = "9.6.6";

  # GHC upstream doesn't release bindist tarballs for some platforms.
  # We're using Debian's binary package, and patching it into a usable-in-Nixpkgs state.
  ghcDebs = {
    powerpc64-linux = {
      variantSuffix = "";
      src = {
        url = "http://ftp.ports.debian.org/debian-ports/pool-ppc64/main/g/ghc/ghc_9.6.6-4_ppc64.deb";
        sha256 = "722cc301b6ba70b342e5e3d9d0671440bcd749cd2f13dcccbd23c3f6a6060171";
      };
      exePathForLibraryCheck = null;
      archSpecificLibraries = [
        {
          nixPackage = gmp;
          fileToCheckFor = null;
        }
        {
          nixPackage = ncurses6;
          fileToCheckFor = "libtinfo.so.6";
        }
        {
          nixPackage = numactl;
          fileToCheckFor = null;
        }
        {
          nixPackage = libffi;
          fileToCheckFor = null;
        }
      ];
    };
  };

  debUsed =
    ghcDebs.${stdenv.hostPlatform.system}
      or (throw "cannot bootstrap GHC on this platform ('${stdenv.hostPlatform.system}') from Debian debs");

  gmpUsed =
    (builtins.head (
      builtins.filter (drv: lib.hasPrefix "gmp" (drv.nixPackage.name or "")) debUsed.archSpecificLibraries
    )).nixPackage;

  runtimeDeps = [
    targetPackages.stdenv.cc
    targetPackages.stdenv.cc.bintools
    coreutils # for cat
  ];

  extraLibraryMapping = {
    gmp = gmpUsed;
    numa = numactl;
    ffi = libffi;
  };

in

stdenv.mkDerivation (finalAttrs: {
  inherit version;
  pname = "ghc-debian-binary${debUsed.variantSuffix}";

  src = fetchurl debUsed.src;

  nativeBuildInputs = [ perl ];

  sourceRoot = "${finalAttrs.pname}-${finalAttrs.version}";

  # Custom unpack phase to handle .deb files
  unpackPhase = ''
    runHook preUnpack

    ar x $src
    tar xf data.tar.xz
    mkdir -p ${finalAttrs.sourceRoot}
    mv -t ${finalAttrs.sourceRoot}/ usr var

    runHook postUnpack
  '';

  postUnpack =
    # Verify our assumptions of which `libtinfo.so` (ncurses) version is used,
    # so that we know when ghc debs upgrade that and we need to update the
    # version used in `archSpecificLibraries`.
    lib.optionalString (debUsed.exePathForLibraryCheck != null) (
      lib.concatStringsSep "\n" [
        ''
          shopt -u nullglob
          echo "Checking that ghc binary exists in deb at ${debUsed.exePathForLibraryCheck}"
          if ! test -e ${debUsed.exePathForLibraryCheck}; then
            echo >&2 "GHC binary ${debUsed.exePathForLibraryCheck} could not be found in the deb unpack directory for arch ${stdenv.hostPlatform.system}, please check that ghcDebs correctly reflect the deb dependencies!"; exit 1;
          fi
        ''
        (lib.concatMapStringsSep "\n" (
          { fileToCheckFor, nixPackage }:
          lib.optionalString (fileToCheckFor != null) ''
            echo "Checking deb for ${fileToCheckFor} to ensure that is still used"
            if ! readelf -d ${debUsed.exePathForLibraryCheck} | grep "${fileToCheckFor}"; then
              echo >&2 "File ${fileToCheckFor} could not be found in ${debUsed.exePathForLibraryCheck} for arch ${stdenv.hostPlatform.system}, please check that ghcDebs correctly reflect the deb dependencies!"; exit 1;
            fi

            echo "Checking that the nix package ${nixPackage} contains ${fileToCheckFor}"
            if ! test -e "${lib.getLib nixPackage}/lib/${fileToCheckFor}"; then
              echo >&2 "Nix package ${nixPackage} did not contain ${fileToCheckFor} for arch ${stdenv.hostPlatform.system}, please check that ghcDebs correctly reflect the deb dependencies!"; exit 1;
            fi
          ''
        ) debUsed.archSpecificLibraries)
      ]
    )

    # Linking to non-compiler libraries requires GHC to know about our non-FHS paths for those libraries
    + (lib.strings.concatMapAttrsStringSep "\n" (libName: libPackage: ''
      for packageDbDir in $(find . -name package.conf.d); do
        for packageDb in $(grep -l 'extra-libraries:.*${libName}' "$packageDbDir"/*.conf); do
          echo "Patching include & library path for ${libName} into package DB: $packageDb"
          sed -i "$packageDb" \
            -e '/^[a-z-]*include-dirs/a \    ${lib.getDev libPackage}/include' \
            -e '/^[a-z-]*library-dirs/a \    ${lib.getLib libPackage}/lib'
        done
      done
    '') extraLibraryMapping)

    +
      # Rename needed libraries and binaries, fix interpreter
      lib.optionalString stdenv.hostPlatform.isLinux ''
        find . -type f -executable -exec patchelf \
            --interpreter ${stdenv.cc.bintools.dynamicLinker} {} \;
      '';

  # Not a bindist, nothing to configure
  dontConfigure = true;

  # Not a bindist, it's already built
  dontBuild = true;

  # Install prebuilt GHC files
  installPhase = ''
    runHook preInstall

    mkdir -p $out

    cp -t $out/ -a usr/*
    rm -f $out/lib/ghc/lib/package.conf.d
    find var -name "package.conf.d" -type d -exec cp -a {} $out/lib/ghc/lib/ \;

    runHook postInstall
  '';

  postInstall =
    # Patch scripts to include runtime dependencies in $PATH.
    ''
      for i in "$out/bin/"*; do
        test ! -h "$i" || continue
        isScript "$i" || continue
        sed -i -e '2i export PATH="${lib.makeBinPath runtimeDeps}:$PATH"' "$i"
      done
    ''

    # Patch /usr paths
    + ''
      for i in "$out/bin/"*; do
        test ! -h "$i" || continue
        isScript "$i" || continue
        substituteInPlace "$i" \
          --replace-fail '="/usr' '="${placeholder "out"}'
      done
      find "$out/lib/ghc/lib/package.conf.d" -type f -name '*.conf' \
        -exec sed -i "s|/usr/|$out/|g" {} +
    ''

    # Patch ghc settings
    + ''
      substituteInPlace $out/lib/ghc/lib/settings \
        --replace-fail powerpc64-linux-gnu-gcc gcc \
        --replace-fail powerpc64-linux-gnu-g++ g++ \
        --replace-fail powerpc64-linux-gnu-ld ld \
        --replace-fail powerpc64-linux-gnu-ar ar \
        --replace-fail powerpc64-linux-gnu-ranlib ranlib \
        --replace-fail llc-18 llc \
        --replace-fail opt-18 opt
    '';

  # On Linux, use patchelf to modify the executables so that they can
  # find editline/gmp.
  postFixup =
    lib.optionalString (stdenv.hostPlatform.isLinux && !(debUsed.isStatic or false))
      # Keep rpath as small as possible, running autoPatchelf makes everything segfault (maybe similar to patchelf#244).
      # All Elfs are 2 directories deep from $out/lib, so pooling symlinks there makes a short rpath.
      ''
        (cd $out/lib; ln -s ${ncurses6.out}/lib/libtinfo.so.6)
        (cd $out/lib; ln -s ${lib.getLib gmpUsed}/lib/libgmp.so.10)
        (cd $out/lib; ln -s ${numactl.out}/lib/libnuma.so.1)
        (cd $out/lib; ln -s ${libffi.out}/lib/libffi.so.8)
        for p in $(find "$out/lib" -type f -name "*\.so*"); do
          (cd $out/lib; ln -s $p)
        done

        for p in $(find "$out/lib" -type f -executable); do
          if isELF "$p"; then
            echo "Patchelfing $p"
            patchelf --set-rpath "\$ORIGIN:\$ORIGIN/../.." $p
          fi
        done
      ''
    # Recache package db which needs to happen because
    # we modify the package db
    + ''
      "$out/bin/ghc-pkg" --package-db=$out/lib/ghc/lib/package.conf.d recache
    '';

  doInstallCheck = true;
  installCheckPhase = ''
    # Sanity check, can ghc create executables?
    cd $TMP
    mkdir test-ghc; cd test-ghc
    cat > main.hs << EOF
      {-# LANGUAGE TemplateHaskell #-}
      module Main where
      main = putStrLn \$([|"yes"|])
    EOF
    env -i $out/bin/ghc --make main.hs || exit 1
    echo compilation ok
    [ $(./main) == "yes" ]
  '';

  passthru = {
    targetPrefix = "";
    enableShared = true;

    llvmPackages = null;

    # Our Cabal compiler name
    haskellCompilerName = "ghc-${version}";

    # Normal GHC derivations expose the hadrian derivation used to build them
    # here. In the case of debs we just make sure that the attribute exists,
    # as it is used for checking if a GHC derivation has been built with hadrian.
    hadrian = null;
  };

  meta = {
    homepage = "http://haskell.org/ghc";
    description = "Glasgow Haskell Compiler";
    license = lib.licenses.bsd3;
    platforms = builtins.attrNames ghcDebs;
    maintainers = [ lib.maintainers.OPNA2608 ];
    teams = [ lib.teams.haskell ];
  };
})
+45 −2
Original line number Diff line number Diff line
@@ -276,6 +276,8 @@ with haskellLib;
    # Ironically, we still need to build the doctest suite.
    # vector-0.13.2.0 has a doctest < 0.24 constraint
    jailbreak = true;
    # inspection-testing doesn't work on all archs & ABIs
    doCheck = !self.inspection-testing.meta.broken;
  }) super.vector;

  # https://github.com/lspitzner/data-tree-print/issues/4
@@ -703,6 +705,12 @@ with haskellLib;
    hash = "sha256-feGEuALVJ0Zl8zJPIfgEFry9eH/MxA0Aw7zlDq0PC/s=";
  }) super.algebraic-graphs;

  # Relies on DWARF <-> register mappings in GHC, not available for every arch & ABI
  # (check dwarfReturnRegNo in compiler/GHC/CmmToAsm/Dwarf/Constants.hs, that's where ppc64 elfv1 gives up)
  inspection-testing = overrideCabal (drv: {
    broken = with pkgs.stdenv.hostPlatform; !(isx86 || (isPower64 && isAbiElfv2) || isAarch64);
  }) super.inspection-testing;

  # Too strict bounds on filepath, hpsec, tasty, tasty-quickcheck, transformers
  # https://github.com/illia-shkroba/pfile/issues/3
  pfile = doJailbreak super.pfile;
@@ -2445,6 +2453,26 @@ with haskellLib;
    ))
  ];

  # Test failures on various archs
  # https://github.com/kazu-yamamoto/crypton/issues/49
  crypton = dontCheckIf (
    pkgs.stdenv.hostPlatform.isPower64 && pkgs.stdenv.hostPlatform.isBigEndian
  ) super.crypton;

  # Test failures on at least ppc64
  # https://github.com/kazu-yamamoto/crypton-certificate/issues/25
  # Likely related to the issues in crypton
  # https://github.com/kazu-yamamoto/crypton/issues/49
  crypton-x509-validation = dontCheckIf (
    pkgs.stdenv.hostPlatform.isPower64 && pkgs.stdenv.hostPlatform.isBigEndian
  ) super.crypton-x509-validation;

  # Likely fallout from the crypton issues
  # exception: HandshakeFailed (Error_Protocol "bad PubKeyALG_Ed448 signature for ecdhparams" DecryptError)
  tls = dontCheckIf (
    pkgs.stdenv.hostPlatform.isPower64 && pkgs.stdenv.hostPlatform.isBigEndian
  ) super.tls;

  # Too strict bounds on text and tls
  # https://github.com/barrucadu/irc-conduit/issues/54
  # Use crypton-connection instead of connection
@@ -2676,8 +2704,23 @@ with haskellLib;
  # hashable <1.4, mmorph <1.2
  composite-aeson = doJailbreak super.composite-aeson;

  hashable = lib.pipe super.hashable [
    # Overly strict bounds on tasty-quickcheck (test suite) (< 0.11)
  hashable = doJailbreak super.hashable;
    doJailbreak

    # Big-endian POWER:
    # Test suite xxhash-tests: RUNNING...
    # xxhash
    #   oneshot
    #     w64-ref:      OK (0.03s)
    #       +++ OK, passed 100 tests.
    #     w64-examples: FAIL
    #       tests/xxhash-tests.hs:21:
    #       expected: 2768807632077661767
    #        but got: 13521078365639231154
    # https://github.com/haskell-unordered-containers/hashable/issues/323
    (dontCheckIf pkgs.stdenv.hostPlatform.isBigEndian)
  ];

  cborg = appendPatches [
    # This patch changes CPP macros form gating on the version of ghc-prim to base
+65 −5
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@ let
    "native-bignum"
    # Binary GHCs
    "ghc902Binary"
    "ghc966DebianBinary"
    "ghc984Binary"
  ];

@@ -86,6 +87,8 @@ in
        inherit llvmPackages;
      };

      ghc966DebianBinary = callPackage ../development/compilers/ghc/9.6.6-debian-binary.nix { };

      ghc984Binary = callPackage ../development/compilers/ghc/9.8.4-binary.nix { };

      ghc948 = callPackage ../development/compilers/ghc/9.4.8.nix {
@@ -99,27 +102,69 @@ in
      };
      ghc94 = compiler.ghc948;
      ghc967 = callPackage ../development/compilers/ghc/9.6.7.nix {
        bootPkgs = bb.packages.ghc948;
        bootPkgs =
          if
            stdenv.buildPlatform.isPower64
            && stdenv.buildPlatform.isBigEndian
            && pkgs.stdenv.hostPlatform.isAbiElfv1
          then
            # No bindist, "borrowing" the GHC from Debian
            bb.packages.ghc966DebianBinary
          else
            bb.packages.ghc948;
        inherit (buildPackages.python3Packages) sphinx;
        inherit (buildPackages.darwin) xattr autoSignDarwinBinariesHook;
        inherit buildTargetLlvmPackages llvmPackages;
      };
      ghc96 = compiler.ghc967;
      ghc984 = callPackage ../development/compilers/ghc/9.8.4.nix {
        bootPkgs = if stdenv.buildPlatform.isi686 then bb.packages.ghc948 else bb.packages.ghc984Binary;
        bootPkgs =
          if
            stdenv.buildPlatform.isPower64
            && stdenv.buildPlatform.isBigEndian
            && pkgs.stdenv.hostPlatform.isAbiElfv1
          then
            # No bindist, "borrowing" the GHC from Debian
            bb.packages.ghc966DebianBinary
          else if stdenv.buildPlatform.isi686 then
            bb.packages.ghc948
          else
            bb.packages.ghc984Binary;
        inherit (buildPackages.python3Packages) sphinx;
        inherit (buildPackages.darwin) xattr autoSignDarwinBinariesHook;
        inherit buildTargetLlvmPackages llvmPackages;
      };
      ghc98 = compiler.ghc984;
      ghc9102 = callPackage ../development/compilers/ghc/9.10.2.nix {
        bootPkgs = if stdenv.buildPlatform.isi686 then bb.packages.ghc967 else bb.packages.ghc984Binary;
        bootPkgs =
          if
            stdenv.buildPlatform.isPower64
            && stdenv.buildPlatform.isBigEndian
            && pkgs.stdenv.hostPlatform.isAbiElfv1
          then
            # No bindist, "borrowing" the GHC from Debian
            bb.packages.ghc966DebianBinary
          else if stdenv.buildPlatform.isi686 then
            bb.packages.ghc967
          else
            bb.packages.ghc984Binary;
        inherit (buildPackages.python3Packages) sphinx;
        inherit (buildPackages.darwin) xattr autoSignDarwinBinariesHook;
        inherit buildTargetLlvmPackages llvmPackages;
      };
      ghc9103 = callPackage ../development/compilers/ghc/9.10.3.nix {
        bootPkgs = if stdenv.buildPlatform.isi686 then bb.packages.ghc967 else bb.packages.ghc984Binary;
        bootPkgs =
          if
            stdenv.buildPlatform.isPower64
            && stdenv.buildPlatform.isBigEndian
            && pkgs.stdenv.hostPlatform.isAbiElfv1
          then
            # No bindist, "borrowing" the GHC from Debian
            bb.packages.ghc966DebianBinary
          else if stdenv.buildPlatform.isi686 then
            bb.packages.ghc967
          else
            bb.packages.ghc984Binary;
        inherit (buildPackages.python3Packages) sphinx;
        inherit (buildPackages.darwin) xattr autoSignDarwinBinariesHook;
        inherit buildTargetLlvmPackages llvmPackages;
@@ -144,7 +189,16 @@ in
      };
      ghc914 = compiler.ghc9141;
      ghcHEAD = callPackage ../development/compilers/ghc/head.nix {
        bootPkgs = bb.packages.ghc984Binary;
        bootPkgs =
          if
            stdenv.buildPlatform.isPower64
            && stdenv.buildPlatform.isBigEndian
            && pkgs.stdenv.hostPlatform.isAbiElfv1
          then
            # No bindist, using older source-built GHC
            bb.packages.ghc910
          else
            bb.packages.ghc984Binary;
        inherit (buildPackages.python3Packages) sphinx;
        inherit (buildPackages.darwin) xattr autoSignDarwinBinariesHook;
        inherit buildTargetLlvmPackages llvmPackages;
@@ -189,6 +243,12 @@ in
        compilerConfig = callPackage ../development/haskell-modules/configuration-ghc-9.0.x.nix { };
        packageSetConfig = bootstrapPackageSet;
      };
      ghc966DebianBinary = callPackage ../development/haskell-modules {
        buildHaskellPackages = bh.packages.ghc966DebianBinary;
        ghc = bh.compiler.ghc966DebianBinary;
        compilerConfig = callPackage ../development/haskell-modules/configuration-ghc-9.6.x.nix { };
        packageSetConfig = bootstrapPackageSet;
      };
      ghc984Binary = callPackage ../development/haskell-modules {
        buildHaskellPackages = bh.packages.ghc984Binary;
        ghc = bh.compiler.ghc984Binary;