Status: Planning Current state:
aarch64-unknown-linux-muslartifacts are not published by upstream CI. All aarch64 support in OpenChimera is blocked until upstream delivers musl-linked binaries.See also:
docs/arch-matrix.md— current architecture support matrixdocs/qa-checklist.md— x86_64 QA patterns (extend for aarch64)chimera-core/Makefile— current x86_64-only download
Enabling aarch64 support in OpenChimera requires coordinated changes across three independent tiers. Each tier is a hard prerequisite for the next.
Tier 1 (Upstream CI)
└─ aarch64-unknown-linux-musl artifact is compiled and published
│
▼
Tier 2 (Package Makefile)
└─ chimera-core/Makefile gains aarch64 PKG_SOURCE / PKG_HASH
│
▼
Tier 3 (QA Verification)
└─ SDK compile, install, and runtime tests pass on aarch64
The upstream ci.yml
build matrix includes these Linux targets:
| Rust Target | Tool | musl/gnu | Present in CI |
|---|---|---|---|
x86_64-unknown-linux-gnu |
cross |
gnu | ✅ |
x86_64-unknown-linux-musl |
cross |
musl | ✅ |
i686-unknown-linux-musl |
cross |
musl | ✅ |
aarch64-unknown-linux-gnu |
cross + zig: "2.17" |
gnu | ✅ |
armv7-unknown-linux-gnueabi |
cross |
gnu | ✅ |
armv7-unknown-linux-gnueabihf |
cross + zig: "2.17" |
gnu | ✅ |
aarch64-unknown-linux-musl |
N/A | musl | ❌ Missing |
Confirmed by: ci.yml matrix include: section.
The block for aarch64-unknown-linux-musl simply does not exist.
Add the following entry to the strategy.matrix.include list in ci.yml:
- os: ubuntu-latest
target: aarch64-unknown-linux-musl
tool: cross
extra-args: -F "perf"
zig: "2.17"Rationale: The existing aarch64-unknown-linux-gnu entry already demonstrates
that aarch64 cross-compilation works with cross + zig. The musl variant needs
the same treatment. The perf feature flag is used for the musl build
(consistent with the x86_64-musl entry), as opposed to plus used for gnu targets.
Key differences from the gnu entry:
extra-args: Use-F "perf"instead of-F "plus"(matching x86_64-musl convention)- The musl target links against musl libc instead of glibc, which may require
different
crossDocker images or zig toolchain settings - If
zig: "2.17"alone is insufficient for musl, the build may needCROSS_BUILD_ZIGcombined with a cross-compilation Docker image that includes musl cross-toolchains (seecross-rs/cross— musl targets use theghcr.io/cross-rs/aarch64-unknown-linux-musl:<toolchain>image)
The existing CI pipeline already handles artifact upload generically:
- The
Upload binariesstep uploads every matrix entry's binary. - The
releasejob merges, hashes, and publishes all artifacts.
No pipeline changes needed for artifact publication — the new matrix entry will automatically be included in the release assets.
The resulting artifact will follow the existing convention:
clash_chimera-aarch64-unknown-linux-musl
Expected location (for tag vX.Y.Z):
https://github.com/MFSGA/Chimera_Client/releases/download/vX.Y.Z/clash_chimera-aarch64-unknown-linux-musl
- A new release (or the
latestpre-release) includes the fileclash_chimera-aarch64-unknown-linux-musl. - The file is executable on an
aarch64Linux system with musl libc. file clash_chimera-aarch64-unknown-linux-muslreports:ELF 64-bit LSB executable, ARM aarch64, version 1 (SYSV), statically linked(or dynamically linked against musl, not glibc).sha256sumof the artifact is recorded for downstream verification.
chimera-core/Makefile currently has a single download target:
PKG_SOURCE:=clash_chimera-x86_64-unknown-linux-musl
PKG_SOURCE_URL:=https://github.com/MFSGA/Chimera_Client/releases/download/$(PKG_SOURCE_VERSION)
PKG_HASH:=850c949dc0176da3d5b57cb78f2e903cbe8823703c819c402f02ca16dea434d0This approach works for x86_64 only because OpenWrt's PKG_SOURCE does not
natively support per-architecture source selection. The current Makefile has no
conditional logic for different targets.
The Makefile must detect the target architecture at build time and select the
correct artifact. OpenWrt provides $(ARCH) (e.g., x86_64, aarch64) and
$(SUBTARGET) (e.g., cortex-a53, generic) variables.
Recommended approach: Use a ifneq ($(filter aarch64%,$(ARCH)),) conditional
to set architecture-specific variables:
# --- Per-architecture artifact selection ---
# x86_64 (musl) — default
PKG_SOURCE:=clash_chimera-x86_64-unknown-linux-musl
PKG_HASH:=850c949dc0176da3d5b57cb78f2e903cbe8823703c819c402f02ca16dea434d0
# aarch64 (musl) — enable once upstream artifact is verified
# ifneq ($(filter aarch64%,$(ARCH)),)
# PKG_SOURCE:=clash_chimera-aarch64-unknown-linux-musl
# PKG_HASH:=<SHA256_HASH_GOES_HERE>
# endif
# ---Note: The aarch64 block is commented out — it must remain commented until a verified upstream artifact is published and its hash is confirmed.
If the upstream CI acquires multiple architectures over time, an alternative
pattern uses OpenWrt's Package/chimera-core DEPENDS and per-architecture
Package/chimera-core-$(ARCH) variants. However, the PKG_SOURCE conditional
approach above is simpler and matches how other OpenWrt prebuilt-binary packages
handle multi-architecture downloads (e.g., mihomo-meta, v2ray-core).
No changes to Package/chimera-core/description, PROVIDES, or ALTERNATIVES
are needed — the binary is installed to the same paths (/usr/libexec/chimera,
exposed as /usr/bin/mihomo) regardless of architecture.
- Do NOT uncomment or activate the aarch64 block until the upstream artifact is verified (Tier 1 complete + hash confirmed).
- Do NOT remove the x86_64 default — x86_64 remains the primary supported architecture even after aarch64 is enabled.
- Do NOT change
PKG_SOURCE_URL— the URL pattern is the same for all architectures; only the filename and hash differ.
A placeholder AARCH64_README file (or a comment block in the Makefile) should
be added to document:
# aarch64 enablement (deferred):
# 1. Upstream CI must add aarch64-unknown-linux-musl to the build matrix
# (see docs/aarch64-enablement.md for details)
# 2. Compute SHA256 of the published artifact
# 3. Uncomment the aarch64 block below and insert the hash
# 4. Run SDK compile QA for aarch64 OpenWrt target
# 5. Run install + runtime QA on an aarch64 OpenWrt device
Once Tiers 1 and 2 are complete, aarch64 support must be verified through the same QA pipeline that x86_64 uses, adapted for the aarch64 target.
| Step | Action | Expected Result |
|---|---|---|
| 3.1.1 | Obtain OpenWrt SDK for aarch64 (e.g., openwrt-sdk-aarch64_cortex-a53-*.tar.xz) |
SDK extracts and make info succeeds |
| 3.1.2 | Add OpenChimera feed, feeds update -a, feeds install -a |
Feeds install without errors |
| 3.1.3 | make package/chimera-core/compile V=s |
Exit 0; downloads aarch64 musl binary |
| 3.1.4 | make package/openchimera/compile V=s |
Exit 0; produces .ipk |
| 3.1.5 | ls bin/packages/aarch64_*/openchimera/*.ipk |
Both .ipk files present |
Evidence: Save output per docs/qa-checklist.md Section 2 convention.
| Step | Action | Expected Result |
|---|---|---|
| 3.2.1 | Copy .ipk files to aarch64 OpenWrt device |
Files transferred |
| 3.2.2 | opkg install chimera-core_*.ipk |
Installed; no dependency errors |
| 3.2.3 | opkg install openchimera_*.ipk |
Installed; no dependency errors |
| Step | Action | Expected Result |
|---|---|---|
| 3.3.1 | file /usr/libexec/chimera |
ELF 64-bit LSB executable, ARM aarch64 |
| 3.3.2 | ldd /usr/libexec/chimera (if dynamic) |
Links against musl, NOT glibc |
| 3.3.3 | /usr/bin/mihomo -V |
Prints Chimera/clash-rs version string |
| 3.3.4 | ls -la /usr/bin/mihomo |
Symlinks to /usr/libexec/chimera |
| Step | Action | Expected Result |
|---|---|---|
| 3.4.1 | Write valid config; /usr/bin/mihomo -t -d <dir> -c <file> |
Exit 0; test successful |
| 3.4.2 | Write invalid config; run test | Exit non-zero; error message |
| 3.4.3 | Write malformed YAML; run test | Exit non-zero; parse error |
| Step | Action | Expected Result |
|---|---|---|
| 3.5.1 | Enable, start service | Process runs; PID captured |
| 3.5.2 | Stop service | Process terminates |
| 3.5.3 | Restart service | PID changes or process cleanly restarts |
| 3.5.4 | Disabled → start | No process spawned |
| 3.5.5 | Invalid config → start | No process; error logged |
| Step | Action | Expected Result |
|---|---|---|
| 3.6.1 | curl -x http://127.0.0.1:7890 http://example.com -I --max-time 10 |
Exit 0; HTTP response returned |
| 3.6.2 | Bad request (nonexistent.invalid) |
Daemon does not crash |
The aarch64 QA should be repeated across at least the primary OpenWrt SDK branch:
| SDK Branch | Priority | Reason |
|---|---|---|
openwrt-24.10 |
Required | Primary milestone target |
openwrt-25.12 |
Recommended | Next stable |
SNAPSHOT |
Optional | Latest toolchain |
Risk: The upstream CI uses cross-rs/cross Docker images with a specific musl
toolchain version. The OpenWrt SDK ships its own musl cross-toolchain
(musl-targeting gcc). If the musl versions differ significantly, the compiled
binary may exhibit ABI mismatches or runtime issues.
Mitigation:
- Confirm that the upstream binary is statically linked where possible (musl supports static linking well). If static, musl version mismatch is irrelevant — the binary carries its own libc.
- If dynamically linked, verify
lddoutput on the target OpenWrt device shows only musl-linked dependencies. - Test critical features (DNS resolution, TLS, TUN) on an aarch64 OpenWrt device before releasing.
Severity: Medium
Risk: The upstream CI builds against Linux kernel headers from the cross
Docker image (typically recent Ubuntu). OpenWrt devices may run older kernels
(e.g., 5.15, 6.1, 6.6). If the binary uses kernel features not present in older
kernels, it may fail at runtime.
Mitigation:
- Upstream should target the oldest reasonable kernel for cross-compilation
(e.g.,
--kernel 5.10or use musl's__OLDKERNELif applicable). - Runtime QA on a representative aarch64 OpenWrt device (kernel 6.1 or 6.6) should catch any compatibility issues.
Severity: Low
Risk: TUN proxy mode on aarch64 may behave differently due to:
- Different endianness behavior in TUN packet parsing
- Different alignment requirements for packet headers
- Kernel module availability (
kmod-tunis available for aarch64, but architecture-specific issues may exist)
Mitigation:
- Run the TUN proxy test from the QA checklist on an aarch64 device.
- Verify that
kmod-tunis loadable and functional. - Test with both
tun_enabled=0(non-TUN) andtun_enabled=1.
Severity: Low-Medium
Risk: Adding aarch64-unknown-linux-musl to the upstream CI matrix may
require a cross Docker image that doesn't exist yet. The cross-rs/cross
project maintains prebuilt images for many targets, but aarch64-unknown-linux-musl
needs confirmation.
Status: The cross project does provide:
ghcr.io/cross-rs/aarch64-unknown-linux-musl:main— confirmed available forcross-based musl cross-compilation to aarch64.
So this risk is low, but the specific zig version compatibility needs verification.
Severity: Low
Risk: aarch64 builds may have different performance characteristics than x86_64. Memory usage, throughput, and latency should be benchmarked if performance is a requirement.
Mitigation: Not a blocker for enablement, but document as a known variable. Add a performance benchmark step if aarch64 is expected to be a primary platform.
Severity: Low (informational)
- 1a: Add
aarch64-unknown-linux-musltoci.ymlbuild matrix withtool: cross,extra-args: -F "perf",zig: "2.17" - 1b: Verify CI build passes for the new matrix entry
- 1c: Confirm artifact
clash_chimera-aarch64-unknown-linux-muslappears in release assets - 1d: Record
sha256sumof the published artifact - 1e: Confirm binary is musl-linked (
lddshows no glibc references;fileshows ARM aarch64)
- 2a: Add conditional aarch64 block in
chimera-core/Makefile(commented out initially) - 2b: Insert verified
PKG_HASHforclash_chimera-aarch64-unknown-linux-musl - 2c: Uncomment the aarch64 block
- 2d: Update
docs/arch-matrix.mdto change aarch64-musl status from ⏳ Deferred to ✅ Supported - 2e: Update
openchimera/arch-matrix.mdto match (if still maintained) - 2f: Update
README.mdarchitecture support table
- 3a: Obtain aarch64 OpenWrt SDK (
openwrt-sdk-aarch64_*-*.tar.xz) - 3b: Run SDK compile QA (build both packages for aarch64)
- 3c: Install
.ipkfiles on aarch64 OpenWrt device - 3d: Verify binary identity (
file,ldd,-V) - 3e: Run config validation tests (valid, invalid, malformed)
- 3f: Run service lifecycle tests (start, stop, restart, disabled, invalid)
- 3g: Run mixed-port proxy test
- 3h: Run TUN mode test (if applicable)
- 3i: Save all QA evidence per
docs/qa-checklist.mdconvention - 3j: Add aarch64 QA scenarios to
docs/qa-checklist.md
| Property | Value |
|---|---|
| Artifact | clash_chimera-x86_64-unknown-linux-musl |
| SHA256 | 850c949dc0176da3d5b57cb78f2e903cbe8823703c819c402f02ca16dea434d0 |
| Size | 14.8 MB |
| URL | https://github.com/MFSGA/Chimera_Client/releases/download/v0.21.1/clash_chimera-x86_64-unknown-linux-musl |
| Property | Value |
|---|---|
| Artifact | clash_chimera-aarch64-unknown-linux-gnu |
| SHA256 | (to be re-verified when aarch64 is enabled) |
| Size | (to be re-verified) |
| URL | https://github.com/MFSGA/Chimera_Client/releases/download/v0.21.1/clash_chimera-aarch64-unknown-linux-gnu |
| Incompatible with OpenWrt musl — do not use |
| Property | Value |
|---|---|
| Artifact | clash_chimera-aarch64-unknown-linux-musl |
| SHA256 | TBD — record from upstream release |
| Size | TBD |
| URL | https://github.com/MFSGA/Chimera_Client/releases/download/vX.Y.Z/clash_chimera-aarch64-unknown-linux-musl |
The OpenWrt build system uses ARCH and SUBTARGET variables that map to
specific toolchain configurations. The following aarch64 targets are relevant:
| OpenWrt Target | ARCH |
SUBTARGET |
Notes |
|---|---|---|---|
aarch64_generic |
aarch64 |
generic |
Broadest compatibility; no arch-specific optimizations |
aarch64_cortex-a53 |
aarch64 |
cortex-a53 |
Optimized for Cortex-A53 (RPi 3/4, many routers) |
aarch64_cortex-a72 |
aarch64 |
cortex-a72 |
Optimized for Cortex-A72 (RPi 4B, higher-end) |
aarch64_cortex-a76 |
aarch64 |
cortex-a76 |
Optimized for Cortex-A76 (newer devices) |
Recommendation: Start with aarch64_generic for maximum compatibility.
Subtarget-specific optimizations can be added later.
The Makefile conditional should match on ARCH only (aarch64), not on
SUBTARGET, since the upstream artifact is a generic aarch64 binary:
ifneq ($(filter aarch64%,$(ARCH)),)
# aarch64 (any subtarget) uses the generic aarch64 musl artifact
PKG_SOURCE:=clash_chimera-aarch64-unknown-linux-musl
PKG_HASH:=<confirmed-sha256>
endifRelevant section of upstream ci.yml for context. The matrix.include list
grows by one entry when aarch64-musl is added:
strategy:
fail-fast: false
matrix:
include:
# ... existing entries ...
# NEW: aarch64 musl (blocked — add when ready)
# - os: ubuntu-latest
# target: aarch64-unknown-linux-musl
# tool: cross
# extra-args: -F "perf"
# zig: "2.17"The Release job does not need modification — it merges and publishes all
artifacts from the compile matrix generically.