Skip to content

fix(build): generalize the lcms2 dylib-collision check to the whole macOS bundle - #841

Merged
marcinz606 merged 1 commit into
marcinz606:mainfrom
thetalkingdrum:fix/pyinstaller-bundled-so-smoke-test
Aug 15, 2026
Merged

fix(build): generalize the lcms2 dylib-collision check to the whole macOS bundle#841
marcinz606 merged 1 commit into
marcinz606:mainfrom
thetalkingdrum:fix/pyinstaller-bundled-so-smoke-test

Conversation

@thetalkingdrum

Copy link
Copy Markdown
Contributor

Summary

  • fix_lcms2_dylib_collision() (fix(export): restore ICC color management on Flat/Print exports #833) hardened only liblcms2.2.dylib against PyInstaller's habit of collapsing same-basename dylibs vendored by multiple packages (cv2/PIL/rawpy/imagecodecs) into one arbitrary canonical copy — the bug that silently broke ICC-managed exports on arm64.
  • That fix's own investigation notes (LIBLCMS2_DYLIB_COLLISION.md) flagged this as a general bug class, not an lcms2-specific one, and named it as a follow-up worth building.
  • check_bundled_dylib_collisions() generalizes the same symbol-closure check to every same-basename collision under Contents/Frameworks, instead of a curated list of "risky" library names — a manual pass reasoning about which libraries might collide missed a real one (three packages vendor byte-different copies of libjpeg.8.3.2.dylib). The scan also found real, currently-benign collisions on libpng16.16.dylib and libtiff.6.dylib (cv2 vs PIL).
  • Runs at macOS build time only, right after fix_lcms2_dylib_collision(); raises (fails the build) rather than warns, matching that function's precedent.
  • Deliberately does not address the libomp.dylib/numba omppool gap noted in the same doc — that's PyInstaller not bundling a library at all, a different failure mode than a collision between multiple bundled copies, and there's still no evidence it affects NegPy (numba's OpenMP pool is optional with a runtime fallback).

Test plan

  • make lint / make type clean
  • Full test suite: 4015 passed (2 pre-existing, unrelated failures from a missing optional pyopticfilm dep in this environment, from Add Plustek (USB) scanner backend for OpticFilm 8200i SE and enable the Scan tab on Windows #783)
  • Ran check_bundled_dylib_collisions() against the real local packaged .app — passes clean
  • Verified the raise path fires correctly: forced the libtiff.6.dylib canonical symlink to point at a copy missing a symbol a real consumer needs, confirmed it raises with the right detail, restored it

…acOS bundle

cv2, PIL, rawpy and imagecodecs each vendor their own copies of common
dylibs (libjpeg, libpng, libtiff, ...) under identical filenames, and
PyInstaller keeps only one arbitrary pick as the canonical @rpath target
for all of them -- the exact bug class that broke ICC export in marcinz606#833.
check_bundled_dylib_collisions() scans every same-basename collision in
Contents/Frameworks instead of a curated list of known-risky basenames,
which caught a real libjpeg.8.3.2.dylib collision a manual pass missed.

Verified against the real local .app: passes clean, and correctly raises
when a canonical symlink is forced to point at a copy missing a symbol a
sibling consumer needs. Deliberately does not touch the libomp.dylib/numba
gap noted alongside this follow-up -- that's absence, not a collision, and
still has no evidence of user impact.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@marcinz606
marcinz606 merged commit 19de4b7 into marcinz606:main Aug 15, 2026
1 check passed
@thetalkingdrum
thetalkingdrum deleted the fix/pyinstaller-bundled-so-smoke-test branch August 15, 2026 19:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants