fix(windows): app.nix copied no shared libraries at all

The liblogos shared-library loop globbed *.dylib and *.so only. On Windows
it matched nothing, and because each candidate is guarded by `[ -f "$f" ]`
with a trailing `|| true`, it copied zero files and exited 0.

Thirteen DLLs sit in that same lib/ -- liblogos_core, libpackage_manager_lib,
liblgx, icuuc76, icudt76, libsodium-26 and the mingw runtime -- and
LogosBasecamp.exe imports liblogos_core.dll DIRECTLY. The result is
0xC0000135 (STATUS_DLL_NOT_FOUND) before main(): no Qt error, no stderr, no
output whatsoever. It has only ever run on Windows because those DLLs were
hand-staged into the payload.

Adds *.dll to the glob, sends DLLs to bin/ rather than lib/ (Windows searches
the executable's own directory, has no rpath, and win-dll-link.sh only
processes $out/bin), and makes copying zero libraries a hard error -- this
loop exiting 0 having done nothing is the whole defect.

Also corrects the comment on bundleFor. It claimed skipping nix-bundle-dir on
Windows was right because a PE needs no relocation. That conflates the
bundler's two jobs: relocation (genuinely unnecessary on PE) and Qt plugin /
QML / qt.conf staging (required on every platform, since those DLLs are
LoadLibrary'd and appear in no import table). Skipping it yields a bundle with
no qt.conf and no QPA plugin. The comment now says so and names the real fix.
This commit is contained in:
Dario Gabriel Lipicar
2026-08-07 22:49:12 -03:00
parent 7ef9f9b514
commit 461ddcd77a
2 changed files with 52 additions and 12 deletions
+22 -9
View File
@@ -265,15 +265,28 @@
mainProgram = "LogosBasecamp";
};
});
# nix-bundle-dir is the ELF/Mach-O relocator: it rewrites rpaths and
# install names so the binaries stop pointing into /nix/store. A PE
# has neither -- its import table carries DLL BASE NAMES only, and
# Windows searches the executable's own directory first -- so the
# Windows build is ALREADY relocatable and nixpkgs' win-dll-link.sh
# has staged the closure into bin/. Running bundle.sh over it would
# not help; it branches `file -b` on Mach-O|ELF with no PE case and
# would emit an EMPTY payload while exiting 0. nix-bundle-lgx skips
# it on Windows for exactly this reason (d539a3f); do the same here.
# INTERIM, and neither branch of this is right yet -- see below.
#
# nix-bundle-dir does two separable jobs. (a) RELOCATION: rewriting
# rpaths / install names so binaries stop pointing into /nix/store.
# A PE genuinely needs none of that -- its import table carries DLL
# BASE NAMES only, Windows searches the executable's own directory
# first, and win-dll-link.sh has already staged bin/. (b) Qt STAGING:
# the Qt plugin scan, the QML module scan and qt.conf generation.
# (b) is FORMAT-AGNOSTIC and is required on Windows just as much as
# anywhere else -- Qt plugins and QML module DLLs are LoadLibrary'd,
# so nothing in the import closure reveals them.
#
# Running the bundler unmodified on Windows takes the (a) path, whose
# `file -b` chain has no PE case, and emits an EMPTY payload while
# exiting 0. Skipping it entirely -- what this does -- keeps the app
# and the modules but produces no qt.conf, no lib/qt-6/plugins and no
# qwindows.dll, so the app cannot start either.
#
# The real fix is a PE branch in nix-bundle-dir's bundle.sh that skips
# (a) and keeps (b), plus a fixpoint sweep of the DLL closure over the
# staged plugins. When that lands, DELETE bundleFor and go back to
# dirBundler on every platform.
winBundler = drv: drv;
bundleFor = if onWindows then winBundler else dirBundler;
binBundleDir = withMainProgram (bundleFor appDistributed);
+30 -3
View File
@@ -332,12 +332,39 @@ WRAPPER_EOF
fi
done
# Copy shared libraries from liblogos (includes logos_core and its dependency package_manager_lib)
for f in "${logosLiblogos}/lib/"*.dylib "${logosLiblogos}/lib/"*.so; do
# Copy shared libraries from liblogos (includes logos_core and its dependency
# package_manager_lib).
#
# The glob listed only *.dylib and *.so, so on Windows it matched NOTHING and
# -- guarded by `[ -f ]` and `|| true` -- copied nothing while exiting 0. The
# thirteen DLLs sitting in that same lib/ (liblogos_core, libpackage_manager_lib,
# liblgx, icuuc76, icudt76, libsodium-26, ...) were silently dropped, and
# LogosBasecamp.exe imports liblogos_core.dll DIRECTLY: the app died at
# 0xC0000135 (STATUS_DLL_NOT_FOUND) before main(), which produces no Qt error,
# no stderr, no output of any kind. It only ever ran because those DLLs were
# hand-staged into the payload by the operator.
#
# DLLs go to bin/, NOT lib/. Windows searches the executable's own directory
# first and has no rpath, and nixpkgs' win-dll-link.sh (which pulls in the rest
# of the closure) only ever processes $out/bin.
_libdest="$out/lib"
${pkgs.lib.optionalString pkgs.stdenv.hostPlatform.isWindows ''_libdest="$out/bin"''}
_copied=0
for f in "${logosLiblogos}/lib/"*.dylib "${logosLiblogos}/lib/"*.so "${logosLiblogos}/lib/"*.dll; do
# A non-matching glob stays literal, so test before copying.
if [ -f "$f" ]; then
cp -L "$f" "$out/lib/" || true
cp -L "$f" "$_libdest/" || true
_copied=$((_copied + 1))
fi
done
echo "Installed $_copied shared librar(y|ies) from liblogos into $_libdest"
# Assert rather than trust: this loop silently copying zero is exactly the
# defect above, and it exits 0 either way.
if [ "$_copied" -eq 0 ]; then
echo "ERROR: copied no shared libraries from ${logosLiblogos}/lib" >&2
ls -la "${logosLiblogos}/lib" >&2 || true
exit 1
fi
# Copy SDK library if it exists
if ls "${logosSdk}/lib/"liblogos_sdk.* >/dev/null 2>&1; then