Skip to content

Add ARM64 cross-build support#323

Merged
wizzomafizzo merged 2 commits into
mainfrom
feat/arm64-build
Jul 3, 2026
Merged

Add ARM64 cross-build support#323
wizzomafizzo merged 2 commits into
mainfrom
feat/arm64-build

Conversation

@wizzomafizzo

@wizzomafizzo wizzomafizzo commented Jul 3, 2026

Copy link
Copy Markdown
Member

Summary

  • Add Dockerized ARM64 Qt toolchain and application build flow
  • Wire CMake/Corrosion for aarch64 Rust target, target qmake, and static EGLFS plugins
  • Document just arm64 and ARM64 toolchain image usage

Validation

  • just lint
  • bash -n scripts/build-arm64.sh scripts/build-toolchain-arm64.sh
  • ARM64 terminology scan clean

Summary by CodeRabbit

  • New Features
    • Added Linux ARM64 cross-compilation support, including a new arm64 build command and Docker Buildx workflow.
    • Added an ARM64 toolchain image builder to enable reusable cross builds.
  • Bug Fixes
    • Improved ARM64 cross-build configuration for Rust/Qt, including static EGLFS plugin integration.
    • Updated ARM target selection and safer toolchain setup for consistent builds.
  • Documentation
    • Expanded ARM32/ARM64 cross-build instructions, including toolchain image options and build verification steps.

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 633f9979-6731-496b-8deb-b24889a4df94

📥 Commits

Reviewing files that changed from the base of the PR and between 94a94a9 and c9510e4.

📒 Files selected for processing (3)
  • Dockerfile.arm64
  • Dockerfile.toolchain.arm64
  • cmake/ZaparooRust.cmake
🚧 Files skipped from review as they are similar to previous changes (3)
  • Dockerfile.arm64
  • cmake/ZaparooRust.cmake
  • Dockerfile.toolchain.arm64

📝 Walkthrough

Walkthrough

Adds ARM64 cross-compilation support across Dockerfiles, build scripts, CMake/Rust wiring, static Qt plugin handling, command aliases, and build documentation.

Changes

ARM64 Cross-Build Pipeline

Layer / File(s) Summary
ARM64 toolchain Docker image
Dockerfile.toolchain.arm64, scripts/toolchain-arm64/VERSION
Multi-stage build compiles static Qt6 host and ARM64 target toolchains, generates a CMake toolchain file, installs Rust aarch64 target and cargo-chef, strips artifacts, and produces a runtime toolchain-base stage; VERSION pinned to 6.10.3-2.
ARM64 application build image
Dockerfile.arm64
New Dockerfile builds the frontend against the toolchain image using cargo-chef planner/cook stages and Qt CMake/Ninja, exporting the binary via a scratch stage.
CMake Rust/Qt cross-compilation wiring
cmake/ZaparooRust.cmake
Sets Rust_CARGO_TARGET for ARM64/ARM32, selects cross qmake6 for static Qt builds, includes EglFS plugin configs, and conditionally links static EGLFS plugin targets with compile definitions.
Static EGLFS plugin import
src/app/main.cpp
Adds conditional Q_IMPORT_PLUGIN statements for QEglFSIntegrationPlugin/QEglFSKmsGbmIntegrationPlugin based on static build macros.
Build scripts and Rust cargo config
scripts/build-arm64.sh, scripts/build-toolchain-arm64.sh, rust/.cargo/config.toml
New scripts validate the toolchain version, select local/official images, build via docker buildx, and verify output; Cargo config adds an aarch64-unknown-linux-gnu linker entry.
Just recipe and documentation
justfile, AGENTS.md, docs/building.md
Adds a just arm64 recipe, documents the command, and expands build docs to cover the ARM64 cross-build flow alongside ARM32.

Estimated code review effort: 4 (Complex) | ~60 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately describes the main change: ARM64 cross-build support.
Description check ✅ Passed The description covers the summary and validation steps, and the omitted template sections are non-critical for this change.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/arm64-build

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
cmake/ZaparooRust.cmake (1)

