haskell.compiler.ghcHEAD: allow building the JavaScript backend

This is now possible by building a cross compiler for js-unknown-ghjs
using `pkgsCross.ghcjs.buildPackages.haskell.compiler.ghcHEAD`.

To allow this, the following things needed to be done:

* Disable dependencies that wouldn't work:

  - Don't pull in ncurses for terminfo
  - Don't pull in libffi
  - Don't pull in libiconv
  - Don't enable the LLVM backend
  - Enable gmp-less native-bignum backend

* Use emscripten instead of a C compiler. The way this works is inspired
  by emscriptenPackages, but avoids the following flaws:

  - Instead of using a custom configurePhase, just set
    `configureScript = "emconfigure ./configure";` which is much simpler.

  - Create writable EM_CACHE before configuring, as configure scripts
    want to compile test programs.

  Additionally, we need to disable the targetCC check, as it is not
  applicable with emscripten which never appears as part of stdenv.

* Use generic $configureScript in installPhase to be able to work with
  our emconfigure trick.

Note that the corresponding Haskell package set does not work yet. Cabal
doesn't seem to like GHC 9.7 yet and the generic-builder is clueless
about the JS backend.
This commit is contained in:
sternenseemann 2023-01-03 23:38:37 +01:00
parent b711b52d15
commit 6392c21c1f

View file

@ -39,7 +39,8 @@
, useLLVM ? !(stdenv.targetPlatform.isx86
|| stdenv.targetPlatform.isPower
|| stdenv.targetPlatform.isSparc
|| (stdenv.targetPlatform.isAarch64 && stdenv.targetPlatform.isDarwin))
|| (stdenv.targetPlatform.isAarch64 && stdenv.targetPlatform.isDarwin)
|| stdenv.targetPlatform.isGhcjs)
, # LLVM is conceptually a run-time-only depedendency, but for
# non-x86, we need LLVM to bootstrap later stages, so it becomes a
# build-time dependency too.
@ -50,6 +51,7 @@
# bignum backend instead of the faster but GPLed gmp backend.
enableNativeBignum ? !(lib.meta.availableOn stdenv.hostPlatform gmp
&& lib.meta.availableOn stdenv.targetPlatform gmp)
|| stdenv.targetPlatform.isGhcjs
, gmp
, # If enabled, use -fPIC when compiling static libs.
@ -63,7 +65,8 @@
enableShared ? with stdenv.targetPlatform; !isWindows && !useiOSPrebuilt && !isStatic
, # Whether to build terminfo.
enableTerminfo ? !stdenv.targetPlatform.isWindows
enableTerminfo ? !(stdenv.targetPlatform.isWindows
|| stdenv.targetPlatform.isGhcjs)
, # Libdw.c only supports x86_64, i686 and s390x as of 2022-08-04
enableDwarf ? (stdenv.targetPlatform.isx86 ||
@ -196,17 +199,19 @@ let
# Splicer will pull out correct variations
libDeps = platform: lib.optional enableTerminfo ncurses
++ [libffi]
++ lib.optionals (!targetPlatform.isGhcjs) [libffi]
# Bindist configure script fails w/o elfutils in linker search path
# https://gitlab.haskell.org/ghc/ghc/-/issues/22081
++ lib.optional enableDwarf elfutils
++ lib.optional (!enableNativeBignum) gmp
++ lib.optional (platform.libc != "glibc" && !targetPlatform.isWindows) libiconv;
++ lib.optional (platform.libc != "glibc" && !targetPlatform.isWindows && !targetPlatform.isGhcjs) libiconv;
# TODO(@sternenseemann): is buildTarget LLVM unnecessary?
# GHC doesn't seem to have {LLC,OPT}_HOST
toolsForTarget = [
pkgsBuildTarget.targetPackages.stdenv.cc
(if targetPlatform.isGhcjs
then pkgsBuildTarget.emscripten
else pkgsBuildTarget.targetPackages.stdenv.cc)
] ++ lib.optional useLLVM buildTargetLlvmPackages.llvm;
targetCC = builtins.head toolsForTarget;
@ -246,7 +251,7 @@ in
# C compiler, bintools and LLVM are used at build time, but will also leak into
# the resulting GHC's settings file and used at runtime. This means that we are
# currently only able to build GHC if hostPlatform == buildPlatform.
assert targetCC == pkgsHostTarget.targetPackages.stdenv.cc;
assert !targetPlatform.isGhcjs -> targetCC == pkgsHostTarget.targetPackages.stdenv.cc;
assert buildTargetLlvmPackages.llvm == llvmPackages.llvm;
assert stdenv.targetPlatform.isDarwin -> buildTargetLlvmPackages.clang == llvmPackages.clang;
@ -329,6 +334,13 @@ stdenv.mkDerivation ({
'*-android*|*-gnueabi*|*-musleabi*)'
done
''
# Need to make writable EM_CACHE for emscripten
# https://gitlab.haskell.org/ghc/ghc/-/wikis/javascript-backend#configure-fails-with-sub-word-sized-atomic-operations-not-available
+ lib.optionalString targetPlatform.isGhcjs ''
export EM_CACHE="$(mktemp -d emcache.XXXXXXXXXX)"
cp -Lr ${targetCC /* == emscripten */}/share/emscripten/cache/* "$EM_CACHE/"
chmod u+rwX -R "$EM_CACHE"
''
# Create bash array hadrianFlagsArray for use in buildPhase. Do it in
# preConfigure, so overrideAttrs can be used to modify it effectively.
# hadrianSettings are passed via the command line so they are more visible
@ -340,6 +352,8 @@ stdenv.mkDerivation ({
)
'';
${if targetPlatform.isGhcjs then "configureScript" else null} = "emconfigure ./configure";
# TODO(@Ericson2314): Always pass "--target" and always prefix.
configurePlatforms = [ "build" "host" ]
++ lib.optional (targetPlatform != hostPlatform) "target";
@ -348,7 +362,7 @@ stdenv.mkDerivation ({
configureFlags = [
"--datadir=$doc/share/doc/ghc"
"--with-curses-includes=${ncurses.dev}/include" "--with-curses-libraries=${ncurses.out}/lib"
] ++ lib.optionals (libffi != null) [
] ++ lib.optionals (libffi != null && !targetPlatform.isGhcjs) [
"--with-system-libffi"
"--with-ffi-includes=${targetPackages.libffi.dev}/include"
"--with-ffi-libraries=${targetPackages.libffi.out}/lib"
@ -387,6 +401,9 @@ stdenv.mkDerivation ({
autoSignDarwinBinariesHook
] ++ lib.optionals enableDocs [
sphinx
] ++ lib.optionals targetPlatform.isGhcjs [
# emscripten itself is added via depBuildTarget / targetCC
python3
];
# For building runtime libs
@ -445,7 +462,7 @@ stdenv.mkDerivation ({
preInstall = ''
pushd _build/bindist/*
./configure $configureFlags "''${configureFlagsArray[@]}"
$configureScript $configureFlags "''${configureFlagsArray[@]}"
'';
postInstall = ''