diff --git a/.github/workflows/build_all_targets.yml b/.github/workflows/build_all_targets.yml index 4c0bc0fcb9..1171d18e1b 100644 --- a/.github/workflows/build_all_targets.yml +++ b/.github/workflows/build_all_targets.yml @@ -265,5 +265,7 @@ jobs: with: draft: true prerelease: ${{ steps.upload-location.outputs.is_prerelease == 'true' }} - files: artifacts/*.px4 + files: | + artifacts/*.px4 + artifacts/*.deb name: ${{ steps.upload-location.outputs.uploadlocation }} diff --git a/Makefile b/Makefile index d23ead0e16..6a8b5f6d56 100644 --- a/Makefile +++ b/Makefile @@ -234,6 +234,13 @@ modalai_voxl2: modalai_voxl2_slpi all_config_targets: $(ALL_CONFIG_TARGETS) all_default_targets: $(CONFIG_TARGETS_DEFAULT) +# DEB package targets: builds _default config, then runs cpack. +# Multi-processor boards (e.g. VOXL2) chain companion builds automatically +# via existing cmake prerequisites. +%_deb: + @$(call cmake-build,$(subst _deb,_default,$@)$(BUILD_DIR_SUFFIX)) + @cd "$(SRC_DIR)/build/$(subst _deb,_default,$@)" && cpack -G DEB + updateconfig: @./Tools/kconfig/updateconfig.py diff --git a/Tools/ci/generate_board_targets_json.py b/Tools/ci/generate_board_targets_json.py index 66fe49b329..1c73c5bb8d 100755 --- a/Tools/ci/generate_board_targets_json.py +++ b/Tools/ci/generate_board_targets_json.py @@ -207,6 +207,47 @@ for manufacturer in sorted(os.scandir(os.path.join(source_dir, '../boards')), ke if t not in companions ] +# Append _deb targets for boards that have cmake/package.cmake +for manufacturer in sorted(os.scandir(os.path.join(source_dir, '../boards')), key=lambda e: e.name): + if not manufacturer.is_dir(): + continue + if manufacturer.name in excluded_manufacturers: + continue + for board in sorted(os.scandir(manufacturer.path), key=lambda e: e.name): + if not board.is_dir(): + continue + board_name = manufacturer.name + '_' + board.name + if board_name in excluded_boards: + continue + package_cmake = os.path.join(board.path, 'cmake', 'package.cmake') + if os.path.exists(package_cmake): + deb_target = board_name + '_deb' + if target_filter and not any(deb_target.startswith(f) for f in target_filter): + continue + # Determine the container and group for this board + container = default_container + if board_name in board_container_overrides: + container = board_container_overrides[board_name] + target_entry = {'target': deb_target, 'container': container} + if args.group: + # Find the group where this board's _default target already lives + default_target = board_name + '_default' + group = None + for g in grouped_targets: + targets_in_group = grouped_targets[g].get('manufacturers', {}).get(manufacturer.name, []) + if default_target in targets_in_group: + group = g + break + if group is None: + group = 'base' + target_entry['arch'] = group + if group not in grouped_targets: + grouped_targets[group] = {'container': container, 'manufacturers': {}} + if manufacturer.name not in grouped_targets[group]['manufacturers']: + grouped_targets[group]['manufacturers'][manufacturer.name] = [] + grouped_targets[group]['manufacturers'][manufacturer.name].append(deb_target) + build_configs.append(target_entry) + if(verbose): import pprint print("============================") diff --git a/Tools/ci/package_build_artifacts.sh b/Tools/ci/package_build_artifacts.sh index 4dd5b2ca09..cd7309a9e7 100755 --- a/Tools/ci/package_build_artifacts.sh +++ b/Tools/ci/package_build_artifacts.sh @@ -3,6 +3,7 @@ mkdir artifacts cp **/**/*.px4 artifacts/ 2>/dev/null || true cp **/**/*.elf artifacts/ 2>/dev/null || true +cp **/**/*.deb artifacts/ 2>/dev/null || true for build_dir_path in build/*/ ; do build_dir_path=${build_dir_path::${#build_dir_path}-1} build_dir=${build_dir_path#*/} diff --git a/boards/modalai/voxl2/cmake/install.cmake b/boards/modalai/voxl2/cmake/install.cmake new file mode 100644 index 0000000000..31eeea4ff5 --- /dev/null +++ b/boards/modalai/voxl2/cmake/install.cmake @@ -0,0 +1,84 @@ +############################################################################ +# +# Copyright (c) 2024 PX4 Development Team. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name PX4 nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +# VOXL2 board-specific install rules for .deb packaging +# Included from platforms/posix/CMakeLists.txt where the px4 target exists + +# SLPI companion build output directory +set(VOXL2_SLPI_BUILD_DIR "${PX4_SOURCE_DIR}/build/modalai_voxl2-slpi_default") + +# Apps processor binary +install(TARGETS px4 RUNTIME DESTINATION bin) + +# px4-alias.sh (generated during build into bin/ subdirectory) +install(PROGRAMS ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/px4-alias.sh DESTINATION bin) + +# Startup scripts from board target directory +install(PROGRAMS + ${PX4_BOARD_DIR}/target/voxl-px4 + ${PX4_BOARD_DIR}/target/voxl-px4-start + ${PX4_BOARD_DIR}/target/voxl-px4-hitl + ${PX4_BOARD_DIR}/target/voxl-px4-hitl-start + DESTINATION bin +) + +# DSP firmware blob from companion SLPI build +install(FILES ${VOXL2_SLPI_BUILD_DIR}/platforms/qurt/libpx4.so + DESTINATION lib/rfsa/adsp + OPTIONAL +) + +# Configuration files +install(FILES + ${PX4_BOARD_DIR}/target/voxl-px4-fake-imu-calibration.config + ${PX4_BOARD_DIR}/target/voxl-px4-hitl-set-default-parameters.config + DESTINATION ../etc/modalai +) + +# Systemd service file +install(FILES ${PX4_BOARD_DIR}/debian/voxl-px4.service + DESTINATION ../etc/systemd/system +) + +# Component metadata JSON files +install(FILES + ${PX4_BINARY_DIR}/actuators.json.xz + ${PX4_BINARY_DIR}/component_general.json.xz + ${PX4_BINARY_DIR}/parameters.json.xz + DESTINATION ../data/px4/etc/extras + OPTIONAL +) +install(FILES ${PX4_BINARY_DIR}/events/all_events.json.xz + DESTINATION ../data/px4/etc/extras + OPTIONAL +) diff --git a/boards/modalai/voxl2/cmake/package.cmake b/boards/modalai/voxl2/cmake/package.cmake new file mode 100644 index 0000000000..90ebd3d1d4 --- /dev/null +++ b/boards/modalai/voxl2/cmake/package.cmake @@ -0,0 +1,63 @@ +############################################################################ +# +# Copyright (c) 2024 PX4 Development Team. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in +# the documentation and/or other materials provided with the +# distribution. +# 3. Neither the name PX4 nor the names of its contributors may be +# used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS +# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +############################################################################ + +# VOXL2 board-specific CPack overrides +# Loaded after cmake/package.cmake sets up CPack defaults + +# Derive Debian-compatible version from git tag (e.g. v1.17.0-alpha1-42-gabcdef -> 1.17.0~alpha1.42.gabcdef) +string(REGEX REPLACE "^v" "" _deb_ver "${PX4_GIT_TAG}") +string(REGEX REPLACE "-" "~" _deb_ver "${_deb_ver}" ) +string(REGEX REPLACE "~([0-9]+)~" ".\\1." _deb_ver "${_deb_ver}") + +# VOXL2 is always aarch64 regardless of build host +set(CPACK_DEBIAN_ARCHITECTURE "arm64") +set(CPACK_DEBIAN_PACKAGE_NAME "voxl-px4") +set(CPACK_DEBIAN_FILE_NAME "voxl-px4_${_deb_ver}_arm64.deb") +set(CPACK_PACKAGING_INSTALL_PREFIX "/usr") +set(CPACK_INSTALL_PREFIX "/usr") +set(CPACK_SET_DESTDIR true) + +set(CPACK_DEBIAN_PACKAGE_DEPENDS "voxl-platform, librc-symlinks") +set(CPACK_DEBIAN_PACKAGE_CONFLICTS "px4-rb5-flight") +set(CPACK_DEBIAN_PACKAGE_REPLACES "px4-rb5-flight") +set(CPACK_DEBIAN_PACKAGE_DESCRIPTION "PX4 Autopilot for ModalAI VOXL2") +set(CPACK_DEBIAN_PACKAGE_MAINTAINER "ModalAI ") + +# Disable shlibdeps for cross-compiled boards +set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS OFF) + +set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA + "${PX4_BOARD_DIR}/debian/postinst;${PX4_BOARD_DIR}/debian/prerm") + +# Install rules are in boards/modalai/voxl2/cmake/install.cmake, +# included from platforms/posix/CMakeLists.txt where the px4 target exists. diff --git a/boards/modalai/voxl2/debian/postinst b/boards/modalai/voxl2/debian/postinst new file mode 100755 index 0000000000..cb50d967f5 --- /dev/null +++ b/boards/modalai/voxl2/debian/postinst @@ -0,0 +1,36 @@ +#!/bin/bash +set -e + +# Create px4-* symlinks from px4-alias.sh +# The alias format is: alias ='px4- --instance $px4_instance' +# We extract the px4- command name and symlink it to the px4 binary +if [ -f /usr/bin/px4-alias.sh ]; then + grep "^alias " /usr/bin/px4-alias.sh | \ + sed -n "s/.*'\(px4-[a-zA-Z0-9_]*\).*/\1/p" | while read cmd; do + ln -sf px4 "/usr/bin/${cmd}" + done +fi + +# Detect platform and generate DSP test signature if needed +if ! /bin/ls /usr/lib/rfsa/adsp/testsig-*.so &> /dev/null; then + echo "[INFO] Generating DSP test signature..." + if [ -f /share/modalai/qcs6490-slpi-test-sig/generate-test-sig.sh ]; then + /share/modalai/qcs6490-slpi-test-sig/generate-test-sig.sh || true + elif [ -f /share/modalai/qrb5165-slpi-test-sig/generate-test-sig.sh ]; then + /share/modalai/qrb5165-slpi-test-sig/generate-test-sig.sh || true + else + echo "[WARNING] Could not find DSP signature generation script" + fi +fi + +# Create required data directories +mkdir -p /data/px4/param +mkdir -p /data/px4/etc/extras +chown -R root:root /data/px4 + +# Reload systemd if available +if command -v systemctl > /dev/null 2>&1; then + systemctl daemon-reload +fi + +echo "voxl-px4 installed successfully" diff --git a/boards/modalai/voxl2/debian/prerm b/boards/modalai/voxl2/debian/prerm new file mode 100755 index 0000000000..71bab592af --- /dev/null +++ b/boards/modalai/voxl2/debian/prerm @@ -0,0 +1,14 @@ +#!/bin/bash +set -e + +# Stop voxl-px4 service if running +if command -v systemctl > /dev/null 2>&1; then + systemctl stop voxl-px4 2>/dev/null || true +fi + +# Remove px4-* symlinks +for f in /usr/bin/px4-*; do + if [ -L "$f" ] && [ "$(readlink "$f")" = "px4" ]; then + rm -f "$f" + fi +done diff --git a/boards/modalai/voxl2/debian/voxl-px4.service b/boards/modalai/voxl2/debian/voxl-px4.service new file mode 100644 index 0000000000..41763c1e8e --- /dev/null +++ b/boards/modalai/voxl2/debian/voxl-px4.service @@ -0,0 +1,14 @@ +[Unit] +Description=PX4 Autopilot for VOXL2 +After=sscrpcd.service +Requires=sscrpcd.service + +[Service] +Type=simple +ExecStart=/usr/bin/voxl-px4 +ExecStopPost=/usr/bin/voxl-reset-slpi +Restart=on-failure +RestartSec=5 + +[Install] +WantedBy=multi-user.target diff --git a/cmake/package.cmake b/cmake/package.cmake index ecc168a92c..b022604a25 100644 --- a/cmake/package.cmake +++ b/cmake/package.cmake @@ -97,4 +97,9 @@ else() set(CPACK_GENERATOR "ZIP") endif() +# Board-specific overrides (loaded after defaults are set) +if(EXISTS "${PX4_BOARD_DIR}/cmake/package.cmake") + include(${PX4_BOARD_DIR}/cmake/package.cmake) +endif() + include(CPack) diff --git a/docs/en/SUMMARY.md b/docs/en/SUMMARY.md index e17d82e7ad..c6417c3ae8 100644 --- a/docs/en/SUMMARY.md +++ b/docs/en/SUMMARY.md @@ -476,6 +476,7 @@ - [Flight Controller Porting Guide](hardware/porting_guide.md) - [PX4 Board Configuration (kconfig)](hardware/porting_guide_config.md) - [NuttX Board Porting Guide](hardware/porting_guide_nuttx.md) + - [Board Firmware Packaging (.deb)](hardware/board_packaging.md) - [Serial Port Mapping](hardware/serial_port_mapping.md) - [Airframes](dev_airframes/index.md) - [Adding a New Airframe](dev_airframes/adding_a_new_frame.md) diff --git a/docs/en/hardware/board_packaging.md b/docs/en/hardware/board_packaging.md new file mode 100644 index 0000000000..b5c7c4db31 --- /dev/null +++ b/docs/en/hardware/board_packaging.md @@ -0,0 +1,298 @@ +# Board Firmware Packaging + +PX4 supports building distributable firmware packages for Linux-based (POSIX) boards. +While NuttX boards produce `.px4` firmware files that are flashed via QGroundControl, POSIX boards can produce `.deb` (Debian) packages that are installed using standard Linux package management tools (`dpkg`, `apt`). + +This page covers how manufacturers can add `.deb` packaging to their boards, with examples for both single-processor and multi-processor architectures. + +## Overview + +The packaging framework uses [CMake CPack](https://cmake.org/cmake/help/latest/module/CPack.html) with the DEB generator. +It is built on two extension points in the PX4 build system: + +- **`boards///cmake/package.cmake`**: CPack variable overrides (package name, version, dependencies, architecture, maintainer info). Loaded during CMake configure. +- **`boards///cmake/install.cmake`**: `install()` rules that define what goes into the package (binaries, scripts, config files, service files). Loaded from `platforms/posix/CMakeLists.txt` where build targets are available. + +When a board provides these files, CI automatically discovers and builds the `_deb` target alongside the normal firmware build. + +## Build Command + +For any board with packaging support: + +```sh +make __deb +``` + +For example: + +```sh +make modalai_voxl2_deb +``` + +This builds the `_default` configuration (and any companion builds for multi-processor boards), then runs `cpack -G DEB` in the build directory. +The resulting `.deb` file is placed in `build/__default/`. + +## Adding Packaging to a Board + +### File Structure + +``` +boards/// + cmake/ + package.cmake # CPack configuration (required) + install.cmake # Install rules (required) + debian/ + postinst # Post-install script (optional) + prerm # Pre-remove script (optional) + .service # Systemd unit file (optional) +``` + +### Step 1: CPack Configuration (package.cmake) + +This file sets CPack variables that control the `.deb` metadata. +It is included from `cmake/package.cmake` after the base CPack defaults are configured. + +```cmake +# boards///cmake/package.cmake + +# Derive Debian-compatible version from git tag +# v1.17.0-alpha1-42-gabcdef -> 1.17.0~alpha1.42.gabcdef +# v1.17.0 -> 1.17.0 +string(REGEX REPLACE "^v" "" _deb_ver "${PX4_GIT_TAG}") +string(REGEX REPLACE "-" "~" _deb_ver "${_deb_ver}") +string(REGEX REPLACE "~([0-9]+)~" ".\\1." _deb_ver "${_deb_ver}") + +# Target architecture (use the target arch, not the build host) +set(CPACK_DEBIAN_ARCHITECTURE "arm64") + +# Package identity +set(CPACK_DEBIAN_PACKAGE_NAME "my-px4-board") +set(CPACK_DEBIAN_FILE_NAME "my-px4-board_${_deb_ver}_arm64.deb") + +# Install prefix +set(CPACK_PACKAGING_INSTALL_PREFIX "/usr") +set(CPACK_INSTALL_PREFIX "/usr") +set(CPACK_SET_DESTDIR true) + +# Package metadata +set(CPACK_DEBIAN_PACKAGE_DESCRIPTION "PX4 Autopilot for My Board") +set(CPACK_DEBIAN_PACKAGE_MAINTAINER "Vendor ") +set(CPACK_DEBIAN_PACKAGE_DEPENDS "some-dependency (>= 1.0)") +set(CPACK_DEBIAN_PACKAGE_CONFLICTS "") +set(CPACK_DEBIAN_PACKAGE_REPLACES "") + +# Disable shlibdeps for cross-compiled boards +set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS OFF) + +# Include post-install and pre-remove scripts (optional) +set(CPACK_DEBIAN_PACKAGE_CONTROL_EXTRA + "${PX4_BOARD_DIR}/debian/postinst;${PX4_BOARD_DIR}/debian/prerm") +``` + +**Key variables:** + +| Variable | Purpose | +|---|---| +| `CPACK_DEBIAN_ARCHITECTURE` | Target architecture. Set explicitly for cross-compiled boards since `dpkg --print-architecture` reports the build host, not the target. | +| `CPACK_DEBIAN_PACKAGE_NAME` | Package name as it appears in `dpkg -l`. | +| `CPACK_DEBIAN_FILE_NAME` | Output `.deb` filename. | +| `CPACK_DEBIAN_PACKAGE_DEPENDS` | Runtime dependencies (comma-separated, Debian format). | +| `CPACK_DEBIAN_PACKAGE_SHLIBDEPS` | Set to `OFF` for cross-compiled boards where `dpkg-shlibdeps` cannot inspect target binaries. | + +### Step 2: Install Rules (install.cmake) + +This file defines what files are packaged in the `.deb`. +It is included from `platforms/posix/CMakeLists.txt` where the `px4` build target is available. + +All paths are relative to `CPACK_PACKAGING_INSTALL_PREFIX` (typically `/usr`). Use `../` to install outside the prefix (e.g., `../etc/` installs to `/etc/`). + +**Minimal example (single-processor board):** + +```cmake +# boards///cmake/install.cmake + +# PX4 binary +install(TARGETS px4 RUNTIME DESTINATION bin) + +# Module alias script (generated during build) +install(PROGRAMS ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/px4-alias.sh DESTINATION bin) + +# Startup scripts +install(PROGRAMS + ${PX4_BOARD_DIR}/target/my-px4-start + DESTINATION bin +) + +# Configuration files +install(FILES + ${PX4_BOARD_DIR}/target/my-config.conf + DESTINATION ../etc/my-board +) + +# Systemd service +install(FILES ${PX4_BOARD_DIR}/debian/my-px4.service + DESTINATION ../etc/systemd/system +) + +# Component metadata +install(FILES + ${PX4_BINARY_DIR}/actuators.json.xz + ${PX4_BINARY_DIR}/parameters.json.xz + DESTINATION ../data/px4/etc/extras + OPTIONAL +) +install(FILES ${PX4_BINARY_DIR}/events/all_events.json.xz + DESTINATION ../data/px4/etc/extras + OPTIONAL +) +``` + +### Step 3: Debian Scripts (optional) + +#### postinst + +Runs after the package is installed. Common tasks: + +- Create `px4-*` module symlinks from `px4-alias.sh` +- Set up required directories with correct ownership +- Run `systemctl daemon-reload` to pick up the service file +- Board-specific setup (e.g., DSP signature generation) + +```bash +#!/bin/bash +set -e + +# Create px4-* symlinks +if [ -f /usr/bin/px4-alias.sh ]; then + grep "^alias " /usr/bin/px4-alias.sh | \ + sed "s/alias \(px4-[a-zA-Z0-9_]*\)=.*/\1/" | while read cmd; do + ln -sf px4 "/usr/bin/${cmd}" + done +fi + +# Create data directories +mkdir -p /data/px4/param +mkdir -p /data/px4/etc/extras + +# Reload systemd +if command -v systemctl > /dev/null 2>&1; then + systemctl daemon-reload +fi +``` + +#### prerm + +Runs before the package is removed: + +```bash +#!/bin/bash +set -e + +# Stop the service +if command -v systemctl > /dev/null 2>&1; then + systemctl stop my-px4 2>/dev/null || true +fi + +# Remove px4-* symlinks +for f in /usr/bin/px4-*; do + if [ -L "$f" ] && [ "$(readlink "$f")" = "px4" ]; then + rm -f "$f" + fi +done +``` + +Both scripts must be executable (`chmod +x`). + +## Multi-Processor Boards + +Some boards run PX4 across multiple processors, for example the ModalAI VOXL2 which has a POSIX apps processor (ARM) and a Hexagon DSP (SLPI). +These produce two separate CMake builds, but the `.deb` must contain artifacts from both. + +### How It Works + +1. The `_default` build (POSIX/apps processor) owns the `.deb`. +2. The Makefile `%_deb` target builds `_default`, which chains any companion builds as CMake prerequisites. +3. The `install.cmake` pulls companion build artifacts via absolute path to the sibling build directory. +4. CPack runs in the `_default` build tree and produces a single `.deb`. + +### Companion Build Artifacts + +In `install.cmake`, reference the companion build output by absolute path: + +```cmake +# DSP firmware blob from companion SLPI build +set(SLPI_BUILD_DIR "${PX4_SOURCE_DIR}/build/_-slpi_default") + +install(FILES ${SLPI_BUILD_DIR}/platforms/qurt/libpx4.so + DESTINATION lib/rfsa/adsp + OPTIONAL +) +``` + +The `OPTIONAL` keyword allows the `.deb` to build even when the companion build hasn't run (useful for development/testing of just the apps-processor side). + +### VOXL2 Reference + +The VOXL2 board is a complete working example of multi-processor packaging: + +``` +boards/modalai/voxl2/ + cmake/ + package.cmake # CPack config: voxl-px4, arm64, deps, shlibdeps off + install.cmake # px4 binary, SLPI libpx4.so, scripts, configs, metadata + debian/ + postinst # Symlinks, DSP signature, directory setup + prerm # Stop service, remove symlinks + voxl-px4.service # Systemd unit (after sscrpcd, restart on-failure) + target/ + voxl-px4 # Main startup wrapper + voxl-px4-start # PX4 module startup script +``` + +The resulting `.deb` installs: + +| Path | Contents | +|---|---| +| `/usr/bin/px4` | Apps processor PX4 binary | +| `/usr/bin/px4-alias.sh` | Module alias script | +| `/usr/bin/voxl-px4` | Startup wrapper | +| `/usr/bin/voxl-px4-start` | Module startup script | +| `/usr/lib/rfsa/adsp/libpx4.so` | DSP firmware (from SLPI build) | +| `/etc/modalai/*.config` | Board configuration files | +| `/etc/systemd/system/voxl-px4.service` | Systemd service | +| `/data/px4/etc/extras/*.json.xz` | Component metadata | + +## CI Integration + +### Automatic Discovery + +The CI system (`Tools/ci/generate_board_targets_json.py`) automatically discovers boards with `cmake/package.cmake` and adds a `__deb` target to the board's existing CI group. +No manual CI configuration is needed. + +### Artifact Collection + +The `Tools/ci/package_build_artifacts.sh` script collects `.deb` files alongside `.px4` and `.elf` artifacts. +On tagged releases, `.deb` files are uploaded to both S3 and GitHub Releases. + +## Version Format + +The `.deb` version is derived from `PX4_GIT_TAG` using Debian-compatible formatting: + +| Git Tag | Debian Version | Notes | +|---|---|---| +| `v1.17.0` | `1.17.0` | Stable release | +| `v1.17.0-beta1` | `1.17.0~beta1` | Pre-release (`~` sorts before release) | +| `v1.17.0-alpha1-42-gabcdef` | `1.17.0~alpha1.42.gabcdef` | Development build | + +The `~` prefix in Debian versioning ensures pre-releases sort lower than the final release: `1.17.0~beta1 < 1.17.0`. + +## Checklist for New Boards + +1. Create `boards///cmake/package.cmake` with CPack variables +2. Create `boards///cmake/install.cmake` with install rules +3. (Optional) Create `boards///debian/postinst` and `prerm` +4. (Optional) Create `boards///debian/.service` +5. Test locally: `make __deb` +6. Verify: `dpkg-deb --info build/__default/_*.deb` +7. Verify: `dpkg-deb --contents build/__default/_*.deb` +8. CI picks it up automatically on the next push diff --git a/platforms/posix/CMakeLists.txt b/platforms/posix/CMakeLists.txt index 5b94634f57..30beec4609 100644 --- a/platforms/posix/CMakeLists.txt +++ b/platforms/posix/CMakeLists.txt @@ -80,7 +80,8 @@ target_link_libraries(px4 PRIVATE uORB) # install # -# TODO: extend to snapdragon +# Generic install rules (skipped when board provides its own install.cmake) +if(NOT EXISTS "${PX4_BOARD_DIR}/cmake/install.cmake") # px4 dirs install( @@ -94,6 +95,8 @@ install( USE_SOURCE_PERMISSIONS ) +endif() # NOT board install.cmake + # Module Symlinks px4_posix_generate_symlinks( MODULE_LIST ${module_libraries} @@ -112,6 +115,11 @@ if(EXISTS "${PX4_BOARD_DIR}/cmake/upload.cmake") include(${PX4_BOARD_DIR}/cmake/upload.cmake) endif() +# board defined install rules for .deb packaging +if(EXISTS "${PX4_BOARD_DIR}/cmake/install.cmake") + include(${PX4_BOARD_DIR}/cmake/install.cmake) +endif() + # board defined link libraries if(EXISTS "${PX4_BOARD_DIR}/cmake/link_libraries.cmake") include(${PX4_BOARD_DIR}/cmake/link_libraries.cmake)