feat: node-gtk bundle for Windows and macOS#492
Open
romgrk wants to merge 2 commits into
Open
Conversation
Implements the two remaining platform modules behind the bundle interface (HANDOFF.md mission; Linux shipped in #489): - platform-win32.js: port of the CI-proven windows-bundle-runtime.sh — ntldd -R DLL closure from the MinGW prefix (System32 stays on the host), typelibs, pixbuf loaders with bare-name cache rewrite, CRLF .cmd launcher wiring PATH/GI/GLib env, Compress-Archive zip. Requires an MSYS2 MINGW64 shell at bundle time only. - platform-darwin.js: otool -L transitive closure from Homebrew (@loader_path/@rpath resolution), install_name_tool -change to @loader_path-relative names + ad-hoc re-sign (mandatory on arm64, no -add_rpath), DYLD_FALLBACK_LIBRARY_PATH launcher as the safety net for typelib-baked absolute paths, .app/Info.plist layout, hdiutil UDZO dmg, strip -x + re-sign for node. - shared: copyTypelibs/copyRuntimeData/pkgConfigVar hoisted into runtime-data.js; node stripping is now a per-platform stripNode hook; app-tree trims the binding dir to node_gtk.node only (the Windows self-contained prebuilt carries a whole GTK runtime there — 250MB that must not be duplicated into app/). - CI: bundle smoke test on build-windows (after the prebuilt step, to exercise the binding-dir trim) and on the macOS leg; the smoke test's platform gate is gone. - docs: per-platform notes in doc/bundling.md (incl. macOS signing/notarization caveat), roadmap updated, HANDOFF.md retired. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Homebrew installs Cellar files read-only (0444). copyFile preserves the source mode, so a) the pixbuf loaders dir's multiple symlink entries for one Cellar file made the second copy EACCES on the read-only first one, and b) install_name_tool/codesign would have failed to rewrite every copied dylib in place. Copy libraries with 0755 and dedupe the realpath'd loader list. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Completes the portable-bundle story across all three desktop platforms (Linux shipped in #489; this is the HANDOFF.md mission, now retired).
Windows —
tools/bundle/platform-win32.jsA JS port of the CI-proven
scripts/windows-bundle-runtime.sh(the logic behind the self-contained npm prebuilt), as a superset that also ships node.exe + the app tree + a launcher:cygpath -m $MINGW_PREFIX, with a clear "run from MINGW64" error outside MSYS2. The bundle has no MSYS2 requirement — only the bundling machine.ntldd -Rtransitive DLL closure seeded from the addon +seeds.js+ pixbuf loaders; only prefix-internal DLLs ship (System32 resolves on the host).loaders.cacherewritten to bare DLL names; the loaders dir goes onPATH(same trick aslib/native.js).<Name>.cmdlauncher:PATH,GI_TYPELIB_PATH,XDG_DATA_DIRS,GSETTINGS_SCHEMA_DIR,GDK_PIXBUF_MODULE_FILE,cdintoapp/, runruntime\node.exe.--archive→Compress-Archivezip.macOS —
tools/bundle/platform-darwin.jsTwo-layer relocation of the Homebrew GTK stack into a
<Name>.app:otool -Lclosure (resolving@loader_path/@rpath), copied flat intoruntime/lib; every copied Mach-O rewritten withinstall_name_tool -changeto@loader_path-relative names (no-add_rpath— needs header padding;-changeto a shorter string always fits) and ad-hoc re-signed (mandatory on arm64).DYLD_FALLBACK_LIBRARY_PATH=$RT/lib:…inside the script (SIP-safe) — this is what resolves the absolute Homebrew dylib paths baked into typelibs on machines without brew, and any load command a-changecouldn't rewrite.Plus minimal
Info.plist,hdiutilUDZO.dmgarchive,strip -x+ re-sign for node. Output is per-arch and ad-hoc-signed; Developer ID + notarization for real distribution is documented as out of scope.Shared changes
copyTypelibs/copyRuntimeData/pkgConfigVarhoisted fromplatform-linux.jsintotools/bundle/runtime-data.js.stripNodehook (GNU--strip-unneededvs Apple-x+re-sign vs none for MSVC node.exe).app-tree.jsfix: the binding dir is trimmed tonode_gtk.nodeonly. The self-contained Windows prebuilt keeps its whole GTK runtime (~250MB of DLLs/typelibs/icons) next to the addon, which would otherwise be duplicated wholesale intoapp/node_modules.CI
build-windows: bundle smoke test on node 24, placed after the prebuilt-bundling step deliberately, so the binding-dir trim is exercised.build: macOS leg now runs the smoke test too (runner has a window server; brew gtk3 + the fixture's Gtk4→Gtk3 fallback).scripts/bundle-smoke-test.jsplatform gate removed — it already asserts the app ran under the bundled node on every OS.Honest-caveat follow-up (documented in the roadmap): the macOS runner has Homebrew, so the DYLD-fallback path isn't truly exercised in CI; a clean-machine consume job mirroring
test-windows-prebuilt.yamlis future work.Docs
doc/bundling.md: "Linux today" banner replaced with per-platform notes (bundling-machine requirements, launcher wiring, archive formats, macOS distribution reality); roadmap updated. README updated.HANDOFF.mddeleted — mission complete.Validated locally on Linux (bundle smoke + flatpak generation smoke both PASS); Windows/macOS validate through the new CI steps.
🤖 Generated with Claude Code