Skip to content

Commit 775c8cf

Browse files
authored
Fix cross compilation issues for musl and aarch64 (#322)
* Enables tests for Musl and AArch64 (also rasbery pi, but leaves them disabled for now) and includes many fixes for the tests that were broken. * Makes Musl cross compiler more like native (including making `ghci` and `runghc` work) * Updates selection of enableShared * Works around missing configFiles attribute issue * Use ghc-extra-packages and compiler.nix-name to pick the right extra packages * Leaves out --cross-compile on hsc2hs for musl * Fixes haddock and hoogle for musl and disables them for other cross compilers * Adds ghc 8.8.3 * Static link components (except libraries and `all`) on musl * Use qemu for the arm cross compile `testWrapper` * Add isCrossHost and isCrossTarget functions * Fixes profiling on AArch64 * Disable split sections when compiling for windows (fixes GHC 8.8 cross compile to windows) * Disable hoogle in cross compiler shells for now
1 parent 7c5c8e7 commit 775c8cf

File tree

26 files changed

+209
-106
lines changed

26 files changed

+209
-106
lines changed

builder/comp-builder.nix

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
, dontStrip ? component.dontStrip
2525

2626
, enableStatic ? component.enableStatic
27-
, enableShared ? component.enableShared && !stdenv.hostPlatform.isWindows && !stdenv.hostPlatform.useiOSPrebuilt
27+
, enableShared ? component.enableShared && !haskellLib.isCrossHost
2828
, enableDeadCodeElimination ? component.enableDeadCodeElimination
2929

3030
# Options for Haddock generation
@@ -95,11 +95,20 @@ let
9595
(enableFeature enableExecutableProfiling "executable-profiling")
9696
(enableFeature enableStatic "static")
9797
(enableFeature enableShared "shared")
98+
] ++ lib.optionals (stdenv.hostPlatform.isMusl && (haskellLib.isExecutableType componentId)) [
99+
# These flags will make sure the resulting executable is statically linked.
100+
# If it uses other libraries it may be necessary for to add more
101+
# `--ghc-option=-optl=-L` options to the `configurationFlags` of the
102+
# component.
103+
"--disable-executable-dynamic"
104+
"--ghc-option=-optl=-pthread"
105+
"--ghc-option=-optl=-static"
106+
"--ghc-option=-optl=-L${gmp.override { withStatic = true; }}/lib"
98107
] ++ lib.optional enableSeparateDataOutput "--datadir=$data/share/${ghc.name}"
99108
++ lib.optional doHaddock' "--docdir=${docdir "$doc"}"
100109
++ lib.optional (enableLibraryProfiling || enableExecutableProfiling) "--profiling-detail=${profilingDetail}"
101110
++ lib.optional stdenv.hostPlatform.isLinux (enableFeature enableDeadCodeElimination "split-sections")
102-
++ lib.optionals (stdenv.hostPlatform != stdenv.buildPlatform) (
111+
++ lib.optionals haskellLib.isCrossHost (
103112
map (arg: "--hsc2hs-option=" + arg) (["--cross-compile"] ++ lib.optionals (stdenv.hostPlatform.isWindows) ["--via-asm"])
104113
++ lib.optional (package.buildType == "Configure") "--configure-option=--host=${stdenv.hostPlatform.config}" )
105114
++ component.configureFlags
@@ -131,7 +140,7 @@ let
131140

132141
doHaddock' = doHaddock
133142
&& (haskellLib.isLibrary componentId)
134-
&& stdenv.hostPlatform == stdenv.buildPlatform;
143+
&& !haskellLib.isCrossHost;
135144

136145
exeExt = lib.optionalString stdenv.hostPlatform.isWindows ".exe";
137146
exeName = componentId.cname + exeExt;

builder/default.nix

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,14 @@ let
3939

4040

4141
hoogleLocal = let
42-
nixpkgsHoogleLocal = import (pkgs.path + /pkgs/development/haskell-modules/hoogle.nix);
43-
in { packages ? [], hoogle ? pkgs.haskell-nix.haskellPackages.hoogle.components.exes.hoogle }:
42+
# Use the latest default nixpkgs hoogle.nix, as the 19.03 one does not work with cross compilers
43+
nixpkgsHoogleLocal = import ((import ../nixpkgs {}).path + /pkgs/development/haskell-modules/hoogle.nix);
44+
in { packages ? [], hoogle ? pkgs.buildPackages.haskell-nix.haskellPackages.hoogle.components.exes.hoogle }:
4445
haskellLib.weakCallPackage pkgs nixpkgsHoogleLocal {
45-
ghc = pkgs.haskell-nix.ghc;
46+
# For musl we can use haddock from the buildGHC
47+
ghc = if stdenv.hostPlatform.isLinux && stdenv.targetPlatform.isMusl
48+
then ghc.buildGHC
49+
else ghc;
4650
inherit packages hoogle;
4751
};
4852

builder/ghc-for-component-wrapper.nix

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,19 @@
1515
}:
1616

1717
let
18-
inherit (configFiles) ghcCommand ghcCommandCaps packageCfgDir;
18+
inherit (configFiles) targetPrefix ghcCommand ghcCommandCaps packageCfgDir;
1919
libDir = "$out/${configFiles.libDir}";
2020
docDir = "$out/share/doc/ghc/html";
21+
# For musl we can use haddock from the buildGHC
22+
haddock = if stdenv.hostPlatform.isLinux && stdenv.targetPlatform.isMusl
23+
then ghc.buildGHC
24+
else ghc;
2125

2226
in runCommand "${componentName}-${ghc.name}-env" {
2327
preferLocalBuild = true;
2428
passthru = {
2529
inherit (ghc) version meta;
30+
inherit targetPrefix;
2631
baseGhc = ghc;
2732
};
2833
} (
@@ -62,7 +67,7 @@ in runCommand "${componentName}-${ghc.name}-env" {
6267
fi
6368
done
6469
65-
for prg in runghc runhaskell; do
70+
for prg in "${targetPrefix}runghc" "${targetPrefix}runhaskell"; do
6671
if [[ -x "${ghc}/bin/$prg" ]]; then
6772
rm -f $out/bin/$prg
6873
makeWrapper ${ghc}/bin/$prg $out/bin/$prg \
@@ -75,9 +80,9 @@ in runCommand "${componentName}-${ghc.name}-env" {
7580
done
7681
7782
# Wrap haddock, if the base GHC provides it.
78-
if [[ -x "${ghc}/bin/haddock" ]]; then
83+
if [[ -x "${haddock}/bin/haddock" ]]; then
7984
rm -f $out/bin/haddock
80-
makeWrapper ${ghc}/bin/haddock $out/bin/haddock \
85+
makeWrapper ${haddock}/bin/haddock $out/bin/haddock \
8186
--add-flags '"-B$NIX_${ghcCommandCaps}_LIBDIR"' \
8287
--set "NIX_${ghcCommandCaps}_LIBDIR" "${libDir}"
8388
fi

builder/make-config-files.nix

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,8 @@ let
6666
in { identifier, component, fullName, flags ? {} }:
6767
# Filters out only library packages that for this GHC target
6868
# TODO investigate why this is needed
69-
let libDeps = lib.filter (p: p.configFiles.targetPrefix == ghc.targetPrefix)
69+
# TODO find out why p ? configFiles helps (for instance for `R1909.aarch64-unknown-linux-gnu.tests.cabal-22.run.x86_64-linux`)
70+
let libDeps = lib.filter (p: (p ? configFiles) && p.configFiles.targetPrefix == ghc.targetPrefix)
7071
(map getLibComponent component.depends);
7172
cfgFiles =
7273
let xs = map

builder/shell-for.nix

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
, ... } @ args:
1313

1414
let
15+
# TODO find out why hoogle index creation can be made to work for cross compilers
16+
withHoogle' = withHoogle && !haskellLib.isCrossHost;
1517
selected = packages hsPkgs;
1618
additionalSelected = additional hsPkgs;
1719
selectedConfigs = map (p: p.components.all.config) selected;
@@ -53,7 +55,7 @@ let
5355
ghcEnv = ghcForComponent {
5456
inherit configFiles;
5557
componentName = name;
56-
postInstall = lib.optionalString withHoogle ''
58+
postInstall = lib.optionalString withHoogle' ''
5759
ln -s ${hoogleIndex}/bin/hoogle $out/bin
5860
'';
5961
};
@@ -79,7 +81,7 @@ in
7981

8082
buildInputs = systemInputs
8183
++ mkDrvArgs.buildInputs or []
82-
++ lib.optional withHoogle hoogleIndex;
84+
++ lib.optional withHoogle' hoogleIndex;
8385
nativeBuildInputs = [ ghcEnv ]
8486
++ nativeBuildInputs
8587
++ mkDrvArgs.nativeBuildInputs or [];

compiler/ghc/default.nix

Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# haskell.nix ships its own version of the ghc expression as it needs more
44
# control over the expression to isolate it against varying <nixpkgs> and
55
# allow us to customize it to the way haskell.nix works.
6-
{ stdenv, targetPackages
6+
{ stdenv, haskell-nix, targetPackages
77

88
# build-tools
99
, bootPkgs
@@ -33,15 +33,24 @@
3333

3434
, # Whether to build dynamic libs for the standard library (on the target
3535
# platform). Static libs are always built.
36-
enableShared ? !stdenv.targetPlatform.isWindows && !stdenv.targetPlatform.useiOSPrebuilt
36+
enableShared ? !haskell-nix.haskellLib.isCrossTarget
3737

38-
, # Whetherto build terminfo.
39-
enableTerminfo ? !stdenv.targetPlatform.isWindows
38+
, # Whetherto build terminfo. Musl fails to build terminfo as ncurses seems to be linked to glibc
39+
enableTerminfo ? !stdenv.targetPlatform.isWindows && !stdenv.targetPlatform.isMusl
4040

4141
, # What flavour to build. An empty string indicates no
4242
# specific flavour and falls back to ghc default values.
43-
ghcFlavour ? stdenv.lib.optionalString (stdenv.targetPlatform != stdenv.hostPlatform)
44-
(if useLLVM then "quick-cross" else "perf-cross-ncg")
43+
ghcFlavour ? stdenv.lib.optionalString haskell-nix.haskellLib.isCrossTarget (
44+
if useLLVM
45+
then (
46+
# TODO check if the issues with qemu and Aarch32 persist. See
47+
# https://github.com/input-output-hk/haskell.nix/pull/411/commits/1986264683067198e7fdc1d665351622b664712e
48+
if stdenv.targetPlatform.isAarch32
49+
then "quick-cross"
50+
else "perf-cross"
51+
)
52+
else "perf-cross-ncg"
53+
)
4554

4655
, # Whether to disable the large address space allocator
4756
# necessary fix for iOS: https://www.reddit.com/r/haskell/comments/4ttdz1/building_an_osxi386_to_iosarm64_cross_compiler/d5qvd67/
@@ -59,9 +68,15 @@ assert !enableIntegerSimple -> gmp != null;
5968

6069
let
6170
inherit (stdenv) buildPlatform hostPlatform targetPlatform;
71+
inherit (haskell-nix.haskellLib) isCrossTarget;
6272

6373
inherit (bootPkgs) ghc;
6474

75+
# TODO check if this posible fix for segfaults works or not.
76+
libffiStaticEnabled = if libffi == null || !stdenv.targetPlatform.isMusl
77+
then libffi
78+
else targetPackages.libffi.overrideAttrs (old: { dontDisableStatic = true; });
79+
6580
# TODO(@Ericson2314) Make unconditional
6681
targetPrefix = stdenv.lib.optionalString
6782
(targetPlatform != hostPlatform)
@@ -75,8 +90,9 @@ let
7590
DYNAMIC_GHC_PROGRAMS = ${if enableShared then "YES" else "NO"}
7691
INTEGER_LIBRARY = ${if enableIntegerSimple then "integer-simple" else "integer-gmp"}
7792
'' + stdenv.lib.optionalString (targetPlatform != hostPlatform) ''
78-
Stage1Only = ${if targetPlatform.system == hostPlatform.system then "NO" else "YES"}
7993
CrossCompilePrefix = ${targetPrefix}
94+
'' + stdenv.lib.optionalString isCrossTarget ''
95+
Stage1Only = ${if targetPlatform.system == hostPlatform.system then "NO" else "YES"}
8096
HADDOCK_DOCS = NO
8197
BUILD_SPHINX_HTML = NO
8298
BUILD_SPHINX_PDF = NO
@@ -88,11 +104,19 @@ let
88104
'' + stdenv.lib.optionalString useLLVM ''
89105
GhcStage2HcOpts += -fast-llvm
90106
GhcLibHcOpts += -fast-llvm
107+
'' + stdenv.lib.optionalString (!enableTerminfo) ''
108+
WITH_TERMINFO=NO
109+
''
110+
# While split sections are now enabled by default in ghc 8.8 for windows,
111+
# the seem to lead to `too many sections` errors when building base for
112+
# profiling.
113+
+ stdenv.lib.optionalString targetPlatform.isWindows ''
114+
SplitSections = NO
91115
'';
92116

93117
# Splicer will pull out correct variations
94118
libDeps = platform: stdenv.lib.optional enableTerminfo [ ncurses ]
95-
++ [libffi]
119+
++ [libffiStaticEnabled]
96120
++ stdenv.lib.optional (!enableIntegerSimple) gmp
97121
++ stdenv.lib.optional (platform.libc != "glibc" && !targetPlatform.isWindows) libiconv;
98122

@@ -184,7 +208,7 @@ in let configured-src = stdenv.mkDerivation (rec {
184208
configureFlags = [
185209
"--datadir=$doc/share/doc/ghc"
186210
"--with-curses-includes=${ncurses.dev}/include" "--with-curses-libraries=${ncurses.out}/lib"
187-
] ++ stdenv.lib.optionals (libffi != null) ["--with-system-libffi" "--with-ffi-includes=${targetPackages.libffi.dev}/include" "--with-ffi-libraries=${targetPackages.libffi.out}/lib"
211+
] ++ stdenv.lib.optionals (libffiStaticEnabled != null) ["--with-system-libffi" "--with-ffi-includes=${libffiStaticEnabled.dev}/include" "--with-ffi-libraries=${libffiStaticEnabled.out}/lib"
188212
] ++ stdenv.lib.optional (!enableIntegerSimple) [
189213
"--with-gmp-includes=${targetPackages.gmp.dev}/include" "--with-gmp-libraries=${targetPackages.gmp.out}/lib"
190214
] ++ stdenv.lib.optional (targetPlatform == hostPlatform && hostPlatform.libc != "glibc" && !targetPlatform.isWindows) [
@@ -298,7 +322,12 @@ in let configured-src = stdenv.mkDerivation (rec {
298322
for i in "$out/bin/"*; do
299323
test ! -h $i || continue
300324
egrep --quiet '^#!' <(head -n 1 $i) || continue
301-
sed -i -e '2i export PATH="$PATH:${stdenv.lib.makeBinPath [ targetPackages.stdenv.cc.bintools coreutils ]}"' $i
325+
# The ghcprog fixup is for musl (where runhaskell script just needs to point to the correct
326+
# ghc program to work).
327+
sed -i \
328+
-e '2i export PATH="$PATH:${stdenv.lib.makeBinPath [ targetPackages.stdenv.cc.bintools coreutils ]}"' \
329+
-e 's/ghcprog="ghc-/ghcprog="${targetPrefix}ghc-/' \
330+
$i
302331
done
303332
'' + installDeps targetPrefix;
304333

lib/default.nix

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,4 +177,15 @@ with haskellLib;
177177
check = import ./check.nix {
178178
inherit stdenv lib haskellLib srcOnly;
179179
};
180+
181+
# Use `isCrossHost` to identify when we are cross compiling and
182+
# the code we are producing will not run on the build system
183+
# without an emulator.
184+
# In most cases we do not want to treat musl as a cross compiler.
185+
# For instance when building ghc we want to include ghci.
186+
isCrossHost = stdenv.hostPlatform != stdenv.buildPlatform
187+
&& !(stdenv.buildPlatform.isLinux && stdenv.hostPlatform.isMusl);
188+
# This is the same as isCrossHost but for use when building ghc itself
189+
isCrossTarget = stdenv.targetPlatform != stdenv.hostPlatform
190+
&& !(stdenv.hostPlatform.isLinux && stdenv.targetPlatform.isMusl);
180191
}

nixpkgs/github.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"url": "https://github.com/input-output-hk/nixpkgs",
3-
"rev": "31aa5316ca232a53667790a99e8b1e76252e065c",
4-
"date": "2019-11-16T23:51:02+13:00",
5-
"sha256": "0g0r473rdrh5vsdvr45nmfs6ibp0pqyzbw9f0iv6r0jkg6jjiykr",
3+
"rev": "8215f2ee01c56a764416f703c66767404a321d92",
4+
"date": "2020-01-25T20:38:55+13:00",
5+
"sha256": "0cdmpwpi19354hqvph7mnxrdbphina1vg61fk487i9559bsv545m",
66
"fetchSubmodules": false
77
}

overlays/armv6l-linux.nix

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,10 @@ self: super:
1515
inherit (pkgs) gmp;
1616
# iserv-proxy needs to come from the buildPackages, as it needs to run on the
1717
# build host.
18-
inherit (config.hsPkgs.buildPackages.iserv-proxy.components.exes) iserv-proxy;
18+
inherit (self.buildPackages.ghc-extra-packages."${config.compiler.nix-name}".iserv-proxy.components.exes) iserv-proxy;
1919
# remote-iserv however needs to come from the regular packages as it has to
2020
# run on the target host.
21-
inherit (config.hsPkgs.remote-iserv.components.exes) remote-iserv;
21+
inherit (self.ghc-extra-packages."${config.compiler.nix-name}".remote-iserv.components.exes) remote-iserv;
2222
# we need to use openssl.bin here, because the .dll's are in the .bin expression.
2323
extra-test-libs = [
2424
# pkgs.rocksdb

overlays/bootstrap.nix

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,22 @@ in {
247247

248248
ghc-patches = ghc-patches "8.8.2";
249249
};
250+
ghc883 = self.callPackage ../compiler/ghc {
251+
extra-passthru = { buildGHC = self.buildPackages.haskell-nix.compiler.ghc883; };
252+
253+
inherit bootPkgs sphinx installDeps;
254+
255+
buildLlvmPackages = self.buildPackages.llvmPackages_7;
256+
llvmPackages = self.llvmPackages_7;
257+
258+
src-spec = rec {
259+
version = "8.8.3";
260+
url = "https://downloads.haskell.org/~ghc/${version}/ghc-${version}-src.tar.xz";
261+
sha256 = "128g932i3wix6ic03v04nh5755vyjiidzri9iybwad72yfmc1p70";
262+
};
263+
264+
ghc-patches = ghc-patches "8.8.3";
265+
};
250266
} // self.lib.optionalAttrs (self.targetPlatform.isGhcjs or false)
251267
# This will inject `exactDeps` and `envDeps` into the ghcjs
252268
# compiler defined below. This is crucial to build packages

0 commit comments

Comments
 (0)