Skip to content

Commit 3337f00

Browse files
authored
Fix/macos py2app libsharpyuv (shlomif#587)
* Bundle libsharpyuv for macOS py2app build py2app doesn't rewrite @rpath load commands, so libwebp's dependency on libsharpyuv (split out since webp 1.3) goes missing from the app bundle and PIL fails to import at launch. Bundle and patch it explicitly, same as the freecell-solver lib. * Re-sign macOS bundle after post-py2app dylib patching install_name_tool invalidates py2app's ad-hoc signature, so a bundle patched after signing (e.g. the libsharpyuv fix, or the existing fc-solve rpath fix) gets silently SIGKILLed by macOS on launch. Verified locally: without this, the fixed app dies with no output at all: the patched dylib breaks the code signature seal.
1 parent 327ad87 commit 3337f00

1 file changed

Lines changed: 40 additions & 2 deletions

File tree

setup_osx.py

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import os
77
import shutil
88
import sys
9-
from subprocess import call
9+
from subprocess import CalledProcessError, call, check_output
1010

1111
from pysollib.settings import PACKAGE, VERSION
1212

@@ -36,6 +36,19 @@
3636
SOLVER_LIB_PATH = None
3737
SOLVER = []
3838

39+
# libwebp (a Pillow dependency) depends on libsharpyuv via a bare
40+
# @rpath reference that py2app's dependency walker doesn't follow.
41+
# Bundle it explicitly, same as the solver lib above.
42+
SHARPYUV_LIB_PATH = None
43+
try:
44+
_webp_prefix = check_output(
45+
["brew", "--prefix", "webp"]).decode().strip()
46+
_candidate = os.path.join(_webp_prefix, "lib", "libsharpyuv.0.dylib")
47+
if os.path.exists(_candidate):
48+
SHARPYUV_LIB_PATH = _candidate
49+
except (OSError, CalledProcessError):
50+
pass
51+
3952
GETINFO_STRING = "PySol Fan Club Edition \
4053
%s %s, (C) 1998-2003 Markus F.X.J Oberhumer \
4154
(C) 2006-2007 Skomoroh" % (PACKAGE, VERSION)
@@ -55,7 +68,8 @@
5568
DATA_FILES = ['docs', 'data', 'locale', 'scripts', 'COPYING', 'README.md',
5669
] + SOLVER
5770
RESOURCES = []
58-
FRAMEWORKS = [SOLVER_LIB_PATH] if SOLVER_LIB_PATH else []
71+
FRAMEWORKS = ([SOLVER_LIB_PATH] if SOLVER_LIB_PATH else []) + \
72+
([SHARPYUV_LIB_PATH] if SHARPYUV_LIB_PATH else [])
5973
# with argv_emulation=True, the app window is not shown when launched
6074
OPTIONS = dict(argv_emulation=False,
6175
emulate_shell_environment=True,
@@ -84,3 +98,27 @@
8498
@executable_path/../Frameworks/libfreecell-solver.0.dylib fc-solve",
8599
shell=True
86100
)
101+
os.chdir(top)
102+
103+
# Point libwebp at the bundled libsharpyuv instead of its broken
104+
# original rpath.
105+
if SHARPYUV_LIB_PATH and "py2app" in sys.argv:
106+
frameworks_dir = os.path.join(
107+
top, 'dist', '%s.app' % PACKAGE, 'Contents', 'Frameworks')
108+
for name in os.listdir(frameworks_dir):
109+
if name.startswith('libwebp'):
110+
call([
111+
'install_name_tool', '-change',
112+
'@rpath/libsharpyuv.0.dylib',
113+
'@executable_path/../Frameworks/libsharpyuv.0.dylib',
114+
os.path.join(frameworks_dir, name),
115+
])
116+
117+
# install_name_tool invalidates py2app's ad-hoc signature above, and
118+
# macOS refuses to launch a bundle whose seal doesn't match its
119+
# contents. Re-sign after any post-processing.
120+
if (SOLVER or SHARPYUV_LIB_PATH) and "py2app" in sys.argv:
121+
call([
122+
'codesign', '--force', '--deep', '--sign', '-',
123+
os.path.join(top, 'dist', '%s.app' % PACKAGE),
124+
])

0 commit comments

Comments
 (0)