Build Packages / Create release (push) Successful in 24s
Build Packages / build:viewer:macos-arm64:nocuda (push) Successful in 3m29s
Build Packages / build:rugnux:macos-arm64:nocuda (push) Successful in 2m43s
Build Packages / build:rugnux:linux-aarch64:cuda (push) Successful in 8m27s
Build Packages / build:rugnux:linux-x86_64:cuda (push) Successful in 9m53s
Build Packages / build:viewer:linux-x86_64:nocuda (push) Successful in 9m58s
Build Packages / build:viewer:linux-x86_64:cuda (push) Successful in 11m22s
Build Packages / build:jfjoch:rocky8:nocuda (push) Successful in 13m39s
Build Packages / build:viewer:windows-x86_64:nocuda (push) Successful in 18m37s
Build Packages / build:jfjoch:rocky9:nocuda (push) Successful in 16m32s
Build Packages / build:viewer:windows-x86_64:cuda (push) Successful in 24m11s
Build Packages / HDF5 consumer tests (DIALS, XDS) (push) Successful in 25m30s
Build Packages / build:jfjoch:ubuntu2404:nocuda (push) Successful in 19m3s
Build Packages / build:jfjoch:ubuntu2204:nocuda (push) Successful in 20m23s
Build Packages / build:jfjoch:rocky8:cuda-sls9 (push) Successful in 19m41s
Build Packages / Generate python client (push) Successful in 50s
Build Packages / Build documentation (push) Successful in 1m16s
Build Packages / build:jfjoch:rocky9:cuda-sls9 (push) Successful in 21m0s
Build Packages / build:jfjoch:rocky8:cuda (push) Successful in 18m38s
Build Packages / build:rugnux:windows-x86_64:cuda (push) Successful in 14m33s
Build Packages / build:jfjoch:rocky9:cuda (push) Successful in 17m55s
Build Packages / build:jfjoch:ubuntu2204:cuda (push) Successful in 20m50s
Build Packages / build:jfjoch:ubuntu2404:cuda (push) Successful in 18m38s
Build Packages / Unit tests (push) Successful in 1h46m14s
* jfjoch_broker: Optional per-dataset authentication - statistics, images and plots can require a bearer token, which jfjoch_viewer supports. * jfjoch_viewer: Dark mode and a theme-matched colour scheme, a magnifier panel, and simpler contrast and background controls. * Rugnux: Multiple performance improvements on GPU and CPU (CPU-only processing up to 40% faster, faster image decoding on ARM), with unchanged results. * Rugnux: `--model` rigid-body refinement runs on the GPU, and the model-validation check is faster and more reliable. * Rugnux: Improved scaling and merging - error model, outlier rejection, absorption correction and French-Wilson amplitudes now agree more closely with XDS and ctruncate. * Rugnux: Improved integration - radial background on powder and ice rings, crowded rotation data keep their reflections, and CPU-only builds integrate large unit cells as GPU builds do. * Rugnux: More robust detector geometry - measured beam centre, X-ray bandwidth and goniometer rate, and geometry refinement accepted only on significant evidence. * Rugnux: Merged files are written in the standard setting, or in the setting of a reference MTZ, structure-factor mmCIF or model, with its free-R flags. * Rugnux: Richer report - ice and powder rings, further lattices, superstructure candidates and mosaicity, with warnings worded as prompts to check. * Rugnux: Clear error messages when a data set needs more GPU or host memory than is available. Reviewed-on: #83 Co-authored-by: Filip Leonarski <filip.leonarski@psi.ch>
331 lines
20 KiB
Markdown
331 lines
20 KiB
Markdown
# jfjoch_viewer
|
||
|
||
`jfjoch_viewer` is the **interactive** desktop application of Jungfraujoch. It opens diffraction
|
||
datasets, displays each image together with the analysis overlay (spots, predictions, azimuthal
|
||
integration, per-image statistics), and can follow a live data collection by syncing with a
|
||
running [`jfjoch_broker`](JFJOCH_BROKER.md) over its HTTP interface.
|
||
|
||
It is a standalone Qt 6 application, distributed pre-built for **Linux, Windows and macOS** on the
|
||
Gitea release page, and for Linux also in the Jungfraujoch RPM/APT repositories — see
|
||
[Release contents](RELEASE_CONTENTS.md) for what each package contains and what it requires, and
|
||
[Deployment](DEPLOYMENT.md) for how to install it. The macOS build needs **macOS 13 (Ventura) or
|
||
newer on an Apple Silicon Mac** (M1 and newer; Intel Macs are not supported) and is CPU-only — see
|
||
[Release contents ▸ macOS](RELEASE_CONTENTS.md#macos), which also covers opening it for the first
|
||
time, as the release is not yet notarized by Apple.
|
||
|
||
## Where it fits among the three analysis tools
|
||
|
||
| Tool | Mode | Driven by | Output |
|
||
| --- | --- | --- | --- |
|
||
| [`jfjoch_broker`](JFJOCH_BROKER.md) | Online, real-time streaming analysis on FPGA + GPU | HTTP/REST + ZeroMQ | Live results and statistics, images streamed to [`jfjoch_writer`](JFJOCH_WRITER.md) |
|
||
| **`jfjoch_viewer`** | **Interactive, on-screen exploration** | **Qt desktop application** | **On screen; a processing job can write the same files as `rugnux`** |
|
||
| [`rugnux`](RUGNUX.md) | Offline batch processing of a stored dataset | Command-line interface | `_process.h5`, and `.mtz`/`.cif`/`.hkl` when merging |
|
||
|
||
## Functionality
|
||
|
||
- Opens HDF5 files written by [`jfjoch_writer`](JFJOCH_WRITER.md) (`*_master.h5`) and the
|
||
`*_process.h5` files produced by [`rugnux`](RUGNUX.md). It also opens NXmx files
|
||
written by DECTRIS detectors, though that path has had only limited testing.
|
||
- Opens PILATUS miniCBF rotation sweeps. These store one frame per file, so naming any frame opens
|
||
the whole sweep it belongs to. A raw CBF carries the images and the geometry but no analysis
|
||
results, so the spot, reflection and per-image plot panels stay empty until something is computed.
|
||
- Runs an **embedded data-processing pipeline** — the same analysis code as the rest of
|
||
Jungfraujoch — performing spot finding, indexing and integration on the displayed image, with the
|
||
result drawn over it. This interactive analysis is not written anywhere.
|
||
- Runs **full processing jobs** on the open dataset with *Analyze dataset*, on the same
|
||
[`rugnux`](RUGNUX.md) engine and off the GUI thread. The settings panel's **MX / AzInt / Calib**
|
||
toggle decides what a run does — full analysis, azimuthal integration only, or a detector
|
||
calibration — over a chosen image range, optionally writing `_process.h5` and the merged
|
||
`.mtz`/`.cif`. A finished run becomes a selectable view of the dataset, so several processing runs
|
||
can be compared against each other, and its merging statistics (or, for a calibration, its fitted
|
||
geometry) open in their own window; the *Processing* panel lists the runs and reopens those
|
||
results. The equivalent `rugnux` command line can also be copied out to run the same job on a
|
||
cluster instead.
|
||
- **Detector calibration** against a powder standard, on the *Calib* page: pick the calibrant
|
||
(`LaB6`, `AgBh`, `CeO2`, `Si`, `ice`, or the open dataset's own unit cell) and fit either the image
|
||
on screen (*Guess* / *Refine detector calibration*) or the whole dataset (*Analyze dataset*, which
|
||
writes a pyFAI `<output prefix>.poni`). The whole-dataset fit measures the rings either from the
|
||
azimuthally-binned profile summed over the run (*Rings*, the default) or from the pooled spot lists
|
||
(*Spots*), and reports PONI x/y, the two tilts and the distance against the header values. Judge it
|
||
by the **radial rms**, not the beam-centre sigma: the sigma shrinks with the number of ring points,
|
||
so a fit that sits a couple of pixels off every ring can still report a small one. *Rings* needs
|
||
the run to be integrated in azimuthal sectors — with the AzInt page's *Azimuthal bins* below 4 the
|
||
calibration run raises it to 32, as `rugnux --mode calibration` does, and says so.
|
||
*Refine detector tilt* is ticked by default and fits the two tilts along with the centre and the
|
||
distance; unticking it holds them where they are, for a calibration meant for a program that
|
||
cannot express a tilted detector (`rugnux --no-refine-tilt`). It applies to both buttons and to
|
||
*Analyze dataset*.
|
||
- **Settings** panel for the geometry, unit cell, spot finding, indexing, azimuthal integration,
|
||
Bragg integration, scaling, powder calibration and a reference dataset — the same settings the
|
||
CLI takes.
|
||
- Auxiliary windows: image list, dataset metadata, spot list, reflection list,
|
||
2D azimuthal-integration image and calibration-image viewer; plus the
|
||
*Inspector* (per-image statistics, image features, resolution rings, ROI statistics), the
|
||
*Magnifier* below it (three zoom levels: ×64 and ×32 with the pixel values written on the pixels,
|
||
×10 without; *Pop out* moves it to a window of its own) and dataset-info charts.
|
||
- The *Inspector*'s **Image features** section decides what the overlay draws — spots, predictions,
|
||
saturated and highest pixels, the beam stop — including whether the non-indexed spots and the
|
||
spots that fall on an ice ring are drawn at all.
|
||
- User-mask editing: build a user mask interactively, load one from TIFF (replacing or adding to the
|
||
current one), save it as TIFF, clear it, or upload it to a connected server.
|
||
- Mouse-driven navigation of the image, the grid scan and the plots — see
|
||
[Mouse shortcuts](#mouse-shortcuts) below, which the viewer also shows under *Help ▸ Mouse
|
||
Shortcuts*.
|
||
- *Help* shows the mouse shortcuts, the [acknowledgements](ACKNOWLEDGEMENT.md) and the third-party
|
||
licenses.
|
||
- Layout presets (*View ▸ Image layout / Processing layout / Reset layout*) rearrange the docks for
|
||
looking at images or at processing results.
|
||
- *View ▸ Theme* picks the light or the dark colour scheme, or *Follow system*. Following the
|
||
system needs a desktop that tells Qt its scheme: macOS and Windows do, and so do GNOME and KDE
|
||
sessions on Linux (elsewhere, `QT_QPA_PLATFORMTHEME=xdgdesktopportal` reaches the portal
|
||
setting); a session Qt cannot read - a bare X server, `ssh -X` - counts as light. The choice is
|
||
remembered across restarts, and the half-sun toolbar button toggles light and dark directly.
|
||
- *View ▸ Font size* (or `Ctrl`+`+` / `Ctrl`+`-`) enlarges the text to 125 % or 150 %, on top of
|
||
whatever scaling the desktop already applies, and the choice is remembered across restarts. The
|
||
viewer also follows the desktop's own text scaling or display scaling on its own; over `ssh -X`,
|
||
where no settings daemon delivers it, launch as `QT_SCALE_FACTOR=1.5 jfjoch_viewer` instead.
|
||
|
||
## A guided tour
|
||
|
||
Four views cover most of what the viewer is used for. The screenshots show the lysozyme reference
|
||
sweep of the in-house test set and a raster scan.
|
||
|
||
### Looking at an image
|
||
|
||
`jfjoch_viewer <file>` opens the file and shows its first image; **File ▸ Open** and the toolbar's
|
||
open button do the same, and **File ▸ Open HTTP** connects to a running `jfjoch_broker` instead.
|
||
|
||

|
||
|
||
The top toolbars step through the images (slider, first/previous/next/last, `Jump` and `Sum` for
|
||
summing consecutive frames) and set the display (foreground limit, `Auto` contrast, HDR, colour
|
||
map, font size, theme). The background limit has a slider of its own, shown from *View ▸
|
||
Background slider* or as soon as `B` + wheel raises it; `Auto` sets it back to zero. The image in the middle zooms with the wheel and
|
||
pans by dragging; hovering shows the pixel position, its value and the resolution on the status
|
||
bar. The **Inspector** on the right lists the dataset's metadata and, once an image has been
|
||
analysed, its spot count, background, indexing result and resolution estimate; the **Magnifier**
|
||
under it follows the cursor while `Shift` is held. On a window too narrow for both, the inspector (with the magnifier) folds
|
||
away and comes back when the window is widened again. The **Dataset info** dock at the bottom plots a per-image quantity
|
||
over the whole sweep - background here; the combo offers spot counts, indexing results, scale
|
||
factors and more once they exist - and `Shift`-hover on it loads the hovered image.
|
||
|
||
### A grid scan
|
||
|
||
A raster scan opens on its two-dimensional map: each cell is one image, coloured by the metric
|
||
chosen in the combo (spot count by default for a grid scan), so the crystal shows up as the bright
|
||
region. `Shift`-hover or double-click a cell to load that image.
|
||
|
||

|
||
|
||
The **Grid** button switches between the map and the per-image line plot; a grid scan remembers
|
||
its own preferred plot, independently of the one used for rotation data.
|
||
|
||
### Processing settings
|
||
|
||
The **Processing** dock on the left (the tab next to **Files**, or **View ▸ Processing layout**)
|
||
holds every setting the analysis takes: geometry and unit cell, the goniometer, spot finding,
|
||
indexing, Bragg integration, scaling, and the reference dataset (MTZ or structure-factor mmCIF)
|
||
with an optional atomic model to validate the merged data against. The MX / AzInt / Calib switch
|
||
selects the kind of analysis and its page.
|
||
|
||

|
||
|
||
**Analyze image** re-analyses the current image with these settings, now and on every change
|
||
while it stays pressed; the inspector and the image overlays update at once.
|
||
|
||
### Processing results
|
||
|
||
**Analyze dataset** runs the whole sweep through the same pipeline as `rugnux` (a job dialog
|
||
takes the image range, the thread count and which files to write, and **Copy command** gives the
|
||
equivalent command line for a cluster). The **Jobs** dock follows the run.
|
||
|
||

|
||
|
||
When it finishes, the job's graph button opens the merge statistics (completeness, CC1/2, I/sigma
|
||
per resolution shell, and the text report), and the dataset-info combo gains the per-image
|
||
indexing result, mosaicity, integrated reflections and scale factors of that run, plotted next to
|
||
the original file's values.
|
||
|
||
## Hardware
|
||
|
||
As with the rest of Jungfraujoch, **serious performance requires an NVIDIA GPU**. On systems with a
|
||
GPU, use the CUDA build (a separate package variant everywhere: RPM/APT repository, `.tgz` and
|
||
Windows installer) for the embedded indexing and integration; the non-CUDA build runs the same
|
||
pipeline on the CPU at much lower throughput. The CUDA build also runs on a machine without a GPU —
|
||
see [Release contents ▸ CUDA and non-CUDA builds](RELEASE_CONTENTS.md#cuda-and-non-cuda-builds).
|
||
|
||
The CUDA build needs an NVIDIA **driver** on the host but no CUDA toolkit — 525.60.13 or newer for
|
||
the CUDA 12 artefacts (RHEL 8 packages, portable Linux `.tgz`), 580.65.06 or newer on Linux and an
|
||
R580 driver on Windows for the CUDA 13 ones (RHEL 9, Ubuntu, Windows installer). The Windows
|
||
installer and the `.tgz` are CUDA 13 and CUDA 12 respectively, which also decides the oldest GPU
|
||
they run on — a V100 needs the CUDA 12 `.tgz`. See
|
||
[Release contents ▸ GPU generations and the NVIDIA driver](RELEASE_CONTENTS.md#gpu-generations-and-the-nvidia-driver).
|
||
|
||
On a Mac there is no CUDA: the viewer always runs the same pipeline on the CPU, with the FFTW
|
||
indexer, like the non-CUDA build elsewhere.
|
||
|
||
### Remote displays
|
||
|
||
The viewer detects a remote display session (`ssh -X` and the like) and limits how often panning,
|
||
zooming and live playback repaint, since on such a link every repaint is shipped as pixels. The
|
||
detection can be overridden in *View ▸ Remote display mode* or with `JFJOCH_VIEWER_REMOTE=0`/`1`.
|
||
A VNC- or xpra-based remote desktop still transports the viewer far more efficiently than plain
|
||
X11 forwarding.
|
||
|
||
## Mouse shortcuts
|
||
|
||
The same list is available in the application under **Help ▸ Mouse Shortcuts**.
|
||
|
||
On macOS, `Ctrl` below means the Command key (`⌘`); right click is also `Ctrl`-click, and on a
|
||
keyboard without them `Home` / `End` are `Fn`+`←` / `Fn`+`→` and `Page Up` / `Page Down` are
|
||
`Fn`+`↑` / `Fn`+`↓`. The Mouse Shortcuts window shows the Mac keys directly.
|
||
|
||
### Diffraction image
|
||
|
||
| Action | Effect |
|
||
| --- | --- |
|
||
| Wheel | Zoom in / out, centred on the cursor |
|
||
| `Shift` + wheel | Move the foreground (upper contrast limit) in linear steps |
|
||
| `Ctrl` + wheel | Move the foreground in multiplicative steps (×1.15 per notch) |
|
||
| `F` held + wheel | Same as `Shift` + wheel, for as long as `F` is held |
|
||
| `B` held + wheel | Move the background (lower contrast limit) in linear steps, for as long as `B` is held; shows the background slider |
|
||
| `A` | Apply auto-contrast once (background back to zero); press it again to switch on continuous Auto |
|
||
| `Home` / `End` | Jump to the first / last image in the dataset |
|
||
| `Page Up` / `Page Down` | Step one image forward / back |
|
||
| Hover | Status bar shows the pixel position, its value and the resolution |
|
||
| Drag | Pan the image |
|
||
| `Shift` + move | Move the magnifier panel to the cursor; a frame shows the area it covers |
|
||
| `Shift` + drag | Draw a rectangular ROI |
|
||
| `Shift` + `Ctrl` + drag | Draw a circular ROI |
|
||
| Drag an ROI or its handle | Move or resize the selected ROI |
|
||
| Right click | Copy / save the image, fit to view, clear the ROI |
|
||
|
||
### Grid scan
|
||
|
||
| Action | Effect |
|
||
| --- | --- |
|
||
| Hover | Status bar shows the image number, the grid position and its value |
|
||
| `Shift` + hover | Load the image under the cursor while moving over the grid |
|
||
| Double click | Load the image under the cursor |
|
||
|
||
### Other views
|
||
|
||
| Action | Effect |
|
||
| --- | --- |
|
||
| 2D azimuthal image: double click | Zoom the diffraction image on the corresponding detector position |
|
||
| Dataset-info plot: hover | Status bar shows the image number and the plotted value |
|
||
| Dataset-info plot: `Shift` + hover | Load the hovered image |
|
||
| Spot / reflection list: double click | Zoom the diffraction image on that spot or prediction |
|
||
| Image list: double click | Load that image |
|
||
|
||
## Opening data
|
||
|
||
- **File ▸ Open** (`Ctrl+O`) — open a local HDF5 file, or any frame of a miniCBF sweep.
|
||
- **File ▸ Open HTTP** (`Ctrl+H`) — connect to a `jfjoch_broker` HTTP endpoint to follow a live
|
||
collection. The dialog defaults to host `localhost` and port `8080`; these defaults can be
|
||
overridden with the environment variables `JUNGFRAUJOCH_HTTP_HOST` and `JUNGFRAUJOCH_HTTP_PORT`.
|
||
The scheme box selects `http://` or `https://` (the latter for a broker behind a TLS proxy), and
|
||
the **Token** field takes the dataset's bearer token when the collection was started with one.
|
||
The token can also come from `JUNGFRAUJOCH_HTTP_TOKEN` or from D-Bus (below); what is typed in the
|
||
dialog overrides both, and nothing is stored between sessions. Without a valid token for a
|
||
protected dataset the viewer shows nothing and says so on the status bar — no dialog, since a
|
||
dataset changing hands is the normal reason.
|
||
- **Command line** — `jfjoch_viewer <file>` opens a file (or an `http://host:port` URL) on
|
||
start-up. `--dbus <true|false>` (`-d`) enables or disables the D-Bus interface (default: enabled);
|
||
`--help` and `--version` behave as usual.
|
||
|
||
## D-Bus interface
|
||
|
||
When enabled, the viewer registers the D-Bus interface `ch.psi.jfjoch_viewer`, so other processes
|
||
can drive it. D-Bus is **Linux only**: the Windows and macOS builds have no D-Bus interface, and
|
||
`--dbus` has no effect there.
|
||
|
||
- `LoadFile(filename, image_number=0, summation=1, token="")` — open a file (or an
|
||
`http://host:port` URL) and display the given image; a non-empty `token` is the bearer token of a
|
||
protected broker dataset.
|
||
- `LoadImage(image_number, summation=1)` — navigate to an image in the already-open dataset.
|
||
- `SetHttpToken(token)` — set the dataset token without reloading; the next request carries it.
|
||
|
||
`summation` sums that many consecutive images before display. A repeated `LoadFile` call naming the
|
||
file that is already open is cheap (it just navigates, like `LoadImage`) rather than reopening it,
|
||
but a client stepping through images of a dataset it opened itself should still prefer `LoadImage` —
|
||
it needs no filename and avoids the file-identity comparison.
|
||
|
||
## Building from source on Windows
|
||
|
||
`jfjoch_viewer` is cross-platform: it builds on Windows 11 with MSVC and the full CUDA GPU path, and
|
||
on macOS (see [below](#building-from-source-on-macos)). (The rest of Jungfraujoch — broker, receiver, FPGA host — is
|
||
Linux-only.) A pre-built installer is published with every release, so building from source is only
|
||
needed to develop or to change the build options. On Windows the build is automatically restricted
|
||
to the viewer and the libraries it needs (`JFJOCH_VIEWER_ONLY` is forced on), and the remaining
|
||
dependencies are fetched and built automatically (the first configure needs network access).
|
||
|
||
Verified toolchain — the same one the released installer is built with:
|
||
|
||
- Windows 11
|
||
- Visual Studio 2026 with the C++ (MSVC) toolset — required; CUDA on Windows builds through MSVC
|
||
- CUDA Toolkit 13.3 (12.8 or newer is required) — for the GPU indexing/integration path
|
||
- Qt 6.11 for MSVC (`msvc2022_64`), including the **Qt Charts** module — e.g. `C:\Qt\6.11.1\msvc2022_64`
|
||
- CMake plus Ninja. The CMake that ships with Visual Studio is the simplest choice and works out of
|
||
the box — it comes with the C++ workload, so there is nothing extra to install. Any recent
|
||
standalone CMake (from cmake.org, or the one bundled with Qt in `C:\Qt\Tools\CMake_64`) works too.
|
||
- Optional: [NSIS](https://nsis.sourceforge.io) to build the `.exe` installer.
|
||
|
||
Configure and build from an **x64 Native Tools Command Prompt for VS 2026** (so `cl`, `nvcc` and
|
||
`ninja` are on `PATH`):
|
||
|
||
```
|
||
cmake -G Ninja -B build-win -DCMAKE_BUILD_TYPE=Release ^
|
||
-DCMAKE_PREFIX_PATH="C:/Qt/6.11.1/msvc2022_64"
|
||
cmake --build build-win --target jfjoch_viewer
|
||
```
|
||
|
||
Notes:
|
||
|
||
- `CMAKE_PREFIX_PATH` (Qt) is the only required flag. Every other dependency, zlib and Eigen
|
||
included, is downloaded and built by the configure itself, so nothing else has to be installed.
|
||
- The CUDA toolchain is located automatically from the `CUDA_PATH` environment variable that the
|
||
CUDA installer sets (or from `nvcc` on `PATH`). Pass `-DCMAKE_CUDA_COMPILER=".../bin/nvcc.exe"`
|
||
only if `nvcc` is installed in a nonstandard location and is not found.
|
||
- For a machine without an NVIDIA GPU, add `-DJFJOCH_USE_CUDA=OFF`: the viewer then runs the same
|
||
pipeline on the CPU (FFTW indexer) at lower throughput.
|
||
|
||
To produce a self-contained installer (bundles the Qt runtime via `windeployqt` and — on the CUDA
|
||
build — the cuFFT runtime DLL, so the target host needs neither Qt nor a CUDA toolkit), with NSIS
|
||
installed:
|
||
|
||
```
|
||
cd build-win
|
||
cpack
|
||
```
|
||
|
||
The NSIS generator is selected automatically on Windows (no `-G` needed). What comes out, and how
|
||
the CUDA and CPU variants are named and told apart, is described in
|
||
[Release contents ▸ Windows installer](RELEASE_CONTENTS.md#windows-installer).
|
||
|
||
## Building from source on macOS
|
||
|
||
The viewer also builds on macOS, **Apple Silicon only** and without CUDA; as on Windows, the build
|
||
is automatically restricted to the viewer and the libraries it needs (`JFJOCH_VIEWER_ONLY` is forced
|
||
on) and fetches every other dependency itself. A pre-built disk image is published with every
|
||
release, so building from source is only needed to develop or to change the build options.
|
||
|
||
Verified toolchain — the same one the released `.dmg` is built with:
|
||
|
||
- An Apple Silicon Mac; the resulting app needs macOS 13 or newer, whatever the build machine runs
|
||
- Xcode (Apple Clang)
|
||
- Qt 6.11 for macOS, including the **Qt Charts** module — e.g. `~/Qt/6.11.2/macos` from the Qt
|
||
online installer
|
||
- CMake (e.g. `CMake.app` from cmake.org, with `/Applications/CMake.app/Contents/bin` on `PATH`)
|
||
|
||
```
|
||
cmake -S . -B build-mac -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH=$HOME/Qt/6.11.2/macos
|
||
cmake --build build-mac -j$(sysctl -n hw.ncpu) --target jfjoch_viewer
|
||
open build-mac/viewer/jfjoch_viewer.app
|
||
```
|
||
|
||
As on Windows, `CMAKE_PREFIX_PATH` (Qt) is the only required flag. To produce the disk image — the
|
||
Qt frameworks and the license notices copied into the app with `macdeployqt`, packed into
|
||
`jfjoch-viewer-<version>-macos-arm64.dmg` — run `cpack` in the build directory. What comes out is
|
||
described in [Release contents ▸ macOS](RELEASE_CONTENTS.md#macos).
|