diff --git a/setup/macos/build.sh b/setup/macos/build.sh index 67b94c46..ca475fa1 100755 --- a/setup/macos/build.sh +++ b/setup/macos/build.sh @@ -174,7 +174,7 @@ rm lib/python3.*/site-packages/PyQt6/QtWebEngine* || true rm -r lib/python3.*/site-packages/PyQt6/Qt6/translations/qtwebengine* || true rm -r lib/python3.*/site-packages/PyQt6/Qt6/plugins/webview/libqtwebview* || true -# Remove unneeded QtQuick/Decaritive components +# Remove unneeded QtQuick/Declarative components rm lib/python3.*/site-packages/PyQt6/QtQml* || true rm lib/python3.*/site-packages/PyQt6/QtQuick* || true rm lib/python3.*/site-packages/PyQt6/WebChannel* || true @@ -200,7 +200,7 @@ mkdir -p $RLS_DIR # --- Create DMG -------------------------------------------------------------------------------- # # Generate .dmg -echo "Packageing DMG ..." +echo "Packaging DMG ..." brew install create-dmg create-dmg --volname "novelWriter $VERSION" --volicon $SRC_DIR/setup/macos/novelwriter.icns \ diff --git a/utils/build_appimage.py b/utils/build_appimage.py index 3b3bf4f8..d32a377e 100644 --- a/utils/build_appimage.py +++ b/utils/build_appimage.py @@ -30,7 +30,8 @@ from pathlib import Path from utils.common import ( ROOT_DIR, SETUP_DIR, appdataXml, copyPackageFiles, copySourceCode, - extractVersion, freshFolder, makeCheckSum, systemCall, toUpload, writeFile + extractVersion, freshFolder, makeCheckSum, removeRedundantQt, systemCall, + toUpload, writeFile ) @@ -113,6 +114,9 @@ def appImage(args: argparse.Namespace) -> None: qt6Lib = siteDir / "PyQt6" / "Qt6" / "lib" shutil.copyfile(libPath / "libxcb-cursor.so.0", qt6Lib / "libxcb-cursor.so.0") + # Remove Redundant + removeRedundantQt(siteDir) + # Build Image appToolExec = os.environ.get("APPIMAGE_TOOL_EXEC", "appimagetool") env = os.environ.copy() diff --git a/utils/build_windows.py b/utils/build_windows.py index a4f0e866..98d5e8c2 100644 --- a/utils/build_windows.py +++ b/utils/build_windows.py @@ -30,7 +30,10 @@ import zipfile from pathlib import Path -from utils.common import ROOT_DIR, SETUP_DIR, copySourceCode, extractVersion, readFile, writeFile +from utils.common import ( + ROOT_DIR, SETUP_DIR, copySourceCode, extractVersion, readFile, + removeRedundantQt, writeFile +) def prepareCode(outDir: Path) -> None: @@ -103,85 +106,6 @@ def installRequirements(libDir: Path) -> None: return -def removeRedundantQt(libDir: Path) -> None: - """Delete Qt files that are not needed""" - - def unlinkIfFound(file: Path) -> None: - if file.is_file(): - file.unlink() - print(f"Deleted: {file}") - - def deleteFolder(folder: Path) -> None: - if folder.is_dir(): - shutil.rmtree(folder) - print(f"Deleted: {folder}") - - def unlinkIfPrefix(folder: Path, prefix: tuple[str, ...]) -> None: - if folder.is_dir(): - for item in folder.iterdir(): - if item.name.startswith(prefix): - if item.is_file(): - unlinkIfFound(item) - elif item.is_dir(): - deleteFolder(item) - - print("Deleting Redundant Files") - print("========================") - print("") - - pyQt6Dir = libDir / "PyQt6" - bindDir = libDir / "PyQt6" / "bindings" - qt6Dir = libDir / "PyQt6" / "Qt6" - binDir = libDir / "PyQt6" / "Qt6" / "bin" - plugDir = libDir / "PyQt6" / "Qt6" / "plugins" - qmDir = libDir / "PyQt6" / "Qt6" / "translations" - dictDir = libDir / "enchant" / "data" / "mingw64" / "share" / "enchant" / "hunspell" - - for item in dictDir.iterdir(): - if not item.name.startswith(("en_GB", "en_US")): - unlinkIfFound(item) - - for item in qmDir.iterdir(): - if not item.name.startswith("qtbase"): - unlinkIfFound(item) - - bulkDel = ("QtQml", "Qt6Qml", "QtQuick", "Qt6Quick") - unlinkIfPrefix(pyQt6Dir, bulkDel) - unlinkIfPrefix(bindDir, bulkDel) - unlinkIfPrefix(binDir, bulkDel) - - delQt6 = [ - "Qt6Bluetooth", "Qt6DBus", "Qt6Designer", "Qt6Help", "Qt6Multimedia", - "Qt6MultimediaWidgets", "Qt6Network", "Qt6Nfc", "Qt6OpenGL", "Qt6Positioning", - "Qt6PositioningQuick", "Qt6Sensors", "Qt6SerialPort", "Qt6Sql", "Qt6Test", - "Qt6TextToSpeech", "Qt6WebChannel", "Qt6WebSockets", "Qt6Xml", - ] - for item in delQt6: - qtItem = item.replace("Qt6", "Qt") - unlinkIfFound(binDir / f"{item}.dll") - unlinkIfFound(pyQt6Dir / f"{qtItem}.pyd") - unlinkIfFound(pyQt6Dir / f"{qtItem}.pyi") - deleteFolder(bindDir / qtItem) - - delList = [ - binDir / "opengl32sw.dll", - qt6Dir / "qml", - plugDir / "renderers", - plugDir / "sensors", - plugDir / "sqldrivers", - plugDir / "texttospeech", - plugDir / "webview", - ] - for item in delList: - unlinkIfFound(item) - deleteFolder(item) - - print("Done") - print("") - - return - - def main(args: argparse.Namespace) -> None: """Set up a package with embedded Python and dependencies for Windows installation. diff --git a/utils/common.py b/utils/common.py index 2c986480..4ba82e00 100644 --- a/utils/common.py +++ b/utils/common.py @@ -210,3 +210,69 @@ def systemCall(cmd: list, cwd: Path | str | None = None, env: dict | None = None print("ERROR:", str(exc)) sys.exit(1) return + + +def removeRedundantQt(qtBase: Path) -> None: + """Delete Qt files that are not needed""" + + def unlinkIfFound(file: Path) -> None: + if file.is_file(): + file.unlink() + print("Deleted:", file.relative_to(ROOT_DIR)) + + def deleteFolder(folder: Path) -> None: + if folder.is_dir(): + shutil.rmtree(folder) + print("Deleted:", folder.relative_to(ROOT_DIR)) + + def unlinkIfPrefix(folder: Path, prefix: tuple[str, ...]) -> None: + if folder.is_dir(): + for item in folder.iterdir(): + if item.name.startswith(prefix): + if item.is_file(): + unlinkIfFound(item) + elif item.is_dir(): + deleteFolder(item) + + print("Deleting redundant files ...") + + pyQt6Dir = qtBase / "PyQt6" + bindDir = qtBase / "PyQt6" / "bindings" + qt6Dir = qtBase / "PyQt6" / "Qt6" + binDir = qtBase / "PyQt6" / "Qt6" / "bin" + libDir = qtBase / "PyQt6" / "Qt6" / "lib" + plugDir = qtBase / "PyQt6" / "Qt6" / "plugins" + qmDir = qtBase / "PyQt6" / "Qt6" / "translations" + dictDir = qtBase / "enchant" / "data" / "mingw64" / "share" / "enchant" / "hunspell" + + # Prune Dictionaries + if dictDir.exists(): + for item in dictDir.iterdir(): + if not item.name.startswith(("en_GB", "en_US")): + unlinkIfFound(item) + + # Prune Translations + for item in qmDir.iterdir(): + if not item.name.startswith("qtbase"): + unlinkIfFound(item) + + # Delete Modules + modules = [ + "Qt6Qml", "Qt6Quick", "Qt6Bluetooth", "Qt6Nfc", + "Qt6Sensors", "Qt6SerialPort", "Qt6Test", + ] + modules.extend([x.replace("Qt6", "Qt") for x in modules]) + modules.extend([f"lib{x}" for x in modules]) + modules = tuple(modules) + + unlinkIfPrefix(pyQt6Dir, modules) + unlinkIfPrefix(bindDir, modules) + unlinkIfPrefix(binDir, modules) + unlinkIfPrefix(libDir, modules) + + # Other Files + deleteFolder(qt6Dir / "qml") + deleteFolder(plugDir / "qmlls") + deleteFolder(plugDir / "qmllint") + + return