Skip to content

Commit

Permalink
Fix darwin pack segment bug
Browse files Browse the repository at this point in the history
  • Loading branch information
jondy committed May 19, 2023
1 parent a58db9d commit 8c43579
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 68 deletions.
11 changes: 2 additions & 9 deletions src/cli/generate.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,15 +141,8 @@ def process(self, options, packer=None):
finder = Finder(self.ctx)
finder.process()

if packer:
if options.get('self_contained'):
finder.process_extra(packer.contents)
if getattr(packer, 'is_darwin_python', None):
sect = self.ctx.cfg['builder']
plugins = sect.get('plugins', '').split()
if 'DylibPlugin' not in plugins:
logger.info('implicitly enable plugin "DylibPlugin"')
sect.set('plugins', ' '.join(plugins + ['DylibPlugin']))
if packer and options.get('self_contained'):
finder.process_extra(packer.contents)

Pytransform3.pre_build(self.ctx)

Expand Down
63 changes: 10 additions & 53 deletions src/cli/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
from . import logger


__all__ = ['PycPlugin']
__all__ = ['PycPlugin', 'CodesignPlugin']


class Plugin(object):
Expand Down Expand Up @@ -100,58 +100,15 @@ class CodesignPlugin:
@staticmethod
def post_runtime(ctx, source, dest, platform):
if platform.startswith('darwin'):
from subprocess import Popen, PIPE
from subprocess import check_call, CalledProcessError, DEVNULL
identity = '-'
cmdlist = ['codesign', '-s', identity, '--force',
cmdlist = ['codesign', '-f', '-s', identity,
'--all-architectures', '--timestamp', dest]
logger.info('%s', ' '.join(cmdlist))
p = Popen(cmdlist, stdout=PIPE, stderr=PIPE, shell=True)
stdout, stderr = p.communicate()
if p.returncode != 0:
logger.warning(
'codesign command (%r) failed with error code %d!\n'
'stdout: %r\n'
'stderr: %r',
cmdlist, p.returncode, stdout, stderr)


class DylibPlugin:

@staticmethod
def post_runtime(ctx, source, dest, platform):
if platform.startswith('darwin'):
from subprocess import Popen, PIPE, check_output
from sys import version_info

output = check_output(['otool', '-L', dest])
for line in output.splitlines():
if line.find(b'@rpath/Python'):
logger.debug('"%s" has been patched by DylibPlugin', dest)
return

pyver = '%s.%s' % version_info[:2]
cmdlist = ['install_name_tool', '-change',
'@rpath/lib/libpython%s.so' % pyver, '@rpath/Python',
dest]
logger.info('%s', ' '.join(cmdlist))
p = Popen(cmdlist, stdout=PIPE, stderr=PIPE, shell=True)
stdout, stderr = p.communicate()
if p.returncode != 0:
logger.warning(
'install_name_tool command failed with error code %d!\n'
'stdout: %r\n'
'stderr: %r',
p.returncode, stdout, stderr)

identity = '-'
cmdlist = ['codesign', '-s', identity, '--force',
'--all-architectures', '--timestamp', dest]
logger.info('%s', ' '.join(cmdlist))
p = Popen(cmdlist, stdout=PIPE, stderr=PIPE, shell=True)
stdout, stderr = p.communicate()
if p.returncode != 0:
logger.warning(
'codesign command failed with error code %d!\n'
'stdout: %r\n'
'stderr: %r',
p.returncode, stdout, stderr)
try:
check_call(cmdlist, stdout=DEVNULL, stderr=DEVNULL)
except CalledProcessError as e:
logger.warning('codesign command failed with error code %d',
e.returncode)
except Exception as e:
logger.warning('codesign command failed with:\n%s', e)
36 changes: 30 additions & 6 deletions src/cli/repack.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import tempfile

from importlib._bootstrap_external import _code_to_timestamp_pyc
from subprocess import check_call
from subprocess import check_call, check_output, DEVNULL

from PyInstaller.archive.writers import ZlibArchiveWriter, CArchiveWriter
from PyInstaller.archive.readers import CArchiveReader
Expand Down Expand Up @@ -242,7 +242,8 @@ def repack_carchive(executable, pkgfile, buildpath, obfpath, rtentry):
logical_toc = pkgarch.get_logical_toc(buildpath, obfpath)
if rtentry is not None:
logical_toc.append(rtentry)
CArchiveWriter2(pkgarch, pkgfile, logical_toc, pylib_name.decode('utf-8'))
pylib_name = pylib_name.strip(b'\x00').decode('utf-8')
CArchiveWriter2(pkgarch, pkgfile, logical_toc, pylib_name)


def repack_executable(executable, buildpath, obfpath, rtentry, codesign=None):
Expand Down Expand Up @@ -315,6 +316,10 @@ def extract_carchive(self, executable, buildpath, clean=True):
pkgarch = CArchiveReader2(executable)
pkgtoc = pkgarch.get_toc()

with open(executable, 'rb') as fp:
*_, pylib_name = pkgarch.get_cookie_info(fp)
self.pylib_name = pylib_name.strip(b'\x00').decode('utf-8')

for name, toc_entry in pkgtoc.items():
logger.debug('extract %s', name)
*_, typecode = toc_entry
Expand All @@ -324,10 +329,6 @@ def extract_carchive(self, executable, buildpath, clean=True):
self.pyztoc = pyzarch.toc
contents.append(extract_pyzarchive(name, pyzarch, buildpath))

elif (is_darwin and typecode == PKG_ITEM_BINARY and
name.strip('.') == 'Python'):
self.is_darwin_python = True

self.contents = contents
self.one_file_mode = len(pkgtoc) > 10

Expand Down Expand Up @@ -361,6 +362,8 @@ def repack(self, obfpath, rtname, entry=None):

if is_darwin:
from PyInstaller.depend import dylib
if self.pylib_name == 'Python':
self._fixup_darwin_dylib(rtbinary)
logger.debug('mac_set_relative_dylib_deps "%s"', rtbinname)
dylib.mac_set_relative_dylib_deps(rtbinary, rtbinname)

Expand All @@ -371,3 +374,24 @@ def repack(self, obfpath, rtname, entry=None):
shutil.copy2(rtbinary, dest)

repack_executable(executable, buildpath, obfpath, rtentry)

def _fixup_darwin_dylib(self, rtbinary):
from sys import version_info
pyver = '%s.%s' % version_info[:2]
output = check_output(['otool', '-L', rtbinary])
for line in output.splitlines():
if line.find(b'libpython%s.dylib' % pyver.encode()) > 0:
reflib = line.split()[0].decode('utf-8')
break
elif line.find(b'@rpath/Python') > 0:
return
else:
raise RuntimeError('fixup dylib failed, no CPython library found')

cmdlist = ['install_name_tool', '-change', reflib, '@rpath/Python',
rtbinary]
logger.info('%s', ' '.join(cmdlist))
try:
check_call(cmdlist, stdout=DEVNULL, stderr=DEVNULL)
except Exception as e:
logger.warning('install_name_tool command failed with:\n%s', e)

0 comments on commit 8c43579

Please sign in to comment.