Repository: pyinstaller/pyinstaller

Issue:
DLL packaging problem under Windows 10 PySide6 6.3 (works fine under PySide6 6.2)
<!--
Welcome to the PyInstaller issue tracker! Before creating an issue, please heed the following:

1. This tracker should only be used to report bugs and request features / enhancements to PyInstaller
    - For questions and general support, use the mailing list, see
	  <http://www.pyinstaller.org/support.html#mailing-list>
2. Use the search function before creating a new issue. Duplicates will be closed and directed to
   the original discussion.
3. When making a bug report, make sure you provide all required information. The easier it is for
   maintainers to reproduce, the faster it'll be fixed.
-->

<!-- +++ ONLY TEXT +++ DO NOT POST IMAGES +++ -->

## Description of the issue
When building on Windows, using PySide6 6.3 or later, the packaged app fails to run, popping up an "Unhandled exception in script" dialog, with the error:
"ImportError: DLL load failed while importing QtCore: The specified module could not be found."

The error does not occur when packaging with PySide 6.2.4.

### Context information (for bug reports)

* Output of `pyinstaller --version`: ```5.1```
* Version of Python: Python 3.10.5
* Platform: Windows-10-10.0.19044-SP0
* How you installed Python: Windows installer from python.org/downloads
* Did you also try this on another platform? Does it work there?
Yes, the build works fine on macOS 10.14

* try the latest development version, using the following command:

```shell
pip install https://github.com/pyinstaller/pyinstaller/archive/develop.zip
```

Tried this, but it made no difference.

The pyinstaller output suggests that some Microsoft runtime DLLs from Shiboken are not being packaged:

54847 INFO: Looking for dynamic libraries
1080 WARNING: lib not found: Qt6Pdf.dll dependency of C:\JamesWorkArea\Code\multiscript\venv3.10\lib\site-packages\PySide6\plugins\imageformats\qpdf.dll
1111 WARNING: lib not found: MSVCP140.dll dependency of C:\JamesWorkArea\Code\multiscript\venv3.10\lib\site-packages\PySide6\plugins\tls\qcertonlybackend.dll
1166 WARNING: lib not found: MSVCP140.dll dependency of C:\JamesWorkArea\Code\multiscript\venv3.10\lib\site-packages\PySide6\plugins\tls\qopensslbackend.dll1208 WARNING: lib not found: api-ms-win-shcore-scaling-l1-1-1.dll dependency of C:\JamesWorkArea\Code\multiscript\venv3.10\lib\site-packages\PySide6\plugins\platforms\qwindows.dll
1215 WARNING: lib not found: MSVCP140.dll dependency of C:\JamesWorkArea\Code\multiscript\venv3.10\lib\site-packages\PySide6\plugins\platforms\qwindows.dll
1339 WARNING: lib not found: MSVCP140.dll dependency of C:\JamesWorkArea\Code\multiscript\venv3.10\lib\site-packages\PySide6\plugins\tls\qschannelbackend.dll
1444 WARNING: lib not found: api-ms-win-shcore-scaling-l1-1-1.dll dependency of C:\JamesWorkArea\Code\multiscript\venv3.10\lib\site-packages\PySide6\plugins\platforms\qdirect2d.dll
1453 WARNING: lib not found: MSVCP140.dll dependency of C:\JamesWorkArea\Code\multiscript\venv3.10\lib\site-packages\PySide6\plugins\platforms\qdirect2d.dll1513 WARNING: lib not found: MSVCP140.dll dependency of C:\JamesWorkArea\Code\multiscript\venv3.10\lib\site-packages\PySide6\plugins\networkinformation\qnetworklistmanager.dll
1706 WARNING: lib not found: MSVCP140_2.dll dependency of C:\JamesWorkArea\Code\multiscript\venv3.10\lib\site-packages\PySide6\QtGui.pyd
1736 WARNING: lib not found: MSVCP140.dll dependency of C:\JamesWorkArea\Code\multiscript\venv3.10\lib\site-packages\PySide6\QtGui.pyd
1782 WARNING: lib not found: MSVCP140.dll dependency of C:\JamesWorkArea\Code\multiscript\venv3.10\lib\site-packages\PySide6\QtWidgets.pyd
1820 WARNING: lib not found: MSVCP140.dll dependency of C:\JamesWorkArea\Code\multiscript\venv3.10\lib\site-packages\PySide6\QtCore.pyd
1852 WARNING: lib not found: MSVCP140.dll dependency of C:\JamesWorkArea\Code\multiscript\venv3.10\lib\site-packages\PySide6\QtNetwork.pyd
1976 WARNING: lib not found: MSVCP140_1.dll dependency of C:\JamesWorkArea\Code\multiscript\venv3.10\Lib\site-packages\PySide6\Qt6Gui.dll
1988 WARNING: lib not found: MSVCP140.dll dependency of C:\JamesWorkArea\Code\multiscript\venv3.10\Lib\site-packages\PySide6\Qt6Gui.dll
2013 WARNING: lib not found: MSVCP140_2.dll dependency of C:\JamesWorkArea\Code\multiscript\venv3.10\Lib\site-packages\PySide6\Qt6Gui.dll
2091 WARNING: lib not found: MSVCP140_1.dll dependency of C:\JamesWorkArea\Code\multiscript\venv3.10\Lib\site-packages\PySide6\Qt6Core.dll
2103 WARNING: lib not found: MSVCP140.dll dependency of C:\JamesWorkArea\Code\multiscript\venv3.10\Lib\site-packages\PySide6\Qt6Core.dll
2151 WARNING: lib not found: MSVCP140.dll dependency of C:\JamesWorkArea\Code\multiscript\venv3.10\Lib\site-packages\PySide6\Qt6Network.dll
2219 WARNING: lib not found: MSVCP140_1.dll dependency of C:\JamesWorkArea\Code\multiscript\venv3.10\Lib\site-packages\PySide6\Qt6Widgets.dll
2235 WARNING: lib not found: MSVCP140.dll dependency of C:\JamesWorkArea\Code\multiscript\venv3.10\Lib\site-packages\PySide6\Qt6Widgets.dll
2290 WARNING: lib not found: MSVCP140.dll dependency of C:\JamesWorkArea\Code\multiscript\venv3.10\Lib\site-packages\PySide6\Qt6VirtualKeyboard.dll
2365 WARNING: lib not found: MSVCP140.dll dependency of C:\JamesWorkArea\Code\multiscript\venv3.10\Lib\site-packages\PySide6\Qt6Qml.dll
2472 WARNING: lib not found: MSVCP140.dll dependency of C:\JamesWorkArea\Code\multiscript\venv3.10\lib\site-packages\PySide6\pyside6.abi3.dll
2581 WARNING: lib not found: MSVCP140_1.dll dependency of C:\JamesWorkArea\Code\multiscript\venv3.10\Lib\site-packages\PySide6\Qt6Quick.dll
2594 WARNING: lib not found: MSVCP140.dll dependency of C:\JamesWorkArea\Code\multiscript\venv3.10\Lib\site-packages\PySide6\Qt6Quick.dll
2611 WARNING: lib not found: MSVCP140_2.dll dependency of C:\JamesWorkArea\Code\multiscript\venv3.10\Lib\site-packages\PySide6\Qt6Quick.dll



