haskell.compiler.ghc*: fall back to host libs for “cross native” ghc

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 <sternenseemann@systemli.org>
This commit is contained in:
Alex Tunstall
2024-09-08 23:50:05 +02:00
committed by sternenseemann
co-authored by sternenseemann
parent 4b00fbf163
commit 1261fe024f
3 changed files with 89 additions and 15 deletions
+34 -5
View File
@@ -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"
@@ -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 doesnt currently work because Cabal never uses `-L` on Darwin. See:
@@ -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"