Files
qt-migration-legatus/qt6-after/qt6-migrated-legatus/README.md
T
berrux-dev 09b6df8bc3 Add per-module unit-test dirs for the Release 2 scope
One unit-test/ directory per module/target, mirroring the existing
TetraIF/unit-test/ layout (one QtTest executable per module, guarded by
BUILD_TESTING and the module target, each registered with ctest):

  Lts/Common/CodeGen      codegen_unit_test
  Lts/Common/LtsCoordinate ltscoordinate_unit_test
  Lts/Common/LtsSession   ltssession_unit_test
  Lts/DDS/Core            ddscore_unit_test
  Lts/DDS/QosProfile      ddsqos_unit_test
  Lts/Tools/LogViewer     logviewer_unit_test
  Lts/Tools/SqlBrowser    sqlbrowser_unit_test
  Z/src/NGLLogger         ngllogger_unit_test
  Z/src/WMS_Interface     wms_json_ds_unit_test
  Z/src/nglapplication    nglcoreapplication_unit_test
  Z/src/nglcompression    nglcompression_unit_test
  Z/src/nglsettings       nglsettings_unit_test
  Z/src/ngltranslator     ngltranslator_unit_test

Where a module is built with hidden visibility and has no export macro
(LogViewer, SqlBrowser, ngltranslator, NGLLogger, nglcompression,
nglsettings), its sources are compiled directly into the test
executable, the same pattern as prtcnv_unit_test.

ctest baseline in the container (QT_QPA_PLATFORM=offscreen): 20/23
passed (13 new + 7 pre-existing in-scope tests), 3 Not Run as before
(nglcomp_test, GrantleeParserSmoke, utils_test).

README: ctest baseline table extended to the 23 registered tests and
section 2.4 now documents the per-module test layout. ddsview has no
unit test (GUI tool, XmlHelper needs the DDS dynamic-xtypes runtime).
2026-11-15 01:08:17 +01:00

17 KiB

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.

The source tree on this branch is pruned to the Release 2 build closure: only the modules the 46 scope targets compile (plus their transitive service dependencies, the codegen inputs, and the build-pipeline files) are present — out-of-scope modules have been removed.

Release 2 Scope

46 targets across 4 build groups (GROUP1, GROUP3, GROUP5, GROUP6):

Group Area Count Targets
GROUP1 AP4 — DDS middleware 6 ddscore, ddsftccore, ddsfts, ddsgen, ddsQoS, ddsconnector
GROUP3 AP3 — shared libraries, TetraIF, Lts/Common, tests 36 see breakdown below
GROUP5 AP9 — viewers 3 ddsview, LogViewer, sqlbrowser
GROUP6 AP9 — tools 1 ngl_codegen

GROUP3 breakdown

Area Targets
NGL stack (14) NGLLogger, nglapplication, nglcompression, nglcoreapplication, ngldb, nglguiapplication, nglsettings, nglsingleapplication, nglsinglecoreapplication, ngltools, ngltranslator, nglwidgets, qtsingleapplication, qtsinglecoreapplication
Services (6) wms_json_ds, tcpserver, LtsCoordinate, LtsCoordTrans, LtsSession, LtsMultiMonitor
Plugin interfaces (2) DataPluginInterface, GuiPluginInterface
TetraIF (5) CoPrtCnv, LogViewLogger, LogView, PrtCnvLib, PrtCnv
Additional (2) LtsLicence, MockCoordTrans
Tests (7) aes_crypt_test, ngltools_qt_smoke, lts_coord_trans_unit_test, test_nglpdfwidget, coprtcnv_unit_test, logview_unit_test, prtcnv_unit_test

The group target lists are the GROUP*_TARGETS arrays in new_docker_build_release2.sh.

Entries at the tree root

  • new_docker_build_release2.sh — Release 2 build driver (compile, ctest, DEB packaging, coverage)
  • Dockerfile — recipe of the 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 own README.md)
  • build4_<timestamp>_<pid>/ — per-run build tree, created by the driver (git-ignored via build4_*)

Toolchain inside the image: Ubuntu 26.04, Qt 6.10.2 (/opt/Qt/6.10.2/gcc_64), Ninja, C++17. Qt is installed via aqt install-qt (no apt Qt6 packages).

Prerequisites

  1. Docker available on the host.
  2. A prebuilt build image. The driver default is qt6-migrated-legatus-release2; any equivalent prebuilt image can be selected with --docker-image (or DOCKER_IMAGE).

