📜 ⬆️ ⬇️

The complexity of building Python3 + Qt5 applications under Windows

Recently it took me to make a small program under Windows. Previously, I could not develop under it.
The program itself is simple, it was written relatively quickly. Much more time was taken away by its assembly under Windows. It is clear that the selected tools (Python3 + Qt5) are not native, but universal, but it took me so much time to build.
Accordingly, I want to share the practice, maybe someone else will have to knock his forehead on this wall.
Under the cut, the instructions come out of how easy it is to build PyQt5 applications in single-file.exe that do not require an installer.

The most well-known solutions for my task - assembling python applications in .exe are: py2exe, cx_freeze, and pyinstaller. About each written a lot of things. But very often the authors sin with a hack - the program is easily and quickly assembled and started ... on the same computer. Needless to say that these are two big differences - the launch on the dev-environment and the user? And so it will work for me without any assemblies and dances with a tambourine. Also, which users will install Qt for themselves?

For each tool there is a tutorial. But each had its own problems: one did not start (the pyinstaller still supports the 3rd python in experimental mode), the other collected what it could not launch, the third didn’t collect anything for a long time, berating everything around.
After a long battle, py2exe was chosen.

The secret of success in the correct installation of components from the correct sources (I do not give direct links, since they are still obsolete, I write what to look for):

')
I share my setup.py:

from distutils.core import setup import os, sys import py2exe from glob import glob import PyQt5 NAME="Proga" qt_platform_plugins = [("platforms", glob(PyQt5.__path__[0] + r'\plugins\platforms\*.*'))] data_files.extend(qt_platform_plugins) msvc_dlls = [('.', glob(r'C:\Windows\System32\msvc?100.dll'))] data_files.extend(msvc_dlls) # print(data_files) sys.argv.append('py2exe') setup( data_files=data_files, windows=[ { "script": "pyftp1.py", "icon_resources": [(0, "resources/favicon.ico")] } ], # zipfile=None, options={ "py2exe": { "includes":["sip", "atexit",], #       atexit   , sip   -      # "packages": ['PyQt5'], "compressed": True, "dist_dir": "dist/" + NAME, # "bundle_files": 0, #   (          msvc*.dll # "zipfile": None, #   "optimize": 2, } } ) 


This is a minimum program. Now you can build the application itself:
 python setup.py py2exe 


At the output we get a folder with the finished prog in dist.
This is good, but not always convenient for users. You can set an installer creator on this folder, such as Inno Setup and get msi. In my case, it was necessary to ensure the operation of the program with minimal user rights - precisely without the right to install lib.

So I went ahead and packed into 1 file using 7-zip. The scheme is as follows: create a 7z-archive and a special SFX-head and config are docked to it. The head unpacks the archive into a temporary folder, looks into the config and launches the necessary exe-file. Going like this:
cat 7zS.sfx resources / config.txt Proga.7z> Proga.exe

You can specify various options in the config file, I set the minimum:
 ;!@Install@!UTF-8! Title="Proga" RunProgram="Proga\\pyftp1.exe" ;!@InstallEnd@! 


The only drawback is the ugly picture of the exe file - the standard unpacker. This is where we replace the picture with the one we need:
RESHACKER.exe -addoverwrite Proga.exe, Proga.exe, resources / favicon.ico, ICONGROUP, MAINICON, 0

In order not to suffer with this all in the console, I made a small Makefile:
 # start settings DIST=dist # change NAME also in setup.py and resource/config.txt NAME=Proga EXT=exe # final name and location of the built program FINAL=$(DIST)/$(NAME).$(EXT) # external programs 7ZIPDIR="C:\Program Files\7-Zip" RESHACKER="/c/Program\ Files/Resource\ Hacker/ResourceHacker.exe" # intermediate steps # no icon version of program NOICON=$(DIST)/$(NAME)_no_icon.$(EXT) # name of .7z archive 7Z_BASENAME=$(NAME).7z 7Z=$(DIST)/$(7Z_BASENAME) # folder with ready .exe PROGDIR=$(DIST)/$(NAME) all: $(FINAL) $(FINAL): $(NOICON) # change icon "$(RESHACKER)" -addoverwrite $(NOICON), $(FINAL), resources/favicon.ico, ICONGROUP, MAINICON, 0 $(NOICON): $(7Z) #build autorunning sfx with default icon cat $(7ZIPDIR)/7zS.sfx resources/config.txt $(7Z) > $(NOICON) $(7Z): exe # compress program folder to .7z cd $(DIST); $(7ZIPDIR)\\\7z.exe a $(7Z_BASENAME) $(NAME) exe: $(DIST) # build program itself python setup.py py2exe $(DIST): # create dist directory # echo $(DIST)/ clean: rm -rf $(DIST)/* 


Now you can very easily reassemble the program:
 mingw492-make.exe clean all 


Successes in assembly!
Tell us about your experience!

Source: https://habr.com/ru/post/264233/


All Articles