Skip to content

Latest commit

 

History

History
319 lines (229 loc) · 17.7 KB

File metadata and controls

319 lines (229 loc) · 17.7 KB

aarch64-linux 生态适配分析报告

起因:mcpp#143 —— 用户在 Android/Termux (aarch64) 上无法编译 mcpp。 范围:让 mcpp 及其工具链生态在 aarch64-linux 上可安装、可自举、可构建。 状态:MVP(musl-static 路线)已闭环。日期:2026-06-22(更新 2026-06-23)。

进度更新(2026-06-23)

musl-static 路线已打通并自举闭环(PR #146/#147/#148 + 后续):

  • xlings install mcppmcpp new/build/run(import std)在原生 aarch64 runner 上通过;
  • self-host 最后一公里:mcpp build --target aarch64-linux-musl 自举 mcpp + xlings。曾因 ensure_ninjaxim:glibc@2.39(aarch64 无资产)卡死而失败。
  • 本轮修复:把 ninja 做成两 arch 全静态自包含(x86_64 glibc-static / aarch64 musl-static),上架 ninja-1.12.1-linux-aarch64.tar.gzxlings-res/ninja(GLOBAL),并在 xim-pkgindexninja.lua 删除 xim:glibc/xim:gcc-runtime runtime deps(引擎按 OS 而非 arch 解析依赖,glibc dep 会在 aarch64 上 404)。模型对齐 patchelf.lua(同为自包含 bootstrap 工具)。
  • arch token 勘误:Linux=aarch64、macOS=arm64(引擎 detect_arch_() 平台感知;§1.4 已更正)。
  • 遗留:① ninja 资产的 gitcode(CN)镜像需手动同步;② glibc-world(glibc/binutils/gcc-16-glibc/gcc-runtime/linux-headers/llvm 的 aarch64 资产)仍全缺 —— 仅 musl-static 路线可用,glibc 原生 ABI(GUI/X11/GL)路线未建,见 §4 阶段①/②。

1. 背景与结论速览

mcpp 是一个 self-host(自己编译自己)的 C++ 构建/包管理工具。它本身不携带 LLVM,而是通过 bundled 的 xlings 包管理器下载托管的 sandbox 工具链(gcc/glibc/llvm 等),并用 patchelf 把 loader/RUNPATH 重写成 sandbox 内的绝对路径。因此 mcpp 的正常工作流 不依赖宿主 OS 的 libc

1.1 issue #143 的误区澄清

用户在 Termux 上遇到的 import std / Bionic 头冲突(sigcontext/sigaction 重定义),是因为他 绕开 mcpp、直接用系统 clang -fmodules 去啃 Bionic 头 —— 那不是 mcpp 的执行路径。mcpp 如果正常跑,Bionic 根本不参与。

1.2 核心结论

目标 难度 本质
A. aarch64-linux (glibc/musl) 中等、可控 mcpp 的 triple 检测本就架构无关;真正阻塞 = 少量硬编码 loader + CI 矩阵 + 外部需产出 aarch64 工具链二进制并上架
B. Termux/Android (bionic) 大一个量级 全生态零 Android 处理;__linux__ 与 glibc 强绑定。取巧路线:走 aarch64-linux-musl 全静态,绕开 bionic ABI 与 "glibc 能否在 Android 内核运行" 两个变量

本报告聚焦 目标 A;目标 B 在 §7 单列。

1.3 三条决定形态的机制(务必先理解)

  1. xlings 按 OS 解析依赖,不按 arch 解析。 包选择 key 是 linux/macosx/windows,archs={...} 字段引擎根本不读(纯元数据)。
  2. arch 只在两处真正参与:
    • XLINGS_RES sentinel → 下载 URL 的 arch token 拼接(xlings/src/core/xim/installer.cppm:146 build_xlings_res_url_,按 detect_arch_() 自动带);
    • libxpkgelfpatch.lua 给 ELF 打 INTERP/rpath 时的 loader 选择。
  3. XLINGS_RES 包的 per-arch 已天然工作 —— 引擎已自动把 arch 拼进 URL。所以走 sentinel 的工具链包 无需改 DSL,只需上架 aarch64 资产。DSL "不支持同平台 per-arch URL"(xim-pkgindex/docs/specs/url-template.md:69)只卡 写显式上游 URL 的包(如 fish/jq)。

1.4 命名决策(贯穿全局,必须统一)

引擎 detect_arch_()(xlings/src/core/xim/installer.cppm:123-133)是 平台感知 的:

  • Linux(及非 Apple 平台)→ aarch64(沿用 GNU/uname -m 拼写,与 aarch64-linux-* 工具链三元组一致);
  • macOS(Apple)→ arm64(Apple 自家拼写)。

Linux 的 XLINGS_RES 资产必须命名 <pkg>-<ver>-linux-aarch64.tar.gz(内层目录同名); macOS 才是 <pkg>-<ver>-macosx-arm64.tar.gz。 已发布资产即此约定:musl-gcc-15.1.0-linux-aarch64.tar.gzaarch64-linux-musl-gcc-15.1.0-linux-aarch64.tar.gzninja-1.12.1-macosx-arm64.tar.gz。 → install.sh 的 PLAT 同步映射成 linux-aarch64

注意:mcpp 内部的 target triple(由编译器 -dumpmachine 产出)是 aarch64-linux-gnu / aarch64-linux-musl —— 工具链三元组与 xlings 资产 token 现已统一为 aarch64(Linux),不再有 arm64 混淆;只有 macOS 资产沿用 Apple 的 arm64


2. 涉及的仓库地图

仓库 角色 适配性质
mcpp-community/mcpp 本体(self-host 构建工具) 代码 + CI + 配置
openxlings/xlings 包管理器引擎(C++23,由 mcpp 编译) 主要是 CI 产出 aarch64 二进制
mcpplibs/libxpkg xlings 的 ELF patch / xpkg 执行库 代码(loader 路径)
openxlings/xim-pkgindex 包索引(每包一个 .lua) 元数据 + 硬编码 loader + (可选)DSL 扩展
xlings-res/* 资产托管(GitHub GLOBAL + gitcode CN) 上架 aarch64 二进制
(横切) 工具链构建 gcc/glibc/llvm/musl 的 aarch64 产出 最重的底层活

3. 适配依赖拓扑图(mermaid)

3.1 全景:仓库/产物级依赖

graph TD
    subgraph build["① 工具链构建 [最底层]"]
        TC_LLVM["llvm/clang aarch64<br/>(LLVM 官方有 Linux-ARM64,可镜像)"]
        TC_GCC["gcc@16 + glibc payload aarch64<br/>(crosstool-ng / 原生构建)"]
        TC_MUSL["musl-cross aarch64-linux-musl<br/>(全静态路线)"]
        TC_AUX["patchelf / ninja aarch64<br/>(上游现成)"]
    end

    subgraph res["② xlings-res 资产上架 (linux-aarch64 命名)"]
        RES["github.com/xlings-res/*<br/>gitcode.com/xlings-res/*"]
    end

    subgraph engine["③ 引擎/库代码"]
        XLINGS["xlings: CI 产出 aarch64 二进制<br/>+ os.arch stub 修正"]
        LIBXPKG["libxpkg: elfpatch 加<br/>aarch64 loader 路径"]
    end

    subgraph index["④ xim-pkgindex"]
        IDX_META["各包 archs 元数据 + aarch64"]
        IDX_HC["硬编码 loader/triple 修正<br/>(glibc/gcc/llvm/musl-gcc)"]
        IDX_DSL["(可选) DSL per-arch URL 扩展"]
    end

    subgraph mcpp["⑤ mcpp 本体"]
        MCPP_CODE["loader/triple 硬编码 4 处<br/>+ host_arch 抽象"]
        MCPP_INSTALL["install.sh 加 Linux-aarch64"]
        MCPP_CI["release.yml aarch64 job"]
        MCPP_TOML["mcpp.toml [target.aarch64-linux-musl]"]
    end

    BOOT0["⓪ 第 0 个 aarch64 mcpp<br/>(一次性引导:交叉/ARM runner)"]

    TC_LLVM --> RES
    TC_GCC --> RES
    TC_MUSL --> RES
    TC_AUX --> RES

    BOOT0 --> XLINGS
    XLINGS --> RES
    LIBXPKG --> XLINGS

    RES --> IDX_META
    IDX_HC --> IDX_META
    IDX_DSL -.可选.-> IDX_META

    IDX_META --> MCPP_INSTALL
    MCPP_CODE --> MCPP_CI
    MCPP_TOML --> MCPP_CI
    LIBXPKG --> IDX_HC
    XLINGS --> MCPP_CI
    RES --> MCPP_CI

    MCPP_INSTALL --> DONE["✅ xlings install mcpp<br/>在 aarch64-linux 闭环"]
    MCPP_CI --> DONE
Loading

3.2 自举链路:打破鸡生蛋

flowchart LR
    A["⓪ 现成编译器<br/>(ARM runner / 交叉)"] -->|引导| B["第 0 个<br/>aarch64 mcpp"]
    B -->|编译| C["xlings aarch64<br/>(静态 musl)"]
    D["aarch64 工具链资产<br/>(优先复用 LLVM 官方)"] -->|上架 aarch64| E["xlings-res"]
    F["libxpkg + glibc.lua<br/>aarch64 loader 修正"] --> G
    C --> G["xlings install mcpp<br/>正常拉取"]
    E --> G
    G -->|self-host| H["✅ aarch64 闭环<br/>(后续版本自动滚动)"]
Loading

3.3 工具链包安装依赖顺序(gcc 主链)

graph LR
    LH["linux-headers"] --> GLIBC["glibc"]
    GLIBC --> BINUTILS["binutils"]
    GLIBC --> GSC["gcc-specs-config"]
    GLIBC --> GRT["gcc-runtime"]
    BINUTILS --> GCC["gcc"]
    GSC --> GCC
    GRT --> GCC
    GLIBC --> NINJA["ninja"]
    GRT --> NINJA
    GCC --> MCPP["mcpp"]
    NINJA --> MCPP
    PATCHELF["patchelf"] -.musl路线.-> MUSL["musl-gcc"]
    GLIBC -.clang路线.-> LLVM["llvm / llvm-tools"]
Loading

4. 按依赖关系排序的适配点清单

图例:[构建] 需为 aarch64 重新编译 · [资产] 需上架二进制 · [代码] 源码改动 · [CI] 流水线 · [决策] 需拍板

阶段 ⓪ — 自举引导(打破鸡生蛋)

  • [构建] 在 aarch64 上(ubuntu-24.04-arm 原生 runner 或 x86_64 交叉)用现成编译器引导出 第 0 个 aarch64 mcpp。参考已有 scripts/bootstrap-macos.sh + .github/workflows/bootstrap-macos.yml 的 xmake "Plan B" 思路。

阶段 ① — 工具链构建(最底层,横切)

  • [构建] llvm/clang aarch64-linux —— LLVM 官方有 …-Linux-ARM64 release,直接镜像最省事;走此路 import std 也通。
  • [构建] gcc@16(glibc)+ glibc payload aarch64 —— crosstool-ng / 原生构建。
  • [构建] musl-cross aarch64-linux-musl —— 全静态路线关键(也是 Termux 取巧路线的基础)。
  • [构建] patchelf / ninja aarch64 —— 上游现成,镜像即可。

阶段 ② — xlings-res 资产上架(linux-aarch64 命名)

github.com/xlings-res/<pkg>(GLOBAL)+ gitcode.com/xlings-res/<pkg>(CN)各上传 <pkg>-<ver>-linux-aarch64.tar.gz(内层目录同名,布局对齐 x86_64):

  • [资产] 最小主链:linux-headersglibcbinutilsgcc-specs-configgcc-runtimegccninjamcpp
  • [资产] 补充:llvm / llvm-tools(clang / import std 路线)、patchelfmusl-gcc / musl-cross-make(musl 路线)

阶段 ③ — 引擎/库代码

mcpplibs/libxpkg(ELF 安装后能否运行的关键)

  • [代码] src/lua-stdlib/xim/libxpkg/elfpatch.lua —— ELF class 检测已支持 aarch64(_EM_AARCH64,:153)✓;但 _detect_system_loader(:287-289)与 subos _resolve_loader(:315-317)只列 x86_64 loader → 补 ld-linux-aarch64.so.1 / ld-musl-aarch64.so.1
  • [代码] src/xpkg-lua-stdlib.cppm:1181 —— 同逻辑的内嵌副本,同步改。

openxlings/xlings(几乎不阻塞)

  • [代码] src/core/xim/installer.cppm:779 —— Lua os.arch stub 硬编码 'arm64',既存疑点,改为反映 detect_arch_() 真值。
  • [CI] tools/linux_release.sh:26,45 —— ARCH / MCPP_TARGET 参数化(aarch64 / aarch64-linux-musl)。
  • [CI] .github/workflows/release.yml —— 新增 build-linux-aarch64 job(runs-on: ubuntu-24.04-arm),加进 release files:
  • [CI] tools/setup_musl_runtime.sh:7-26 —— musl loader/SDK 路径参数化(ld-musl-aarch64.so.1)。
  • [CI] xlings-ci-linux*.yml —— 可选 aarch64 矩阵。

阶段 ④ — xim-pkgindex(包索引)

D-1. 必改的硬编码 loader/triple(install/config 钩子,被 elfpatch 直接消费)

  • [代码] pkgs/g/glibc.lua:33,40-42 —— loader=lib64/ld-linux-x86-64.so.2abi=linux-x86_64-glibc、库清单 → aarch64 版(lib/ld-linux-aarch64.so.1 / linux-aarch64-glibc)。不改会打错 INTERP。
  • [代码] pkgs/g/gcc.lua:81,106-108,169 —— x86_64-linux-gnu-* triple + ld-linux-x86-64.so.2 → arch 派生 aarch64-linux-gnu-*
  • [代码] pkgs/g/gcc-specs-config.lua:48,76-77,87 —— old_dynamic_linker 表加 aarch64 项,消除 :87multi-arch? TODO。
  • [代码] pkgs/g/gcc-runtime.lua:67 —— 内层目录名 arch 化。
  • [代码] pkgs/l/llvm.lua:117,124,142-143,165,256 —— 内层目录 + triple x86_64-unknown-linux-gnu + 链接器 → aarch64。
  • [代码] pkgs/l/llvm-tools.lua:24-25 —— url 表 arch 化。
  • [代码] pkgs/m/musl-gcc.lua:59-79,83,162-167,225 —— 改动最大,整套 x86_64-linux-musl-* + ld-musl-x86_64.so.1aarch64-linux-musl-*
  • [代码] pkgs/m/mcpp.lua:41pkgs/p/patchelf.lua:39 —— url_template 写死 x86_64,仅影响 CI version-check,install 走 XLINGS_RES。

D-2. 元数据

  • [代码] 各包 archs={...}aarch64(gcc/glibc/binutils/ninja/patchelf/linux-headers/gcc-runtime/llvm-tools 当前只 {x86_64})。

D-3. 委托型

  • [构建] pkgs/l/linux-headers.lua —— 委托 scode:linux-headers,需源包提供 aarch64 内核头(asm/)。

D-0. (可选/长期)DSL 引擎扩展 per-arch URL

  • [决策]``[代码] xim-pkgindex/docs/specs/url-template.md:69 列为 TODO。两种形态择一:
    • 形态 A(推荐):让显式 URL 也支持 {arch} 占位 + 引擎按 detect_arch_() 填(与 XLINGS_RES 同源)。
    • 形态 B:新增平台 key linux-aarch64(沿用 ubuntu={ref="linux"} 继承哲学),引擎识别。
    • 注:mcpp 工具链链几乎全走 XLINGS_RES,此项主要为将来镜像上游显式 URL 的包铺路,非主链阻塞

阶段 ⑤ — mcpp 本体

安装入口

  • [代码] install.sh:28-38 —— caseLinux-aarch64) PLAT="linux-aarch64" ;;(映射 aarch64),改行 33 文案。

生产代码硬编码 loader/triple

  • [代码] src/platform/linux.cppm:85 —— runtime lib dir 写死 x86_64-unknown-linux-gnu → 按探测 triple 拼。
  • [代码] src/build/flags.cppm:336 —— --dynamic-linker 写死 ld-linux-x86-64.so.2 → arch 派生 ld-linux-aarch64.so.1
  • [代码] src/pack/pack.cppm:648 —— PT_INTERP 写死 /lib64/ld-linux-x86-64.so.2/lib/ld-linux-aarch64.so.1(且不在 /lib64)。
  • [代码] src/pack/pipeline.cppm:37,61 —— pack 默认 target 写死 x86_64-linux-musl → 按 host 推导。
  • [代码] src/toolchain/post_install.cppm(93/115/118/146/249/306/319)、src/toolchain/lifecycle.cppm(382/387/406/407)—— glibc loader 名 + x86_64-* triple 目录(patchelf/specs/cfg 修复链)→ arch 派生。
  • [代码] 建议新增 src/platform/common.cppmhost_arch 抽象 + arch→loader 映射表,统一上面所有点(当前只有 OS 维度,无 CPU arch 维度)。

配置

  • [代码] mcpp.toml:24 —— 新增 [target.aarch64-linux-musl](前提:xlings 有 aarch64 musl-gcc)。
  • .xlings.json:3 —— bootstrap pin 纯版本号,无需改 arch(前提:xim-x-mcpp 有 aarch64 资产)。

发布/CI

  • [CI] .github/workflows/release.yml —— 新增 aarch64 job(runs-on: ubuntu-24.04-arm)或 matrix;改行 102(xlings 引导下载)、127/131/143-146(--target/资产名)、165-168(别名)、248-256(files:)。
  • [CI] ci-linux.yml / ci-fresh-install.yml —— 可选 aarch64 leg。
  • [代码] README.md:215 / README.zh-CN.md:215 —— Linux aarch64 状态 🔄→✅。

测试夹具

  • [代码] tests/unit/*tests/e2e/*.sh 多处断言 x86_64-linux-* 路径 → 参数化或加 aarch64 用例。

顺手 bug(非 arch,但影响所有 Clang 宿主)

  • [代码] src/doctor.cppm:106 —— std 模块检查只认 std.gcm,Clang 产 std.pcm 会误报。

5. 最小可用路径(MVP)

只为跑通 gcc 路线的 xlings install mcpp + mcpp build:

⓪ 引导第0个 aarch64 mcpp
 → ① 构建 gcc/glibc/binutils/ninja aarch64(linux-headers 走 scode)
 → ② 上架 aarch64 资产(8 个最小主链包)
 → ③ libxpkg elfpatch + glibc.lua loader 修正
 → ⑤ mcpp 4 处硬编码 + install.sh + release.yml aarch64 job

llvm(clang/import std)、musl-gcc、DSL 扩展可作为第二阶段。


6. 关键技术依据(代码出处)

结论 出处
引擎 arch token:Linux=aarch64 / macOS=arm64(平台感知) xlings/src/core/xim/installer.cppm:123-133 detect_arch_()
XLINGS_RES 自动拼 arch xlings/src/core/xim/installer.cppm:146 build_xlings_res_url_
依赖解析只按 OS 不按 arch xlings resolver/catalog/index 全用 platform key
DSL 不支持同平台 per-arch URL xim-pkgindex/docs/specs/url-template.md:69-72
elfpatch loader 只列 x86_64 libxpkg/.../elfpatch.lua:287-289,315-317
mcpp 二进制全静态(musl) mcpp/mcpp.toml:24-26 [target.x86_64-linux-musl] linkage=static
mcpp 静态链接不挂 glibc payload mcpp/src/build/flags.cppm:322-323
triple 由 -dumpmachine 动态产出 mcpp/src/toolchain/probe.cppm:260-269

7. Termux/Android (bionic) —— 单列

目标 A(aarch64-linux)做完,在 Termux 原生(bionic)上仍不能直接用,因为 Android 用 bionic libc,与 glibc/musl ABI 不兼容,且全生态零 android 平台维度。

额外阻塞:

  1. xlings/xim-pkgindex 需新增 android/termux 平台 key(改 src/platform/、所有 entries.find(platform)、索引数据)。
  2. ELF loader 完全不同(/system/bin/linker64、Termux $PREFIX/lib),elfpatch 的 ld-linux 假设全失效。
  3. sysroot 在 $PREFIX,glibc 探测(/usr/includefeatures.h/lib64)全不成立。
  4. 工具链需 NDK aarch64-linux-android 或 Termux 自身工具链。

推荐取巧路线: 优先做 aarch64-linux-musl 全静态 —— 产物和工具链全静态,同时绕开 bionic ABI 和 "glibc 能否在 Android 内核运行" 两个变量。代价是 musl-gcc.lua 那套三元组/loader 改动量大(§4 D-1)。

给 #143 报告人的最快验证: 出一个 aarch64-linux-musl 全静态 mcpp,让其在 Termux 原生直接跑(不进 proot)试探;或先用 aarch64-linux glibc 包在 proot-distro(Ubuntu)里验证 self-contained 路线成立。


8. 风险与待确认

  • LLVM 官方 Linux-ARM64 libc++ 是否带 std.cppm + -print-library-module-manifest-path(决定 aarch64 上 import std 是否开箱即用)。
  • GitHub ubuntu-24.04-arm runner 在本项目 org 是否可用(决定原生构建 vs 交叉)。
  • scode:linux-headers 是否已有 aarch64 源(委托型,§4 D-3)。
  • CN 镜像(gitcode)aarch64 资产同步是否需要额外脚本(参考 [[release-publish-pipeline]] 的双端镜像流程)。