stlehmann / pyads

Python wrapper for TwinCAT ADS
MIT License
254 stars 94 forks source link

pyinstaller executable on windows - application startup fails #283

Closed ScherzerThomas closed 2 years ago

ScherzerThomas commented 2 years ago

Windows executable, created using pyinstaller fails at application startup. It seems that the dll "TcAdsDLL" is missing in the created temporary folder, see errorlog.txt

I tried to add the dll at the pyinstaller setup (I think wrong), but it had no effect. I used the following call, (and previously copied TcAdsDll.dll (right version for target machine) to 'data' directory): pyinstaller TestScript.py --onefile --clean --debug=all --add-binary data/TcAdsDll.dll;.\

Python 3.7.9, 32bit (because exe should also run on older machines)

ScherzerThomas commented 2 years ago

Now I've tried it again with python 3.9.6, with a similar result. I added the dll to the pyinstaller configuration (I can see the dll it in the temporary folder), but it isn't found/accepted by the runtime

ErrorAfterCopyingDll

chrisbeardy commented 2 years ago

When running, I believe the application should look for the DLL to be in the normal twincat path, e.g. C :/ TwinCat/3.1.... do you have twincat installed on the pc that is running the python application? If not you need to install at a minimum the twincat ads version. This installs only the ads router on the pc and not the runtime or engineering version.

ScherzerThomas commented 2 years ago

Hello,

I've installed TwinCAT on the machine (including the XAE shell, version 4024.20). The dlls are existing on the machine, and the environment variables are fine paths

So, the executable doesn't even work on the development machine. In contrast, when i use the same script (and execute it (in VSCode)), everything is fine and the ads access is possible without problems Should i create a mwe?

chrisbeardy commented 2 years ago

There's a few things which may be causing this. I believe it is likely a installer related issue. I regularly use pyinstaller with pyads with no such problems and do not have to specify any additional binary data. Although I only tend to use 64 bit.

Can you try building a basic application, e.g. a few line script that that just reads a single variable from the PLC and closes. and try to freeze a 64 bit version of that only using pyinstaller TestScript.py --onefile. And see what happens.

chrisbeardy commented 2 years ago

If that works then I suspect it could be a 64 bit / 32 bit issue or an issue with the right DLL etc.

ScherzerThomas commented 2 years ago

Hello, i've played a bit, the error is still the same (see at the end).

@chrisbeardy I think your guess is right, the 64bit python version works fine. It would be fine if 32bit also works, since we've still some TC2 machines, where only 32bit windows is supported (and win7).

I've made two different setups (x86 and x64), you can find them here, play with them: https://github.com/ScherzerThomas/PyInstallerAdsTest https://github.com/ScherzerThomas/PyInstallerAdsTestx64

Some logs are in the folder BugData. The TwinCAT project is also included, if you need it (TC3)

Logfile x86 `Traceback (most recent call last): File "PyInstaller\loader\pyimod04_ctypes.py", line 77, in init File "C:\Users\User\AppData\Local\Programs\Python\Python39-32\lib\ctypes__init.py", line 374, in init__ self._handle = _dlopen(self._name, mode) OSError: [WinError 193] %1 is not a valid Win32 application

The above exception was the direct cause of the following exception:

Traceback (most recent call last): File "TestScript.py", line 1, in File "", line 1007, in _find_and_load File "", line 986, in _find_and_load_unlocked File "", line 680, in _load_unlocked File "", line 850, in exec_module File "", line 228, in _call_with_frames_removed File "c:\users\user\source\repos\pyinstalleradstest.venv\lib\site-packages\pyads__init.py", line 10, in from .ads import ( File "", line 1007, in _find_and_load File "", line 986, in _find_and_load_unlocked File "", line 680, in _load_unlocked File "", line 850, in exec_module File "", line 228, in _call_with_frames_removed File "c:\users\user\source\repos\pyinstalleradstest.venv\lib\site-packages\pyads\ads.py", line 57, in from .pyads_ex import ( File "", line 1007, in _find_and_load File "", line 986, in _find_and_load_unlocked File "", line 680, in _load_unlocked File "", line 850, in exec_module File "", line 228, in _call_with_frames_removed File "c:\users\user\source\repos\pyinstalleradstest.venv\lib\site-packages\pyads\pyads_ex.py", line 68, in _adsDLL = ctypes.WinDLL("TcAdsDll.dll") # type: ignore File "PyInstaller\loader\pyimod04_ctypes.py", line 79, in init__ pyimod04_ctypes.PyInstallerImportError: Failed to load dynlib/dll 'C:\Users\User\AppData\Local\Temp\_MEI64522\TcAdsDll.dll'. Most likely this dynlib/dll was not found when the application was frozen. [10032] Failed to execute script 'TestScript' due to unhandled exception!`

chrisbeardy commented 2 years ago

Is it possible that the DLL installed on a 64 not windows is only 64 bit compatible? I'm afraid this is now getting outside my understanding. I would try running the exe on a 32 bit machine and/or freezing it on one too just to see what happens. But I defo think is just a configuration and pyinstaller issue. You could create an issue at pyinstaller about general c extension with DLLs to see if they have a better idea.

chrisbeardy commented 2 years ago

have you got any further with this issue @ScherzerThomas? I think this is a pyinstaller related issue, if you believe so could you please close this issue on pyads. Thanks.

ScherzerThomas commented 2 years ago

@chrisbeardy Hello, i've tried to build the application on a 32bit windows machine now, it's working there. To summarize, cross compilation (32bit application on 64bit machine) is not possible.

stlehmann commented 2 years ago

@ScherzerThomas great it worked out for you. I'll close this issue now. Feel free to comment or reopen if there should be any further issues.