This commit is contained in:
cheng
2026-07-03 11:29:32 +08:00
parent 15088f9810
commit ec15850ffa
112 changed files with 1315 additions and 953 deletions
+19
View File
@@ -0,0 +1,19 @@
@echo off
setlocal
cd /d "%~dp0.."
call conda activate py311
if errorlevel 1 (
echo Failed to activate conda environment: py311
pause
exit /b 1
)
python "%~dp0build_exe.py" %*
if errorlevel 1 (
echo.
echo Build failed.
pause
exit /b 1
)
echo.
echo Build finished.
pause
+19
View File
@@ -0,0 +1,19 @@
param(
[string]$CondaEnv = "py311"
)
$ErrorActionPreference = "Stop"
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$ProjectRoot = Split-Path -Parent $ScriptDir
Set-Location $ProjectRoot
Write-Host "Project root: $ProjectRoot"
Write-Host "Conda env: $CondaEnv"
$ForwardArgs = $args -join " "
cmd /d /s /c "call conda activate $CondaEnv && python `"$ScriptDir\build_exe.py`" $ForwardArgs"
if ($LASTEXITCODE -ne 0) {
throw "build failed"
}
+123
View File
@@ -0,0 +1,123 @@
import argparse
import importlib.util
import shutil
import subprocess
import sys
from pathlib import Path
BUILD_DIR = Path(__file__).resolve().parent
PROJECT_ROOT = BUILD_DIR.parent
def module_exists(name):
return importlib.util.find_spec(name) is not None
def require_module(name, install_hint):
if module_exists(name):
return
raise SystemExit(f"Missing module '{name}'. Install it first: {install_hint}")
def data_arg(source, target):
return f"{source};{target}"
def copy_runtime_dir(source, app_dir, name):
target = app_dir / name
if target.exists():
shutil.rmtree(target)
shutil.copytree(
source,
target,
ignore=shutil.ignore_patterns("__pycache__", "*.pyc"),
)
return target
def build(app_name, clean_dist):
require_module("PyInstaller", "pip install pyinstaller")
dist_dir = PROJECT_ROOT / "dist"
work_dir = BUILD_DIR / "_pyinstaller"
launcher = BUILD_DIR / "run_visualizer.py"
if clean_dist:
app_dist = dist_dir / app_name
if app_dist.exists():
shutil.rmtree(app_dist)
args = [
sys.executable,
"-m",
"PyInstaller",
"--noconfirm",
"--clean",
"--onedir",
"--windowed",
"--name",
app_name,
"--distpath",
str(dist_dir),
"--workpath",
str(work_dir),
"--specpath",
str(BUILD_DIR),
"--paths",
str(PROJECT_ROOT),
"--paths",
str(PROJECT_ROOT / "sdk"),
"--add-data",
data_arg(PROJECT_ROOT / "config", "config"),
"--add-data",
data_arg(PROJECT_ROOT / "sdk", "sdk"),
"--hidden-import",
"changingtek_p_rtu_Servo",
"--hidden-import",
"minimalmodbus",
"--hidden-import",
"serial",
"--hidden-import",
"cv2",
"--hidden-import",
"numpy",
"--collect-all",
"PyQt5",
"--collect-all",
"pyqtgraph",
]
if module_exists("orisys"):
args.extend(["--collect-submodules", "orisys"])
else:
print("Warning: module 'orisys' was not found; camera runtime may fail unless it is installed.")
args.append(str(launcher))
subprocess.run(args, cwd=PROJECT_ROOT, check=True)
exe_path = dist_dir / app_name / f"{app_name}.exe"
if not exe_path.exists():
raise SystemExit(f"Build finished but exe was not found: {exe_path}")
app_dir = exe_path.parent
config_dir = copy_runtime_dir(PROJECT_ROOT / "config", app_dir, "config")
sdk_dir = copy_runtime_dir(PROJECT_ROOT / "sdk", app_dir, "sdk")
print()
print(f"Build complete: {exe_path}")
print(f"Runtime config copied to: {config_dir}")
print(f"Runtime sdk copied to: {sdk_dir}")
def main():
parser = argparse.ArgumentParser()
parser.add_argument("--name", default="GripperDemo02", help="Output exe/app folder name.")
parser.add_argument("--clean-dist", action="store_true", help="Delete dist/<name> before building.")
args = parser.parse_args()
build(args.name, args.clean_dist)
if __name__ == "__main__":
main()
+15
View File
@@ -0,0 +1,15 @@
import multiprocessing as mp
import os
import sys
from pathlib import Path
if getattr(sys, "frozen", False):
os.chdir(Path(sys.executable).resolve().parent)
from gripper.visualizer import main
if __name__ == "__main__":
mp.freeze_support()
raise SystemExit(main(sys.argv[1:]))