diff --git a/make_windows.py b/make_windows.py old mode 100644 new mode 100755 index cc75f519..d5b938c0 --- a/make_windows.py +++ b/make_windows.py @@ -1,191 +1,204 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- -""" -This script will either build: - * A single file executable named dist/novelWriter.exe. This is a quite - slow option, and the file is fairly big. Option --onefile - * A single directory named dist/novelWriter with a novelWriter.exe, and - all dependecies included. This is the default. - * The latter can be combined with a build stage of a setup.exe file - named setup-novelwriter-.exe. Option --setup. - -In addition, providing the --pip flag will cause the script to try to -install all dependencies needed for runing the build, and for running -novelWriter itself. -""" - -import os -import sys -import getopt -import subprocess - -# Defaults -buildWindowed = True -runPip = False -oneFile = False -makeSetup = False -innoSetup = None - -# Parse Options -shortOpt = "hd" -longOpt = [ - "help", - "debug", - "pip", - "onefile", - "setup", - "inno=", -] -helpMsg = ( - "\n" - "novelWriter Install Script for Windows\n" - "\n" - "Usage:\n" - " -h, --help Print this message.\n" - " --pip Install dependecies first.\n" - " --onefile Create a single executable file.\n" - " --setup Make Inno Setup file.\n" - " --inno= Path to the Inno Setup exec.\n" - " -d, --debug Build novelWriter for debugging. To debug novelwriter after build,\n" - " run it from command line with the debug options. Please check the\n" - " novelWriter --help output for details.\n" -) - -try: - inOpts, inArgs = getopt.getopt(sys.argv[1:], shortOpt, longOpt) -except getopt.GetoptError: - print(helpMsg) - sys.exit(1) - -for inOpt, inArg in inOpts: - if inOpt in ("-h", "--help"): - print(helpMsg) - sys.exit(0) - elif inOpt in ("-d", "--debug"): - buildWindowed = False - elif inOpt == "--pip": - runPip = True - elif inOpt == "--onefile": - oneFile = True - elif inOpt == "--setup": - makeSetup = True - elif inOpt == "--inno": - innoSetup = inArg - -# Run pip -if runPip: - print("") - print("###########################") - print(" Installing Dependencies") - print("###########################") - print("") - try: - subprocess.call([ - sys.executable, "-m", - "pip", "install", "--user", "--upgrade", "pip" - ]) - subprocess.call([ - sys.executable, "-m", - "pip", "install", "--user", "--upgrade", "pyinstaller" - ]) - subprocess.call([ - sys.executable, "-m", - "pip", "install", "--user", "--upgrade", "-r", "requirements.txt" - ]) - except Exception as e: - print("Failed with error:") - print(str(e)) - sys.exit(1) - -# Run pyinstaller -print("") -print("#######################") -print(" Running PyInstaller") -print("#######################") -print("") -instOpt = [ - "--name=novelWriter", - "--clean", - "--add-data=%s;%s" % (os.path.join("nw", "assets"), "assets"), - "--icon=%s" % os.path.join("nw", "assets", "icons", "novelwriter.ico"), - "--exclude-module=PyQt5.QtQml", - "--exclude-module=PyQt5.QtBluetooth", - "--exclude-module=PyQt5.QtDBus", - "--exclude-module=PyQt5.QtMultimedia", - "--exclude-module=PyQt5.QtMultimediaWidgets", - "--exclude-module=PyQt5.QtNetwork", - "--exclude-module=PyQt5.QtNetworkAuth", - "--exclude-module=PyQt5.QtNfc", - "--exclude-module=PyQt5.QtQuick", - "--exclude-module=PyQt5.QtQuickWidgets", - "--exclude-module=PyQt5.QtRemoteObjects", - "--exclude-module=PyQt5.QtSensors", - "--exclude-module=PyQt5.QtSerialPort", - "--exclude-module=PyQt5.QtSql", -] - -if buildWindowed: - instOpt.append("--windowed") - -if oneFile and not makeSetup: - instOpt.append("--onefile") -else: - instOpt.append("--onedir") - -instOpt.append("novelWriter.py") - -import PyInstaller.__main__ # noqa: E402 -PyInstaller.__main__.run(instOpt) - -if not oneFile: - # These dll files are not nee3ded, and take up a fair bit of space. - delIfExists = [ - "Qt5DBus.dll", "Qt5Network.dll", "Qt5Qml.dll", "Qt5QmlModels.dll", "Qt5Quick.dll", - "Qt5Quick3D.dll", "Qt5Quick3DAssetImport.dll", "Qt5Quick3DRender.dll", - "Qt5Quick3DRuntimeRender.dll", "Qt5Quick3DUtils.dll", "Qt5Sql.dll" - ] - distDir = os.path.join(os.getcwd(), "dist", "novelWriter") - for delFile in delIfExists: - delPath = os.path.join(distDir, delFile) - if os.path.isfile(delPath): - print("Deleting file: %s" % delPath) - os.unlink(delPath) - -print("") -print("Build Finished") -print("") -print("If everything went well, the novelWriter executable should be in the folder named 'dist'") -print("") - -if makeSetup: - print("") - print("######################") - print(" Running Inno Setup") - print("######################") - print("") - if innoSetup is None: - innoSetup = "C:\\Program Files (x86)\\Inno Setup 6\\ISCC.exe" - if not os.path.isfile(innoSetup): - print("ERROR: Cannot fine Inno Setup's ISCC.exe file.") - print(" Looked in: %s" % innoSetup) - print(" Please provide a path with the --inno= option.") - sys.exit(1) - - # Read the iss template - issData = "" - with open(os.path.join("setup", "win_setup.iss"), mode="r") as inFile: - issData = inFile.read() - - import nw # noqa: E402 - issData = issData.replace(r"%%version%%", nw.__version__) - issData = issData.replace(r"%%dir%%", os.getcwd()) - - with open("setup.iss", mode="w+") as outFile: - outFile.write(issData) - - try: - subprocess.call([innoSetup, "setup.iss"]) - except Exception as e: - print("Failed with error:") - print(str(e)) - sys.exit(1) +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +""" +This script will either build: + * A single file executable named dist/novelWriter.exe. This is a quite + slow option, and the file is fairly big. Option --onefile + * A single directory named dist/novelWriter with a novelWriter.exe, and + all dependecies included. This is the default. + * The latter can be combined with a build stage of a setup.exe file + named setup-novelwriter-.exe. Option --setup. + +In addition, providing the --pip flag will cause the script to try to +install all dependencies needed for runing the build, and for running +novelWriter itself. +""" + +import os +import sys +import getopt +import subprocess + +if not sys.platform.startswith("win32"): + print("ERROR: This script is intended for Windows only.") + sys.exit(1) + +# Defaults +buildWindowed = True +runPip = False +oneFile = False +makeSetup = False +innoSetup = None + +# Parse Options +shortOpt = "hd" +longOpt = [ + "help", + "debug", + "pip", + "onefile", + "setup", + "inno=", +] +helpMsg = ( + "\n" + "novelWriter Install Script for Windows\n" + "\n" + "Usage:\n" + " -h, --help Print this message.\n" + " --pip Install dependecies first.\n" + " --onefile Create a single executable file.\n" + " --setup Make Inno Setup file.\n" + " --inno= Path to the Inno Setup exec.\n" + " -d, --debug Build novelWriter for debugging. To debug novelwriter after build,\n" + " run it from command line with the debug options. Please check the\n" + " novelWriter --help output for details.\n" +) + +try: + inOpts, inArgs = getopt.getopt(sys.argv[1:], shortOpt, longOpt) +except getopt.GetoptError: + print(helpMsg) + sys.exit(1) + +for inOpt, inArg in inOpts: + if inOpt in ("-h", "--help"): + print(helpMsg) + sys.exit(0) + elif inOpt in ("-d", "--debug"): + buildWindowed = False + elif inOpt == "--pip": + runPip = True + elif inOpt == "--onefile": + oneFile = True + elif inOpt == "--setup": + makeSetup = True + elif inOpt == "--inno": + innoSetup = inArg + +# Run pip +if runPip: + print("") + print("###########################") + print(" Installing Dependencies") + print("###########################") + print("") + try: + subprocess.call([ + sys.executable, "-m", + "pip", "install", "--user", "--upgrade", "pip" + ]) + subprocess.call([ + sys.executable, "-m", + "pip", "install", "--user", "--upgrade", "pyinstaller" + ]) + subprocess.call([ + sys.executable, "-m", + "pip", "install", "--user", "--upgrade", "-r", "requirements.txt" + ]) + except Exception as e: + print("Failed with error:") + print(str(e)) + sys.exit(1) + +# Run pyinstaller +print("") +print("#######################") +print(" Running PyInstaller") +print("#######################") +print("") +instOpt = [ + "--name=novelWriter", + "--clean", + "--add-data=%s;%s" % (os.path.join("nw", "assets"), "assets"), + "--icon=%s" % os.path.join("nw", "assets", "icons", "novelwriter.ico"), + "--exclude-module=PyQt5.QtQml", + "--exclude-module=PyQt5.QtBluetooth", + "--exclude-module=PyQt5.QtDBus", + "--exclude-module=PyQt5.QtMultimedia", + "--exclude-module=PyQt5.QtMultimediaWidgets", + "--exclude-module=PyQt5.QtNetwork", + "--exclude-module=PyQt5.QtNetworkAuth", + "--exclude-module=PyQt5.QtNfc", + "--exclude-module=PyQt5.QtQuick", + "--exclude-module=PyQt5.QtQuickWidgets", + "--exclude-module=PyQt5.QtRemoteObjects", + "--exclude-module=PyQt5.QtSensors", + "--exclude-module=PyQt5.QtSerialPort", + "--exclude-module=PyQt5.QtSql", +] + +if buildWindowed: + instOpt.append("--windowed") + +if oneFile and not makeSetup: + instOpt.append("--onefile") +else: + instOpt.append("--onedir") + +instOpt.append("novelWriter.py") + +# Make sample.zip first +print("Building sample.zip") +try: + subprocess.call([sys.executable, "setup.py" "sample"]) +except Exception as e: + print("Failed with error:") + print(str(e)) + sys.exit(1) + +import PyInstaller.__main__ # noqa: E402 +PyInstaller.__main__.run(instOpt) + +if not oneFile: + # These dll files are not nee3ded, and take up a fair bit of space. + delIfExists = [ + "Qt5DBus.dll", "Qt5Network.dll", "Qt5Qml.dll", "Qt5QmlModels.dll", "Qt5Quick.dll", + "Qt5Quick3D.dll", "Qt5Quick3DAssetImport.dll", "Qt5Quick3DRender.dll", + "Qt5Quick3DRuntimeRender.dll", "Qt5Quick3DUtils.dll", "Qt5Sql.dll" + ] + distDir = os.path.join(os.getcwd(), "dist", "novelWriter") + for delFile in delIfExists: + delPath = os.path.join(distDir, delFile) + if os.path.isfile(delPath): + print("Deleting file: %s" % delPath) + os.unlink(delPath) + +print("") +print("Build Finished") +print("") +print("If everything went well, the novelWriter executable should be in the folder named 'dist'") +print("") + +if makeSetup: + print("") + print("######################") + print(" Running Inno Setup") + print("######################") + print("") + if innoSetup is None: + innoSetup = "C:\\Program Files (x86)\\Inno Setup 6\\ISCC.exe" + if not os.path.isfile(innoSetup): + print("ERROR: Cannot fine Inno Setup's ISCC.exe file.") + print(" Looked in: %s" % innoSetup) + print(" Please provide a path with the --inno= option.") + sys.exit(1) + + # Read the iss template + issData = "" + with open(os.path.join("setup", "win_setup.iss"), mode="r") as inFile: + issData = inFile.read() + + import nw # noqa: E402 + issData = issData.replace(r"%%version%%", nw.__version__) + issData = issData.replace(r"%%dir%%", os.getcwd()) + + with open("setup.iss", mode="w+") as outFile: + outFile.write(issData) + + try: + subprocess.call([innoSetup, "setup.iss"]) + except Exception as e: + print("Failed with error:") + print(str(e)) + sys.exit(1)