55-59: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Hardcoded toolchain paths with no existence check.

/opt/qt6-arm64/bin/qmake6 and /opt/qt6-arm32/bin/qmake6 are hardcoded absolute paths tied to the Docker toolchain image layout (confirmed by the Dockerfile.arm64 snippet using the same path). There's no EXISTS guard, so if the path is wrong or the toolchain layout changes, the failure surfaces later and less clearly (e.g., during corrosion's Rust build) instead of at configure time.

♻️ Optional early validation
     if(CMAKE_SYSTEM_PROCESSOR STREQUAL "aarch64")
         set(_rs_qmake "/opt/qt6-arm64/bin/qmake6")
     else()
         set(_rs_qmake "/opt/qt6-arm32/bin/qmake6")
     endif()
+    if(NOT EXISTS "${_rs_qmake}")
+        message(FATAL_ERROR "Cross qmake6 not found at ${_rs_qmake}; check toolchain image layout")
+    endif()
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cmake/ZaparooRust.cmake` around lines 55 - 59, The qmake path selection in
ZaparooRust.cmake uses hardcoded absolute toolchain paths without validating
that the chosen qmake6 exists. Update the logic around the
CMAKE_SYSTEM_PROCESSOR branch that sets _rs_qmake to add an EXISTS check (or
equivalent configure-time validation) for the selected path, and fail early with
a clear message if neither /opt/qt6-arm64/bin/qmake6 nor
/opt/qt6-arm32/bin/qmake6 is present.
Dockerfile.toolchain.arm64 (1)

244-260: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Redundant Rust toolchain installation.

Line 245 bootstraps rustup with --default-toolchain stable, then lines 259-260 separately install a pinned 1.96.0 toolchain (with its own aarch64-unknown-linux-gnu target). Since rustup stores toolchains under distinct directory names (stable-... vs 1.96.0-...), this likely results in two full toolchain downloads/installs even if they resolve to the same version, wasting image size and build time. Since the actual build later relies on rust-toolchain.toml (pinning presumably to 1.96.0) for reproducibility, the "stable" bootstrap toolchain appears to serve no further purpose once 1.96.0 is installed.

♻️ Suggested fix — bootstrap without a default toolchain
 RUN wget -qO- https://sh.rustup.rs \
-        | sh -s -- -y --default-toolchain stable --profile minimal \
-    && /root/.cargo/bin/rustup target add aarch64-unknown-linux-gnu
+        | sh -s -- -y --default-toolchain none --profile minimal
 
 ENV PATH="/root/.cargo/bin:${PATH}"
 
 ...
 
 RUN rustup toolchain install 1.96.0 --profile minimal \
-    && rustup target add --toolchain 1.96.0 aarch64-unknown-linux-gnu
+    && rustup target add --toolchain 1.96.0 aarch64-unknown-linux-gnu \
+    && rustup default 1.96.0
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Dockerfile.toolchain.arm64` around lines 244 - 260, The Rust setup in the
Dockerfile is installing two separate toolchains: the initial rustup bootstrap
uses a default stable toolchain, then the later rustup toolchain install pins
1.96.0, which duplicates downloads and image size. Update the bootstrap step to
install rustup without setting stable as the default, and rely on the pinned
1.96.0 toolchain plus its target setup for the build; keep the existing aarch64
target and cargo config setup unchanged. Locate the fix in the rustup
initialization and the rustup toolchain install block.
Dockerfile.arm64 (1)

46-67: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

build.ninja existence check appears to have no effect without a cache mount.

The if [ ! -f build.ninja ] guard (lines 56-65) only skips re-running qt-cmake if build.ninja already exists in build/. Since this Dockerfile doesn't use --mount=type=cache (or any other mechanism to persist /src/build across builds), each docker build invocation starts with an empty build/ directory, making the check always true. If the intent was to speed up iterative local builds, consider adding a BuildKit cache mount for /src/build; otherwise this conditional can be simplified away.