The driver resolves the pipeline root with this precedence: exported MIGRATE_PIPELINE_ROOT → MIGRATE_PIPELINE_ROOT from the .envrc in this directory → derived from the script location. The pipeline root is mounted in the container at /repo (override with --docker-mount-root), so the tree is reachable at /repo/qt-migration-legatus/qt6-after/qt6-migrated-legatus.

All commands below are run from this directory (qt6-migrated-legatus/).

Step 1 — Compile the Release 2 scope

./new_docker_build_release2.sh --use-prebuilt-image --docker-image <image>

What the driver does inside the container:

  1. Creates a fresh build tree build4_<timestamp>_<pid> (unique per run).

  2. Configures with CMake (Ninja generator):

    cmake -B build4_<ts> \
      -G Ninja \
      -DBUILD_TESTING=ON \
      -DCMAKE_BUILD_TYPE=RelWithDebInfo \
      -DCMAKE_PREFIX_PATH=/opt/Qt/6.10.2/gcc_64 \
      -DCMAKE_CXX_FLAGS="-DRTI_LINUX -DRTI_UNIX" \
      -DCMAKE_C_FLAGS="-DRTI_LINUX -DRTI_UNIX" \
      -DBUILD_RTI=ON \
      -DBUILD_GROUP1=ON -DBUILD_GROUP3=ON -DBUILD_GROUP5=ON -DBUILD_GROUP6=ON \
      .
    

    BUILD_RTI=ON is required: RTI codegen consumers (e.g. svcPdmCommon) need the generated headers, and the BUILD_RTI=OFF stubs are not part of this tree. The scope is selected by the BUILD_GROUP* flags.

  3. Builds the 46 scope targets with cmake --build ... --target <t> (Ninja, per target, in group order).

  4. Runs ctest (see Step 2).

