pyqtdeploy, or we pack the Python program in exe'shnik ... the hard way

KDPV


Surely, everyone who at least once wrote something in Python thought about how to distribute their program (or even a simple script) without any headache: without having to install the interpreter itself, various dependencies, cross-platform, in order to use one file -exe'shnikom (as a last resort, archive) and the smallest possible size.


: PyInstaller, cx_Freeze, py2exe, py2app, Nuitka … , PyQt? , ( ) , PyQt, PyQt pyqtdeploy. , , , . , , , β€” ( ). , : , , , , .


pyqtdeploy , , , , ?


. linux. , "exe'" .


, ( ). PyInstaller β€” , , . 170 ( , PyQt5 180 ). , , β€” QtCore, QtGui, QtWidgets β€” . --exclude-module . , --onefile , 60 , . , , ( - ) 170 .


pyqtdeploy. " PyQt… - , - PyQt Qt?" β€” .


pyqtdeploy? , , . ( , PyQt, ) Qt ( rcc) , C++, , //… . pyqtdeploy Python 3.5+ PyQt5. ( ):


  • exe' PyQt4 PyQt5, Python 2.7 Python 3.3+ ( Python 3.7.2);
  • ( exe') ( , β€” );
  • :
    • android-32;
    • android-64;
    • ios-64;
    • linux-64;
    • macos-64;
    • win-32;
    • win-64;
  • PyQt Qt , - QtCore, - .

pyqtdeploy


, Python 3.5+ PyQt5:


pip install PyQt5 pyqtdeploy

exe' :


  • Python-, (!);
  • sysroot , ;
  • "" .pdy, exe' ( Qt, PyQt, Python, );
  • exe' qmake.


: main.py β€” " " , mainwindow.py β€” , resources icon.png mainwindow.ui, Qt Designer. , :


main.py
src/
    |---__init__.py
    |---gui/
        |---mainwindow.py
        |---__init__.py
    |---resources/
        |---__init__.py
        |---images/
            |---icon.png
            |---__init__.py
        |---ui/
            |---mainwindow.ui
            |---__init__.py

sysroot ()


, , . sysroot.json ( , ). , (Python, Qt ..). pyqtdeploy API, , //whatever, pyqtdeploy. ( ):


openssl ( ) β€” (). , sysroot.json, :


"android|macos|win#openssl": {
    "android#source": "openssl-1.0.2r.tar.gz",
    "macos|win#source": "openssl-1.1.0j.tar.gz",

    "win#no_asm": true
}

, , : arch1|arch2|...#plugin-name. , (ios, android, macos, win, linux), β€” . , .


:


  • source () β€” ;
  • no_asm ( ) β€” . , PATH nasm;
  • python_source ( ) β€” , , OpenSSL macOS Python v3.6.4 ;

zlib ( ) β€” ( , , , ) ():


"ios|linux|macos|win#zlib": {
    "source": "zlib-1.2.11.tar.gz",

    "static_msvc_runtime": true
}

:


  • source () β€” , ;
  • static_msvc_runtime ( ) β€” MSVC (Windows);

qt5 () β€” ():


"qt5": {
    "android-32#qt_dir": "android_armv7",
    "android-64#qt_dir": "android_arm64_v8a",
    "ios#qt_dir": "ios",

    "linux|macos|win#source": "qt-everywhere-src-5.12.2.tar.xz",
    "edition": "opensource",

    "android|linux#ssl": "openssl-runtime",
    "ios#ssl": "securetransport",
    "macos|win#ssl": "openssl-linked",

    "configure_options": [
        "-opengl", "desktop", "-no-dbus", "-qt-pcre"
    ],
    "skip": [
        "qtactiveqt", "qtconnectivity", "qtdoc", "qtgamepad",
        ...
    ],

    "static_msvc_runtime": true
}

:


  • qt_dir ( , source) β€” Qt;
  • source ( , qt_dir) β€” Qt;
  • edition (, source) β€” 2 :
    • commercial;
    • opensource;
  • ssl β€” 3 :
    • openssl-linked β€” ( openssl);
    • securetransport β€” SSL, Qt (, , Apple’s Secure Transport);
    • openssl-runtime β€” OpenSSL, ;
  • configure_options β€” , Qt. , ;
  • skip β€” ( , top-level , ). Qt , qt β€” top-level . , , . , top-level ();
  • disabled_features β€” . configure -list-features ()
  • static_msvc_runtime ( ) β€” MSVC (Windows);

python () β€” ():


"python": {
    "build_host_from_source": false,
    "build_target_from_source": true,
    "source": "Python-3.7.2.tar.xz"
}

:


  • build_host_from_source () β€” true β€” Python , false β€” Python ( win32);
  • build_target_from_source () β€” true β€” Python , false β€” Python ( Python win32);
  • source (, Python ) β€” Python;
  • version (, Python) β€” Python;
  • dynamic_loading ( ) β€” true β€” (, C);
  • host_installation_bin_dir ( ) β€” Python, ( , win , β€” PATH);

sip () β€” , Python-bindings C/C++ ( ):


"sip": {
    "module_name": "PyQt5.sip",
    "source": "sip-4.19.15.tar.gz"
}

:


  • module_name () β€” sip-;
  • source () β€” sip;

pyqt5 () β€” ():


"pyqt5": {
    "android#disabled_features": [
        "PyQt_Desktop_OpenGL", "PyQt_Printer", "PyQt_PrintDialog",
        "PyQt_PrintPreviewDialog", "PyQt_PrintPreviewWidget"
    ],
    "android#modules": [
        "QtCore", "QtGui", "QtNetwork", "QtPrintSupport", "QtWidgets",
        "QtAndroidExtras"
    ],

    "ios#disabled_features": [
        "PyQt_Desktop_OpenGL", "PyQt_MacOSXOnly",
        ...
    ],
    "ios|macos#modules": [
        "QtCore", "QtGui", "QtNetwork", "QtPrintSupport", "QtWidgets",
        "QtMacExtras"
    ],

    "linux#modules": [
        "QtCore", "QtGui", "QtNetwork", "QtPrintSupport", "QtWidgets",
        "QtX11Extras"
    ],

    "win#disabled_features": ["PyQt_Desktop_OpenGL"],
    "win#modules": [
        "QtCore", "QtGui", "QtNetwork", "QtPrintSupport", "QtWidgets",
        "QtWinExtras"
    ],

    "source": "PyQt5_*-5.12.1.tar.gz"
}

:


  • disabled_features ( ) β€” . , , Qt ();
  • modules () β€” , ();
  • source () β€” PyQt;

pyqt3D, pyqtchart, pyqtdatavisualization, pyqtpurchasing, qscintilla ( ) β€” , PyQt. source β€” .


, . sysroot , . , , .


sysroot


sysroot.json :


{
    "linux#zlib": {
        "source": "zlib-1.2.11.tar.gz"
    },

    "linux#qt5": {
        "source": "qt-everywhere-src-5.12.2.tar",
        "edition": "opensource",

        "configure_options": [
            "-no-dbus", "-no-system-proxies", "-no-cups", "-no-sql-db2",
            "-no-sql-ibase", "-no-sql-mysql", "-no-sql-sqlite",
            "-no-sql-sqlite2", "-no-sql-oci", "-no-sql-odbc",
            "-no-sql-psql", "-no-sql-tds", "-no-sqlite", "-ccache",
            "-optimize-size"
        ],
        "skip": [
            "qt3d", "qtactiveqt", "qtandroidextras", "qtcanvas3d",
            "qtcharts", "qtconnectivity", "qtdatavis3d", "qtdeclarative",
            "qtdoc", "qtgamepad", "qtgraphicaleffects", "qtlocation",
            "qtmacextras", "qtmultimedia", "qtnetworkauth", "qtpurchasing",
            "qtquickcontrols", "qtquickcontrols2", "qtremoteobjects",
            "qtscript", "qtscxml", "qtsensors", "qtserialbus",
            "qtserialport", "qtspeech", "qtsvg", "qttools",
            "qttranslations", "qtvirtualkeyboard", "qtwayland",
            "qtwebchannel", "qtwebengine", "qtwebglplugin",
            "qtwebsockets", "qtwebview", "qtwinextras", "qtx11extras",
            "qtxmlpatterns"
        ],
        "disabled_features": [
            "network", "bearermanagement", "dnslookup", "dtls", "ftp",
            "http", "localserver", "networkdiskcache", "networkinterface",
            "networkproxy", "socks5", "udpsocket", "concurrent", "future",
            "cups", "printer", "printdialog", "printpreviewdialog",
            "printpreviewwidget", "sql", "sqlmodel", "testlib", "xml"
        ]
    },

    "linux#python": {
        "build_host_from_source": false,
        "build_target_from_source": true,
        "source": "Python-3.7.2.tgz",

        "dynamic_loading": true
    },

    "linux#sip": {
        "module_name": "PyQt5.sip",
        "source": "sip-4.19.15.tar.gz"
    },

    "linux#pyqt5": {
        "modules": ["QtCore", "QtGui", "QtWidgets"],
        "source": "PyQt5_*-5.12.2.tar.gz"
    }
}

? -, (, ssl, pyqt3D ). -, exe' linux ( , linux-64; , ).


, qt5 - , (, ). top-level QtBase. -optimize-size -ccache. Qt , , ( 5 ), , β€” ccache ( , linux), ( 5). , apt install ccache.


pyqt5 QtCore, QtGui, QtWidgets.


python dynamic_loading, C-extension.


sysroot, : zlib, Qt5, Python, sip, PyQt5 sysroot.json ( , ). :


pyqtdeploy-sysroot sysroot.json

, .


--verbose. , , . , dev-. , . , python3-dev, (, Requirements). , Qt Python ( , ).


, , , .


"" ()


, , exe'. pyqtdeploy GUI. ( .pdy ):


pyqtdeploy main.pdy

Application source


Application Source. :


  • Name β€” exe';
  • Main script file ( , Entry Point) β€” , ( , main.py);
  • Entry Point ( , Main script file) β€” , setuptools;
  • sys.path β€” , zip- (, Python egg), sys.path ( , , );
  • Target Python version β€” Python;
  • Target PyQt version β€” PyQt4 PyQt5 (, , PyQt, );
  • Use console β€” , ( Windows). ;
  • Application bundle β€” , bundle ( MacOS);
  • Application Package Directory β€” , . Scan… "" (src) main.py, , . (.. main.py src), main.py ( , Main script file).

: .py "" ( -) β€” .


:


  • Scan… β€” Application Package Directory;
  • Remove all β€” Application Package Directory;
  • Include all β€” Application Package Directory;
  • Exclude all β€” Application Package Directory;
  • Exclusions β€” , Application Package Directory. ;

qmake. qmake, ( );


PyQt Modules


PyQt Modules. PyQt-, . , . QtCore, QtGui, QtWidgets, uic; sip .
PyQt, , ( ).


Standard library


Standard Library. , , . - , . ( ) , ().


. - ( pip), - ( ), ImportError. . , PIL, fractions.


Python / (, ssl), . , . INCLUDEPATH (headers), LIBS β€” ( , ).


Other packages


Other Packages. (, pypi). , Application source: , ( , site-packages virtual environment), Scan / ( PIL).


Other Extension Modules. C, exe' (; , , ).


, . . Package Lib.a, Name , β€” Package.Lib ( .a); LIBS , , -L/home/user1/venv/programme1/lib/python3.7/site-packages/Package -lLib ( , " ", /home/user1/venv/programme1/lib/python3.7/site-packages/Package/Lib.a).


, , -, , -, qmake ( , pyqt' ).


, , , Lib.so? β€” Package.Lib.so (.. , + ) exe'. , . , ImportError. , , _imaging.so, PIL'.


Locations. , . ( sysroot , main.pdy), .


exe' ()


- :


pyqtdeploy-build main.pdy
cd build-linux-64
../sysroot-linux-64/host/bin/qmake
make #nmake  win

, , β€” .


#1 β€” , ""


, exe', , PyInstaller:


if getattr(sys, 'frozen', False):
    #   exe'
else:
    #    exe'

#2 β€” (, .)


Qt " ", rcc exe'. . icon.png src/resources/images, " " β€” :/src/resources/images/icon.png. , . β€” Qt' . .. - :


icon = QIcon(':/src/resources/images/icon.png')

. , , :


icon_file = open(':/src/resources/images/icon.png', 'rb')
icon = icon_file.read()

, open , , .


Qt (, , , GUI Qt Designer .ui, loadUi), - :


ui_file = QtCore.QFile(':/src/resources/images/icon.png')
ui_file.open(QtCore.QIODevice.ReadOnly)
data = ui_file.readAll()
ui_file.close()
ui_file = BytesIO(bytes(data))


, exe', - ? PyQt, , , . - ( PyInstaller). β€” . ~40 (c -optimize-size ~35 ), - , .


When we have collected the minimum necessary Qt and PyQt, it would be nice to try to make an exe based on them using PyInstaller or cx_Freeze and look at the size, but this, as they say, is another story ...

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


All Articles