@@ -0,0 +1,389 @@
# DO NOT port this expression to hadrian. It is not possible to build a GHC
# cross compiler with 9.4.* and hadrian.
{ lib , stdenv , pkgsBuildTarget , pkgsHostTarget , targetPackages
# build-tools
, bootPkgs
, autoconf , automake , coreutils , fetchpatch , fetchurl , perl , python3 , m4 , sphinx
, xattr , autoSignDarwinBinariesHook
, bash
, libiconv ? null , ncurses
, glibcLocales ? null
, # GHC can be built with system libffi or a bundled one.
libffi ? null
, useLLVM ? ! ( stdenv . targetPlatform . isx86
|| stdenv . targetPlatform . isPower
|| stdenv . targetPlatform . isSparc
|| ( stdenv . targetPlatform . isAarch64 && stdenv . targetPlatform . isDarwin ) )
, # LLVM is conceptually a run-time-only depedendency, but for
# non-x86, we need LLVM to bootstrap later stages, so it becomes a
# build-time dependency too.
buildTargetLlvmPackages , llvmPackages
, # If enabled, GHC will be built with the GPL-free but slightly slower native
# bignum backend instead of the faster but GPLed gmp backend.
enableNativeBignum ? ! ( lib . meta . availableOn stdenv . hostPlatform gmp
&& lib . meta . availableOn stdenv . targetPlatform gmp )
, gmp
, # If enabled, use -fPIC when compiling static libs.
enableRelocatedStaticLibs ? stdenv . targetPlatform != stdenv . hostPlatform
# aarch64 outputs otherwise exceed 2GB limit
, enableProfiledLibs ? ! stdenv . targetPlatform . isAarch64
, # 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
, # What flavour to build. An empty string indicates no
# specific flavour and falls back to ghc default values.
ghcFlavour ? lib . optionalString ( stdenv . targetPlatform != stdenv . hostPlatform )
( if useLLVM then " p e r f - c r o s s " else " p e r f - c r o s s - n c g " )
, # Whether to build sphinx documentation.
enableDocs ? (
# Docs disabled for musl and cross because it's a large task to keep
# all `sphinx` dependencies building in those environments.
# `sphinx` pulls in among others:
# Ruby, Python, Perl, Rust, OpenGL, Xorg, gtk, LLVM.
( stdenv . targetPlatform = = stdenv . hostPlatform )
&& ! stdenv . hostPlatform . isMusl
)
, enableHaddockProgram ?
# Disabled for cross; see note [HADDOCK_DOCS].
( 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
}:
assert ! enableNativeBignum -> gmp != null ;
# Cross cannot currently build the `haddock` program for silly reasons,
# see note [HADDOCK_DOCS].
assert ( stdenv . targetPlatform != stdenv . hostPlatform ) -> ! enableHaddockProgram ;
let
inherit ( stdenv ) buildPlatform hostPlatform targetPlatform ;
inherit ( bootPkgs ) ghc ;
# TODO(@Ericson2314) Make unconditional
targetPrefix = lib . optionalString
( targetPlatform != hostPlatform )
" ${ targetPlatform . config } - " ;
buildMK = ''
B u i l d F l a v o u r = ${ ghcFlavour }
i f n e q \ " \ $( B u i l d F l a v o u r ) \ " \ " \ "
i n c l u d e m k / f l a v o u r s / \ $( B u i l d F l a v o u r ) . m k
e n d i f
B U I L D _ S P H I N X _ H T M L = ${ if enableDocs then " Y E S " else " N O " }
B U I L D _ S P H I N X _ P D F = N O
'' +
# Note [HADDOCK_DOCS]:
# Unfortunately currently `HADDOCK_DOCS` controls both whether the `haddock`
# program is built (which we generally always want to have a complete GHC install)
# and whether it is run on the GHC sources to generate hyperlinked source code
# (which is impossible for cross-compilation); see:
# https://gitlab.haskell.org/ghc/ghc/-/issues/20077
# This implies that currently a cross-compiled GHC will never have a `haddock`
# program, so it can never generate haddocks for any packages.
# If this is solved in the future, we'd like to unconditionally
# build the haddock program (removing the `enableHaddockProgram` option).
''
H A D D O C K _ D O C S = ${ if enableHaddockProgram then " Y E S " else " N O " }
# B u i l d h a d d o c k s f o r b o o t p a c k a g e s w i t h h y p e r l i n k i n g
E X T R A _ H A D D O C K _ O P T S + = - - h y p e r l i n k e d - s o u r c e - - q u i c k j u m p
D Y N A M I C _ G H C _ P R O G R A M S = ${ if enableShared then " Y E S " else " N O " }
B I G N U M _ B A C K E N D = ${ if enableNativeBignum then " n a t i v e " else " g m p " }
'' + lib . optionalString ( targetPlatform != hostPlatform ) ''
S t a g e 1 O n l y = ${ if targetPlatform . system = = hostPlatform . system then " N O " else " Y E S " }
C r o s s C o m p i l e P r e f i x = ${ targetPrefix }
'' + lib . optionalString ( ! enableProfiledLibs ) ''
G h c L i b W a y s = " v d y n "
'' +
# -fexternal-dynamic-refs apparently (because it's not clear from the documentation)
# makes the GHC RTS able to load static libraries, which may be needed for TemplateHaskell.
# This solution was described in https://www.tweag.io/blog/2020-09-30-bazel-static-haskell
lib . optionalString enableRelocatedStaticLibs ''
G h c L i b H c O p t s + = - f P I C - f e x t e r n a l - d y n a m i c - r e f s
G h c R t s H c O p t s + = - f P I C - f e x t e r n a l - d y n a m i c - r e f s
'' + lib . optionalString targetPlatform . useAndroidPrebuilt ''
E X T R A _ C C _ O P T S + = - s t d = g n u 9 9
'' ;
# Splicer will pull out correct variations
libDeps = platform : lib . optional enableTerminfo ncurses
++ [ libffi ]
++ lib . optional ( ! enableNativeBignum ) gmp
++ lib . optional ( platform . libc != " g l i b c " && ! targetPlatform . isWindows ) libiconv ;
# TODO(@sternenseemann): is buildTarget LLVM unnecessary?
# GHC doesn't seem to have {LLC,OPT}_HOST
toolsForTarget = [
pkgsBuildTarget . targetPackages . stdenv . cc
] ++ lib . optional useLLVM buildTargetLlvmPackages . llvm ;
targetCC = builtins . head toolsForTarget ;
# Sometimes we have to dispatch between the bintools wrapper and the unwrapped
# derivation for certain tools depending on the platform.
bintoolsFor = {
# GHC needs install_name_tool on all darwin platforms. On aarch64-darwin it is
# part of the bintools wrapper (due to codesigning requirements), but not on
# x86_64-darwin.
install_name_tool =
if stdenv . targetPlatform . isAarch64
then targetCC . bintools
else targetCC . bintools . bintools ;
# Same goes for strip.
strip =
# TODO(@sternenseemann): also use wrapper if linker == "bfd" or "gold"
if stdenv . targetPlatform . isAarch64 && stdenv . targetPlatform . isDarwin
then targetCC . bintools
else targetCC . bintools . bintools ;
} ;
# Use gold either following the default, or to avoid the BFD linker due to some bugs / perf issues.
# But we cannot avoid BFD when using musl libc due to https://sourceware.org/bugzilla/show_bug.cgi?id=23856
# see #84670 and #49071 for more background.
useLdGold = targetPlatform . linker = = " g o l d " ||
( targetPlatform . linker = = " b f d " && ( targetCC . bintools . bintools . hasGold or false ) && ! targetPlatform . isMusl ) ;
# Makes debugging easier to see which variant is at play in `nix-store -q --tree`.
variantSuffix = lib . concatStrings [
( lib . optionalString stdenv . hostPlatform . isMusl " - m u s l " )
( lib . optionalString enableNativeBignum " - n a t i v e - b i g n u m " )
] ;
in
# 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 ;
stdenv . mkDerivation ( rec {
version = " 9 . 4 . 5 " ;
pname = " ${ targetPrefix } g h c ${ variantSuffix } " ;
src = fetchurl {
url = " h t t p s : / / d o w n l o a d s . h a s k e l l . o r g / g h c / ${ version } / g h c - ${ version } - s r c . t a r . x z " ;
sha256 = " 6 2 5 6 c f 9 c a f 6 d 6 d c 7 b 6 1 1 d c f b b 2 4 7 d f 2 d 5 2 8 e 8 5 a a 3 9 d 2 2 a 6 9 8 e 8 7 0 e 5 a 5 9 0 e 8 6 0 1 " ;
} ;
enableParallelBuilding = true ;
outputs = [ " o u t " " d o c " ] ;
patches = [
# Don't generate code that doesn't compile when --enable-relocatable is passed to Setup.hs
# Can be removed if the Cabal library included with ghc backports the linked fix
( fetchpatch {
url = " h t t p s : / / g i t h u b . c o m / h a s k e l l / c a b a l / c o m m i t / 6 c 7 9 6 2 1 8 c 9 2 f 9 3 c 9 5 e 9 4 d 5 e c 2 d 0 7 7 f 6 9 5 6 f 6 8 e 9 8 . p a t c h " ;
stripLen = 1 ;
extraPrefix = " l i b r a r i e s / C a b a l / " ;
sha256 = " s h a 2 5 6 - y R Q 6 Y m M i w B w i Y s e C 5 B s r E t D g F b W v s t + m a G g D t d D 0 v A Y = " ;
} )
# Fix docs build with sphinx >= 6.0
# https://gitlab.haskell.org/ghc/ghc/-/issues/22766
( fetchpatch {
name = " g h c - d o c s - s p h i n x - 6 . 0 . p a t c h " ;
url = " h t t p s : / / g i t l a b . h a s k e l l . o r g / g h c / g h c / - / c o m m i t / 1 0 e 9 4 a 5 5 6 b 4 f 9 0 7 6 9 b 7 f d 7 1 8 b 9 7 9 0 d 5 8 a e 5 6 6 6 0 0 . p a t c h " ;
sha256 = " 0 k m h f a m r 1 6 w 8 g c h 0 l g l n 2 9 1 2 r 8 a r y j k y 1 h f c d a 3 j k c w a 5 c d z g j d v " ;
} )
] ;
postPatch = " p a t c h S h e b a n g s . " ;
# GHC needs the locale configured during the Haddock phase.
LANG = " e n _ U S . U T F - 8 " ;
# GHC is a bit confused on its cross terminology.
# TODO(@sternenseemann): investigate coreutils dependencies and pass absolute paths
preConfigure = ''
f o r e n v i n $( e n v | g r e p ' ^ T A R G E T _ ' | s e d - E ' s | \ + ? = . * | | ' ) ; d o
e x p o r t " ''$ { e n v # T A R G E T _ } = ''$ { ! e n v } "
d o n e
# G H C i s a b i t c o n f u s e d o n i t s c r o s s t e r m i n o l o g y , a s t h e s e w o u l d n o r m a l l y b e
# t h e * h o s t * t o o l s .
e x p o r t C C = " ${ targetCC } / b i n / ${ targetCC . targetPrefix } c c "
e x p o r t C X X = " ${ targetCC } / b i n / ${ targetCC . targetPrefix } c + + "
# U s e g o l d t o w o r k a r o u n d h t t p s : / / s o u r c e w a r e . o r g / b u g z i l l a / s h o w _ b u g . c g i ? i d = 1 6 1 7 7
e x p o r t L D = " ${ targetCC . bintools } / b i n / ${ targetCC . bintools . targetPrefix } l d ${ lib . optionalString useLdGold " . g o l d " } "
e x p o r t A S = " ${ targetCC . bintools . bintools } / b i n / ${ targetCC . bintools . targetPrefix } a s "
e x p o r t A R = " ${ targetCC . bintools . bintools } / b i n / ${ targetCC . bintools . targetPrefix } a r "
e x p o r t N M = " ${ targetCC . bintools . bintools } / b i n / ${ targetCC . bintools . targetPrefix } n m "
e x p o r t R A N L I B = " ${ targetCC . bintools . bintools } / b i n / ${ targetCC . bintools . targetPrefix } r a n l i b "
e x p o r t R E A D E L F = " ${ targetCC . bintools . bintools } / b i n / ${ targetCC . bintools . targetPrefix } r e a d e l f "
e x p o r t S T R I P = " ${ bintoolsFor . strip } / b i n / ${ bintoolsFor . strip . targetPrefix } s t r i p "
'' + lib . optionalString ( stdenv . targetPlatform . linker = = " c c t o o l s " ) ''
e x p o r t O T O O L = " ${ targetCC . bintools . bintools } / b i n / ${ targetCC . bintools . targetPrefix } o t o o l "
e x p o r t I N S T A L L _ N A M E _ T O O L = " ${ bintoolsFor . install_name_tool } / b i n / ${ bintoolsFor . install_name_tool . targetPrefix } i n s t a l l _ n a m e _ t o o l "
'' + lib . optionalString useLLVM ''
e x p o r t L L C = " ${ lib . getBin buildTargetLlvmPackages . llvm } / b i n / l l c "
e x p o r t O P T = " ${ lib . getBin buildTargetLlvmPackages . llvm } / b i n / o p t "
'' + lib . optionalString ( useLLVM && stdenv . targetPlatform . isDarwin ) ''
# L L V M b a c k e n d o n D a r w i n n e e d s c l a n g : h t t p s : / / d o w n l o a d s . h a s k e l l . o r g / ~ g h c / l a t e s t / d o c s / h t m l / u s e r s _ g u i d e / c o d e g e n s . h t m l # l l v m - c o d e - g e n e r a t o r - f l l v m
e x p o r t C L A N G = " ${ buildTargetLlvmPackages . clang } / b i n / ${ buildTargetLlvmPackages . clang . targetPrefix } c l a n g "
'' + ''
e c h o - n " ${ buildMK } " > m k / b u i l d . m k
s e d - i - e ' s | - i s y s r o o t / D e v e l o p e r / S D K s / M a c O S X 1 0 . 5 . s d k | | ' c o n f i g u r e
'' + lib . optionalString ( stdenv . isLinux && hostPlatform . libc = = " g l i b c " ) ''
e x p o r t L O C A L E _ A R C H I V E = " ${ glibcLocales } / l i b / l o c a l e / l o c a l e - a r c h i v e "
'' + lib . optionalString ( ! stdenv . isDarwin ) ''
e x p o r t N I X _ L D F L A G S + = " - r p a t h $o u t / l i b / g h c - ${ version } "
'' + lib . optionalString stdenv . isDarwin ''
e x p o r t N I X _ L D F L A G S + = " - n o _ d t r a c e _ d o f "
# G H C t r i e s t h e h o s t x a t t r / u s r / b i n / x a t t r b y d e f a u l t w h i c h f a i l s s i n c e i t e x p e c t s p y t h o n t o b e 2 . 7
e x p o r t X A T T R = ${ lib . getBin xattr } / b i n / x a t t r
'' + lib . optionalString targetPlatform . useAndroidPrebuilt ''
s e d - i - e ' 5 i , ( " a r m v 7 a - u n k n o w n - l i n u x - a n d r o i d e a b i " , ( " e - m : e - p : 3 2 : 3 2 - i 6 4 : 6 4 - v 1 2 8 : 6 4 : 1 2 8 - a : 0 : 3 2 - n 3 2 - S 6 4 " , " c o r t e x - a 8 " , " " ) ) ' l l v m - t a r g e t s
'' + lib . optionalString targetPlatform . isMusl ''
e c h o " p a t c h i n g l l v m - t a r g e t s f o r m u s l t a r g e t s . . . "
e c h o " C l o n i n g t h e s e e x i s t i n g ' * - l i n u x - g n u * ' t a r g e t s : "
g r e p l i n u x - g n u l l v m - t a r g e t s | s e d ' s / ^ / / '
e c h o " ( g o g o g a d g e t s e d ) "
s e d - i ' s , \ ( ^ . * l i n u x - \ ) g n u \ ( . * \ ) $, \ 0 \ n \ 1 m u s l \ 2 , ' l l v m - t a r g e t s
e c h o " l l v m - t a r g e t s n o w c o n t a i n s t h e s e ' * - l i n u x - m u s l * ' t a r g e t s : "
g r e p l i n u x - m u s l l l v m - t a r g e t s | s e d ' s / ^ / / '
e c h o " A n d n o w p a t c h i n g t o p r e s e r v e ' - m u s l e a b i ' a s d o n e w i t h ' - g n u e a b i ' "
# ( a c l o c a l . m 4 i s a c t u a l s o u r c e , b u t p a t c h c o n f i g u r e a s w e l l s i n c e w e d o n ' t r e - g e n )
f o r x i n c o n f i g u r e a c l o c a l . m 4 ; d o
s u b s t i t u t e I n P l a c e $x \
- - r e p l a c e ' * - a n d r o i d * | * - g n u e a b i * ) ' \
' * - a n d r o i d * | * - g n u e a b i * | * - m u s l e a b i * ) '
d o n e
''
# HACK: allow bootstrapping with GHC 8.10 which works fine, as we don't have
# binary 9.0 packaged. Bootstrapping with 9.2 is broken without hadrian.
+ ''
s u b s t i t u t e I n P l a c e c o n f i g u r e - - r e p l a c e \
' M i n B o o t G h c V e r s i o n = " 9 . 0 " ' \
' M i n B o o t G h c V e r s i o n = " 8 . 1 0 " '
'' ;
# TODO(@Ericson2314): Always pass "--target" and always prefix.
configurePlatforms = [ " b u i l d " " h o s t " ]
++ lib . optional ( targetPlatform != hostPlatform ) " t a r g e t " ;
# `--with` flags for libraries needed for RTS linker
configureFlags = [
" - - d a t a d i r = $ d o c / s h a r e / d o c / g h c "
" - - w i t h - c u r s e s - i n c l u d e s = ${ ncurses . dev } / i n c l u d e " " - - w i t h - c u r s e s - l i b r a r i e s = ${ ncurses . out } / l i b "
] ++ lib . optionals ( libffi != null ) [
" - - w i t h - s y s t e m - l i b f f i "
" - - w i t h - f f i - i n c l u d e s = ${ targetPackages . libffi . dev } / i n c l u d e "
" - - w i t h - f f i - l i b r a r i e s = ${ targetPackages . libffi . out } / l i b "
] ++ lib . optionals ( targetPlatform = = hostPlatform && ! enableNativeBignum ) [
" - - w i t h - g m p - i n c l u d e s = ${ targetPackages . gmp . dev } / i n c l u d e "
" - - w i t h - g m p - l i b r a r i e s = ${ targetPackages . gmp . out } / l i b "
] ++ lib . optionals ( targetPlatform = = hostPlatform && hostPlatform . libc != " g l i b c " && ! targetPlatform . isWindows ) [
" - - w i t h - i c o n v - i n c l u d e s = ${ libiconv } / i n c l u d e "
" - - w i t h - i c o n v - l i b r a r i e s = ${ libiconv } / l i b "
] ++ lib . optionals ( targetPlatform != hostPlatform ) [
" - - e n a b l e - b o o t s t r a p - w i t h - d e v e l - s n a p s h o t "
] ++ lib . optionals useLdGold [
" C F L A G S = - f u s e - l d = g o l d "
" C O N F _ G C C _ L I N K E R _ O P T S _ S T A G E 1 = - f u s e - l d = g o l d "
" C O N F _ G C C _ L I N K E R _ O P T S _ S T A G E 2 = - f u s e - l d = g o l d "
] ++ lib . optionals ( disableLargeAddressSpace ) [
" - - d i s a b l e - l a r g e - a d d r e s s - s p a c e "
] ;
# Make sure we never relax`$PATH` and hooks support for compatibility.
strictDeps = true ;
# Don’ t add -liconv to LDFLAGS automatically so that GHC will add it itself.
dontAddExtraLibs = true ;
nativeBuildInputs = [
perl autoconf automake m4 python3
ghc bootPkgs . alex bootPkgs . happy bootPkgs . hscolour
] ++ lib . optionals ( stdenv . isDarwin && stdenv . isAarch64 ) [
autoSignDarwinBinariesHook
] ++ lib . optionals enableDocs [
sphinx
] ;
# For building runtime libs
depsBuildTarget = toolsForTarget ;
buildInputs = [ perl bash ] ++ ( libDeps hostPlatform ) ;
depsTargetTarget = map lib . getDev ( libDeps targetPlatform ) ;
depsTargetTargetPropagated = map ( lib . getOutput " o u t " ) ( libDeps targetPlatform ) ;
# required, because otherwise all symbols from HSffi.o are stripped, and
# that in turn causes GHCi to abort
stripDebugFlags = [ " - S " ] ++ lib . optional ( ! targetPlatform . isDarwin ) " - - k e e p - f i l e - s y m b o l s " ;
checkTarget = " t e s t " ;
hardeningDisable =
[ " f o r m a t " ]
# In nixpkgs, musl based builds currently enable `pie` hardening by default
# (see `defaultHardeningFlags` in `make-derivation.nix`).
# But GHC cannot currently produce outputs that are ready for `-pie` linking.
# Thus, disable `pie` hardening, otherwise `recompile with -fPIE` errors appear.
# See:
# * https://github.com/NixOS/nixpkgs/issues/129247
# * https://gitlab.haskell.org/ghc/ghc/-/issues/19580
++ lib . optional stdenv . targetPlatform . isMusl " p i e " ;
# big-parallel allows us to build with more than 2 cores on
# Hydra which already warrants a significant speedup
requiredSystemFeatures = [ " b i g - p a r a l l e l " ] ;
postInstall = ''
# I n s t a l l t h e b a s h c o m p l e t i o n f i l e .
i n s t a l l - D - m 4 4 4 u t i l s / c o m p l e t i o n / g h c . b a s h $o u t / s h a r e / b a s h - c o m p l e t i o n / c o m p l e t i o n s / ${ targetPrefix } g h c
'' ;
passthru = {
inherit bootPkgs targetPrefix ;
inherit llvmPackages ;
inherit enableShared ;
# This is used by the haskell builder to query
# the presence of the haddock program.
hasHaddock = enableHaddockProgram ;
# Our Cabal compiler name
haskellCompilerName = " g h c - ${ version } " ;
} ;
meta = {
homepage = " h t t p : / / h a s k e l l . o r g / g h c " ;
description = " T h e G l a s g o w H a s k e l l C o m p i l e r " ;
maintainers = with lib . maintainers ; [
guibou
] ++ lib . teams . haskell . members ;
timeout = 24 * 3600 ;
inherit ( ghc . meta ) license platforms ;
} ;
} // lib . optionalAttrs targetPlatform . useAndroidPrebuilt {
dontStrip = true ;
dontPatchELF = true ;
noAuditTmpdir = true ;
} )