Output to inspect after the run (in the run's build4_* dir):

  • bin/ — executables (apps + test binaries)
  • lib/ — shared libraries

To rebuild incrementally without a fresh tree, run ninja in an interactive container against the existing build dir:

B=$(ls -dt build4_* | head -1)
docker run --rm -it -v "$MIGRATE_PIPELINE_ROOT":/repo <image> \
  bash -c "cd /repo/qt-migration-legatus/qt6-after/qt6-migrated-legatus/${B} && ninja -j$(nproc)"

Run an executable directly

To run a built executable interactively — e.g. the GUI apps under bin/ (LogView, LogViewer, PrtCnv) against your local display — start a shell inside the container with X11 forwarding:

B=$(ls -dt build4_* | head -1)
docker run --rm -it \
  -e DISPLAY \
  -e LC_ALL=C.UTF-8 \
  -v /tmp/.X11-unix:/tmp/.X11-unix \
  -v "$MIGRATE_PIPELINE_ROOT":/repo \
  <image> \
  bash -c "cd /repo/qt-migration-legatus/qt6-after/qt6-migrated-legatus/${B} && exec bash"

Step 2 — Run the tests

2.1 ctest (automatic)

The driver runs ctest --output-on-failure -j$(nproc) (with QT_QPA_PLATFORM=offscreen — the container is headless) after the compile. Expected baseline (23 registered, 20 in-scope tests passed, 3 Not Run):

# Test Module Result
1 coprtcnv_unit_test TetraIF (CoPrtCnv) Passed
2 logview_unit_test TetraIF (LogView) Passed
3 prtcnv_unit_test TetraIF (PrtCnv) Passed
4 wms_json_ds_unit_test WMS_Interface Passed
5 nglcoreapplication_unit_test nglapplication Passed
6 nglcomp_test nglcompression Not Run
7 nglcompression_unit_test nglcompression Passed
8 nglsettings_unit_test nglsettings Passed
9 ngltranslator_unit_test ngltranslator Passed
10 NGLToolsQtSmoke NGLToolsQt Passed
11 test_nglpdfwidget NGLPDFWidget Passed
12 ngllogger_unit_test NGLLogger Passed
13 logviewer_unit_test LogViewer Passed
14 sqlbrowser_unit_test SqlBrowser Passed
15 ddsqos_unit_test DDS/QosProfile Passed
16 ddscore_unit_test DDS/Core Passed
17 GrantleeParserSmoke Grantlee Not Run
18 codegen_unit_test CodeGen Passed
19 lts_coord_trans_unit_test LtsCoordTrans Passed
20 ltscoordinate_unit_test LtsCoordinate Passed
21 aes_crypt_test Common (AES crypt) Passed
22 ltssession_unit_test LtsSession Passed
23 utils_test Common (LtsUtils) Not Run

A few tests registered by in-scope CMakeLists are not part of the 46 built targets and show up as ***Not Run (nglcomp_test, GrantleeParserSmoke, utils_test) — that is expected and the driver continues. (Out-of-scope modules were pruned from this branch, so the tests they registered are gone with them.)

2.2 Build the unit tests only

B=$(ls -dt build4_* | head -1)
docker run --rm -v "$MIGRATE_PIPELINE_ROOT":/repo <image> \
  bash -c "cd /repo/qt-migration-legatus/qt6-after/qt6-migrated-legatus/${B} \
  && ninja coprtcnv_unit_test logview_unit_test prtcnv_unit_test \
           codegen_unit_test ddscore_unit_test ddsqos_unit_test \
           logviewer_unit_test sqlbrowser_unit_test \
           ltscoordinate_unit_test ltssession_unit_test \
           wms_json_ds_unit_test nglcompression_unit_test \
           nglsettings_unit_test ngltranslator_unit_test \
           ngllogger_unit_test nglcoreapplication_unit_test"

2.3 Run a test executable directly

GUI-free tests need the offscreen Qt platform in a headless container:

B=$(ls -dt build4_* | head -1)
docker run --rm -it -v "$MIGRATE_PIPELINE_ROOT":/repo <image> \
  bash -c "export QT_QPA_PLATFORM=offscreen
cd /repo/qt-migration-legatus/qt6-after/qt6-migrated-legatus/${B}
./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.

2.4 Unit tests per module

Each in-scope module has its own unit-test/ directory (the original TetraIF/unit-test/ layout, one test executable per module, each registered with ctest):

Test Module Covers
coprtcnv_unit_test TetraIF CoPrtCnv — telegram header fields, payload access, length checks, fragmentation/reassembly roundtrip, id→string helpers
logview_unit_test TetraIF LogView — IntegerCalculator (arithmetic, precedence, error codes, variables)
prtcnv_unit_test TetraIF PrtCnv — PrtCnvMember state + fragmented-telegram add/reassembly
codegen_unit_test Common/CodeGen name transforms, member/data/function/IDL wrappers, Grantlee wrapper getters (incl. JSON↔variant fallbacks), base data classes (MemberInformation/CppData toString)
ddscore_unit_test DDS/Core ddsview-independent DDS core helpers
ddsqos_unit_test DDS/QosProfile DDS_DefaultQos — default profile load, SHM/UDP/TCP participant QoS, default datawriter/datareader QoS, print()
logviewer_unit_test Tools/LogViewer LogViewTableModel (dimensions, roles, invalid index, header data, level colors, add/set data) + SortFilterModel (string/date filters, reset, date/level sort, figureFilterOut)
sqlbrowser_unit_test Tools/SqlBrowser DataModel (swap lists, role handling, tooltip timestamp, editability, set-data slots, delete lines) + AddModel (row creation, value stringification, remove/clear)
ltscoordinate_unit_test Common/LtsCoordinate constructors/geo accessors, validity checks, MGRS formatting, geo↔UTM roundtrips, UTM distances, angle degrees, elevation callback, LtsCoordVector
ltssession_unit_test Common/LtsSession session API roundtrips
wms_json_ds_unit_test WMS_Interface JSON dataset roundtrips (exercises, requirements, units) — toJson/fromJson fidelity
nglcompression_unit_test nglcompression nglcomp archive/tar filter helpers
nglsettings_unit_test nglsettings NGL::Settings + NGL::Connections (port offset, server hostname)
ngltranslator_unit_test ngltranslator Translator — catalog + translate (missing context, plural, disambiguation), JSON catalog import (valid/invalid, md5 cache, compressed), locale handling
ngllogger_unit_test NGLLogger LoggerHierarchyHelper naming/instance caching, log level ordering/enabled checks, bootstrap create/get, AlreadyCreatedError
nglcoreapplication_unit_test nglapplication LoggerHandler — createLogger naming (prefix/postfix), duplicate-root AlreadyCreatedError

Hidden-visibility note: the tree builds with CMAKE_CXX_VISIBILITY_PRESET hidden, so classes without an export macro are not in the shared library's dynamic symbol table. Where a module has no export macro (LogViewer, SqlBrowser, ngltranslator, NGLLogger, nglcompression, nglsettings), its test compiles the module source files directly into the test executable (same pattern as prtcnv_unit_test).

ddsview has no unit test: it is a GUI tool whose XmlHelper needs the DDS dynamic-xtypes runtime and a GUI model.

Sources are registered with ctest via each module's unit-test/CMakeLists.txt (guarded by BUILD_TESTING and by the module target existing).

Step 3 — Produce the Release 2 DEB packages

./new_docker_build_release2.sh --use-prebuilt-image --docker-image <image> \
  --run-jenkins-builder \
  --package-output-dir ./packages-out \
  > /path/to/build.log 2>&1

The driver compiles the Release 2 scope (46 targets), runs ctest, then stages the tree and runs rpmbuild/make_rpm_ubuntu26_release2.py, which builds the scope again (Release configuration, Ninja, scoped target list) and produces 5 DEBs in ${MIGRATE_PIPELINE_ROOT}/rpms/${PROJECT}/${OS_VERSION}/ (default rpms/guez/26.04/). A copy is also placed in --package-output-dir (default ./packages-out):

DEB Contents
qt6-release-runtime_1.0-1_amd64.deb Release 2 executables + libraries, staged from the scoped build's bin/ and lib/
qt6-release-sources_1.0-1_amd64.deb Release 2 scope sources (source files + CMakeLists under the release dirs)
qt6-release-ctest-runtime_1.0-1_amd64.deb Test executables under /usr/lib/ctest/ (currently empty — the producer looks for a build4/bin/ dir, which the driver's timestamped build4_<ts>/ dirs do not match)
qt6-release-ctest-sources_1.0-1_amd64.deb Test sources (files with "test" in the name under release dirs)
qt6-release-build-pipeline_1.0-1_amd64.deb In-tree pipeline files (the producer's PIPELINE_FILES: new_docker_build_release2.sh, Dockerfile, jenkins-ci-rme/*, rpmbuild/make_rpm_ubuntu26_release2.py, CMakeLists.txt) under /usr/src/pipeline/

(Version string = --lts-version + - + --build-number, default 1.0-1.)

Verify a package:

dpkg -c "${MIGRATE_PIPELINE_ROOT}/rpms/guez/26.04/qt6-release-runtime_1.0-1_amd64.deb"
dpkg -i "${MIGRATE_PIPELINE_ROOT}/rpms/guez/26.04/"*.deb   # install locally, if wanted

Step 4 — 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 5 — Code coverage (lcov)

./new_docker_build_release2.sh --use-prebuilt-image --docker-image <image> \
  --run-coverage \
  --coverage-output-dir ./coverage-out \
  > /path/to/coverage.log 2>&1

The driver builds the Release 2 scope with -O0 --coverage, runs the same ctest suite, then captures the data with lcov: the report covers the Release 2 scope (AP3, AP4, AP9, TetraIF, Z/src, Lts/Common), 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); 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
--group1 / --group3 / --group5 / --group6 (or --no-…) all on enable/disable the build groups (AP4 / AP3 / AP9 / AP9)
--no-ctest off skip ctest
--tests-only off run ctest only, skip the build groups
--use-prebuilt-image / --no-prebuilt-image off use a prebuilt image vs. apt install in-container
--docker-image IMAGE qt6-migrated-legatus-release2 image to use
--cmake_build_flags FLAGS — extra -D flags for the in-container configure
--run-jenkins-builder off produce the DEB packages (Step 3)
--package-output-dir DIR ./packages-out host dir that receives the DEB copy
--lts-version VERSION 1.0 package version prefix
--project NAME guez project name for package naming
--build-number NUM / --build-tag TAG 1 / manual-build package metadata
--run-coverage off coverage build + lcov report (Step 5)
--coverage-output-dir DIR ./coverage-out where the coverage report is written
--docker-mount-root PATH /repo container-side mount root

Environment overrides: BUILD_GROUP1..6, RUN_CTEST, TESTS_ONLY, USE_PREBUILT_IMAGE, DOCKER_IMAGE, CMAKE_BUILD_FLAGS, DOCKER_MOUNT_ROOT, RUN_JENKINS_BUILDER, PACKAGE_OUTPUT_DIR, LTS_VERSION, PROJECT, BUILD_NUMBER, BUILD_TAG, RUN_COVERAGE, COVERAGE_OUTPUT_DIR, GUEZ_MODE, 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 creates a fresh build4_<timestamp>_<pid> dir per run; old dirs are git-ignored scratch areas and can be deleted freely.
  • DEBs not on the host → the output dir must be a path that exists on the host; check the --package-output-dir argument and the rpms/<project>/<os>/ dir under the pipeline root.
  • Build fails with missing Qt modules → the image must be a prebuilt Release 2 image (Qt 6.10.2 installed via aqt install-qt); select it with --docker-image.
  • DDS build fails on the license → rti_license.dat must be present at the source tree root; the driver exports RTI_LICENSE for in-container use.