When I try to distribute a Python program in binary, neither pyinstaller nor nuitka is a little unsatisfactory. Qt can build binaries on cross-platform, and pyqt deploy seems to be able to build binaries in Python as well. So I started it straightforwardly, but surprisingly there is no article in Japanese so I wrote it.
pyqtdeploy https://www.riverbankcomputing.com/software/pyqtdeploy/intro
https://www.riverbankcomputing.com/static/Docs/pyqtdeploy/demo.html
About 10GB of free disk Visual Studio Community Edition 2017 Perl (ActivePerl, Strawberry Perl, etc., put in PATH) Python2.7 (required to build Qt: installer version, not anaconda / miniconda) Python3.7 (for target: installer version, not anaconda / miniconda)
Put pyqt5 and pyqtdeploy with pip of Python3.
Since the number of PATH characters exceeds 255 in Qt build, make it compatible with long file names in advance by changing the registry. https://orebibou.com/2017/05/windows-10-insider-preview%E3%81%A7explorer%E3%81%A7260%E6%96%87%E5%AD%97%E4%BB%A5% See E4% B8% 8A% E3% 81% AEpath% E3% 82% 92% E5% 8F% 96% E3% 82% 8A% E6% 89% B1% E3% 81% 86 /
Pick up the sources such as Qt and Python and put them in the demo folder of the pyqt deploy source. The required source is in sysroot.json. (OpenSSL, Python, PyQt5, zlib, qt-everywhere, etc.)
--MSV 2015/2017 not found Execute the build command from the command prompt of Visual Studio. Build on 64bit: x64 Native Tools Command Prompt for VS20xx Build on 32bit: Use x86 Native Tools command prompt for VS20xx.
――The display is too small to understand the progress Display as python build-demo.py --verbose.
--File not found appears during decompression of Qt source Due to the above PATH character limit.
--Project ERROR: Building QtQml requires Python The setting for coexistence of Python2 and Python3 is not good. At the command prompt, set py --version to get Python3 and py -2 --version to get Python2. If PYTHONPATH and PYTHONHOME are in the environment variables, delete them. Only the Python3 path was set in the PATH, and the Python2 path was not set.
--If sysroot build fails, it will be cleaned when rebuilding, so you will have to start over. 6th generation i5 memory 8GB requires about 3 hours (Qt is huge).
https://www.riverbankcomputing.com/static/Docs/pyqtdeploy/pyqtdeploy.html Set as. Again, try compiling the homemade Python script I tried earlier with NUITKA-Utilities.
test.py
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'test.ui'
#
# Created by: PyQt5 UI code generator 5.13.1
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
import time
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(300, 200)
MainWindow.setMaximumSize(QtCore.QSize(300, 200))
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(100, 130, 75, 23))
self.pushButton.setObjectName("pushButton")
self.label = QtWidgets.QLabel(self.centralwidget)
self.label.setGeometry(QtCore.QRect(100, 50, 50, 12))
self.label.setObjectName("label")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 300, 21))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.pushButton.setText(_translate("MainWindow", "Start"))
self.label.setText(_translate("MainWindow", "Time:"))
self.pushButton.pressed.connect(calc)
def calc():
start = time.time()
i = 10000000
while i >= 0:
i = i - 1
stop = time.time()
ui.label.setText(str(stop - start))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
Duplicate pyqt-demo.pdy into test.pdy and use it as a template. Duplicate test.py in \ pyqtdeploy-2.4 \ demo \ data Rename it to test.py.dat and keep it.
pyqtdeploy test.pdy To execute. Set the source file and rescan the data folder. Save the contents of other tabs from the File menu as they are.
https://www.riverbankcomputing.com/static/Docs/pyqtdeploy/building.html Do the following in order
Makefile is created by qmake, and Makefile is executed by nmake. You should have a single exe file test.exe in build-win-64 \ release.
The time required to compile test.exe was as short as 30 seconds excluding the sysroot creation time.
PyInstaller | NUITKA(-Utilities) | pyqtdeploy | |
---|---|---|---|
Single exe size | 34.8MB | 17.1MB | 36.2MB |
Execution result | 0.8277249s | 0.7182800s | 0.7182917s |
Start-up | Slightly slow | slow | early |
The size is the smallest created by the single exe creation command of nuitka-utilities, but this is because it is compressed by the installer, and it will be executed after it is installed in the Temp folder at the time of execution, so startup will be slow. ..
The size of a single exe is almost the same between Pyinstaller and pyqtdeploy, but pyqtdeploy creates a compiled binary so it starts and runs faster.
By removing unnecessary libraries with pyqt deploy (checking pyqt modules only for QtWidget, QtGui, QtCore, sip), I was able to reduce the size of the binary to about 25MB. It seems that pyqt deploy is superior in terms of binary size, startup, and execution speed.
Also, pyqtdeploy says that you can develop cross-platform (Windows, MacOS, Linux, iOS, Android) with the same source, so I would like to actively use it.
Recommended Posts