Skip to content

variants/linux: container build script and build fixes - #1

Open
mmmorks wants to merge 1 commit into
staging/upstream-linuxfrom
pr/01-build-tooling
Open

mmmorks wants to merge 1 commit into
staging/upstream-linuxfrom
pr/01-build-tooling

Conversation

@mmmorks

@mmmorks mmmorks commented Sep 7, 2026

Copy link
Copy Markdown
Owner

Summary

Two scripts for building and shipping the Linux firmware, plus the small build fixes found while getting them to work on a fresh machine.

What changed

  • build-docker.sh builds linux_repeater for arm64 inside a Debian container, so the firmware can be built from macOS or any host without the ardulinux toolchain. BASE_IMAGE picks the libgpiod major the binary links against (debian:bookworm = 1.x, default; debian:trixie = 2.x). Each base gets its own build directory and PlatformIO cache volume, because PlatformIO does not track system headers and would otherwise relink objects compiled against the other gpiod.h. It runs without a TTY (so it works from CI and | tee), and hands the artifacts under the bind-mounted .pio back to the invoking user, scoped to this run's own paths so a read-only file left by another env cannot fail the script after a successful build.
  • platformio.ini: linux_base force-includes /usr/include/string.h. ArduinoCore-API and the ardulinux core use str*/mem* without including it, which newer GCC/libstdc++ no longer provide transitively. The absolute path matters (a bare -include string.h resolves to the Arduino shim), and stdlib.h/stdio.h must not be added the same way (their select() collides with the static one in lib/ed25519/ge.c).
  • src/helpers/ConfigSerializer.cpp includes <stdlib.h> for atoi/atol/atof. MCU builds reach these through Arduino.h; the host native test build does not, and fails to compile on macOS without it (the whole pio test -e native suite errors on the current linux branch there).
  • variants/linux/platformio.ini: drops [env:linux], which defines neither RADIO_CLASS nor WRAPPER_CLASS (required by target.cpp) and builds no application, and the SKIP_CONFIG_OVERWRITE flag, which nothing reads.
  • meshcored.service: the header comment named /var/lib/systemd/system, a directory systemd never reads.
  • README: a "Container cross-build" paragraph.

How it was tested

  • build-docker.sh is how every Linux binary in this series was produced (bookworm and trixie bases, on Apple Silicon). The ownership fix-up was reproduced before and after the change with a planted read-only file under another env's libdeps (build succeeded, chown failed, script exited 1 before; build and scoped chown succeeded after).
  • On this branch as submitted: arm64 build in Docker succeeds; pio test -e native passes on macOS (44 tests). Without the ConfigSerializer.cpp include the suite does not compile there.

Dependencies

Independent. The other PRs in this series are based on it only so that their native tests compile on macOS.

Shared code touched

  • platformio.ini (linux_base only)
  • src/helpers/ConfigSerializer.cpp (one include; also a candidate for meshcore-dev)

@mmmorks mmmorks changed the title variants/linux: container build and remote deploy scripts, build fixes variants/linux: container build script and build fixes Sep 8, 2026
@mmmorks
mmmorks force-pushed the pr/01-build-tooling branch from bb47913 to 41a35c8 Compare September 8, 2026 04:11
build-docker.sh builds linux_repeater for arm64 inside a Debian container,
so the firmware can be built from a non-Linux host. BASE_IMAGE selects the
container's libgpiod major (bookworm = 1.x, trixie = 2.x); each base gets
its own build directory and package-cache volume, because PlatformIO does
not track system headers and would otherwise relink objects compiled
against the other version's gpiod.h. The build runs without a TTY, and
FIRMWARE_VERSION reaches the compiler through PLATFORMIO_BUILD_FLAGS the
same way build.sh does it for the MCU targets, so `meshcored -V` reports
the version the script was asked for instead of the #ifndef default in
MyMesh.h. The artifacts left under the bind-mounted .pio are handed back
to the invoking user, scoped to this run's own paths so a read-only file
from another env's libdeps cannot fail the script after a successful
build; the three .pio parent directories get a separate non-recursive
chown, because on a Linux host the container is what creates them on a
fresh checkout, and the invoking user could otherwise no longer run
`pio test -e native`.

Build fixes found along the way:

  * linux_base force-includes /usr/include/string.h when that path exists:
    ArduinoCore-API and the ardulinux core use str*/mem* without including
    it, which newer GCC/libstdc++ no longer provide transitively. The
    existence test keeps the build usable where there is no /usr/include
    -- unlike -I, an -include of a missing absolute path is fatal in every
    translation unit.
  * ConfigSerializer.cpp includes <stdlib.h> for atoi/atol/atof. MCU builds
    reach these through Arduino.h; the host `native` test build does not,
    and fails to compile on macOS without it.
  * Drop [env:linux] from variants/linux/platformio.ini: it defines neither
    RADIO_CLASS nor WRAPPER_CLASS (which target.cpp requires) and builds no
    application, and nothing references it. Drop SKIP_CONFIG_OVERWRITE from
    linux_repeater, which nothing reads.
  * The unit file's own comment named /var/lib/systemd/system, a directory
    systemd never reads; units install to /etc/systemd/system.
@mmmorks
mmmorks force-pushed the pr/01-build-tooling branch from 41a35c8 to 37a7709 Compare September 12, 2026 21:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant