on e94de40 help sign in
haskell.nix/compiler/ghc/default.nix
330 lines 13 kB history raw
1# This is the nix expression to build ghc. The Glasgow Haskell Compiler. It is
2# heavily inspired (and based) upon the ghc expression from nixos/nixpkgs.
3# haskell.nix ships its own version of the ghc expression as it needs more
4# control over the expression to isolate it against varying <nixpkgs> and
5# allow us to customize it to the way haskell.nix works.
6{ stdenv, haskell-nix, targetPackages
8# build-tools
9, bootPkgs
10, autoconf, automake, coreutils, fetchurl, fetchpatch, perl, python3, m4, sphinx, numactl
11, autoreconfHook
12, bash
14, libiconv ? null, ncurses
16, installDeps
18, # GHC can be built with system libffi or a bundled one.
19 libffi ? null
21, useLLVM ? !stdenv.targetPlatform.isx86
22, # LLVM is conceptually a run-time-only dependency, but for
23 # non-x86, we need LLVM to bootstrap later stages, so it becomes a
24 # build-time dependency too.
25 buildLlvmPackages, llvmPackages
27, # If enabled, GHC will be built with the GPL-free but slower integer-simple
28 # library instead of the faster but GPLed integer-gmp library.
29 enableIntegerSimple ? !(stdenv.lib.any (stdenv.lib.meta.platformMatch stdenv.hostPlatform) gmp.meta.platforms), gmp
31, # If enabled, use -fPIC when compiling static libs.
32 enableRelocatedStaticLibs ? stdenv.targetPlatform != stdenv.hostPlatform && !stdenv.targetPlatform.isAarch32
34, # Whether to build dynamic libs for the standard library (on the target
35 # platform). Static libs are always built.
36 enableShared ? !haskell-nix.haskellLib.isCrossTarget
38, enableLibraryProfiling ? true
40, # Whether to build terminfo. Musl fails to build terminfo as ncurses seems to be linked to glibc
41 enableTerminfo ? !stdenv.targetPlatform.isWindows && !stdenv.targetPlatform.isMusl
43, # What flavour to build. An empty string indicates no
44 # specific flavour and falls back to ghc default values.
45 ghcFlavour ? stdenv.lib.optionalString haskell-nix.haskellLib.isCrossTarget (
46 if useLLVM
47 then "perf-cross"
48 else "perf-cross-ncg"
49 )
51, # Whether to disable the large address space allocator
52 # necessary fix for iOS: https://www.reddit.com/r/haskell/comments/4ttdz1/building_an_osxi386_to_iosarm64_cross_compiler/d5qvd67/
53 disableLargeAddressSpace ? stdenv.targetPlatform.isDarwin && stdenv.targetPlatform.isAarch64
55, ghc-version ? src-spec.version
56, src-spec
57, ghc-patches ? []
59# extra values we want to have available as passthru values.
60, extra-passthru ? {}
61}:
63assert !enableIntegerSimple -> gmp != null;
65let
66 inherit (stdenv) buildPlatform hostPlatform targetPlatform;
67 inherit (haskell-nix.haskellLib) isCrossTarget;
69 inherit (bootPkgs) ghc;
71 # TODO check if this possible fix for segfaults works or not.
72 targetLibffi =
73 # on native platforms targetPlatform.{libffi, gmp} do not exist; thus fall back
74 # to the non-targetPlatform version in those cases.
75 let targetLibffi = targetPackages.libffi or libffi; in
76 # we need to set `dontDisableStatic` for musl for libffi to work.
77 if stdenv.targetPlatform.isMusl
78 then targetLibffi.overrideAttrs (old: { dontDisableStatic = true; })
79 else targetLibffi;
81 targetGmp = targetPackages.gmp or gmp;
83 # TODO(@Ericson2314) Make unconditional
84 targetPrefix = stdenv.lib.optionalString
85 (targetPlatform != hostPlatform)
86 "${targetPlatform.config}-";
88 buildMK = ''
89 BuildFlavour = ${ghcFlavour}
90 ifneq \"\$(BuildFlavour)\" \"\"
91 include mk/flavours/\$(BuildFlavour).mk
92 endif
93 DYNAMIC_GHC_PROGRAMS = ${if enableShared then "YES" else "NO"}
94 INTEGER_LIBRARY = ${if enableIntegerSimple then "integer-simple" else "integer-gmp"}
95 '' + stdenv.lib.optionalString (targetPlatform != hostPlatform) ''
96 CrossCompilePrefix = ${targetPrefix}
97 '' + stdenv.lib.optionalString isCrossTarget ''
98 Stage1Only = ${if targetPlatform.system == hostPlatform.system then "NO" else "YES"}
99 HADDOCK_DOCS = NO
100 BUILD_SPHINX_HTML = NO
101 BUILD_SPHINX_PDF = NO
102 '' + stdenv.lib.optionalString enableRelocatedStaticLibs ''
103 GhcLibHcOpts += -fPIC
104 GhcRtsHcOpts += -fPIC
105 '' + stdenv.lib.optionalString targetPlatform.useAndroidPrebuilt ''
106 EXTRA_CC_OPTS += -std=gnu99
107 '' + stdenv.lib.optionalString (!enableTerminfo) ''
108 WITH_TERMINFO=NO
109 ''
110 # musl doesn't have a system-linker. Only on x86, and on x86 we need it, as
111 # our elf linker for x86_64 is broken.
112 + stdenv.lib.optionalString (targetPlatform.isMusl && !targetPlatform.isx86) ''
113 compiler_CONFIGURE_OPTS += --flags=-dynamic-system-linker
114 ''
115 # While split sections are now enabled by default in ghc 8.8 for windows,
116 # the seem to lead to `too many sections` errors when building base for
117 # profiling.
118 + stdenv.lib.optionalString targetPlatform.isWindows ''
119 SplitSections = NO
120 '' + stdenv.lib.optionalString (!enableLibraryProfiling) ''
121 BUILD_PROF_LIBS = NO
122 '';
124 # Splicer will pull out correct variations
125 libDeps = platform: stdenv.lib.optional enableTerminfo [ ncurses ]
126 ++ [targetLibffi]
127 ++ stdenv.lib.optional (!enableIntegerSimple) gmp
128 ++ stdenv.lib.optional (platform.libc != "glibc" && !targetPlatform.isWindows) libiconv
129 ++ stdenv.lib.optional (platform.isLinux && !platform.isAarch32) numactl;
131 toolsForTarget =
132 if hostPlatform == buildPlatform then
133 [ targetPackages.stdenv.cc ] ++ stdenv.lib.optional useLLVM llvmPackages.llvm
134 else assert targetPlatform == hostPlatform; # build != host == target
135 [ stdenv.cc ] ++ stdenv.lib.optional useLLVM buildLlvmPackages.llvm;
137 targetCC = builtins.head toolsForTarget;
139 configured-src = import ./configured-src.nix {
140 inherit stdenv fetchurl
141 ghc-version ghc-patches src-spec
142 targetPrefix
143 targetPlatform hostPlatform
144 targetPackages
145 perl autoconf automake m4 python3 sphinx ghc bootPkgs
146 autoreconfHook toolsForTarget bash
147 libDeps
148 useLLVM llvmPackages
149 targetCC
150 enableIntegerSimple targetGmp
151 ncurses targetLibffi libiconv
152 disableLargeAddressSpace
153 buildMK
154 ;
155 };
156in
157stdenv.mkDerivation (rec {
158 version = ghc-version;
159 name = "${targetPrefix}ghc-${version}";
161 patches = ghc-patches;
163 # for this to properly work (with inheritance of patches, postPatch, ...)
164 # this needs to be a function over the values we want to inherit and then called
165 # accordingly. Most trivial might be to just have args, and mash them into the
166 # attrset.
167 src = configured-src;
169 # configure was run by configured-src already.
170 phases = [ "unpackPhase" "buildPhase"
171 "checkPhase" "installPhase"
172 "fixupPhase"
173 "installCheckPhase"
174 "distPhase"
175 ];
177 # ghc hardcodes the TOP dir during config, this breaks when
178 # splitting the configured src from the build process.
179 postUnpack = ''
180 (cd $sourceRoot
181 TOP=$(cat mk/config.mk|grep ^TOP|awk -F\ '{ print $3 }')
182 PREFIX=$(cat mk/install.mk|grep ^prefix|awk -F\ '{ print $3 }')
184 # these two are required
185 substituteInPlace mk/config.mk --replace "$TOP" "$PWD" \
186 --replace "$PREFIX" "$out"
188 substituteInPlace mk/install.mk --replace "$TOP" "$PWD" \
189 --replace "$PREFIX" "$out"
191 # these two only for convencience.
192 substituteInPlace config.log --replace "$TOP" "$PWD"\
193 --replace "$PREFIX" "$out"
194 substituteInPlace config.status --replace "$TOP" "$PWD"\
195 --replace "$PREFIX" "$out")
198 '';
200 enableParallelBuilding = true;
201 postPatch = "patchShebangs .";
203 outputs = [ "out" "doc" "generated" ];
205 # Make sure we never relax`$PATH` and hooks support for compatibility.
206 strictDeps = true;
208 # Don’t add -liconv to LDFLAGS automatically so that GHC will add it itself.
209 dontAddExtraLibs = true;
211 nativeBuildInputs = [
212 perl autoconf automake m4 python3 sphinx
213 ghc bootPkgs.alex bootPkgs.happy bootPkgs.hscolour
214 ] ++ stdenv.lib.optional (patches != []) autoreconfHook;
216 # For building runtime libs
217 depsBuildTarget = toolsForTarget;
219 buildInputs = [ perl bash ] ++ (libDeps hostPlatform);
221 propagatedBuildInputs = [ targetPackages.stdenv.cc ]
222 ++ stdenv.lib.optional useLLVM llvmPackages.llvm;
224 depsTargetTarget = map stdenv.lib.getDev (libDeps targetPlatform);
225 depsTargetTargetPropagated = map (stdenv.lib.getOutput "out") (libDeps targetPlatform);
227 # required, because otherwise all symbols from HSffi.o are stripped, and
228 # that in turn causes GHCi to abort
229 stripDebugFlags = [ "-S" ] ++ stdenv.lib.optional (!targetPlatform.isDarwin) "--keep-file-symbols";
231 # See #63511 - the only unstripped file is the debug rts which isn't meant to
232 # be stripped.
233 stripDebugList = [ "lib/${name}/bin" ];
235 checkTarget = "test";
237 hardeningDisable = [ "format" ]
238 ++ stdenv.lib.optional stdenv.targetPlatform.isAarch32 "pic"
239 ++ stdenv.lib.optional stdenv.targetPlatform.isMusl "pie";
241 postInstall = ''
242 # Install the bash completion file.
243 install -D -m 444 utils/completion/ghc.bash $out/share/bash-completion/completions/${targetPrefix}ghc
245 # Patch scripts to include "readelf" and "cat" in $PATH.
246 for i in "$out/bin/"*; do
247 test ! -h $i || continue
248 egrep --quiet '^#!' <(head -n 1 $i) || continue
249 # The ghcprog fixup is for musl (where runhaskell script just needs to point to the correct
250 # ghc program to work).
251 sed -i \
252 -e '2i export PATH="$PATH:${stdenv.lib.makeBinPath [ targetPackages.stdenv.cc.bintools coreutils ]}"' \
253 -e 's/ghcprog="ghc-/ghcprog="${targetPrefix}ghc-/' \
254 $i
255 done
257 # Save generated files for needed when building ghcjs
258 mkdir -p $generated/includes/dist-derivedconstants/header
259 cp includes/dist-derivedconstants/header/GHCConstantsHaskellExports.hs \
260 includes/dist-derivedconstants/header/GHCConstantsHaskellType.hs \
261 includes/dist-derivedconstants/header/GHCConstantsHaskellWrappers.hs \
262 $generated/includes/dist-derivedconstants/header
263 if [[ -f includes/ghcplatform.h ]]; then
264 cp includes/ghcplatform.h $generated/includes
265 elif [[ -f includes/dist-install/build/ghcplatform.h ]]; then
266 cp includes/dist-install/build/ghcplatform.h $generated/includes
267 fi
268 mkdir -p $generated/compiler/stage2/build
269 cp compiler/stage2/build/Config.hs $generated/compiler/stage2/build || true
270 mkdir -p $generated/rts/build
271 cp rts/build/config.hs-incl $generated/rts/build || true
273 # Save generated files for needed when building ghc-boot
274 mkdir -p $generated/libraries/ghc-boot/dist-install/build/GHC/Platform
275 if [[ -f libraries/ghc-boot/dist-install/build/GHC/Version.hs ]]; then
276 cp libraries/ghc-boot/dist-install/build/GHC/Version.hs $generated/libraries/ghc-boot/dist-install/build/GHC/Version.hs
277 fi
278 if [[ -f libraries/ghc-boot/dist-install/build/GHC/Platform/Host.hs ]]; then
279 cp libraries/ghc-boot/dist-install/build/GHC/Platform/Host.hs $generated/libraries/ghc-boot/dist-install/build/GHC/Platform/Host.hs
280 fi
282 ${installDeps targetPrefix}
284 # Sanity checks for https://github.com/input-output-hk/haskell.nix/issues/660
285 if ! "$out/bin/${targetPrefix}ghc" --version; then
286 echo "ERROR: Missing file $out/bin/${targetPrefix}ghc"
287 exit 0
288 fi
289 if ! "$out/bin/${targetPrefix}ghc-pkg" --version; then
290 echo "ERROR: Missing file $out/bin/${targetPrefix}ghc-pkg"
291 exit 0
292 fi
293 if [[ ! -d "$out/lib/${targetPrefix}ghc-${version}" ]]; then
294 echo "ERROR: Missing directory $out/lib/${targetPrefix}ghc-${version}"
295 exit 0
296 fi
297 if (( $(ls -1 "$out/lib/${targetPrefix}ghc-${version}" | wc -l) < 30 )); then
298 echo "ERROR: Expected more files in $out/lib/${targetPrefix}ghc-${version}"
299 exit 0
300 fi
301 '';
303 passthru = {
304 inherit bootPkgs targetPrefix;
306 inherit llvmPackages;
307 inherit enableShared;
308 inherit useLLVM;
310 # Our Cabal compiler name
311 haskellCompilerName = "ghc-${version}";
313 configured-src = configured-src;
315 # Used to detect non haskell-nix compilers (accidental use of nixpkgs compilers can lead to unexpected errors)
316 isHaskellNixCompiler = true;
317 } // extra-passthru;
319 meta = {
320 homepage = http://haskell.org/ghc;
321 description = "The Glasgow Haskell Compiler";
322 maintainers = [];
323 inherit (ghc.meta) license platforms;
324 };
326} // stdenv.lib.optionalAttrs targetPlatform.useAndroidPrebuilt {
327 dontStrip = true;
328 dontPatchELF = true;
329 noAuditTmpdir = true;
330})