# 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 **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__/` — 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 ```bash ./new_docker_build_release2.sh --use-prebuilt-image --docker-image ``` What the driver does inside the container: 1. Creates a fresh build tree `build4__` (unique per run). 2. Configures with CMake (Ninja generator): ```bash cmake -B build4_ \ -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 ` (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: ```bash B=$(ls -dt build4_* | head -1) docker run --rm -it -v "$MIGRATE_PIPELINE_ROOT":/repo \ 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: ```bash 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 \ \ 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 (7 in-scope 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 | Tests registered by out-of-scope modules show up as `***Not Run` (`nglcomp_test`, `ddsGenericDataTests`, `ddsDataTopicTests`, `ddsFunctionTopicTests`, `coordTransTests_gtest`, `GrantleeParserSmoke`, `utils_test`, `exmDtUnitTest`, `migration_tests_NOT_BUILT`) — that is expected and the driver continues. ### 2.2 Build the unit tests only ```bash B=$(ls -dt build4_* | head -1) docker run --rm -v "$MIGRATE_PIPELINE_ROOT":/repo \ bash -c "cd /repo/qt-migration-legatus/qt6-after/qt6-migrated-legatus/${B} \ && ninja coprtcnv_unit_test logview_unit_test prtcnv_unit_test" ``` ### 2.3 Run a test executable directly GUI-free tests need the offscreen Qt platform in a headless container: ```bash B=$(ls -dt build4_* | head -1) docker run --rm -it -v "$MIGRATE_PIPELINE_ROOT":/repo \ 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 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`. ## Step 3 — Produce the Release 2 DEB packages ```bash ./new_docker_build_release2.sh --use-prebuilt-image --docker-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_/` 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.sh`, `Dockerfile`, `jenkins-ci-rme/*`, `rpmbuild/make_rpm_ubuntu26.py`, `CMakeLists.txt`) under `/usr/src/pipeline/` | (Version string = `--lts-version` + `-` + `--build-number`, default `1.0-1`.) Verify a package: ```bash 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: ```bash jenkins-ci-rme/release-16-10-2026.sh ``` See `jenkins-ci-rme/README.md` for the pipeline details. ## Step 5 — Code coverage (lcov) ```bash ./new_docker_build_release2.sh --use-prebuilt-image --docker-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__` 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///` 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.