1{
2 lib,
3 stdenv,
4 fetchurl,
5 perl,
6 gcc,
7 ncurses5,
8 ncurses6,
9 gmp,
10 glibc,
11 libiconv,
12 llvmPackages,
13 coreutils,
14 targetPackages,
15}:
16
17# Prebuilt only does native
18assert stdenv.targetPlatform == stdenv.hostPlatform;
19
20let
21 useLLVM =
22 !(stdenv.targetPlatform.isx86 || stdenv.targetPlatform.isPower || stdenv.targetPlatform.isSparc);
23
24 useNcurses6 =
25 stdenv.hostPlatform.system == "x86_64-linux"
26 || (with stdenv.hostPlatform; isPower64 && isLittleEndian);
27
28 ourNcurses = if useNcurses6 then ncurses6 else ncurses5;
29
30 libPath = lib.makeLibraryPath (
31 [
32 ourNcurses
33 gmp
34 ]
35 ++ lib.optional (stdenv.hostPlatform.isDarwin) libiconv
36 );
37
38 libEnvVar = lib.optionalString stdenv.hostPlatform.isDarwin "DY" + "LD_LIBRARY_PATH";
39
40 glibcDynLinker =
41 assert stdenv.hostPlatform.isLinux;
42 if stdenv.hostPlatform.libc == "glibc" then
43 # Could be stdenv.cc.bintools.dynamicLinker, keeping as-is to avoid rebuild.
44 ''"$(cat $NIX_CC/nix-support/dynamic-linker)"''
45 else
46 "${lib.getLib glibc}/lib/ld-linux*";
47
48 downloadsUrl = "https://downloads.haskell.org/ghc";
49
50 runtimeDeps = [
51 targetPackages.stdenv.cc
52 targetPackages.stdenv.cc.bintools
53 coreutils # for cat
54 ]
55 ++
56 lib.optionals
57 (
58 assert useLLVM -> !(llvmPackages == null);
59 useLLVM
60 )
61 [
62 (lib.getBin llvmPackages.llvm)
63 ]
64 # On darwin, we need unwrapped bintools as well (for otool)
65 ++ lib.optionals (stdenv.targetPlatform.linker == "cctools") [
66 targetPackages.stdenv.cc.bintools.bintools
67 ];
68
69in
70
71stdenv.mkDerivation rec {
72 version = "8.6.5";
73 pname = "ghc-binary";
74
75 # https://downloads.haskell.org/~ghc/8.6.5/
76 src = fetchurl (
77 {
78 i686-linux = {
79 # Don't use the Fedora27 build (as below) because there isn't one!
80 url = "${downloadsUrl}/${version}/ghc-${version}-i386-deb9-linux.tar.xz";
81 sha256 = "1p2h29qghql19ajk755xa0yxkn85slbds8m9n5196ris743vkp8w";
82 };
83 x86_64-linux = {
84 # This is the Fedora build because it links against ncurses6 where the
85 # deb9 one links against ncurses5, see here
86 # https://github.com/NixOS/nixpkgs/issues/85924 for a discussion
87 url = "${downloadsUrl}/${version}/ghc-${version}-x86_64-fedora27-linux.tar.xz";
88 sha256 = "18dlqm5d028fqh6ghzn7pgjspr5smw030jjzl3kq6q1kmwzbay6g";
89 };
90 x86_64-darwin = {
91 url = "${downloadsUrl}/${version}/ghc-${version}-x86_64-apple-darwin.tar.xz";
92 sha256 = "0s9188vhhgf23q3rjarwhbr524z6h2qga5xaaa2pma03sfqvvhfz";
93 };
94 powerpc64le-linux = {
95 url = "https://downloads.haskell.org/~ghc/${version}/ghc-${version}-powerpc64le-fedora29-linux.tar.xz";
96 sha256 = "sha256-tWSsJdPVrCiqDyIKzpBt5DaXb3b6j951tCya584kWs4=";
97 };
98 }
99 .${stdenv.hostPlatform.system} or (throw "cannot bootstrap GHC on this platform")
100 );
101
102 nativeBuildInputs = [ perl ];
103
104 # Cannot patchelf beforehand due to relative RPATHs that anticipate
105 # the final install location/
106 ${libEnvVar} = libPath;
107
108 postUnpack =
109 # GHC has dtrace probes, which causes ld to try to open /usr/lib/libdtrace.dylib
110 # during linking
111 lib.optionalString stdenv.hostPlatform.isDarwin ''
112 export NIX_LDFLAGS+=" -no_dtrace_dof"
113 # not enough room in the object files for the full path to libiconv :(
114 for exe in $(find . -type f -executable); do
115 isScript $exe && continue
116 ln -fs ${libiconv}/lib/libiconv.dylib $(dirname $exe)/libiconv.dylib
117 install_name_tool -change /usr/lib/libiconv.2.dylib @executable_path/libiconv.dylib -change /usr/local/lib/gcc/6/libgcc_s.1.dylib ${gcc.cc.lib}/lib/libgcc_s.1.dylib $exe
118 done
119 ''
120 +
121
122 # Some scripts used during the build need to have their shebangs patched
123 ''
124 patchShebangs ghc-${version}/utils/
125 patchShebangs ghc-${version}/configure
126 test -d ghc-${version}/inplace/bin && \
127 patchShebangs ghc-${version}/inplace/bin
128 ''
129 +
130
131 # We have to patch the GMP paths for the integer-gmp package.
132 ''
133 find . -name integer-gmp.buildinfo \
134 -exec sed -i "s@extra-lib-dirs: @extra-lib-dirs: ${gmp.out}/lib@" {} \;
135 ''
136 + lib.optionalString stdenv.hostPlatform.isDarwin ''
137 find . -name base.buildinfo \
138 -exec sed -i "s@extra-lib-dirs: @extra-lib-dirs: ${libiconv}/lib@" {} \;
139 ''
140 +
141 # Rename needed libraries and binaries, fix interpreter
142 lib.optionalString stdenv.hostPlatform.isLinux ''
143 find . -type f -perm -0100 \
144 -exec patchelf \
145 --replace-needed libncurses${lib.optionalString stdenv.hostPlatform.is64bit "w"}.so.5 libncurses.so \
146 ${
147 # This isn't required for x86_64-linux where we use ncurses6
148 lib.optionalString (!useNcurses6) "--replace-needed libtinfo.so libtinfo.so.5"
149 } \
150 --interpreter ${glibcDynLinker} {} \;
151
152 sed -i "s|/usr/bin/perl|perl\x00 |" ghc-${version}/ghc/stage2/build/tmp/ghc-stage2
153 sed -i "s|/usr/bin/gcc|gcc\x00 |" ghc-${version}/ghc/stage2/build/tmp/ghc-stage2
154 ''
155 +
156 # We're kludging a glibc bindist into working with non-glibc...
157 # Here we patch up the use of `__strdup` (part of glibc binary ABI)
158 # to instead use `strdup` since musl doesn't provide __strdup
159 # (`__strdup` is defined to be an alias of `strdup` anyway[1]).
160 # [1] http://refspecs.linuxbase.org/LSB_4.0.0/LSB-Core-generic/LSB-Core-generic/baselib---strdup-1.html
161 # Use objcopy magic to make the change:
162 lib.optionalString stdenv.hostPlatform.isMusl ''
163 find ./ghc-${version}/rts -name "libHSrts*.a" -exec ''${OBJCOPY:-objcopy} --redefine-sym __strdup=strdup {} \;
164 '';
165
166 configurePlatforms = [ ];
167 configureFlags = [
168 "--with-gmp-includes=${lib.getDev gmp}/include"
169 # Note `--with-gmp-libraries` does nothing for GHC bindists:
170 # https://gitlab.haskell.org/ghc/ghc/-/merge_requests/6124
171 ]
172 ++ lib.optional stdenv.hostPlatform.isDarwin "--with-gcc=${./gcc-clang-wrapper.sh}"
173 ++ lib.optional stdenv.hostPlatform.isMusl "--disable-ld-override";
174
175 # No building is necessary, but calling make without flags ironically
176 # calls install-strip ...
177 dontBuild = true;
178
179 # GHC tries to remove xattrs when installing to work around Gatekeeper
180 # (see https://gitlab.haskell.org/ghc/ghc/-/issues/17418). This step normally
181 # succeeds in nixpkgs because xattrs are not allowed in the store, but it
182 # can fail when a file has the `com.apple.provenance` xattr, and it can’t be
183 # modified (such as target of the symlink to `libiconv.dylib`).
184 # The `com.apple.provenance` xattr is a new feature of macOS as of macOS 13.
185 # See: https://eclecticlight.co/2023/03/13/ventura-has-changed-app-quarantine-with-a-new-xattr/
186 makeFlags = lib.optionals stdenv.buildPlatform.isDarwin [ "XATTR=/does-not-exist" ];
187
188 # Patch scripts to include runtime dependencies in $PATH.
189 postInstall = ''
190 for i in "$out/bin/"*; do
191 test ! -h "$i" || continue
192 isScript "$i" || continue
193 sed -i -e '2i export PATH="${lib.makeBinPath runtimeDeps}:$PATH"' "$i"
194 done
195 '';
196
197 # On Linux, use patchelf to modify the executables so that they can
198 # find editline/gmp.
199 postFixup =
200 lib.optionalString stdenv.hostPlatform.isLinux ''
201 for p in $(find "$out" -type f -executable); do
202 if isELF "$p"; then
203 echo "Patchelfing $p"
204 patchelf --set-rpath "${libPath}:$(patchelf --print-rpath $p)" $p
205 fi
206 done
207 ''
208 + lib.optionalString stdenv.hostPlatform.isDarwin ''
209 # not enough room in the object files for the full path to libiconv :(
210 for exe in $(find "$out" -type f -executable); do
211 isScript $exe && continue
212 ln -fs ${libiconv}/lib/libiconv.dylib $(dirname $exe)/libiconv.dylib
213 install_name_tool -change /usr/lib/libiconv.2.dylib @executable_path/libiconv.dylib -change /usr/local/lib/gcc/6/libgcc_s.1.dylib ${gcc.cc.lib}/lib/libgcc_s.1.dylib $exe
214 done
215
216 for file in $(find "$out" -name setup-config); do
217 substituteInPlace $file --replace /usr/bin/ranlib "$(type -P ranlib)"
218 done
219 '';
220
221 # GHC cannot currently produce outputs that are ready for `-pie` linking.
222 # Thus, disable `pie` hardening, otherwise `recompile with -fPIE` errors appear.
223 # See:
224 # * https://github.com/NixOS/nixpkgs/issues/129247
225 # * https://gitlab.haskell.org/ghc/ghc/-/issues/19580
226 hardeningDisable = [ "pie" ];
227
228 doInstallCheck = true;
229 installCheckPhase = ''
230 # Sanity check, can ghc create executables?
231 cd $TMP
232 mkdir test-ghc; cd test-ghc
233 cat > main.hs << EOF
234 {-# LANGUAGE TemplateHaskell #-}
235 module Main where
236 main = putStrLn \$([|"yes"|])
237 EOF
238 env -i $out/bin/ghc --make main.hs || exit 1
239 echo compilation ok
240 [ $(./main) == "yes" ]
241 '';
242
243 passthru = {
244 targetPrefix = "";
245 enableShared = true;
246
247 inherit llvmPackages;
248
249 # Our Cabal compiler name
250 haskellCompilerName = "ghc-${version}";
251 };
252
253 meta = rec {
254 license = lib.licenses.bsd3;
255 platforms = [
256 "x86_64-linux"
257 "i686-linux"
258 "x86_64-darwin"
259 "powerpc64le-linux"
260 ];
261 # build segfaults, use ghc8107Binary which has proper musl support instead
262 broken = stdenv.hostPlatform.isMusl;
263 maintainers = with lib.maintainers; [
264 guibou
265 ];
266 teams = [ lib.teams.haskell ];
267 };
268}