Skip to content

Commit

Permalink
building: limit package import in binary dependency analysis to Windows
Browse files Browse the repository at this point in the history
Limit the collected package import in the binary dependency analysis
subprocess (performed prior to the actual analysis) to Windows.

Windows is the only platform where the packages' initialization
code can modify shared library search paths (either by modifying
`PATH` environment variables, or by calling `os.add_dll_search_path`),
so importing the collected packages to initialize the environment
makes sense only there.

Furthermore, non-deterministic package import order may cause issues
with particular package combinations and import orders, so it is
better to avoid it where we do not need it (i.e., on non-Windows
platforms).
  • Loading branch information
rokm committed Jun 10, 2023
1 parent d44373a commit b9ddc35
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 17 deletions.
39 changes: 22 additions & 17 deletions PyInstaller/building/build_main.py
Expand Up @@ -159,32 +159,37 @@ def find_binary_dependencies(binaries, binding_redirects, import_packages):
if compat.is_win:
extra_libdirs.append(compat.base_prefix)

# On Windows with python >= 3.8, attempt to track calls to os.add_dll_directory() to obtain DLL search paths that
# are dynamically set during packages' initialization.
if compat.is_win and compat.is_py38:
added_dll_directories = []
_orig_add_dll_directory = os.add_dll_directory
# On Windows, packages' initialization code might register additional DLL search paths, either by modifying the
# `PATH` environment variable, or (on pythonn >= 3.8) by calling `os.add_dll_directory`. Therefore, we import
# all collected packages, and track changes made to the environment.
if compat.is_win:
# Track changes made via `os.add_dll_directory`.
if compat.is_py38:
added_dll_directories = []
_orig_add_dll_directory = os.add_dll_directory

def _pyi_add_dll_directory(path):
added_dll_directories.append(path)
return _orig_add_dll_directory(path)
def _pyi_add_dll_directory(path):
added_dll_directories.append(path)
return _orig_add_dll_directory(path)

os.add_dll_directory = _pyi_add_dll_directory
os.add_dll_directory = _pyi_add_dll_directory

# Import collected packages to set up environment
for package in import_packages:
try:
__import__(package)
except Exception:
pass
# Import collected packages to set up environment.
for package in import_packages:
try:
__import__(package)
except Exception:
pass

# Process extra search paths on Windows
if compat.is_win:
# Process extra search paths...
# Directories added via os.add_dll_directory() calls.
if compat.is_py38:
logger.info("Extra DLL search directories (AddDllDirectory): %r", added_dll_directories)
extra_libdirs += added_dll_directories

# Restore original function
os.add_dll_directory = _orig_add_dll_directory

# Directories set via PATH environment variable.
# NOTE: PATH might contain empty entries that need to be filtered out.
path_directories = [directory for directory in os.environ.get("PATH", '').split(os.pathsep) if directory]
Expand Down
4 changes: 4 additions & 0 deletions news/7698.bugfix.rst
@@ -0,0 +1,4 @@
Limit the import of collected packages prior to performing binary
dependency analysis to only Windows, where it is actually useful.
On non-Windows platforms, there is no benefit to it, and it might
cause issues with particular orders of package imports.

1 comment on commit b9ddc35

@peterramses
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how does this code actually do

Please sign in to comment.