The driver builds into build4_$(date +%Y%m%d_%H%M%S)_$; the old build4_2* pattern only covered current-year timestamps. Ignore the whole family so build artifacts stop showing up as untracked. Co-Authored-By: Claude Code <noreply@anthropic.com>
qt6-migrated-legatus — Release 2 Build Guide
Build guide for the Qt6-migrated legatus tree for Release 2 (guez project). Everything runs inside a prebuilt Docker image; the host only needs Docker.
Release 2 Scope
Release 2 includes all Release 1 packages plus new modules:
| Area | Contents | Targets |
|---|---|---|
| Release 1 Packages | TetraIF, Z module, Lts/Common, Tests | 35 targets |
| AP3 — Shared Libraries | LtsUtils, Widgets, Session, Krypto, PluginManager | 6 targets |
| AP4 — DDS Middleware | Core, DDSConnector, Routing, QosProfile, RTI DDS compatibility | 6 targets |
| AP9 — Tools & Translations | DdsView, LogViewer, SqlBrowser, generators, lupdate toolchain | 4 targets |
Total: 38 targets across 4 build groups (GROUP1, GROUP3, GROUP5, GROUP6)
Target Breakdown
| Group | Area | Targets | Count |
|---|---|---|---|
| GROUP1 | DDS/AP4 | ddscore, ddsftccore, ddsfts, ddsgen, ddsQoS, ddsconnector | 6 |
| GROUP3 | Lts/AP3/TetraIF/Tests | NGL (14), Lts (4), Plugin Interfaces (2), AP3 Libraries (4), Release 1 Additions (2), Tests (7) | 28 |
| GROUP5 | Viewer/AP9 | ddsview, LogViewer, sqlbrowser | 3 |
| GROUP6 | Tools/AP9 | ngl_codegen | 1 |
Release 1 Modules Included
| Module | Targets | Description |
|---|---|---|
| TetraIF | 5 | CoPrtCnv, LogView, LogViewLogger, PrtCnv, PrtCnvLib |
| Z Module | 16 | NGL application/core library stack (NGLLogger, nglapplication, nglcompression, nglcoreapplication, ngldb, nglguiapplication, nglsettings, nglsingleapplication, nglsinglecoreapplication, ngltools, ngltranslator, nglwidgets, qtsingleapplication, qtsinglecoreapplication) |
| Lts/Common | 3 | LtsCoordinate, LtsCoordTrans, LtsMultiMonitor |
| Tests | 7 | aes_crypt_test, ngltools_qt_smoke, lts_coord_trans_unit_test, test_nglpdfwidget, coprtcnv_unit_test, logview_unit_test, prtcnv_unit_test |
| Additional | 2 | LtsLicence, MockCoordTrans |
Entries at the tree root
new_docker_build_release2.sh— Release 2 build driver (image build, compile, ctest, DEB packaging)Dockerfile— recipe of the prebuilt build image (Ubuntu 26.04 + Qt 6.10.2 + deps)rpmbuild/make_rpm_ubuntu26_release2.py— Release 2 DEB package producer (5 packages)jenkins-ci-rme/— in-tree copy of the Jenkins CI flow (see its ownREADME.md)build4/— build tree, created by the driver (git-ignored scratch area)
Toolchain inside the image: Ubuntu 26.04, GCC 15.2.0, Qt 6.10.2 (/opt/Qt/6.10.2/gcc_64), C++17, Release build.
Qt Installation: Qt 6.10.2 installed via aqt install-qt (no apt Qt6 packages).
Prerequisites
- Docker available on the host.
- The tree must be reachable inside the container at
/workspace/qt-migration-legatus/qt6-after/qt6-migrated-legatus, i.e. mount the pipeline root on/workspace— this is hownew_docker_build_release2.shinvokes Docker, so running the driver as-is satisfies this.
The driver resolves the pipeline root from its own location (override
with the exported MIGRATE_PIPELINE_ROOT or the .envrc in this
directory).
All commands below are run from this directory
(qt6-migrated-legatus/).
Step 1 — Build the prebuilt Docker image (once)
./new_docker_build_release2.sh --build-prebuilt-image --docker-image guez-release2:2.0
This builds the image from the in-tree Dockerfile (Ubuntu 26.04 base,
apt deps, Qt 6.10.2 via aqtinstall, KDReports from source). Re-run it
only after changing the Dockerfile or the APT_PACKAGES list in
new_docker_build_release2.sh.
To remove it later:
./new_docker_build_release2.sh --delete-prebuilt-image --docker-image guez-release2:2.0
Step 2 — Compile the Release 2 scope
./new_docker_build_release2.sh --docker-image guez-release2:2.0
What the driver does inside the container:
-
rm -rf build4 && mkdir build4 && cd build4(fresh build tree) -
Configure with CMake:
cmake .. \ -DBUILD_TESTING=ON \ -DRELEASE_BUILD=ON \ -DCMAKE_CXX_STANDARD=17 \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_PREFIX_PATH=/opt/Qt/6.10.2/gcc_64:/usr/local(
RELEASE_BUILD=ONselects the Release 2 scope; everything else is at its CMake default.) -
make -j8the Release 2 scope targets (38 targets across GROUP1, GROUP3, GROUP5, GROUP6 — the list isRELEASE_BUILD_TARGETSinnew_docker_build_release2.sh). -
Run ctest (see Step 3).
Output to inspect after the run:
build4/release_build.log— full make outputbuild4/bin/— executables (apps + test binaries)build4/lib/— shared libraries
To rebuild incrementally without a fresh tree, run make directly in an
interactive container against the existing build4/:
docker run --rm -it -v /path/to/pipeline-root:/workspace guez-release2:2.0 \
bash -c 'cd /workspace/qt-migration-legatus/qt6-after/qt6-migrated-legatus/build4 \
&& make -j8'
Run an executable directly
To run a built executable interactively — e.g. the GUI apps under
build4/bin/ (LogView, PrtCnv) against your local display — start a
shell inside the container with X11 forwarding:
docker run --rm -it \
-e DISPLAY \
-e LC_ALL=C.UTF-8 \
-v /tmp/.X11-unix:/tmp/.X11-unix \
-v /path/to/pipeline-root:/workspace \
legatus-qt6:1.0 \
bash -c 'cd /workspace/qt-migration-legatus/qt6-after/qt6-migrated-legatus/build4 && exec bash'
Step 3 — Run the tests
3.1 ctest (automatic)
new_docker_build.sh already runs ctest --test-dir build4 --output-on-failure after the compile. Expected baseline (7 tests, all
passed):
| # | Test | Result |
|---|---|---|
| 1 | coprtcnv_unit_test |
Passed |
| 2 | logview_unit_test |
Passed |
| 3 | prtcnv_unit_test |
Passed |
| 4 | NGLToolsQtSmoke |
Passed |
| 5 | test_nglpdfwidget |
Passed |
| 6 | lts_coord_trans_unit_test |
Passed |
| 7 | aes_crypt_test |
Passed |
3.2 Build the unit tests only
docker run --rm -v /path/to/pipeline-root:/workspace legatus-qt6:1.0 \
bash -c 'cd /workspace/qt-migration-legatus/qt6-after/qt6-migrated-legatus/build4 \
&& make -j8 coprtcnv_unit_test logview_unit_test prtcnv_unit_test'
3.3 Run a test executable directly
GUI-free tests need the offscreen Qt platform in a headless container:
docker run --rm -it -v /path/to/pipeline-root:/workspace legatus-qt6:1.0 \
bash -c 'export QT_QPA_PLATFORM=offscreen
cd /workspace/qt-migration-legatus/qt6-after/qt6-migrated-legatus/build4
./bin/coprtcnv_unit_test # CoPrtCnv: telegrams, fragmentation, helpers
./bin/logview_unit_test # LogView: IntegerCalculator
./bin/prtcnv_unit_test # PrtCnv: PrtCnvMember fragmented-telegram handling
./bin/lts_coord_trans_unit_test
./bin/aes_crypt_test
./bin/test_nglpdfwidget
# or everything registered:
ctest --output-on-failure'
Each QtTest binary accepts a single slot name to run just one test,
e.g. ./bin/coprtcnv_unit_test radioTelegramFragmentationRoundtrip.
3.4 TetraIF unit tests (TetraIF/unit-test/)
| Test | Module covered | Note |
|---|---|---|
coprtcnv_unit_test |
CoPrtCnv — central & radio telegram header fields, payload access, length checks, fragmentation/reassembly roundtrip, id→string helpers |
links CoPrtCnv |
logview_unit_test |
LogView — IntegerCalculator (arithmetic, precedence, error codes, variables) |
compiles LogView/IntegerCalculator.cpp into the test (the class otherwise lives in the LogView executable) |
prtcnv_unit_test |
PrtCnv — PrtCnvMember state + fragmented-telegram add/reassembly |
compiles PrtCnv/PrtCnvMember.cpp into the test because PrtCnvLib is built with hidden visibility (its symbols are not linkable from outside) |
Sources are registered with ctest via TetraIF/unit-test/CMakeLists.txt
and packaged into the ctest DEBs (see Step 4).
Step 4 — Produce the Release 2 DEB packages
export WORKSPACE=/path/to/pipeline-root # e.g. ~/release/qt6-migration-pipeline
export PROJECT=guez
export OS_VERSION=26.04
./new_docker_build_release2.sh --docker-image guez-release2:2.0 \
--run-jenkins-builder \
--package-output-dir "${WORKSPACE}/rpms/${PROJECT}/${OS_VERSION}/" \
> /path/to/build.log 2>&1
(export the variables before the command — command-prefix variables are not expanded in the same command's arguments.)
The driver compiles the Release 2 scope (38 targets), runs ctest,
then stages the tree and runs the in-tree rpmbuild/make_rpm_ubuntu26_release2.py,
which produces 5 DEBs in ${WORKSPACE}/rpms/${PROJECT}/${OS_VERSION}/:
| DEB | Contents |
|---|---|
guez-runtime_2.0_amd64.deb |
Runtime libraries (Lts, AP3, AP4, TetraIF, Z) + executables |
guez-sources_2.0_amd64.deb |
Release 2 scope sources |
guez-ctest-runtime_2.0_amd64.deb |
Test executables under /usr/lib/ctest/ (13 tests incl. TetraIF unit tests) |
guez-ctest-sources_2.0_amd64.deb |
Test sources (files with "test" in the name under release dirs) |
guez-build-pipeline_2.0_amd64.deb |
Pipeline files (new_docker_build_release2.sh, Dockerfile, CMakeLists.txt, rpmbuild/, jenkins-ci-rme/) under /usr/src/pipeline/ |
Verify a package:
dpkg -c "${WORKSPACE}/rpms/guez/26.04/guez-ctest-runtime_2.0_amd64.deb" \
| grep unit_test
dpkg -i "${WORKSPACE}/rpms/guez/26.04/"*.deb # install locally, if wanted
A copy of the DEBs is also placed in the container's
/workspace/packages-out mount (same-file skip guarded by device:inode).
Step 5 — CI / Jenkins flow (optional)
The in-tree jenkins-ci-rme/ directory contains the full Jenkins
pipeline (Jenkinsfile, builder, publisher) adapted to this tree. For a
local dry run of the same flow without Jenkins:
jenkins-ci-rme/release-16-10-2026.sh
See jenkins-ci-rme/README.md for the pipeline details.
Step 6 — Code coverage (lcov)
export WORKSPACE=/path/to/pipeline-root # e.g. ~/release/qt6-migration-pipeline
export PROJECT=guez
export OS_VERSION=26.04
./new_docker_build_release2.sh --docker-image guez-release2:2.0 \
--run-coverage \
--coverage-output-dir "${WORKSPACE}/coverage/${PROJECT}/${OS_VERSION}/" \
> /path/to/coverage.log 2>&1
(export the variables before the command — command-prefix variables are not expanded in the same command's arguments.)
The driver builds the Release 2 scope with -O0 --coverage, runs the same ctest
suite (13 tests), then captures the data with lcov: the report covers the Release 2 scope
(AP3, AP4, AP9, TetraIF, Z/src, Lts/Common, Lts/Proxies/TrainingAreaBase), and test
sources are filtered out of the report, so the percentages reflect the module
code.
Artifacts in the coverage output directory:
| File | Contents |
|---|---|
html/index.html |
browsable report (line + branch coverage per file) |
coverage.info |
machine-readable lcov tracefile |
coverage_summary.txt |
whole-scope totals |
--run-coverage is mutually exclusive with --run-jenkins-builder (different
instrumentation of the same build tree).
The Jenkins pipeline runs the same step on every build (RunCoverage
parameter, on by default) and archives the report as build artifacts under
coverage/<project>/<os>/; the local dry run
(jenkins-ci-rme/release-16-10-2026.sh) does the same, with
DRYRUN_COVERAGE=OFF to skip coverage there.
Options reference
./new_docker_build_release2.sh --help prints the full option list. The main
ones:
| Option | Default | Purpose |
|---|---|---|
--docker-image IMAGE |
guez-release2:2.0 |
image to use/build/delete |
--build-prebuilt-image |
— | build the image from ./Dockerfile and exit |
--delete-prebuilt-image |
— | delete the image and exit |
--run-jenkins-builder |
off | produce the DEB packages (Step 4) |
--package-output-dir DIR |
./packages-out |
where the DEBs are written |
--lts-version / --project / --build-number / --build-tag |
2.0 / guez / 1 / manual-build |
package metadata |
--run-coverage |
off | coverage build + lcov report (Step 6) |
--coverage-output-dir DIR |
./coverage-out |
where the coverage report is written |
Environment overrides: DOCKER_IMAGE, RUN_JENKINS_BUILDER,
PACKAGE_OUTPUT_DIR, RUN_COVERAGE, COVERAGE_OUTPUT_DIR, PROJECT,
LTS_VERSION, GUEZ_MODE, BUILD_NUMBER, BUILD_TAG,
MIGRATE_PIPELINE_ROOT.
Troubleshooting
- "no Qt platform plugin could be initialized" when running a test
binary by hand →
export QT_QPA_PLATFORM=offscreen. - Stale build tree → the driver always recreates
build4/; for manual builds deletebuild4/and rerun Step 2 if CMake behaves oddly. - DEBs not on the host → the output dir must be a path that exists
on the host (it is bind-mounted into the container as
/workspace/packages-out); check thepackage-output-dirargument. - Build fails with missing Qt modules → ensure the container uses
new_docker_build_release2.shwhich installs Qt 6.10.2 viaaqt install-qt. The image must beguez-release2:2.0(notlegatus-qt6:1.0).