Skip to content

Commit 3e4262c

Browse files
angermanhamishmack
andauthored
Fix Windows and GHC/ucrt. (#2034)
* Use Cabal 3.10 when building hoogle * Add windows R_X86_64_PC64 relocation support * Patch wine to fix addDllDirectory Fixes errors like this when trying to load DLLs into template haskell code with GHC 9.4 and above: ``` iserv-proxy-interpreter.exe: addLibrarySearchPath: \\?\Z:\nix\store\gjsf5jazfbfv21hvvgf1amd5rdx3ycf3-x86_64-w64-mingw32-ghc-9.4.3\lib\x86_64-windows-ghc-9.4.3\ghc-bignum-1.3 (Win32 error 87): Invalid parameter. ``` These errors arise with GHC 9.4 and above because it uses UNC paths to avoid limits on path length. The `RtlDetermineDosPathNameType_U` function classifies these as a `DEVICE_PATH` and `LdrAddDllDirectory` gives up at that point. * patch wine to support UNC paths * Force msvcrt instead of ucrt for GHC Nixpkgs `mingw64` is a msvcrt based toolchain. GHC 9.4+ moved on to a ucrt based toolchain. We can hover reverse this change in GHC and keep using msvcrt for now. We also need to prevent the linker for linking ucrt, as that is is incompatible with ucrt. By doing so we can also upgrade to a newer wine, which contains ucrt libs. This would previously have thrown our TH logic off. * Revert "Use Cabal 3.10 when building hoogle" This reverts commit f23f307. * revert flake.lock change * Restrict range of patch * no-ucrt from 9.6 onwards only * closure_sizeW also only from 9.6 --------- Co-authored-by: Hamish Mackenzie <[email protected]>
1 parent 3f6abf9 commit 3e4262c

10 files changed

+193
-17
lines changed

modules/configuration-nix.nix

+1
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ in {
4444
(fromUntil "3.2.0.0" "3.5" ../overlays/patches/Cabal/Cabal-3.0.0.0-no-final-checks.diff)
4545
(fromUntil "3.6.0.0" "3.11" ../overlays/patches/Cabal/Cabal-3.6.0.0-drop-pkg-db-check.diff)
4646
(fromUntil "3.6.0.0" "3.11" ../overlays/patches/Cabal/Cabal-3.6.0.0-no-final-checks.diff)
47+
(fromUntil "3.10" "3.11" ../overlays/patches/Cabal/9220.patch)
4748
];
4849

4950
# These two patches are:

overlays/bootstrap.nix

+13
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,18 @@ in {
184184
++ final.lib.optionals (final.stdenv.targetPlatform.isWindows) (fromUntil "9.4.1" "9.4.5" ./patches/ghc/ghc-9.4-hadrian-win-cross.patch)
185185
++ final.lib.optionals (final.stdenv.targetPlatform.isWindows) (fromUntil "9.4.7" "9.4.8" ./patches/ghc/ghc-9.8-hadrian-win-cross.patch)
186186
++ final.lib.optionals (final.stdenv.targetPlatform.isWindows) (fromUntil "9.8.1" "9.10" ./patches/ghc/ghc-9.8-hadrian-win-cross.patch)
187+
# support R_X86_64_PC64 (ELF constant 24) - IMAGE_REL_AMD64_SREL32 (PE constant 14), which seems to appear with 9.6 more frequently, and
188+
# results in "unhandled PEi386 relocation type 14".
189+
++ final.lib.optionals (final.stdenv.targetPlatform.isWindows) (fromUntil "9.4.1" "9.10" ./patches/ghc/win-reloc-x86_64-pc64.patch)
190+
# ++ final.lib.optionals (final.stdenv.targetPlatform.isWindows) (fromUntil "9.4.1" "9.10" ./patches/ghc/Win32-depends-on-mingwex.patch)
191+
# if the host system provides ucrt (e.g. wine with ucrtbase.dll), we may end up linking against symbols from ucrtbase, instead of msvcrt,
192+
# thus leading to broken code. E.g. the handles we create and hand to wine will all be busted, because they come from one and are processed
193+
# by another crt.
194+
++ final.lib.optionals (final.stdenv.targetPlatform.isWindows) (fromUntil "8.10" "9.10" ./patches/ghc/win-linker-no-ucrt.patch)
195+
# Nixos/nixpkgs is mscvrt for now, thus we must disable ucrt in ghc, otherwise we end up with broken linking.
196+
++ final.lib.optionals (final.stdenv.targetPlatform.isWindows) (fromUntil "9.6" "9.10" ./patches/ghc/no-ucrt.patch)
197+
# the following is needed for cardano-prelude as it uses closure_sizeW :-/
198+
++ final.lib.optionals (final.stdenv.targetPlatform.isWindows) (fromUntil "9.6" "9.10" ./patches/ghc/win-add-closure_sizeW-to-rtssyms.patch)
187199
++ fromUntil "9.4.5" "9.4.8" ./patches/ghc/ghc-9.4.5-include-order-fix.patch
188200
++ fromUntil "9.6.2" "9.8" ./patches/ghc/ghc-9.4.5-include-order-fix.patch
189201
++ fromUntil "9.6.1" "9.10" ./patches/ghc/MR10116.patch
@@ -209,6 +221,7 @@ in {
209221
++ final.lib.optional (versionAtLeast "8.10" && versionLessThan "9.0" && final.stdenv.targetPlatform.isAarch64) ./patches/ghc/ghc-8.10-aarch64-handle-none-rela.patch
210222
++ final.lib.optional (versionAtLeast "9.0" && final.stdenv.targetPlatform.isAarch64) ./patches/ghc/ghc-9.0-better-symbol-addr-debug.patch
211223
++ final.lib.optional (versionAtLeast "9.0" && final.stdenv.targetPlatform.isAarch64) ./patches/ghc/ghc-9.0-aarch64-handle-none-rela.patch
224+
212225
;
213226
in ({
214227
ghc865 = final.callPackage ../compiler/ghc (traceWarnOld "8.6" {

overlays/patches/Cabal/9220.patch

+70
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
diff --git a/src/Distribution/Simple/Configure.hs b/src/Distribution/Simple/Configure.hs
2+
index ac7bd852f..803475283 100644
3+
--- a/src/Distribution/Simple/Configure.hs
4+
+++ b/src/Distribution/Simple/Configure.hs
5+
@@ -637,22 +637,6 @@ configure (pkg_descr0, pbi) cfg = do
6+
"--enable-split-objs; ignoring")
7+
return False
8+
9+
- let compilerSupportsGhciLibs :: Bool
10+
- compilerSupportsGhciLibs =
11+
- case compilerId comp of
12+
- CompilerId GHC version
13+
- | version > mkVersion [9,3] && windows ->
14+
- False
15+
- CompilerId GHC _ ->
16+
- True
17+
- CompilerId GHCJS _ ->
18+
- True
19+
- _ -> False
20+
- where
21+
- windows = case compPlatform of
22+
- Platform _ Windows -> True
23+
- Platform _ _ -> False
24+
-
25+
let ghciLibByDefault =
26+
case compilerId comp of
27+
CompilerId GHC _ ->
28+
@@ -669,15 +653,6 @@ configure (pkg_descr0, pbi) cfg = do
29+
not (GHCJS.isDynamic comp)
30+
_ -> False
31+
32+
- withGHCiLib_ <-
33+
- case fromFlagOrDefault ghciLibByDefault (configGHCiLib cfg) of
34+
- True | not compilerSupportsGhciLibs -> do
35+
- warn verbosity $
36+
- "--enable-library-for-ghci is no longer supported on Windows with"
37+
- ++ " GHC 9.4 and later; ignoring..."
38+
- return False
39+
- v -> return v
40+
-
41+
let sharedLibsByDefault
42+
| fromFlag (configDynExe cfg) =
43+
-- build a shared library if dynamically-linked
44+
@@ -774,7 +749,7 @@ configure (pkg_descr0, pbi) cfg = do
45+
withProfExeDetail = ProfDetailNone,
46+
withOptimization = fromFlag $ configOptimization cfg,
47+
withDebugInfo = fromFlag $ configDebugInfo cfg,
48+
- withGHCiLib = withGHCiLib_,
49+
+ withGHCiLib = fromFlagOrDefault ghciLibByDefault (configGHCiLib cfg),
50+
splitSections = split_sections,
51+
splitObjs = split_objs,
52+
stripExes = strip_exe,
53+
diff --git a/src/Distribution/Simple/Setup.hs b/src/Distribution/Simple/Setup.hs
54+
index 36f6aa22f..aa60b73b8 100644
55+
--- a/src/Distribution/Simple/Setup.hs
56+
+++ b/src/Distribution/Simple/Setup.hs
57+
@@ -384,12 +384,7 @@ defaultConfigFlags progDb = emptyConfigFlags {
58+
configCabalFilePath = NoFlag,
59+
configVerbosity = Flag normal,
60+
configUserInstall = Flag False, --TODO: reverse this
61+
-#if defined(mingw32_HOST_OS)
62+
- -- See #8062 and GHC #21019.
63+
- configGHCiLib = Flag False,
64+
-#else
65+
- configGHCiLib = NoFlag,
66+
-#endif
67+
+ configGHCiLib = Flag True,
68+
configSplitSections = Flag False,
69+
configSplitObjs = Flag False, -- takes longer, so turn off by default
70+
configStripExes = NoFlag,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
diff --git a/libraries/Win32/Win32.cabal b/libraries/Win32/Win32.cabal
2+
index e986b7e..603354f 100644
3+
--- a/libraries/Win32/Win32.cabal
4+
+++ b/libraries/Win32/Win32.cabal
5+
@@ -138,7 +138,7 @@ Library
6+
System.Win32.Time.Internal
7+
8+
extra-libraries:
9+
- "user32", "gdi32", "winmm", "advapi32", "shell32", "shfolder", "shlwapi", "msimg32", "imm32"
10+
+ "user32", "gdi32", "winmm", "advapi32", "shell32", "shfolder", "shlwapi", "msimg32", "imm32", "mingwex"
11+
ghc-options: -Wall
12+
include-dirs: include
13+
includes: "alphablend.h", "diatemp.h", "dumpBMP.h", "ellipse.h", "errors.h", "HsGDI.h", "HsWin32.h", "Win32Aux.h", "win32debug.h", "windows_cconv.h", "WndProc.h", "alignment.h"

overlays/patches/ghc/no-ucrt.patch

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
diff --git a/libraries/ghc-prim/ghc-prim.cabal b/libraries/ghc-prim/ghc-prim.cabal
2+
index 5393363..4f5db98 100644
3+
--- a/libraries/ghc-prim/ghc-prim.cabal
4+
+++ b/libraries/ghc-prim/ghc-prim.cabal
5+
@@ -73,7 +73,7 @@ Library
6+
-- mingw32 which is required by mingwex.
7+
-- user32: provides access to apis to modify user components (UI etc)
8+
-- on Windows. Required because of mingw32.
9+
- extra-libraries: user32, mingw32, ucrt
10+
+ extra-libraries: user32, mingw32, msvcrt, mingwex
11+
12+
if os(linux)
13+
-- we need libm, but for musl and other's we might need libc, as libm
14+
diff --git a/m4/fp_setup_windows_toolchain.m4 b/m4/fp_setup_windows_toolchain.m4
15+
index 1f44a38..122a205 100644
16+
--- a/m4/fp_setup_windows_toolchain.m4
17+
+++ b/m4/fp_setup_windows_toolchain.m4
18+
@@ -86,7 +86,7 @@ AC_DEFUN([FP_SETUP_WINDOWS_TOOLCHAIN],[
19+
# Signal that we are linking against UCRT with the _UCRT macro. This is
20+
# necessary to ensure correct behavior when MinGW-w64 headers are in the
21+
# header include path (#22159).
22+
- cflags="--rtlib=compiler-rt -D_UCRT"
23+
+ cflags=""
24+
CFLAGS="$cflags"
25+
CONF_CC_OPTS_STAGE1="$cflags"
26+
CONF_CC_OPTS_STAGE2="$cflags"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
diff --git a/rts/RtsSymbols.c b/rts/RtsSymbols.c
2+
index 10efb2a..d8ea070 100644
3+
--- a/rts/RtsSymbols.c
4+
+++ b/rts/RtsSymbols.c
5+
@@ -160,7 +160,9 @@ extern char **environ;
6+
SymI_HasProto(__mingw_vsnwprintf) \
7+
/* ^^ Need to figure out why this is needed. */ \
8+
SymI_HasProto(__mingw_vfprintf) \
9+
- /* ^^ Need to figure out why this is needed. */
10+
+ /* ^^ Need to figure out why this is needed. */ \
11+
+ SymI_HasProto(closure_sizeW_) \
12+
+ /* ^^ This one needed for cardano-prelude m( */
13+
#else
14+
#define RTS_MINGW_ONLY_SYMBOLS /**/
15+
#endif
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
diff --git a/rts/linker/PEi386.c b/rts/linker/PEi386.c
2+
index c404992..fd060e4 100644
3+
--- a/rts/linker/PEi386.c
4+
+++ b/rts/linker/PEi386.c
5+
@@ -1132,6 +1132,11 @@ lookupSymbolInDLLs ( const SymbolName* lbl, ObjectCode *dependent )
6+
for (o_dll = opened_dlls; o_dll != NULL; o_dll = o_dll->next) {
7+
/* debugBelch("look in %ls for %s\n", o_dll->name, lbl); */
8+
9+
+ if (wcsncmp(o_dll->name,WSTR("ucrtbase.dll"),wcslen(WSTR("ucrtbase.dll"))) == 0) {
10+
+ IF_DEBUG(linker, debugBelch("warning: ignoring %s\n", o_dll->name));
11+
+ continue;
12+
+ }
13+
+
14+
sym = GetProcAddress(o_dll->instance, lbl+STRIP_LEADING_UNDERSCORE);
15+
if (sym != NULL) {
16+
/*debugBelch("found %s in %s\n", lbl+1,o_dll->name);*/
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
diff --git a/rts/linker/PEi386.c b/rts/linker/PEi386.c
2+
index 0b328df..c404992 100644
3+
--- a/rts/linker/PEi386.c
4+
+++ b/rts/linker/PEi386.c
5+
@@ -2071,6 +2071,15 @@ ocResolve_PEi386 ( ObjectCode* oc )
6+
*(uint32_t *)pP = (uint32_t)v;
7+
break;
8+
}
9+
+ case 14: /* R_X86_64_PC64 (ELF constant 24) - IMAGE_REL_AMD64_SREL32 (PE constant 14) */
10+
+ {
11+
+ /* mingw will emit this for a pc-rel 64 relocation */
12+
+ uint64_t A;
13+
+ checkProddableBlock(oc, pP, 8);
14+
+ A = *(uint64_t*)pP;
15+
+ *(uint64_t *)pP = S + A - (intptr_t)pP;
16+
+ break;
17+
+ }
18+
case 4: /* R_X86_64_PC32 (ELF constant 2) - IMAGE_REL_AMD64_REL32 (PE constant 4) */
19+
{
20+
intptr_t v;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
diff --git a/dlls/ntdll/loader.c b/dlls/ntdll/loader.c
2+
index 85eb2976807..36d92b32d1c 100644
3+
--- a/dlls/ntdll/loader.c
4+
+++ b/dlls/ntdll/loader.c
5+
@@ -4015,7 +4015,7 @@ NTSTATUS WINAPI LdrAddDllDirectory( const UNICODE_STRING *dir, void **cookie )
6+
struct dll_dir_entry *ptr;
7+
DOS_PATHNAME_TYPE type = RtlDetermineDosPathNameType_U( dir->Buffer );
8+
9+
- if (type != ABSOLUTE_PATH && type != ABSOLUTE_DRIVE_PATH)
10+
+ if (type != ABSOLUTE_PATH && type != ABSOLUTE_DRIVE_PATH && type != DEVICE_PATH )
11+
return STATUS_INVALID_PARAMETER;
12+
13+
status = RtlDosPathNameToNtPathName_U_WithStatus( dir->Buffer, &nt_name, NULL, NULL );

overlays/wine.nix

+6-17
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,10 @@
22
# files from TH code) for GHC built with msvcrt (ghc<9.6).
33
# This will inevitably replace *any* wine version. Thus this might not really be what we ultimately want.
44
# Wine 5.4 does not build on macOS so that is not pinned and TH code will probably break.
5-
final: prev:
6-
prev.lib.optionalAttrs (!prev.stdenv.hostPlatform.isDarwin) {
7-
winePackages = prev.winePackages // {
8-
minimal = prev.winePackages.minimal.overrideAttrs (oldAttrs: {
9-
name = "wine-5.4";
10-
version = "5.4";
11-
src = prev.fetchurl {
12-
url = "https://dl.winehq.org/wine/source/5.x/wine-5.4.tar.xz";
13-
sha256 = "sha256-Sz4rD/pUFfGZVA5gUcKMOXb86R6lv7LPSgmcJXMXBSw=";
14-
};
15-
patches = [];
16-
# Turning off the tests as there is a problem with the `schedsvc` test.
17-
# With recent nixpkgs both the IDL files generate `_c.c` files with
18-
# `handle_t rpc_handle` and that results in a linker error (duplicate symbols).
19-
configureFlags = oldAttrs.configureFlags or [] ++ ["--disable-tests"];
20-
});
21-
};
5+
final: prev: {
6+
winePackages = prev.winePackages // {
7+
minimal = prev.winePackages.minimal.overrideAttrs (oldAttrs: {
8+
patches = oldAttrs.patches or [] ++ [ ./patches/wine-add-dll-directory.patch ];
9+
});
10+
};
2211
}

0 commit comments

Comments
 (0)