LoginSignup
16
21

More than 3 years have passed since last update.

NUITKA-Utilitiesで簡単Pythonコンパイル

Last updated at Posted at 2019-11-05

いいもの見つけた

NUITKA-Utilities

exe-maker.jpg

.pyファイルと出力先のフォルダを指定すると、Nuitkaでコンパイルを勝手にやってくれるのだ。(exe-maker.py)

WindowsではMingw-w64、PySimpleGUIをあらかじめインストールしておくこと。

conda install m2w64-gcc libpython

pip install nuitka

pip install pysimplegui

Nuitkaのstandaloneはdllがたくさんできていやだ

コンパイルした.distフォルダを指定するだけで、単一のexeファイルを作ってくれるのだ。(onefile-maker-windows.py)

onefile.png

WindowsではあらかじめNSISをインストールしておくこと。

サイズを小さくしたい

hinted-compilationを使おう。(2019年末時点では動かない)

get-hints.pyを実行すると、必要なライブラリだけを拾ってきてくれる。
サイズとコンパイル時間が短くなるという。

PyInstallerと比べてみた

手製の60行ほどのGUI付pythonスクリプトで比較してみた。

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_())
PyInstaller NUITKA(-Utilities)
単一exeサイズ 34.8MB 17.1MB
実行結果 0.8277249s 0.7182800s
起動 やや遅い 遅い

起動にちょっと時間がかかるのが残念だがサイズは半分。
コンパイルされたバイナリなので、実行速度もやや速い。
コンパイルは手持ちのPCで55秒、単一exe作成に43秒だった。
pyinstallerは20秒ほどで単一exeができた。

おまけ

コマンドラインからnuitkaを実行すると、オプションをどうつけてよいか悩む。

まず、ライブラリを全部外してコンパイルして、できた実行ファイルを実行すれば、ライブラリが足らないと叱られるので、適宜追加してゆけばいつかできあがる。

python -m nuitka hoge.py --standalone --recurse-none --remove-output

でhode.distの中にhoge.exeができるのでコマンドラインで実行する。

返ってくるエラーで、オプションの付け方が異なる。

  • Nuitka:WARNING:Use '--plugin-enable=Hoge' for: Inclusion of Hoge plugins.

Warningの時は、--plugin-enable= と --recurse-to= をつける。
Qtやnumpyなどはこのタイプ。
--plugin-enable=qt-plugins --recurse-to=PyQt5
--plugin-enable=numpy --recurse-to=numpy

  • ModuleNotFoundError: No module named 'Hoge'

ModuleNotFoundErrorの時は、--recurse-to= のみをつける。
PyserialやOpenCVがこのタイプ.
--recurse-to=serial
--recurse-to=cv2

めでたく起動するようになったら、不要なdll等を調べて削除すると配布サイズをより小さくできる。たとえばQtをGUIライブラリに使ったならば、Tcl,Tk のdllは削除してかまわない。ネットワークを使わないならば、SSLやソケットのdllは削除してかまわない。

16
21
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
16
21