diff options
Diffstat (limited to 'pkgs/development/compilers/ghc/common-make-native-bignum.nix')
-rw-r--r-- | pkgs/development/compilers/ghc/common-make-native-bignum.nix | 187 |
1 files changed, 151 insertions, 36 deletions
diff --git a/pkgs/development/compilers/ghc/common-make-native-bignum.nix b/pkgs/development/compilers/ghc/common-make-native-bignum.nix index 2b23cd75a0ed..7593a175c77c 100644 --- a/pkgs/development/compilers/ghc/common-make-native-bignum.nix +++ b/pkgs/development/compilers/ghc/common-make-native-bignum.nix @@ -3,7 +3,7 @@ , url ? "https://downloads.haskell.org/ghc/${version}/ghc-${version}-src.tar.xz" }: -{ lib, stdenv, pkgsBuildTarget, pkgsHostTarget, targetPackages +{ lib, stdenv, pkgsBuildTarget, pkgsHostTarget, buildPackages, targetPackages # build-tools , bootPkgs @@ -35,14 +35,19 @@ , # If enabled, use -fPIC when compiling static libs. enableRelocatedStaticLibs ? stdenv.targetPlatform != stdenv.hostPlatform -, enableProfiledLibs ? true + # Exceeds Hydra output limit (at the time of writing ~3GB) when cross compiled to riscv64. + # A riscv64 cross-compiler fits into the limit comfortably. +, enableProfiledLibs ? !stdenv.hostPlatform.isRiscV64 , # Whether to build dynamic libs for the standard library (on the target # platform). Static libs are always built. enableShared ? with stdenv.targetPlatform; !isWindows && !useiOSPrebuilt && !isStatic , # Whether to build terminfo. - enableTerminfo ? !stdenv.targetPlatform.isWindows + enableTerminfo ? !(stdenv.targetPlatform.isWindows + # terminfo can't be built for cross + || (stdenv.buildPlatform != stdenv.hostPlatform) + || (stdenv.hostPlatform != stdenv.targetPlatform)) , # What flavour to build. An empty string indicates no # specific flavour and falls back to ghc default values. @@ -58,24 +63,33 @@ , enableHaddockProgram ? # Disabled for cross; see note [HADDOCK_DOCS]. - (stdenv.targetPlatform == stdenv.hostPlatform) + (stdenv.buildPlatform == stdenv.hostPlatform && stdenv.targetPlatform == stdenv.hostPlatform) , # Whether to disable the large address space allocator # necessary fix for iOS: https://www.reddit.com/r/haskell/comments/4ttdz1/building_an_osxi386_to_iosarm64_cross_compiler/d5qvd67/ disableLargeAddressSpace ? stdenv.targetPlatform.isiOS + +, # Whether to build an unregisterised version of GHC. + # GHC will normally auto-detect whether it can do a registered build, but this + # option will force it to do an unregistered build when set to true. + # See https://gitlab.haskell.org/ghc/ghc/-/wikis/building/unregisterised + # Registerised RV64 compiler produces programs that segfault + # See https://gitlab.haskell.org/ghc/ghc/-/issues/23957 + enableUnregisterised ? stdenv.hostPlatform.isRiscV64 || stdenv.targetPlatform.isRiscV64 }: assert !enableNativeBignum -> gmp != null; # Cross cannot currently build the `haddock` program for silly reasons, # see note [HADDOCK_DOCS]. -assert (stdenv.targetPlatform != stdenv.hostPlatform) -> !enableHaddockProgram; +assert (stdenv.buildPlatform != stdenv.hostPlatform || stdenv.targetPlatform != stdenv.hostPlatform) -> !enableHaddockProgram; + +# GHC does not support building when all 3 platforms are different. +assert stdenv.buildPlatform == stdenv.hostPlatform || stdenv.hostPlatform == stdenv.targetPlatform; let inherit (stdenv) buildPlatform hostPlatform targetPlatform; - inherit (bootPkgs) ghc; - # TODO(@Ericson2314) Make unconditional targetPrefix = lib.optionalString (targetPlatform != hostPlatform) @@ -88,6 +102,8 @@ let endif BUILD_SPHINX_HTML = ${if enableDocs then "YES" else "NO"} BUILD_SPHINX_PDF = NO + + WITH_TERMINFO = ${if enableTerminfo then "YES" else "NO"} '' + # Note [HADDOCK_DOCS]: # Unfortunately currently `HADDOCK_DOCS` controls both whether the `haddock` @@ -134,7 +150,9 @@ let pkgsBuildTarget.targetPackages.stdenv.cc ] ++ lib.optional useLLVM buildTargetLlvmPackages.llvm; + buildCC = buildPackages.stdenv.cc; targetCC = builtins.head toolsForTarget; + installCC = pkgsHostTarget.targetPackages.stdenv.cc; # toolPath calculates the absolute path to the name tool associated with a # given `stdenv.cc` derivation, i.e. it picks the correct derivation to take @@ -145,12 +163,13 @@ let tools = { "cc" = cc; "c++" = cc; - as = cc.bintools.bintools; + as = cc.bintools; - ar = cc.bintools.bintools; - ranlib = cc.bintools.bintools; - nm = cc.bintools.bintools; - readelf = cc.bintools.bintools; + ar = cc.bintools; + ranlib = cc.bintools; + nm = cc.bintools; + readelf = cc.bintools; + objdump = cc.bintools; ld = cc.bintools; "ld.gold" = cc.bintools; @@ -169,6 +188,9 @@ let if stdenv.targetPlatform.isDarwin then cc.bintools else cc.bintools.bintools; + + # clang is used as an assembler on darwin with the LLVM backend + clang = cc; }.${name}; in "${tools}/bin/${tools.targetPrefix}${name}"; @@ -185,14 +207,30 @@ let (lib.optionalString enableNativeBignum "-native-bignum") ]; -in + # These libraries are library dependencies of the standard libraries bundled + # by GHC (core libs) users will link their compiled artifacts again. Thus, + # they should be taken from targetPackages. + # + # We need to use pkgsHostTarget if we are cross compiling a native GHC compiler, + # though (when native compiling GHC, pkgsHostTarget == targetPackages): + # + # 1. targetPackages would be empty(-ish) in this situation since we can't + # execute cross compiled compilers in order to obtain the libraries + # that would be in targetPackages. + # 2. pkgsHostTarget is fine to use since hostPlatform == targetPlatform in this + # situation. + # 3. The core libs used by the final GHC (stage 2) for user artifacts are also + # used to build stage 2 GHC itself, i.e. the core libs are both host and + # target. + targetLibs = { + inherit + (if hostPlatform != targetPlatform then targetPackages else pkgsHostTarget) + gmp + libffi + ncurses; + }; -# 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 buildTargetLlvmPackages.llvm == llvmPackages.llvm; -assert stdenv.targetPlatform.isDarwin -> buildTargetLlvmPackages.clang == llvmPackages.clang; +in stdenv.mkDerivation (rec { pname = "${targetPrefix}ghc${variantSuffix}"; @@ -282,6 +320,8 @@ stdenv.mkDerivation (rec { for env in $(env | grep '^TARGET_' | sed -E 's|\+?=.*||'); do export "''${env#TARGET_}=''${!env}" done + # Stage0 (build->build) which builds stage 1 + export GHC="${bootPkgs.ghc}/bin/ghc" # GHC is a bit confused on its cross terminology, as these would normally be # the *host* tools. export CC="${toolPath "cc" targetCC}" @@ -294,6 +334,7 @@ stdenv.mkDerivation (rec { export RANLIB="${toolPath "ranlib" targetCC}" export READELF="${toolPath "readelf" targetCC}" export STRIP="${toolPath "strip" targetCC}" + export OBJDUMP="${toolPath "objdump" targetCC}" '' + lib.optionalString (stdenv.targetPlatform.linker == "cctools") '' export OTOOL="${toolPath "otool" targetCC}" export INSTALL_NAME_TOOL="${toolPath "install_name_tool" targetCC}" @@ -302,20 +343,35 @@ stdenv.mkDerivation (rec { export OPT="${lib.getBin buildTargetLlvmPackages.llvm}/bin/opt" '' + lib.optionalString (useLLVM && stdenv.targetPlatform.isDarwin) '' # LLVM backend on Darwin needs clang: https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/codegens.html#llvm-code-generator-fllvm - export CLANG="${buildTargetLlvmPackages.clang}/bin/${buildTargetLlvmPackages.clang.targetPrefix}clang" + # The executable we specify via $CLANG is used as an assembler (exclusively, it seems, but this isn't + # clarified in any user facing documentation). As such, it'll be called on assembly produced by $CC + # which usually comes from the darwin stdenv. To prevent a situation where $CLANG doesn't understand + # the assembly it is given, we need to make sure that it matches the LLVM version of $CC if possible. + # It is unclear (at the time of writing 2024-09-01) whether $CC should match the LLVM version we use + # for llc and opt which would require using a custom darwin stdenv for targetCC. + export CLANG="${ + if targetCC.isClang + then toolPath "clang" targetCC + else "${buildTargetLlvmPackages.clang}/bin/${buildTargetLlvmPackages.clang.targetPrefix}clang" + }" '' + '' + # No need for absolute paths since these tools only need to work during the build + export CC_STAGE0="$CC_FOR_BUILD" + export LD_STAGE0="$LD_FOR_BUILD" + export AR_STAGE0="$AR_FOR_BUILD" + echo -n "${buildMK}" > mk/build.mk '' + lib.optionalString (lib.versionOlder version "9.2" || lib.versionAtLeast version "9.4") '' sed -i -e 's|-isysroot /Developer/SDKs/MacOSX10.5.sdk||' configure - '' + lib.optionalString (stdenv.isLinux && hostPlatform.libc == "glibc") '' + '' + lib.optionalString (stdenv.hostPlatform.isLinux && hostPlatform.libc == "glibc") '' export LOCALE_ARCHIVE="${glibcLocales}/lib/locale/locale-archive" - '' + lib.optionalString (!stdenv.isDarwin) '' + '' + lib.optionalString (!stdenv.hostPlatform.isDarwin) '' export NIX_LDFLAGS+=" -rpath $out/lib/ghc-${version}" - '' + lib.optionalString stdenv.isDarwin '' + '' + lib.optionalString stdenv.hostPlatform.isDarwin '' export NIX_LDFLAGS+=" -no_dtrace_dof" - '' + lib.optionalString (stdenv.isDarwin && lib.versionAtLeast version "9.2") '' + '' + lib.optionalString (stdenv.hostPlatform.isDarwin && lib.versionAtLeast version "9.2") '' # GHC tries the host xattr /usr/bin/xattr by default which fails since it expects python to be 2.7 export XATTR=${lib.getBin xattr}/bin/xattr @@ -346,21 +402,26 @@ stdenv.mkDerivation (rec { 'MinBootGhcVersion="8.10"' ''; + # Although it is usually correct to pass --host, we don't do that here because + # GHC's usage of build, host, and target is non-standard. + # See https://gitlab.haskell.org/ghc/ghc/-/wikis/building/cross-compiling # TODO(@Ericson2314): Always pass "--target" and always prefix. - configurePlatforms = [ "build" "host" ] - ++ lib.optional (targetPlatform != hostPlatform) "target"; + configurePlatforms = [ "build" ] + ++ lib.optional (buildPlatform != hostPlatform || targetPlatform != hostPlatform) "target"; # `--with` flags for libraries needed for RTS linker configureFlags = [ "--datadir=$doc/share/doc/ghc" - "--with-curses-includes=${ncurses.dev}/include" "--with-curses-libraries=${ncurses.out}/lib" + ] ++ lib.optionals enableTerminfo [ + "--with-curses-includes=${lib.getDev targetLibs.ncurses}/include" + "--with-curses-libraries=${lib.getLib targetLibs.ncurses}/lib" ] ++ lib.optionals (libffi != null) [ "--with-system-libffi" - "--with-ffi-includes=${targetPackages.libffi.dev}/include" - "--with-ffi-libraries=${targetPackages.libffi.out}/lib" + "--with-ffi-includes=${targetLibs.libffi.dev}/include" + "--with-ffi-libraries=${targetLibs.libffi.out}/lib" ] ++ lib.optionals (targetPlatform == hostPlatform && !enableNativeBignum) [ - "--with-gmp-includes=${targetPackages.gmp.dev}/include" - "--with-gmp-libraries=${targetPackages.gmp.out}/lib" + "--with-gmp-includes=${targetLibs.gmp.dev}/include" + "--with-gmp-libraries=${targetLibs.gmp.out}/lib" ] ++ lib.optionals (targetPlatform == hostPlatform && hostPlatform.libc != "glibc" && !targetPlatform.isWindows) [ "--with-iconv-includes=${libiconv}/include" "--with-iconv-libraries=${libiconv}/lib" @@ -372,6 +433,8 @@ stdenv.mkDerivation (rec { "CONF_GCC_LINKER_OPTS_STAGE2=-fuse-ld=gold" ] ++ lib.optionals (disableLargeAddressSpace) [ "--disable-large-address-space" + ] ++ lib.optionals enableUnregisterised [ + "--enable-unregisterised" ]; # Make sure we never relax`$PATH` and hooks support for compatibility. @@ -382,21 +445,39 @@ stdenv.mkDerivation (rec { nativeBuildInputs = [ perl autoconf automake m4 python3 - ghc bootPkgs.alex bootPkgs.happy bootPkgs.hscolour - ] ++ lib.optionals (stdenv.isDarwin && stdenv.isAarch64) [ + bootPkgs.alex bootPkgs.happy bootPkgs.hscolour + bootPkgs.ghc-settings-edit + ] ++ lib.optionals (stdenv.hostPlatform.isDarwin && stdenv.hostPlatform.isAarch64) [ autoSignDarwinBinariesHook ] ++ lib.optionals enableDocs [ sphinx - ] ++ lib.optionals (stdenv.isDarwin && lib.versions.majorMinor version == "9.0") [ + ] ++ lib.optionals (stdenv.hostPlatform.isDarwin && lib.versions.majorMinor version == "9.0") [ # TODO(@sternenseemann): backport addition of XATTR env var like # https://gitlab.haskell.org/ghc/ghc/-/merge_requests/6447 xattr ]; + # Everything the stage0 compiler needs to build stage1: CC, bintools, extra libs. + # See also GHC, {CC,LD,AR}_STAGE0 in preConfigure. + depsBuildBuild = [ + # N.B. We do not declare bootPkgs.ghc in any of the stdenv.mkDerivation + # dependency lists to prevent the bintools setup hook from adding ghc's + # lib directory to the linker flags. Instead we tell configure about it + # via the GHC environment variable. + buildCC + # stage0 builds terminfo unconditionally, so we always need ncurses + ncurses + ]; # For building runtime libs depsBuildTarget = toolsForTarget; - buildInputs = [ perl bash ] ++ (libDeps hostPlatform); + # Prevent stage0 ghc from leaking into the final result. This was an issue + # with GHC 9.6. + disallowedReferences = [ + bootPkgs.ghc + ]; + + buildInputs = [ bash ] ++ (libDeps hostPlatform); depsTargetTarget = map lib.getDev (libDeps targetPlatform); depsTargetTargetPropagated = map (lib.getOutput "out") (libDeps targetPlatform); @@ -423,6 +504,39 @@ stdenv.mkDerivation (rec { requiredSystemFeatures = [ "big-parallel" ]; postInstall = '' + settingsFile="$out/lib/${targetPrefix}${passthru.haskellCompilerName}/settings" + + # Make the installed GHC use the host->target tools. + ghc-settings-edit "$settingsFile" \ + "C compiler command" "${toolPath "cc" installCC}" \ + "Haskell CPP command" "${toolPath "cc" installCC}" \ + "C++ compiler command" "${toolPath "c++" installCC}" \ + "ld command" "${toolPath "ld${lib.optionalString useLdGold ".gold"}" installCC}" \ + "Merge objects command" "${toolPath "ld${lib.optionalString useLdGold ".gold"}" installCC}" \ + "ar command" "${toolPath "ar" installCC}" \ + "ranlib command" "${toolPath "ranlib" installCC}" + '' + + lib.optionalString (stdenv.targetPlatform.linker == "cctools") '' + ghc-settings-edit "$settingsFile" \ + "otool command" "${toolPath "otool" installCC}" \ + "install_name_tool command" "${toolPath "install_name_tool" installCC}" + '' + + lib.optionalString useLLVM '' + ghc-settings-edit "$settingsFile" \ + "LLVM llc command" "${lib.getBin llvmPackages.llvm}/bin/llc" \ + "LLVM opt command" "${lib.getBin llvmPackages.llvm}/bin/opt" + '' + + lib.optionalString (useLLVM && stdenv.targetPlatform.isDarwin) '' + ghc-settings-edit "$settingsFile" \ + "LLVM clang command" "${ + # See comment for CLANG in preConfigure + if installCC.isClang + then toolPath "clang" installCC + else "${llvmPackages.clang}/bin/${llvmPackages.clang.targetPrefix}clang" + }" + '' + + '' + # Install the bash completion file. install -D -m 444 utils/completion/ghc.bash $out/share/bash-completion/completions/${targetPrefix}ghc ''; @@ -448,7 +562,8 @@ stdenv.mkDerivation (rec { guibou ] ++ lib.teams.haskell.members; timeout = 24 * 3600; - inherit (ghc.meta) license platforms; + platforms = lib.platforms.all; + inherit (bootPkgs.ghc.meta) license; }; } // lib.optionalAttrs targetPlatform.useAndroidPrebuilt { |