From 1261fe024fada592533a61a1f6ca1e03be50a4c6 Mon Sep 17 00:00:00 2001 From: Alex Tunstall Date: Sun, 23 Jul 2023 09:43:41 +0100 Subject: [PATCH] =?UTF-8?q?haskell.compiler.ghc*:=20fall=20back=20to=20hos?= =?UTF-8?q?t=20libs=20for=20=E2=80=9Ccross=20native=E2=80=9D=20ghc?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The goal of this commit is basically to eliminate the use of targetPackages for finding libraries. Instead, we introduce a `targetLibs` set that can be used instead. The libraries in there philosophically come from targetPackages since they are used by the core libs and will be linked against user code. However, when cross compiling GHC it's always a native compiler, so we can and have to use pkgsHostTarget (targetPackages would be empty). This is explained more in the acccompanying comment. An alternative to this approach is not to pass in the libraries explicitly via `--with-*` flags and rely on cc-wrapper and splicing to pick the correct library. This works well for ncurses and probably merits testing for other libraries as well since it's very simple. It would need to be verified, however, that configure doesn't discover the “wrong” library and leaks it somewhere. Co-authored-by: sternenseemann --- pkgs/development/compilers/ghc/8.10.7.nix | 39 ++++++++++++++++--- .../compilers/ghc/common-hadrian.nix | 35 ++++++++++++++--- .../ghc/common-make-native-bignum.nix | 30 ++++++++++++-- 3 files changed, 89 insertions(+), 15 deletions(-) diff --git a/pkgs/development/compilers/ghc/8.10.7.nix b/pkgs/development/compilers/ghc/8.10.7.nix index 873925417c16..8874f4221e81 100644 --- a/pkgs/development/compilers/ghc/8.10.7.nix +++ b/pkgs/development/compilers/ghc/8.10.7.nix @@ -72,7 +72,6 @@ assert !enableIntegerSimple -> gmp != null; assert (stdenv.targetPlatform != stdenv.hostPlatform) -> !enableHaddockProgram; let - libffi_name = if stdenv.isDarwin && stdenv.isAarch64 then "libffi" else "libffi_3_3"; inherit (stdenv) buildPlatform hostPlatform targetPlatform; inherit (bootPkgs) ghc; @@ -191,6 +190,36 @@ let (lib.optionalString enableIntegerSimple "-integer-simple") ]; + libffi_name = if stdenv.isDarwin && stdenv.isAarch64 then "libffi" else "libffi_3_3"; + + # 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 = + let + basePackageSet = + if hostPlatform != targetPlatform + then targetPackages + else pkgsHostTarget; + in + { + inherit (basePackageSet) gmp; + # dynamic inherits are not possible in Nix + libffi = basePackageSet.${libffi_name}; + }; + in # C compiler, bintools and LLVM are used at build time, but will also leak into @@ -348,11 +377,11 @@ stdenv.mkDerivation (rec { "--datadir=$doc/share/doc/ghc" ] ++ lib.optionals (args.${libffi_name} != null) [ "--with-system-libffi" - "--with-ffi-includes=${targetPackages.${libffi_name}.dev}/include" - "--with-ffi-libraries=${targetPackages.${libffi_name}.out}/lib" + "--with-ffi-includes=${targetLibs.libffi.dev}/include" + "--with-ffi-libraries=${targetLibs.libffi.out}/lib" ] ++ lib.optionals (targetPlatform == hostPlatform && !enableIntegerSimple) [ - "--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" diff --git a/pkgs/development/compilers/ghc/common-hadrian.nix b/pkgs/development/compilers/ghc/common-hadrian.nix index 78e0e2dd167e..11d6059a5616 100644 --- a/pkgs/development/compilers/ghc/common-hadrian.nix +++ b/pkgs/development/compilers/ghc/common-hadrian.nix @@ -324,6 +324,29 @@ let (lib.optionalString enableNativeBignum "-native-bignum") ]; + # 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) + elfutils + gmp + libffi; + }; + in # C compiler, bintools and LLVM are used at build time, but will also leak into @@ -447,11 +470,11 @@ stdenv.mkDerivation ({ "--datadir=$doc/share/doc/ghc" ] ++ lib.optionals (libffi != null && !targetPlatform.isGhcjs) [ "--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" @@ -465,8 +488,8 @@ stdenv.mkDerivation ({ "--disable-large-address-space" ] ++ lib.optionals enableDwarf [ "--enable-dwarf-unwind" - "--with-libdw-includes=${lib.getDev targetPackages.elfutils}/include" - "--with-libdw-libraries=${lib.getLib targetPackages.elfutils}/lib" + "--with-libdw-includes=${lib.getDev targetLibs.elfutils}/include" + "--with-libdw-libraries=${lib.getLib targetLibs.elfutils}/lib" ] ++ lib.optionals targetPlatform.isDarwin [ # Darwin uses llvm-ar. GHC will try to use `-L` with `ar` when it is `llvm-ar` # but it doesn’t currently work because Cabal never uses `-L` on Darwin. See: diff --git a/pkgs/development/compilers/ghc/common-make-native-bignum.nix b/pkgs/development/compilers/ghc/common-make-native-bignum.nix index 3d5d9d6329a5..812bb8fa95ab 100644 --- a/pkgs/development/compilers/ghc/common-make-native-bignum.nix +++ b/pkgs/development/compilers/ghc/common-make-native-bignum.nix @@ -191,6 +191,28 @@ let (lib.optionalString enableNativeBignum "-native-bignum") ]; + # 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; + }; + in # C compiler, bintools and LLVM are used at build time, but will also leak into @@ -366,11 +388,11 @@ stdenv.mkDerivation (rec { "--datadir=$doc/share/doc/ghc" ] ++ 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"