Discussion:
Hmm... looks like`PySide6` 6.3.x moved the bundled VC runtime DLLs from `PySide6` directory into `shiboken6` one, and our library search fails to find them there. 

I suppose the most sure-fire way to work around this is to ensure that VC runtime is installed on your build system, so the DLLs end up collected from there. Or manually copying them back from `shiboken6` into `PySide6`.

Long-term, we'll have to check if we can make our library search on Windows a bit smarter, accounting for search paths added via `PATH` and `AddDllDirectory`. 
FWIW, having VC runtime DLLs in `shiboken6` instead `PySide6` directory also seems to break `PySide6` 6.3.x under python 3.7 on Windows systems without VC runtime installed (i.e., without PyInstaller involved); the `os.add_dll_directory()` is not available in that python version and therefore dynamic DLL search path is not set correctly.

Resolving patch:
diff --git a/PyInstaller/building/build_main.py b/PyInstaller/building/build_main.py
--- a/PyInstaller/building/build_main.py
+++ b/PyInstaller/building/build_main.py
@@ -140,7 +140,10 @@ def find_binary_dependencies(binaries, binding_redirects, import_packages):
 
     :return: expanded list of binaries and then dependencies.
     """
+    import os
+
     from PyInstaller.depend import bindepend
+    from PyInstaller.building.build_main import logger
     from PyInstaller import compat
 
     # In the case of MS App Store python, add compat.base_prefix to extra library search paths. In addition to
@@ -151,6 +154,18 @@ def find_binary_dependencies(binaries, binding_redirects, import_packages):
     if compat.is_ms_app_store:
         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
+
+        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
+
     # Import collected packages to set up environment
     for package in import_packages:
         try:
@@ -158,6 +173,19 @@ def find_binary_dependencies(binaries, binding_redirects, import_packages):
         except Exception:
             pass
 
+    # Process extra search paths on Windows
+    if compat.is_win:
+        # 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
+
+        # 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]
+        logger.info("Extra DLL search directories (PATH): %r", path_directories)
+        extra_libdirs += path_directories
+
     # Search for dependencies of the given binaries
     return bindepend.Dependencies(binaries, redirects=binding_redirects, xtrapath=extra_libdirs)
 


Test patch: