installer/README.md
A self-contained Windows installer for PJ4, built with the Qt Installer
Framework (IFW) — the same mechanism PlotJuggler 3 uses. Output is a single
offline <YYYY.MM.DD>.PlotJuggler-<version>-Windows-x64.<main-commit>.exe (dated,
and stamped with the main commit hash): a wizard that installs the app with a
Start-Menu + Desktop shortcut and a maintenance/uninstall tool.
There is no portable-zip path — the deployment target is this installer.
installer/
├── config.xml # installer identity — version tokenised as __PJ_VERSION__
├── build_windows_installer.ps1 # staging + binarycreator orchestrator (run on Windows)
└── packages/
└── io.plotjuggler.application/
└── meta/
├── package.xml # component metadata — version tokenised
├── installscript.qs # shortcuts, per-user install, custom target-dir page
├── targetwidget.ui # the target-dir wizard page
├── license_mpl.txt # MPL-2.0 (PlotJuggler)
└── license_lgpl.txt # LGPL (Qt)
The source tree is templated (__PJ_VERSION__ / __PJ_RELEASE_DATE__
placeholders) and never mutated by a build: the script renders the XMLs into
a scratch staging directory under %TEMP%\pj4-installer-stage and points
binarycreator -p at that staged packages/ tree.
The staged payload mirrors the prefix layout the app discovers plugins from —
the same convention the Linux AppImage uses (bin beside lib):
<TargetDir>/ # @ApplicationsDirX64@/PlotJuggler4
├── bin/
│ ├── PlotJuggler4.exe # + Qt DLLs, Qt plugins, MSVC runtime, FFmpeg, CPython (+ Lib/, DLLs/, ._pth)
│ └── platforms/ …
└── lib/plotjuggler/plugins/ # verified published plugins; app resolves bin/../lib/plotjuggler/plugins
└── <registry-id>/
├── manifest.json
└── *_plugin.dll
The app scans bin/../lib/plotjuggler/plugins (via applicationDirPath), so
bundled plugins MUST live there — dropping them next to the exe is not scanned.
Plugins load their Qt/FFmpeg/CPython DLLs from bin/ (the exe's directory, which
Windows searches at load time); windeployqt --dir bin puts any plugin-only Qt
modules there too.
conan install . --output-folder=build --build=missing `
-s build_type=RelWithDebInfo -s compiler.cppstd=20 `
-o "cpython/*:shared=True" -s "cpython/*:build_type=Release"
cmake --preset ... ; cmake --build build --config RelWithDebInfo
cpython/*:shared=True override matches Windows CI and produces
python3XX.dll — the local default is static on MSVC and the installer
would then fail to find the runtime.windeployqt.exe. Auto-detected under .qt
(the install_qt6.sh / aqt layout); otherwise pass -QtDir.binarycreator.exe. Install via the Qt
Maintenance Tool, or aqt install-tool --outputdir .qt windows desktop tools_ifw.
Auto-detected next to -QtDir (aqt .qt\Tools) and under C:\Qt\Tools.pj-plugin-registry and their registry SHA-256 is
mandatory. Use -SkipPlugins for an app-only installer, or point
-PluginRegistryUrl at a local registry mirror.The Windows CI and release workflows first resolve Conan 2 packages through the
shared plotjuggler-conan repository at
https://plotjuggler.jfrog.io/artifactory/api/conan/plotjuggler-conan. Configure
these repository-level GitHub Actions settings before dispatching a build:
JFROG_USER: the username shown by the JFrog profile menu (often the
account email address). An Actions secret with the same name is also accepted
for organizations that provision both JFrog values as secrets.JFROG_TOKEN: a scoped JFrog identity/access token with read and
deploy/write access to the repository.These may be repository- or organization-level settings. Organization-level
settings must grant PlotJuggler/PJ4 access.
Trusted push and manual jobs authenticate, install with
-r=plotjuggler-conan -r=conancenter, and publish only missing Conan revisions
to JFrog. This requires one local Conan repository in JFrog; an Artifactory
remote proxy and virtual repository are not required. Pull-request and
noncanonical-repository jobs never reference the JFrog credential; Windows CI
uses public ConanCenter for those jobs and never uploads. Release jobs require
the JFrog settings and fail early with an actionable error when either is
missing. No workflow archives or restores the complete ~/.conan2 directory.
From the repo root, after a Windows build of the app — a plain run downloads the curated published plugins and produces the full installer:
.\installer\build_windows_installer.ps1
-QtDir / -IfwDir are auto-detected (.qt first, then C:\Qt); pass them only
if Qt/IFW live elsewhere. -Version defaults to PJ_APP_VERSION from repo-root
versions.env; override with -Version <x.y.z>.
The script:
plotjuggler4.exe / pj_app.exe under -BuildDir; stages
it as bin\PlotJuggler4.exe in a scratch tree under %TEMP%.-PluginIds against -PluginRegistryUrl for
windows-x86_64, downloads the published marketplace ZIP, verifies its
mandatory SHA-256, checks the package manifest id/version, and unpacks it under
lib\plotjuggler\plugins\<registry-id>. A missing or malformed whitelisted
plugin fails the release; nothing is silently skipped.windeployqt over the exe and every bundled plugin DLL (--dir bin,
so plugin-only Qt modules land in bin).~/.conan2/p/<hash>/p/bin and built-from-source
~/.conan2/p/b/<hash>/p/bin layouts; everything else in the graph is static).Lib/ + DLLs/ (from the DLL's own dir — the Conan package
nests them next to python3XX.dll on Windows) and either reuses the package's
python3XX._pth or synthesizes one, so the embedded interpreter resolves its
stdlib relative to the DLL instead of the build-machine PYTHONHOME baked into
the binary.--validate-plugins mode. This loads every downloaded
DLL through the real runtime catalog and checks the embedded C-ABI manifest,
instance/capability probe, dialog-vtable contract, exact registry id/version,
and absence of non-whitelisted plugins. Any failure stops before packaging.config.xml / package.xml into the stage tree (version +
release-date tokens substituted).binarycreator --offline-only against the stage.Options: -SkipPlugins (fast core-only installer), -PluginIds a,b,c (override
the curated registry ids), -PluginRegistryUrl <url-or-json-path> (registry
source), and -PluginPlatform <key> (defaults to windows-x86_64).
The default whitelist bundles these 13 published plugins:
mcap-loader, csv-loader, parquet-loader, ulog-loader, dummy-streamer,
foxglove-bridge, plotjuggler-bridge, ros-parser, protobuf-parser,
json-parser, toolbox-quaternion, toolbox-transform-editor, and
toolbox-mosaico.
%LOCALAPPDATA%\PlotJuggler4
and does not call gainAdminRights(). Corporate machines that block UAC
prompts install without an escalation dialog. Admin-write locations still
work; the user just picks one.maintenancetool purge. The
earlier flow purged silently.PlotJuggler4.exe..exe is unsigned, so SmartScreen warns on first
run ("More info" → "Run anyway").