Wrong python3.dll is collected if more than one Python version is installed
After packaging using the PyInstaller version 5.4.1, the application cannot be executed. Only a couple of generated dlls are different packaging the application with PyInstaller 5.3 and PyInstaller 5.4.1. One of them is python3.dll.
Replacing the python3.dll with the generated one using PyInstaller 5.3 for the packaging, solves the problem.
Can you open build/<name>/Analysis-00.toc file when building with 5.4.1 and when building 5.3, and check from where python3.dll was collected in each case?
Different versions are collected!
PyInstaller 5.3: ('python3.dll', 'C:\Python39\python3.dll', 'BINARY') PyInstaller 5.4.1: ('python3.dll', 'C:\Python310\python3.dll', 'BINARY')
Which python version are you actually using? And, are both python versions in PATH?
My application use a virtual environment with Python 3.9 but both versions are listed within PATH in following order:
...
C:\Python310
C:\Python39
....
The first to clear would be the different behavior of PyInstaller in relation with this. The second question would be why is Python 3.10 packaged if my application does not need it... Is there any way to avoid it? I can find two Python dlls in the dist folder: python3.dll python39.dll
Additional information: Python39 is in the local user PATH Python310 is in the system PATH
Hmmm, well, I think the most straightforward solution to the problem here would be to remove python 3.10 from the PATH; temporarily, in the environment that you are running PyInstaller in.
With PATH order
C:\Python310
C:\Python39
running where python3.dll in terminal with your virtual environment probably resolves the python3.dll in both installations, in that order. So by chance (or due to ordering. if the order within PyInstaller's internals is the same), we end up picking the wrong one. I'm not sure why 5.3 picks the correct one, but I wouldn't be surprised if it was up to the chance as well (off my head, I can't think of any change made between the both versions that would affect this).
(As a side note, I think python3.dll is usually required by extensions in some 3rd party package that you are using...)
Thanks rokm!
I have been able to independently and consistently reproduce this behavior with PyInstaller 5.4.1 on GitHub Actions -- where multiple python3-versions are installed and on the PATH. I cannot reproduce it with PyInstaller 5.3, however, or under environments where only one version of python3 is installed.
Two additional things I've noticed (which seems to support @rokm's hypothesis above of this being an ordering issue) is that, when this happens, the resultant PyInstaller bundle (i.e., the set of files generated by PyInstaller under the dist/ directory) will a) contain more than one python3*.dll file (e.g., a python310.dll and a python39.dll) and b) the version(s) of python3*.dll files included seems somewhat indeterminate/arbitrary (e.g., sometimes I get a python310.dll and a python39.dll, other times I get a python310.dll and a python37.dll). The latter of these is especially surprising since my project doesn't even support python3.7 (and I build my PyInstaller bundles inside tox/virtualenv where, presumably, only the specified interpreter should be used).
Now that I think about it, this is very likely a side effect of #6925 - because it extends the search path for shared libraries with paths found in PATH (among other things).
What happens is that if we collect a binary extension that is linked against python3.dll (the "unversioned" one, i.e., not python3X.dll, but python3.dll that forwards its symbols to the versioned python3X.dll), we need to find and collect that DLL. And due to multiple python installations being in PATH, we pick the wrong one (the one belonging to different python version). And because python3.dll forwards its symbols to versioned python3X.dll, we also collect that one (in addition to the correct versioned python DLL that the interpreter executable is linked against).
So we'll need to refine the DLL search path extension approach... Maybe consider only paths that are added to PATH during the package imports, which is the core idea behind #6925... or maybe handle python3.dll as a special case.
Perhaps always adding sys.base_prefix as a first search path on Windows (instead of just for MS store python) would also ensure that we pick correct python3.dll (and python3X.dll in case there are multiple installations of same version in PATH):
https://github.com/pyinstaller/pyinstaller/blob/7b2b93a186de0d47b67eed0077d748c8feb6d190/PyInstaller/building/build_main.py#L154-L155