Add Windows executable build and locked dependencies
This commit is contained in:
7 files changed
+684
-9
No files matched your search
@@ -0,0 +1,89 @@
|
||||
"""Build the Tk controller with Windows Python and PyInstaller.
|
||||
|
||||
Run `uv run --python 3.14 --group bundle python scripts/build_exe.py`.
|
||||
Build output stays under dist/ and temporary files under build/. A Windows
|
||||
executable must be built on Windows; this script never attempts cross-compiling.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import importlib.util
|
||||
import subprocess
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def build_arguments(root, onefile=False, console=False):
|
||||
"""Include the dynamically selected WinRT backend and its namespace modules."""
|
||||
root = Path(root).resolve()
|
||||
return [
|
||||
"--noconfirm",
|
||||
"--clean",
|
||||
"--name",
|
||||
"SoundTowerController",
|
||||
"--console" if console else "--windowed",
|
||||
"--onefile" if onefile else "--onedir",
|
||||
"--distpath",
|
||||
str(root / "dist"),
|
||||
"--workpath",
|
||||
str(root / "build" / "pyinstaller"),
|
||||
"--specpath",
|
||||
str(root / "build"),
|
||||
"--paths",
|
||||
str(root),
|
||||
# Bleak chooses backends dynamically. WinRT's generated namespaces
|
||||
# and extension modules must also be present in the frozen application.
|
||||
"--collect-submodules",
|
||||
"bleak.backends.winrt",
|
||||
"--collect-all",
|
||||
"winrt",
|
||||
"--copy-metadata",
|
||||
"bleak",
|
||||
"--copy-metadata",
|
||||
"winrt-runtime",
|
||||
str(root / "controller" / "__main__.py"),
|
||||
]
|
||||
|
||||
|
||||
def main(argv=None):
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument(
|
||||
"--onefile",
|
||||
action="store_true",
|
||||
help="Make one self-extracting .exe instead of an application folder",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--console", action="store_true", help="Keep a console for diagnosing startup errors"
|
||||
)
|
||||
args = parser.parse_args(argv)
|
||||
if sys.platform != "win32":
|
||||
parser.error(
|
||||
"Build with Windows Python in PowerShell, or Windows uv.exe from WSL. Linux Python cannot build a Windows executable."
|
||||
)
|
||||
if importlib.util.find_spec("PyInstaller") is None:
|
||||
parser.error(
|
||||
"PyInstaller is missing. Run with: uv run --group bundle python scripts/build_exe.py"
|
||||
)
|
||||
if importlib.util.find_spec("tkinter") is None:
|
||||
parser.error(
|
||||
"This Python installation lacks Tk. Use --python with a Windows Python installation that includes Tcl/Tk."
|
||||
)
|
||||
root = Path(__file__).resolve().parents[1]
|
||||
subprocess.run(
|
||||
[sys.executable, "-m", "PyInstaller", *build_arguments(root, args.onefile, args.console)],
|
||||
cwd=root,
|
||||
check=True,
|
||||
)
|
||||
executable = (
|
||||
root / "dist" / "SoundTowerController.exe"
|
||||
if args.onefile
|
||||
else root / "dist" / "SoundTowerController" / "SoundTowerController.exe"
|
||||
)
|
||||
if not executable.is_file():
|
||||
raise RuntimeError(f"Build finished without the expected executable: {executable}")
|
||||
print(f"Built: {executable}")
|
||||
if not args.onefile:
|
||||
print("Keep the whole SoundTowerController folder together, including _internal.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user