diff --git a/CLAUDE.md b/CLAUDE.md index beb1391..94ac2e3 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -242,6 +242,11 @@ hides world surfaces itself. Keep the teardown rule: overlays, then SteamVR, the the build tree and an install. - The manifest passes `--log-file logs/.log` (`arguments`), so SteamVR-started instances log to the install folder (or `build//logs/` from the build tree). +- **libmosquitto** (MQTT, D14/D35) comes from pkg-config (`cmake/Mosquitto.cmake`). The Frame + has none, so `FRAMEASSISTANT_SHIP_MOSQUITTO=ON` (all package presets) installs it into `lib/` + as `libmosquitto.so.1`, with Debian's copyright file (it contains the EPL-2.0/EDL-1.0 + texts), and adds it to `VRDASH_BUNDLE_EXCLUDE`. Include it after `BundleQt`, which sets that + list. - `cmake/OpenVR.cmake` downloads only `openvr.h`, `LICENSE` and the matching `bin/linux64|linuxarm64/libopenvr_api.so` into `third_party/openvr-/` (gitignored). - **Deploying to the Frame uses its system Qt by default.** Bundling Qt is the fallback for diff --git a/CMakeLists.txt b/CMakeLists.txt index 324f58f..fb7338d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,6 +56,8 @@ include(Dashboard) if(VRDASH_DEPLOY_QT) include(BundleQt) endif() +# After BundleQt: adds libmosquitto to its exclusion list when shipping it. +include(Mosquitto) add_subdirectory(src) add_subdirectory(resources) diff --git a/CMakePresets.json b/CMakePresets.json index dd55c75..2988fff 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -30,6 +30,7 @@ "cacheVariables": { "CMAKE_BUILD_TYPE": "RelWithDebInfo", "VRDASH_DEPLOY_QT": "ON", + "FRAMEASSISTANT_SHIP_MOSQUITTO": "ON", "VRDASH_BUILD_TESTS": "OFF" } }, @@ -41,6 +42,7 @@ "cacheVariables": { "CMAKE_BUILD_TYPE": "RelWithDebInfo", "VRDASH_DEPLOY_QT": "ON", + "FRAMEASSISTANT_SHIP_MOSQUITTO": "ON", "VRDASH_BUILD_TESTS": "OFF" } }, @@ -52,6 +54,7 @@ "CMAKE_BUILD_TYPE": "RelWithDebInfo", "VRDASH_DEPLOY_QT": "OFF", "VRDASH_QML_BYTECODE_ONLY": "ON", + "FRAMEASSISTANT_SHIP_MOSQUITTO": "ON", "VRDASH_BUILD_TESTS": "OFF" } }, @@ -64,6 +67,7 @@ "CMAKE_BUILD_TYPE": "RelWithDebInfo", "VRDASH_DEPLOY_QT": "OFF", "VRDASH_QML_BYTECODE_ONLY": "ON", + "FRAMEASSISTANT_SHIP_MOSQUITTO": "ON", "VRDASH_BUILD_TESTS": "OFF" } } diff --git a/README.md b/README.md index 517dc06..de738ea 100644 --- a/README.md +++ b/README.md @@ -96,6 +96,9 @@ only produce a warning. Keep the file private (`chmod 600`) when it holds a pass ## Development +- **Host build dependencies:** Qt 6 (≥ 6.5) and libmosquitto with its pkg-config file + (Arch: `mosquitto`, Debian: `libmosquitto-dev`); the `mosquitto` broker for the MQTT + integration tests. The containers (`docker/`) have everything. - **App identity** (app key `net.matzman.frameassistant`, tab name, executable name `frame-assistant`, texture size) is set in the root `CMakeLists.txt`. The executable must not be named like a SteamVR process such as `vrdashboard` (CMake checks this). diff --git a/THIRD_PARTY_NOTICES.md b/THIRD_PARTY_NOTICES.md index a25d79f..142917c 100644 --- a/THIRD_PARTY_NOTICES.md +++ b/THIRD_PARTY_NOTICES.md @@ -6,6 +6,7 @@ This project is MIT-licensed (see `LICENSE`). `` below is the CMake pro | Component | License | How it is used | |-----------|---------|----------------| | [OpenVR SDK](https://github.com/ValveSoftware/openvr) (`libopenvr_api.so`, `openvr.h`) | BSD-3-Clause | Shipped in `lib/`; license in `share/doc//third-party/openvr.LICENSE` | +| [Eclipse Mosquitto](https://mosquitto.org/) client library (`libmosquitto.so.1`) | EPL-2.0 or EDL-1.0 (BSD-3-Clause) | Linked dynamically. Release packages ship Debian's build unmodified in `lib/`; its copyright file in `share/doc//third-party/libmosquitto1.copyright` | | [Qt 6](https://www.qt.io/) (Core, Gui, Qml, Quick, Quick Controls, Wayland/XCB plugins) | LGPL-3.0 (Qt open-source license) | Linked dynamically. Default builds use the system's Qt (not shipped). Bundled builds ship Qt's shared libraries unmodified in `lib/`, `plugins/`, `qml/`: replace them to use another compatible Qt build | **Bundled builds** (`--bundle-qt`) also ship further shared libraries that Qt depends on, diff --git a/cmake/Mosquitto.cmake b/cmake/Mosquitto.cmake new file mode 100644 index 0000000..4dc26fb --- /dev/null +++ b/cmake/Mosquitto.cmake @@ -0,0 +1,39 @@ +# Provides the imported target PkgConfig::MOSQUITTO (libmosquitto, the MQTT client +# library; docs/DESIGN.md, D14/D35). +# +# Found through pkg-config (Debian: libmosquitto-dev, Arch: mosquitto). The Frame has no +# libmosquitto, so package builds ship it like libopenvr_api.so: with +# FRAMEASSISTANT_SHIP_MOSQUITTO=ON the library is installed into lib/ under its soname +# (found through RPATH $ORIGIN/../lib), together with Debian's copyright file. + +option(FRAMEASSISTANT_SHIP_MOSQUITTO "Install libmosquitto into lib/ (package builds)" OFF) + +find_package(PkgConfig REQUIRED) +pkg_check_modules(MOSQUITTO REQUIRED IMPORTED_TARGET libmosquitto) +message(STATUS "libmosquitto: ${MOSQUITTO_VERSION}") + +if(FRAMEASSISTANT_SHIP_MOSQUITTO) + find_library(MOSQUITTO_LIBRARY NAMES mosquitto HINTS ${MOSQUITTO_LIBRARY_DIRS} REQUIRED) + get_filename_component(_mosquitto_dir ${MOSQUITTO_LIBRARY} DIRECTORY) + # The soname has been libmosquitto.so.1 since 1.x; the file behind it is versioned. + set(_mosquitto_soname libmosquitto.so.1) + if(NOT EXISTS ${_mosquitto_dir}/${_mosquitto_soname}) + message(FATAL_ERROR "${_mosquitto_dir}/${_mosquitto_soname} not found") + endif() + file(REAL_PATH ${_mosquitto_dir}/${_mosquitto_soname} _mosquitto_file) + install(FILES ${_mosquitto_file} DESTINATION ${CMAKE_INSTALL_LIBDIR} + RENAME ${_mosquitto_soname}) + + # Debian's copyright file (same path for every architecture through multiarch). + set(_mosquitto_copyright /usr/share/doc/libmosquitto1/copyright) + if(EXISTS ${_mosquitto_copyright}) + install(FILES ${_mosquitto_copyright} + DESTINATION ${CMAKE_INSTALL_DOCDIR}/third-party + RENAME libmosquitto1.copyright) + else() + message(WARNING "${_mosquitto_copyright} not found: package lacks libmosquitto's license") + endif() + + # Shipped by the rule above: the Qt bundler must not copy it a second time. + list(APPEND VRDASH_BUNDLE_EXCLUDE "^libmosquitto") +endif() diff --git a/docker/cross-arm64.Dockerfile b/docker/cross-arm64.Dockerfile index 26a66fe..88169e0 100644 --- a/docker/cross-arm64.Dockerfile +++ b/docker/cross-arm64.Dockerfile @@ -13,6 +13,7 @@ RUN dpkg --add-architecture arm64 \ qt6-base-dev qt6-base-dev-tools qt6-declarative-dev qt6-declarative-dev-tools \ qt6-base-dev:arm64 qt6-declarative-dev:arm64 \ libgl-dev:arm64 libegl-dev:arm64 libvulkan-dev:arm64 libxkbcommon-dev:arm64 \ + libmosquitto-dev:arm64 \ qml6-module-qtquick:arm64 qml6-module-qtquick-controls:arm64 \ qml6-module-qtquick-layouts:arm64 qml6-module-qtquick-templates:arm64 \ qml6-module-qtqml-workerscript:arm64 qml6-module-qtquick-window:arm64 \ diff --git a/docker/native.Dockerfile b/docker/native.Dockerfile index 9e517e5..4536833 100644 --- a/docker/native.Dockerfile +++ b/docker/native.Dockerfile @@ -9,7 +9,7 @@ RUN apt-get update \ && apt-get install -y --no-install-recommends \ ca-certificates cmake ninja-build pkgconf file patchelf g++ \ qt6-base-dev qt6-base-dev-tools qt6-declarative-dev qt6-declarative-dev-tools \ - libgl-dev libegl-dev libvulkan-dev libxkbcommon-dev \ + libgl-dev libegl-dev libvulkan-dev libxkbcommon-dev libmosquitto-dev \ qml6-module-qtquick qml6-module-qtquick-controls qml6-module-qtquick-layouts \ qml6-module-qtquick-templates qml6-module-qtqml-workerscript qml6-module-qtquick-window \ qml6-module-qttest qt6-qpa-plugins qt6-wayland \ diff --git a/docker/test.Dockerfile b/docker/test.Dockerfile index c73dca4..d471f1a 100644 --- a/docker/test.Dockerfile +++ b/docker/test.Dockerfile @@ -1,9 +1,10 @@ # Test environment on top of docker/native.Dockerfile: Mesa Vulkan/GL drivers (incl. the -# lavapipe software rasterizer), Khronos validation layers and Xvfb. See scripts/container-test.sh. +# lavapipe software rasterizer), Khronos validation layers, Xvfb, and the mosquitto broker +# for the MQTT integration tests. See scripts/container-test.sh. FROM frameassistant-build-native RUN apt-get update \ && apt-get install -y --no-install-recommends \ mesa-vulkan-drivers vulkan-validationlayers vulkan-tools libgl1-mesa-dri \ - xvfb xauth fonts-dejavu-core \ + xvfb xauth fonts-dejavu-core mosquitto \ && rm -rf /var/lib/apt/lists/* diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 9225ca6..12a8ca7 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -153,6 +153,9 @@ sequenceDiagram - `libopenvr_api.so` next to the executable - install rules and registration for Qt bundling - the check against SteamVR process names +- **`cmake/Mosquitto.cmake`** (app, not platform) finds libmosquitto through pkg-config. With + `FRAMEASSISTANT_SHIP_MOSQUITTO=ON` (all package presets) it installs the library into `lib/` + under its soname plus Debian's copyright file, and excludes it from the Qt bundler. - **App identity** (root `CMakeLists.txt`): `project()` name and version, `VRDASH_APP_KEY`, `VRDASH_DISPLAY_NAME`, `VRDASH_EXECUTABLE_NAME`, texture size. CMake generates from them `AppConfig.h` and the SteamVR manifest, with `binary_path_linux_arm` for ARM builds and diff --git a/docs/PROGRESS.md b/docs/PROGRESS.md index c23f45a..4bf3669 100644 --- a/docs/PROGRESS.md +++ b/docs/PROGRESS.md @@ -22,8 +22,9 @@ CLAUDE.md ("Working rules"). The error itself is covered off the device by `tst_config`. Checks 3 and 4 run in the next session on the Frame (iteration 2 testing needs it too). -- **Implementation** follows the order in DESIGN.md (steps 1–7); step 1: libmosquitto in - CMake and the containers. +- **Implementation** follows the order in DESIGN.md (steps 1–7). Step 1 (libmosquitto in + CMake and the containers) done; next: step 2 (`MqttClient`, `MosquittoClient`, + integration test). ## Next steps @@ -124,6 +125,14 @@ Known limitation: the bundled-Qt package does not support WebEngine in this iter - Design of iteration 2 written (DESIGN.md). User's decisions: libmosquitto's own thread (D42), app commands in the platform for `--ha-remove` (D43), committed TLS test certificates (D44). Design approved; phase 3 started. +- Step 1: `cmake/Mosquitto.cmake` (pkg-config; `FRAMEASSISTANT_SHIP_MOSQUITTO=ON` in all + package presets installs `lib/libmosquitto.so.1` and Debian's copyright file, which already + contains the EPL-2.0/EDL-1.0 texts); `libmosquitto-dev(:arm64)` in the build containers, + `mosquitto` in the test container; THIRD_PARTY_NOTICES entry. Checked: host configure finds + 2.1.2; `container-test.sh` 8/8, no Vulkan validation messages; the cross build stages + 2.0.21 (aarch64) and the copyright file. The binary doesn't need the library yet (nothing + calls it; `--as-needed`), which changes in step 2. On the host, the GUI tests can't run in + this session (no display). ### 2026-10-05: requirements approved diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5892416..a87fcaa 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -54,7 +54,7 @@ qt_add_library(frameassistant_lib STATIC config/Config.h config/Config.cpp ) target_include_directories(frameassistant_lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) -target_link_libraries(frameassistant_lib PUBLIC Qt6::Core) +target_link_libraries(frameassistant_lib PUBLIC Qt6::Core PkgConfig::MOSQUITTO) target_compile_options(frameassistant_lib PRIVATE -Wall -Wextra) # The app: its UI is the QML module "FrameAssistant" (src/qml/).