Skip to content

Commit

Permalink
building: collect built-in extensions into lib-dynload sub-directory
Browse files Browse the repository at this point in the history
On macOS and linux, some of the python's built-ins have extension
modules that originally reside in python3.X/lib-dynload directory.
This directory is in sys.path, therefore the collected extensions
have no parent directory and end up directly in the _MEIPASS.

This commit explicitly diverts such extensions into lib-dynload
sub-directory in the _MEIPASS.

In addition to decluttering the _MEIPASS on linux and macOS, this
also prevents ctypes.CDLL() from picking up the extensions'
shared libraries and causing inconsistent behavior between
frozen and unfrozen application, which in some corner cases
leads to issues with shadowing, such as in pyinstaller#5583.
  • Loading branch information
rokm committed Mar 18, 2021
1 parent 402006f commit d7ba2dd
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 1 deletion.
6 changes: 5 additions & 1 deletion PyInstaller/building/api.py
Expand Up @@ -829,7 +829,11 @@ def _set_dependencies(self, analysis, path):
# relative path needs to be reconstructed from the
# name components.
if tpl[2] == 'EXTENSION':
ext_components = tpl[0].split('.')[:-1]
# Split on os.path.sep first, to handle additional
# path prefix (e.g., lib-dynload)
ext_components = tpl[0].split(os.path.sep)
ext_components = ext_components[:-1] \
+ ext_components[-1].split('.')[:-1]
if ext_components:
rel_path = os.path.join(*ext_components)
else:
Expand Down
12 changes: 12 additions & 0 deletions PyInstaller/building/build_main.py
Expand Up @@ -480,6 +480,18 @@ def assemble(self):
self.binding_redirects[:] = list(set(self.binding_redirects))
logger.info("Found binding redirects: \n%s", self.binding_redirects)

# Filter binaries to adjust path of extensions that come from
# python's lib-dynload directory. Prefix them with lib-dynload
# so that we'll collect them into subdirectory instead of
# directly into _MEIPASS
for idx, tpl in enumerate(self.binaries):
name, path, typecode = tpl
if typecode == 'EXTENSION' \
and not os.path.dirname(os.path.normpath(name)) \
and os.path.basename(os.path.dirname(path)) == 'lib-dynload':
name = os.path.join('lib-dynload', name)
self.binaries[idx] = (name, path, typecode)

# Place Python source in data files for the noarchive case.
if self.noarchive:
# Create a new TOC of ``(dest path for .pyc, source for .py, type)``.
Expand Down

0 comments on commit d7ba2dd

Please sign in to comment.