official 0.1.0 version
This commit is contained in:
+133
-32
@@ -1,40 +1,79 @@
|
||||
# Build
|
||||
|
||||
Windows packaging for the studio desktop app.
|
||||
Windows packaging for the studio desktop app: **one provisioning step per machine, then
|
||||
repeatable builds.**
|
||||
|
||||
## Layout
|
||||
|
||||
```text
|
||||
build/
|
||||
studio/
|
||||
entry.py # frozen entry (no source chdir)
|
||||
orisys-studio.spec # PyInstaller onedir spec
|
||||
build.ps1 # create/reuse .venv-build and build
|
||||
_pyinstaller/ # PyInstaller workpath (gitignored)
|
||||
setup.bat / setup.ps1 # provision the build venv (run once per machine)
|
||||
constraints-build.txt # pinned build-time versions
|
||||
build.bat / build.ps1 # build the EXE and verify it
|
||||
entry.py # frozen entry (no source chdir)
|
||||
orisys-studio.spec # PyInstaller onedir spec
|
||||
_pyinstaller/ # PyInstaller workpath (gitignored)
|
||||
_smoke/ # log of the last build's start-up smoke test
|
||||
dist/
|
||||
OrisysStudio/
|
||||
OrisysStudio.exe
|
||||
config/ # lean locales + sensors (no finger visualization/)
|
||||
_internal/ # Python, PyQt5, opencv-headless, orisys, …
|
||||
config/ # lean locales + sensors (no finger visualization/)
|
||||
_internal/ # Python, PyQt5, opencv-headless, orisys, OpenGL, …
|
||||
```
|
||||
|
||||
## Prerequisites
|
||||
## Why there are two steps
|
||||
|
||||
- Windows + Python 3.10+ on PATH
|
||||
- `orisys` installable into the build venv (`pip install orisys>=0.5`)
|
||||
- Do **not** install `orisys[gui]` / Open3D for this build
|
||||
A PyInstaller bundle depends on the *machine* as much as on the sources: which interpreter,
|
||||
whether it is Anaconda (whose `libexpat`/`libffi`/OpenSSL DLLs live outside the venv and are
|
||||
therefore **not** bundled), and where the `orisys` SDK checkout is. Those facts are decided
|
||||
once, by `setup.ps1`, and recorded in `.venv-build\orisys-build-env.json`.
|
||||
|
||||
`build.ps1` then installs nothing and guesses nothing: it verifies the environment, builds,
|
||||
and verifies the artefact. That split is what keeps a build reproducible instead of
|
||||
"works on my machine".
|
||||
|
||||
## First time on a machine
|
||||
|
||||
```bat
|
||||
cd build\studio
|
||||
setup.bat
|
||||
setup.bat -Python C:\Python310\python.exe
|
||||
setup.bat -AllowConda
|
||||
```
|
||||
|
||||
`setup.bat` finds an interpreter, creates or repairs `.venv-build`, installs the pinned
|
||||
toolchain plus the app's extras (including the studio's `three-d` extra — without it the 3D
|
||||
pane silently reports "PyOpenGL is not installed" on the customer's machine), writes the
|
||||
stamp, and then verifies the result by importing what the frozen app imports.
|
||||
|
||||
Interpreter resolution, in order: `-Python <path>`; `py -3.10`; `python`; the interpreter
|
||||
already behind `.venv-build`. The Microsoft Store `python.exe` alias is refused (it is not an
|
||||
interpreter), and an Anaconda interpreter is refused unless `-AllowConda` is passed — in that
|
||||
case its `Library\bin` is recorded and the spec adds the runtime DLLs, because PyInstaller
|
||||
does not search there and the EXE would otherwise die at start-up with
|
||||
`ImportError: DLL load failed while importing pyexpat`. Building with python.org CPython is
|
||||
still the preferred answer.
|
||||
|
||||
The SDK is installed from `..\..\..\orisys-sdk` when that checkout exists (`-SdkPath` to point
|
||||
elsewhere, `-FromPypi` to install the published wheel instead). Installing the published SDK
|
||||
is how a build once shipped with no `orisys.finger` at all.
|
||||
|
||||
Re-running `setup.bat` is safe: with a valid stamp for this checkout it reports and exits;
|
||||
without one it repairs the existing venv rather than deleting it. `-Force` recreates it.
|
||||
|
||||
## Build
|
||||
|
||||
From `build\studio` (recommended):
|
||||
|
||||
```bat
|
||||
build.bat
|
||||
build.bat -Clean
|
||||
build.bat -SkipInstall
|
||||
build.bat -Clean # after dependency/spec changes
|
||||
build.bat -RebuildVenv # setup.bat -Force, then build
|
||||
build.bat -SkipInstall # never provision: fail instead
|
||||
build.bat -SkipSmokeTest # do not launch the produced EXE
|
||||
build.bat -StrictSmokeTest # treat a 3D-context warning as a failure
|
||||
```
|
||||
|
||||
Or from repo root:
|
||||
Or from the repo root:
|
||||
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File .\build\studio\build.ps1
|
||||
@@ -42,35 +81,97 @@ powershell -ExecutionPolicy Bypass -File .\build\studio\build.ps1
|
||||
|
||||
`build.bat` always resolves `build.ps1` next to itself (cwd-independent) and forwards flags.
|
||||
|
||||
Flags:
|
||||
## What the build verifies, and why
|
||||
|
||||
| Flag | Meaning |
|
||||
|------|---------|
|
||||
| `-Clean` | Pass `--clean` to PyInstaller (use after dep/spec changes) |
|
||||
| `-SkipInstall` | Reuse packages already in `.venv-build` (faster iteration) |
|
||||
Every silent failure this packaging has produced looked like a *successful* build, so the
|
||||
script checks the things that only show up when the EXE runs:
|
||||
|
||||
Output: `dist\OrisysStudio\OrisysStudio.exe`
|
||||
| check | failure it prevents |
|
||||
|---|---|
|
||||
| the venv imports `orisys_app_shared`, `orisys_studio`, `orisys`, `OpenGL`, `cv2`, `PyInstaller` | a stale editable install still builds (the spec's `pathex` finds the modules) and produces an EXE that cannot start |
|
||||
| `collect_data_files('orisys_app_shared', includes=['theme/*.json'])` is non-empty | the theme colours are package data; without them the app dies in `build_qss()` before logging anything |
|
||||
| every `config\sensors\**\*.oryscene` is present, and the finger manifest/`sensor.json`/unroll map survive the config strip | the 3D pane refuses the scene when the device description cannot be derived |
|
||||
| no `open3d*` under `dist` | the offline tool leaking into the shipped bundle |
|
||||
| **smoke test**: start the produced EXE, wait for its own log to say `Studio shell started` (and `3D scene loaded` when a finger scene shipped), then stop it | a bundle that cannot start at all — missing runtime DLLs, an excluded module, missing data. The log is kept under `build\_smoke\` |
|
||||
|
||||
The smoke test seeds a `preference.json` beside the EXE to select the finger sensor with the
|
||||
3D pane on, and restores (or removes) it afterwards. A *GL context* failure is reported as a
|
||||
warning, because it is environment-dependent; `-StrictSmokeTest` turns it into a failure.
|
||||
|
||||
## Where the app's own code lives in the bundle
|
||||
|
||||
`_internal\` contains **native code and data files only**. Every pure-Python module —
|
||||
`orisys_studio.*`, `orisys_app_shared.*`, `orisys.*` — is compiled into the `PYZ` archive that
|
||||
sits *inside* `OrisysStudio.exe` (that is most of the EXE's ~13 MB). So there is deliberately
|
||||
no `_internal\orisys_studio\` folder, and no `.py` files anywhere: PyInstaller ships bytecode,
|
||||
never sources.
|
||||
|
||||
`_internal` therefore shows only these orisys-related paths:
|
||||
|
||||
```text
|
||||
_internal\orisys_app_shared\theme\colors_dark.json <- package data, bundled (qss.py reads it)
|
||||
_internal\orisys_app_shared\theme\colors_light.json
|
||||
_internal\orisys\.gitignore <- stray non-.py file of the SDK package
|
||||
_internal\branding\... <- logos
|
||||
```
|
||||
|
||||
(`collect_data_files("orisys")` exists for the case where the SDK is installed from a wheel that
|
||||
bundles `sensors/` assets; with a local editable checkout the only non-`.py` file is that
|
||||
`.gitignore`. It is harmless — the app prefers `config\sensors` — but it does look odd.)
|
||||
|
||||
To list what is really in the archive:
|
||||
|
||||
```bat
|
||||
.venv-build\Scripts\python.exe -m PyInstaller.utils.cliutils.archive_viewer ^
|
||||
-l -r -b dist\OrisysStudio\OrisysStudio.exe
|
||||
```
|
||||
|
||||
(The `PYZ-00.toc` under `build\_pyinstaller\orisys-studio\` is the same information at build
|
||||
time, and `build\_smoke\*.log` is the runtime proof: "Studio shell started" and "3D scene
|
||||
loaded" can only be printed if those modules imported.)
|
||||
|
||||
## Dependency notes
|
||||
|
||||
- App shared dep uses **`opencv-python-headless`** (PyQt owns the GUI).
|
||||
- Upstream `orisys` may still declare `opencv-python`. `build.ps1` uninstalls that wheel and installs **`opencv-python-headless>=4.10,<5`** (5.x has shipped broken wheels without a `cv2` module). The script verifies `import cv2` before packaging.
|
||||
- **Open3D is excluded** (spec + build env). Finger 3D remains a placeholder in the UI.
|
||||
- App shared dep uses **`opencv-python-headless`** (PyQt owns the GUI). `setup.ps1` uninstalls
|
||||
any `opencv-python` and pins `opencv-python-headless>=4.10,<5` (5.x has shipped wheels
|
||||
without a `cv2` module) and verifies `import cv2`.
|
||||
- **PyOpenGL** is the GL binding for the 3D pane and comes from the studio's `three-d` extra.
|
||||
Add the `protected-assets` extra (`cryptography`) if sealed `.oryscene` packages are shipped.
|
||||
- **Open3D stays excluded** (spec + build env): it is an offline geometry tool. The 3D pane is
|
||||
Qt `QOpenGLWidget` + PyOpenGL.
|
||||
- `constraints-build.txt` pins the toolchain. Move a pin only together with `setup.bat -Force`
|
||||
and a passing `build.bat` — the smoke test is the acceptance evidence, not the file.
|
||||
|
||||
## GL note
|
||||
|
||||
The pane asks for the profile in `gl_profile` (`desktop33` by default, `gles30` otherwise). A
|
||||
`desktop33` request needs a desktop GL 3.3 core context; on some sessions Qt falls back to its
|
||||
ANGLE (GLES) backend, which cannot satisfy it, and the widget then reports no context on a
|
||||
machine whose GPU is fine. `QT_OPENGL=desktop` is the workaround; the durable fix is to pin
|
||||
the backend in `orisys_studio.main` before `QApplication` is constructed
|
||||
(`Qt.AA_UseDesktopOpenGL` / `Qt.AA_UseOpenGLES`). `build.bat -StrictSmokeTest` makes this a
|
||||
build failure.
|
||||
|
||||
## Size / startup
|
||||
|
||||
- **onedir** (not onefile): faster cold start; ship the whole `OrisysStudio` folder.
|
||||
- Finger `assets/visualization/` is stripped from the shipped `config/` (~11 MB saved).
|
||||
- Finger `assets/visualization/` is stripped from the shipped `config/` (~11 MB saved). Nothing
|
||||
in the app reads it (`manifest.json`'s `viz_pose` is used only by the SDK examples); the 3D
|
||||
pane needs `scene/*.oryscene` plus `assets/30fps-0703`, and the build checks both.
|
||||
- Studio shell defers OpenCV / acquisition imports until Preview or Run.
|
||||
|
||||
Expect hundreds of MB total (Qt + numpy/scipy/numba + OpenCV). Without Open3D this stays smaller than a full `orisys[gui]` bundle.
|
||||
Expect ~450 MB total (Qt + numpy/scipy/numba + OpenCV + PyOpenGL).
|
||||
|
||||
## Verification
|
||||
## Verification on a new machine
|
||||
|
||||
1. Launch `OrisysStudio.exe` on the build machine (and ideally a clean PC without Python).
|
||||
2. Theme / locale / prefs work; `preference.json` and `outputs\` appear next to the EXE.
|
||||
3. Camera preview + box/mini/finger Run (video) with image modes and force plots.
|
||||
4. Confirm no `open3d*` files under `dist\OrisysStudio`.
|
||||
1. `setup.bat` (see its report: interpreter, conda or not, SDK source).
|
||||
2. `build.bat` — its smoke test must print "the application started" and "the packaged 3D
|
||||
scene loaded".
|
||||
3. Launch `OrisysStudio.exe` and check theme/locale/prefs; `preference.json` and `outputs\`
|
||||
appear next to the EXE.
|
||||
4. Camera preview + box/mini/finger Run (video) with image modes and force plots.
|
||||
5. Open the 3D pane on a finger source: the surface draws, the legend shows the field.
|
||||
6. Confirm no `open3d*` files under `dist\OrisysStudio`.
|
||||
|
||||
## Editable run (unchanged)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user