import subprocess import shutil import os from pathlib import Path from PIL import Image # нужна библиотека Pillow для конвертации PNG в ICO import PySide2 from PyInstaller.utils.hooks import collect_data_files # === Конфигурация === USE_NUITKA = True # True — сборка через Nuitka, False — через PyInstaller SCRIPT_PATH = Path("./Src/DebugVarEdit_GUI.py") OUTPUT_NAME = "DebugVarEdit" DIST_PATH = Path("./").resolve() WORK_PATH = Path("./build_temp").resolve() SPEC_PATH = WORK_PATH SCRIPT_DIR = Path(__file__).resolve().parent ICON_PATH = SCRIPT_DIR / "icon.png" ICON_ICO_PATH = SCRIPT_DIR / "icon.ico" # === Пути к DLL и прочим зависимостям === LIBS = { "libclang.dll": SCRIPT_DIR / "libclang.dll", "libssl.dll": SCRIPT_DIR / "libssl-3-x64.dll", "libcrypto.dll": SCRIPT_DIR / "libcrypto-3-x64.dll" } # === PySide2 плагины === PySide2_path = Path(PySide2.__file__).parent datas = [] datas += collect_data_files('PySide2', includes=['plugins/platforms/*']) datas += collect_data_files('PySide2', includes=['plugins/styles/*']) datas += collect_data_files('PySide2', includes=['plugins/imageformats/*']) add_data_list = [f"{src};{dest}" for src, dest in datas] add_binary_list = [f"{str(LIBS['libclang.dll'])};."] # Проверка наличия DLL и добавление for name, path in LIBS.items(): if path.exists(): if name != "libclang.dll": add_binary_list.append(f"{str(path)};{name}") else: print(f"WARNING: {path.name} не найден — он не будет включён в сборку") # === Сборка === env = os.environ.copy() env["CC"] = r"C:\Users\I\AppData\Local\Nuitka\Nuitka\Cache\DOWNLOADS\gcc\x86_64\14.2.0posix-19.1.1-12.0.0-msvcrt-r2\bin\gcc.exe" env["CXX"] = r"C:\Users\I\AppData\Local\Nuitka\Nuitka\Cache\DOWNLOADS\gcc\x86_64\14.2.0posix-19.1.1-12.0.0-msvcrt-r2\bin\g++.exe" # Конвертация PNG в ICO, если ICO нет или PNG новее ICO if ICON_PATH.exists(): if (not ICON_ICO_PATH.exists()) or (ICON_PATH.stat().st_mtime > ICON_ICO_PATH.stat().st_mtime): img = Image.open(ICON_PATH) img.save(ICON_ICO_PATH, format='ICO', sizes=[(256,256), (128,128), (64,64), (32,32), (16,16)]) # Удалим временные папки до сборки def clean_temp(): for folder in ["build_temp", "__pycache__", "DebugVarEdit_GUI.build", "DebugVarEdit_GUI.dist", "DebugVarEdit_GUI.onefile-build"]: path = Path(folder) if path.exists(): shutil.rmtree(path, ignore_errors=True) if USE_NUITKA: # Формируем include-data-file только для DLL include_data_files = [f"--include-data-file={str(path)}={name}" for name, path in LIBS.items() if path.exists()] cmd = [ "python", "-m", "nuitka", "--standalone", "--debug", "--debugger", "--mingw64", "--enable-plugin=pyside2", f"--output-dir={DIST_PATH}", f"--output-filename={OUTPUT_NAME}.exe", f"--windows-icon-from-ico={ICON_ICO_PATH}", *include_data_files, str(SCRIPT_PATH) ] else: # PyInstaller cmd = [ "pyinstaller", "--name", OUTPUT_NAME, "--distpath", str(DIST_PATH), "--workpath", str(WORK_PATH), "--specpath", str(SPEC_PATH), "--windowed", f"--icon={ICON_ICO_PATH}", "--hidden-import=PySide2.QtWidgets", "--hidden-import=PySide2.QtGui", "--hidden-import=PySide2.QtCore", *[arg for b in add_binary_list for arg in ("--add-binary", b)], *[arg for d in add_data_list for arg in ("--add-data", d)], str(SCRIPT_PATH) ] # === Запуск сборки === print("Выполняется сборка с помощью " + ("Nuitka" if USE_NUITKA else "PyInstaller")) print(" ".join(cmd)) try: subprocess.run(cmd, check=True, env=env) print("\nСборка успешно завершена!") # Удаление временных папок после сборки #clean_temp() except subprocess.CalledProcessError: print("\nОшибка при сборке.")