♻️ Suggested fix — add a cache mount to make the guard meaningful
-RUN mkdir -p build && cd build && \
+RUN --mount=type=cache,target=/src/build,sharing=locked \
+    mkdir -p build && cd build && \
     if [ -n "${ZAPAROO_OFFICIAL_BUILD}" ]; then \
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Dockerfile.arm64` around lines 46 - 67, The build.ninja guard in the
Dockerfile.arm64 build step is ineffective because the build directory is not
persisted between builds. Update the Dockerfile arm64 build stage around the RUN
block using the qt-cmake and ninja steps: either add a BuildKit cache mount for
the build directory so build.ninja can be reused, or remove the conditional
entirely if no caching is intended. Keep the logic centered on the existing
qt-cmake and ninja invocation so the change is localized.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@Dockerfile.toolchain.arm64`:
- Around line 93-111: The host Qt build in the Dockerfile.toolchain.arm64 image
is using ICU-enabled binaries without ensuring the runtime is present in the
final host toolchain image. Update the host toolchain stage so the Qt host tools
built by the qtbase-host-build step (including moc, rcc, and lupdate) have the
ICU runtime available, either by installing the required ICU runtime package in
the toolchain-base image or by explicitly disabling ICU in the qtbase/configure
invocation if that is the intended behavior.

---

Nitpick comments:
In `@cmake/ZaparooRust.cmake`:
- Around line 55-59: The qmake path selection in ZaparooRust.cmake uses
hardcoded absolute toolchain paths without validating that the chosen qmake6
exists. Update the logic around the CMAKE_SYSTEM_PROCESSOR branch that sets
_rs_qmake to add an EXISTS check (or equivalent configure-time validation) for
the selected path, and fail early with a clear message if neither
/opt/qt6-arm64/bin/qmake6 nor /opt/qt6-arm32/bin/qmake6 is present.

In `@Dockerfile.arm64`:
- Around line 46-67: The build.ninja guard in the Dockerfile.arm64 build step is
ineffective because the build directory is not persisted between builds. Update
the Dockerfile arm64 build stage around the RUN block using the qt-cmake and
ninja steps: either add a BuildKit cache mount for the build directory so
build.ninja can be reused, or remove the conditional entirely if no caching is
intended. Keep the logic centered on the existing qt-cmake and ninja invocation
so the change is localized.

In `@Dockerfile.toolchain.arm64`:
- Around line 244-260: The Rust setup in the Dockerfile is installing two
separate toolchains: the initial rustup bootstrap uses a default stable
toolchain, then the later rustup toolchain install pins 1.96.0, which duplicates
downloads and image size. Update the bootstrap step to install rustup without
setting stable as the default, and rely on the pinned 1.96.0 toolchain plus its
target setup for the build; keep the existing aarch64 target and cargo config
setup unchanged. Locate the fix in the rustup initialization and the rustup
toolchain install block.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 68e5d061-c01a-48e1-88ee-55a4d2be69b9

📥 Commits

Reviewing files that changed from the base of the PR and between 5ce2a07 and 94a94a9.

📒 Files selected for processing (11)
  • AGENTS.md
  • Dockerfile.arm64
  • Dockerfile.toolchain.arm64
  • cmake/ZaparooRust.cmake
  • docs/building.md
  • justfile
  • rust/.cargo/config.toml
  • scripts/build-arm64.sh
  • scripts/build-toolchain-arm64.sh
  • scripts/toolchain-arm64/VERSION
  • src/app/main.cpp

Comment thread Dockerfile.toolchain.arm64
@wizzomafizzo
wizzomafizzo merged commit bb4c4f8 into main Jul 3, 2026
9 of 10 checks passed
@wizzomafizzo
wizzomafizzo deleted the feat/arm64-build branch July 3, 2026 03:53
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