wine: improve Darwin support

- Add a setup hook to allow Darwin to build PE DLLs using MinGW;
- Add a postConfigure script to fix preloader brekage on Apple Silicon
Macs running under Rosetta 2;
- Disable linking against X11 libraries (pulled in by ffmpeg); and
- Allow building Wine 7.0 using the 10.12 SDK on x86_64-darwin.

+101 -4
+33 -4
pkgs/applications/emulators/wine/base.nix
··· 1 - { stdenv, lib, pkgArches, callPackage, 1 + { stdenv, lib, pkgArches, callPackage, makeSetupHook, 2 2 name, version, src, mingwGccs, monos, geckos, platforms, 3 3 bison, flex, fontforge, makeWrapper, pkg-config, 4 4 autoconf, hexdump, perl, nixosTests, ··· 15 15 prevName = name; 16 16 prevPlatforms = platforms; 17 17 prevConfigFlags = configureFlags; 18 + setupHookDarwin = makeSetupHook { 19 + name = "darwin-mingw-hook"; 20 + substitutions = { 21 + darwinSuffixSalt = stdenv.cc.suffixSalt; 22 + mingwGccsSuffixSalts = map (gcc: gcc.suffixSalt) mingwGccs; 23 + }; 24 + } ./setup-hook-darwin.sh; 18 25 in 19 26 stdenv.mkDerivation ((lib.optionalAttrs (buildScript != null) { 20 27 builder = buildScript; 28 + }) // (lib.optionalAttrs stdenv.isDarwin { 29 + postConfigure = '' 30 + # dynamic fallback, so this shouldn’t cause problems for older versions of macOS and will 31 + # provide additional functionality on newer ones. This can be removed once the x86_64-darwin 32 + # SDK is updated. 33 + sed 's|/\* #undef HAVE_MTLDEVICE_REGISTRYID \*/|#define HAVE_MTLDEVICE_REGISTRYID 1|' \ 34 + -i include/config.h 35 + ''; 36 + postBuild = '' 37 + # The Wine preloader must _not_ be linked to any system libraries, but `NIX_LDFLAGS` will link 38 + # to libintl, libiconv, and CoreFoundation no matter what. Delete the one that was built and 39 + # rebuild it with empty NIX_LDFLAGS. 40 + rm loader/wine64-preloader 41 + make loader/wine64-preloader NIX_LDFLAGS="" NIX_LDFLAGS_${stdenv.cc.suffixSalt}="" 42 + ''; 21 43 }) // rec { 22 44 inherit src; 23 45 ··· 38 60 hexdump 39 61 perl 40 62 ] 41 - ++ lib.optionals supportFlags.mingwSupport mingwGccs; 63 + ++ lib.optionals supportFlags.mingwSupport (mingwGccs 64 + ++ lib.optional stdenv.isDarwin setupHookDarwin); 42 65 43 66 buildInputs = toBuildInputs pkgArches (with supportFlags; (pkgs: 44 67 [ pkgs.freetype pkgs.perl pkgs.libunwind ] 45 68 ++ lib.optional stdenv.isLinux pkgs.libcap 69 + ++ lib.optional stdenv.isDarwin pkgs.libinotify-kqueue 46 70 ++ lib.optional cupsSupport pkgs.cups 47 71 ++ lib.optional gettextSupport pkgs.gettext 48 72 ++ lib.optional dbusSupport pkgs.dbus ··· 85 109 wayland libxkbcommon wayland-protocols wayland.dev libxkbcommon.dev 86 110 ]))); 87 111 88 - patches = [ ] ++ patches'; 112 + patches = [ ] 113 + # Wine requires `MTLDevice.registryID` for `winemac.drv`, but that property is not available 114 + # in the 10.12 SDK (current SDK on x86_64-darwin). Work around that by using selector syntax. 115 + ++ lib.optional stdenv.isDarwin ./darwin-metal-compat.patch 116 + ++ patches'; 89 117 90 118 configureFlags = prevConfigFlags 91 119 ++ lib.optionals supportFlags.waylandSupport [ "--with-wayland" ] 92 120 ++ lib.optionals supportFlags.vulkanSupport [ "--with-vulkan" ] 93 - ++ lib.optionals supportFlags.vkd3dSupport [ "--with-vkd3d" ]; 121 + ++ lib.optionals supportFlags.vkd3dSupport [ "--with-vkd3d" ] 122 + ++ lib.optionals (stdenv.isDarwin && !supportFlags.xineramaSupport) [ "--without-x" ]; 94 123 95 124 # Wine locates a lot of libraries dynamically through dlopen(). Add 96 125 # them to the RPATH so that the user doesn't have to set them in
+31
pkgs/applications/emulators/wine/darwin-metal-compat.patch
··· 1 + diff --git a/dlls/winemac.drv/cocoa_display.m b/dlls/winemac.drv/cocoa_display.m 2 + index f64a6c0f6ad..6da0391e3fa 100644 3 + --- a/dlls/winemac.drv/cocoa_display.m 4 + +++ b/dlls/winemac.drv/cocoa_display.m 5 + @@ -289,7 +289,7 @@ static int macdrv_get_gpus_from_metal(struct macdrv_gpu** new_gpus, int* count) 6 + * the primary GPU because we need to hide the integrated GPU for an automatic graphic switching pair to avoid apps 7 + * using the integrated GPU. This is the behavior of Windows on a Mac. */ 8 + primary_device = [MTLCreateSystemDefaultDevice() autorelease]; 9 + - if (macdrv_get_gpu_info_from_registry_id(&primary_gpu, primary_device.registryID)) 10 + + if (macdrv_get_gpu_info_from_registry_id(&primary_gpu, (uint64_t)[primary_device registryID])) 11 + goto done; 12 + 13 + /* Hide the integrated GPU if the system default device is a dedicated GPU */ 14 + @@ -301,7 +301,7 @@ static int macdrv_get_gpus_from_metal(struct macdrv_gpu** new_gpus, int* count) 15 + 16 + for (i = 0; i < devices.count; i++) 17 + { 18 + - if (macdrv_get_gpu_info_from_registry_id(&gpus[gpu_count], devices[i].registryID)) 19 + + if (macdrv_get_gpu_info_from_registry_id(&gpus[gpu_count], (uint64_t)[devices[i] registryID])) 20 + goto done; 21 + 22 + if (hide_integrated && devices[i].isLowPower) 23 + @@ -354,7 +354,7 @@ static int macdrv_get_gpu_info_from_display_id_using_metal(struct macdrv_gpu* gp 24 + 25 + device = [CGDirectDisplayCopyCurrentMetalDevice(display_id) autorelease]; 26 + if (device && [device respondsToSelector:@selector(registryID)]) 27 + - ret = macdrv_get_gpu_info_from_registry_id(gpu, device.registryID); 28 + + ret = macdrv_get_gpu_info_from_registry_id(gpu, (uint64_t)[device registryID]); 29 + 30 + done: 31 + [pool release];
+37
pkgs/applications/emulators/wine/setup-hook-darwin.sh
··· 1 + 2 + fixupCFlagsForDarwin() { 3 + # Because it’s getting called from a Darwin stdenv, MinGW will pick up on Darwin-specific 4 + # flags, and the ./configure tests will fail to consider it a working cross-compiler. 5 + # Strip them out, so Wine can use MinGW to build its DLLs instead of trying to use Clang. 6 + # Ideally, it would be possible to build the DLLs on Windows (i.e., as part of `pkgsCross``), 7 + # but that is not the case currently with Wine’s build system. 8 + cflagsFilter='s|-F[^ ]*||g;s|-iframework [^ ]*||g;s|-isystem [^ ]*||g;s| *| |g' 9 + 10 + # libiconv and libintl aren’t needed by Wine, and having them causes linking to fail. 11 + # The `CoreFoundation` reference is added by `linkSystemCoreFoundationFramework` in the 12 + # Apple SDK’s setup hook. Remove that because MingW will fail due to file not found. 13 + ldFlagsFilter='s|-lintl||g;s|-liconv||g;s|/nix/store/[^-]*-apple-framework-CoreFoundation[^ ]*||g' 14 + 15 + # `cc-wrapper.sh`` supports getting flags from a system-specific salt. While it is currently a 16 + # tuple, that’s not considered a stable interface, so the Wine derivation will provide them: 17 + # - for Darwin: The source is `stdenv.cc.suffixSalt`; and 18 + # - for MinGW: The source is the `suffixSalt`` attribute of each of the `mingwGccs`. 19 + export NIX_CFLAGS_COMPILE_@darwinSuffixSalt@=${NIX_CFLAGS_COMPILE-} 20 + export NIX_LDFLAGS_@darwinSuffixSalt@=${NIX_LDFLAGS-} 21 + for mingwSalt in @mingwGccsSuffixSalts@; do 22 + echo removing @darwinSuffixSalt@-specific flags from NIX_CFLAGS_COMPILE for $mingwSalt 23 + export NIX_CFLAGS_COMPILE_$mingwSalt+="$(sed "$cflagsFilter" <<< "$NIX_CFLAGS_COMPILE")" 24 + echo removing @darwinSuffixSalt@-specific flags from NIX_LDFLAGS for $mingwSalt 25 + export NIX_LDFLAGS_$mingwSalt+="$(sed "$ldFlagsFilter;$cflagsFilter" <<< "$NIX_LDFLAGS")" 26 + done 27 + 28 + # Make sure the global flags aren’t accidentally influencing the platform-specific flags. 29 + export NIX_CFLAGS_COMPILE="" 30 + export NIX_LDFLAGS="" 31 + } 32 + 33 + # This is pretty hacky, but this hook _must_ run after `linkSystemCoreFoundationFramework`. 34 + function runFixupCFlagsForDarwinLast() { 35 + preConfigureHooks+=(fixupCFlagsForDarwin) 36 + } 37 + postUnpackHooks+=(runFixupCFlagsForDarwinLast)