From 352f2fc24d2a027281a5a19c65bdc8e8b3e28009 Mon Sep 17 00:00:00 2001 From: Dario Gabriel Lipicar Date: Thu, 6 Aug 2026 10:28:31 -0300 Subject: [PATCH] feat(windows): make the Qt plugin backend cross-compilable Three changes, all needed before any module can target mingw: * meta.platforms gained windows in the three generated derivations. Without it every module fails at EVALUATION with "not available on the requested hostPlatform". * getPluginFilename returned ".so" on Windows while getLibExtension two lines above already answered "dll". They disagreed because each carried its own copy of the platform branch, so the attribute set is now `rec` and getPluginFilename REUSES getLibExtension rather than repeating it. * wrapQtAppsNoGuiHook is gated behind !isWindows and dontWrapQtApps is set on both plugin derivations. Both halves are required and neither is optional: the hook does not even EVALUATE for a mingw host, and would be inert anyway (wrap-qt-apps-hook skips anything that is not ELF or Mach-O), while qtbase's own setup hook hard-errors in qtPreHook unless dontWrapQtApps is set. --- lib/buildPlugin.nix | 14 ++++++++++++++ lib/common.nix | 26 ++++++++++++++++++++------ lib/default.nix | 6 +++--- 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/lib/buildPlugin.nix b/lib/buildPlugin.nix index f0b50c2..370802f 100644 --- a/lib/buildPlugin.nix +++ b/lib/buildPlugin.nix @@ -198,6 +198,13 @@ in { libExt = gen.libExt; in pkgs.stdenv.mkDerivation (commonArgs // { + # Required wherever the Qt wrapper hooks are absent (Windows -- see + # common.nix): qtbase's setup hook hard-errors in qtPreHook with + # "depends on qtbase, but no wrapping behavior was specified" unless one of + # the two is present. Harmless elsewhere: these are plugins, not + # applications, so there is nothing to wrap. + dontWrapQtApps = true; + pname = "${commonArgs.pname}-lib"; inherit src; @@ -366,6 +373,13 @@ in { }; in pkgs.stdenv.mkDerivation (commonArgs // { + # Required wherever the Qt wrapper hooks are absent (Windows -- see + # common.nix): qtbase's setup hook hard-errors in qtPreHook with + # "depends on qtbase, but no wrapping behavior was specified" unless one of + # the two is present. Harmless elsewhere: these are plugins, not + # applications, so there is nothing to wrap. + dontWrapQtApps = true; + pname = "${commonArgs.pname}-generated"; inherit src; diff --git a/lib/common.nix b/lib/common.nix index 5b38ecf..b014a8a 100644 --- a/lib/common.nix +++ b/lib/common.nix @@ -5,9 +5,13 @@ # and it's passed in by the caller. { lib }: -{ - # Supported target systems - systems = [ "aarch64-darwin" "x86_64-darwin" "aarch64-linux" "x86_64-linux" ]; +# `rec` so getPluginFilename can reuse getLibExtension instead of repeating the +# platform branch -- the duplication is exactly what let them disagree about +# Windows. +rec { + # Supported target systems. "x86_64-windows" is a pseudo-system: a cross + # derivation's `system` attribute is its BUILD platform. + systems = [ "aarch64-darwin" "x86_64-darwin" "aarch64-linux" "x86_64-linux" "x86_64-windows" ]; # Determine library extension based on platform getLibExtension = pkgs: @@ -15,16 +19,26 @@ else if pkgs.stdenv.hostPlatform.isWindows then "dll" else "so"; - # Get the plugin filename for a module + # Get the plugin filename for a module. + # + # Reuses getLibExtension rather than repeating the branch: this used to have + # its own darwin/else test and returned ".so" on Windows, disagreeing with + # getLibExtension two lines above, which already answered "dll". getPluginFilename = pkgs: name: - "${name}_plugin.${if pkgs.stdenv.hostPlatform.isDarwin then "dylib" else "so"}"; + "${name}_plugin.${getLibExtension pkgs}"; # Qt-specific native build inputs commonNativeBuildInputs = pkgs: [ pkgs.cmake pkgs.ninja pkgs.pkg-config - pkgs.qt6.wrapQtAppsNoGuiHook + # Mandatory guard, not an optimisation: wrapQtAppsNoGuiHook does not even + # EVALUATE for a mingw host, and would be inert anyway -- wrap-qt-apps-hook + # skips anything that is not ELF or Mach-O, so a PE is never wrapped. + # qtbase's own setup hook then hard-errors in qtPreHook unless + # dontWrapQtApps is set, which is why both halves are needed. + ] ++ pkgs.lib.optional (!pkgs.stdenv.hostPlatform.isWindows) + pkgs.qt6.wrapQtAppsNoGuiHook ++ [ ]; # Qt-specific build inputs diff --git a/lib/default.nix b/lib/default.nix index 081f7e2..6ab40fb 100644 --- a/lib/default.nix +++ b/lib/default.nix @@ -51,7 +51,7 @@ in { } // extraEnv; meta = with lib; { description = config.description; - platforms = platforms.unix; + platforms = platforms.unix ++ platforms.windows; }; }; in mkBuildPlugin.build { @@ -93,7 +93,7 @@ in { } // extraEnv; meta = with lib; { description = config.description; - platforms = platforms.unix; + platforms = platforms.unix ++ platforms.windows; }; }; in mkBuildPlugin.generate { @@ -122,7 +122,7 @@ in { version = config.version; meta = with lib; { description = config.description; - platforms = platforms.unix; + platforms = platforms.unix ++ platforms.windows; }; }; in mkBuildHeaders.build {