Skip to content

Commit f3d3a4b

Browse files
committed
docs: aarch64 musl-gcc canadian-cross rebuild guide (musl 1.2.5, Android 13)
Full reproducible build recipe + every hurdle/fix: NATIVE=1 needs cross gcc in PATH; gawk 5.2.1 PMA segfault -> setarch -R; corrupt options-urls.cc cleanup; --disable-decimal-float libgcc breakage; usr/ sysroot symlink for default header resolution. Plus verification (0 set_robust_list), packaging (strip+dereference), upload. Marks Plan C done in the analysis report (artifact 80MB, sha 2277f07c).
1 parent e031484 commit f3d3a4b

2 files changed

Lines changed: 228 additions & 11 deletions

File tree

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,212 @@
1+
# 原生 aarch64 musl-gcc 用 musl 1.2.5 重建(canadian-cross)— 复现指南
2+
3+
**日期**: 2026-06-23
4+
**目的**: 重建在 aarch64 Termux 上本地编译用的 **原生** musl-gcc 工具链
5+
(`musl-gcc-15.1.0-linux-aarch64`),使其链接 **musl 1.2.5**(而非 1.2.6),
6+
避开 Android 13 seccomp 对 `set_robust_list` 的 SIGSYS。
7+
**背景与根因**: 见 [2026-06-23-termux-android-adaptation.md](./2026-06-23-termux-android-adaptation.md) §6。
8+
9+
> 一句话:musl ≥1.2.6 启动期注册主线程 robust list(`set_robust_list`),
10+
> Android 13 app 沙盒 seccomp 把它 TRAP 成 SIGSYS → 整个 1.2.6 工具链在 Termux 上
11+
> 启动即 "Bad system call"。1.2.5 不调该 syscall。必须用 1.2.5 **重建**(换 libc 文件
12+
> 无用,musl 已静态链进每个 gcc/g++/as 二进制)。
13+
14+
---
15+
16+
## 0. 为什么是 canadian-cross
17+
18+
原生包的 gcc/g++ 二进制要 **跑在 aarch64**(host=target=aarch64)。三种构建法:
19+
- A. 真 aarch64 机器:直接 musl-cross-make。
20+
- B. qemu-aarch64 模拟构建:gcc bootstrap 模拟下 10+ 小时。
21+
- **C. canadian-cross(本指南)**:本机 x86_64 速度,用现成的 x86_64-host aarch64
22+
交叉工具链去编译 host=aarch64 的 gcc/g++。本次实测 build 全程 ~15 分钟(8 核)。
23+
24+
musl-cross-make 通过 `NATIVE = 1`(`HOST = $(TARGET)`)支持 canadian/native 构建:
25+
它用 **PATH 里已有的 `<target>-gcc` 交叉编译器** 来编 host=target 的工具链。
26+
27+
---
28+
29+
## 1. 前置条件
30+
31+
| 依赖 | 说明 |
32+
|---|---|
33+
| 交叉工具链 `aarch64-linux-musl-gcc`(**musl 1.2.5**) | `~/.mcpp/.../xpkgs/xim-x-aarch64-linux-musl-gcc/15.1.0/bin`;**必须在 PATH**(NATIVE 构建用它编 host 部分) |
34+
| 本机 `gcc`/`g++`/`make` | 编 build 端工具 |
35+
| musl-cross-make + 源码 | `~/.xlings/.../xim-x-musl-cross-make/0.0.1/musl-cross-make`;已含 musl-1.2.5、gcc-15.1.0、binutils-2.44、gmp/mpfr/mpc 源 |
36+
| `setarch` | 关 ASLR(绕 gawk PMA segfault,见 §3.2) |
37+
| `qemu-aarch64` + binfmt | 本机验证产物(strace / 跑 hello) |
38+
39+
确认交叉工具链是 1.2.5(关键):
40+
```bash
41+
qemu-aarch64 <cross>/aarch64-linux-musl/lib/libc.so 2>&1 | grep -i version # → Version 1.2.5
42+
# 或:用它编个 hello,strace 应只有 set_tid_address、无 set_robust_list
43+
```
44+
45+
---
46+
47+
## 2. 构建步骤(最终可用版)
48+
49+
```bash
50+
# 1) 复制一份 musl-cross-make(别污染已安装的)
51+
cp -a ~/.xlings/data/xpkgs/xim-x-musl-cross-make/0.0.1/musl-cross-make mcm-native
52+
cd mcm-native
53+
54+
# 2) 写 config.mak(最终可用,已剔除所有踩坑项)
55+
cat > config.mak <<'EOF'
56+
GCC_VER = 15.1.0
57+
MUSL_VER = 1.2.5
58+
TARGET = aarch64-linux-musl
59+
NATIVE = 1
60+
COMMON_CONFIG += CFLAGS="-g0 -Os" CXXFLAGS="-g0 -Os"
61+
COMMON_CONFIG += LDFLAGS="-static --static -s"
62+
COMMON_CONFIG += --disable-nls
63+
GCC_CONFIG += --enable-languages=c,c++ --disable-multilib
64+
EOF
65+
66+
# 3) 交叉工具链入 PATH + 关 ASLR 构建
67+
export PATH="$HOME/.mcpp/registry/data/xpkgs/xim-x-aarch64-linux-musl-gcc/15.1.0/bin:$PATH"
68+
which aarch64-linux-musl-gcc # 必须能找到
69+
setarch $(uname -m) -R make -j8
70+
setarch $(uname -m) -R make install OUTPUT="$(pwd)/output-native"
71+
```
72+
73+
产物在 `output-native/`(`bin aarch64-linux-musl include lib libexec share`)。
74+
75+
### config.mak 关键项说明
76+
- `NATIVE = 1`:触发 HOST=TARGET 的 canadian-cross。
77+
- `MUSL_VER = 1.2.5`**核心**。不写则吃 musl-cross-make 默认(可能漂到 1.2.6)。
78+
→ 已在 `xim-pkgindex/pkgs/m/musl-cross-make.lua` 的 config.mak 模板里 **显式 pin**,
79+
根治版本漂移。
80+
- `LDFLAGS = "-static --static -s"`:产物静态(免 loader)+ 链接期 strip。
81+
`--static` 穿透 binutils libtool(单 `-static` 会被丢成 dynamic)。
82+
- `CFLAGS/CXXFLAGS = "-g0 -Os"`:去调试信息 + 优化体积。
83+
- **不要** `--disable-decimal-float`(见 §3.3)、不要 `--disable-libquadmath`
84+
85+
---
86+
87+
## 3. 踩坑与修复(按出现顺序)
88+
89+
### 3.1 `cannot find a C compiler`(NATIVE 直接进 native 阶段)
90+
NATIVE=1 **不自动建 stage-1 交叉工具链**,它期望 `aarch64-linux-musl-gcc` 已在 PATH。
91+
**把交叉工具链 bin 加进 PATH** 再 make。
92+
93+
### 3.2 ⭐ gawk PMA segfault(系统 gawk 5.2.1)
94+
```
95+
gawk: opt-functions.awk:62: fatal error: internal error: segfault
96+
make[3]: *** [options-urls.cc] Error 134
97+
```
98+
GNU Awk 5.2.x 的 **PMA(persistent memory allocator, "Avon")** 在某些 ASLR 地址下
99+
segfault(地址相关,非确定性)。
100+
**全程 `setarch $(uname -m) -R make ...` 关 ASLR**,稳定绕过。
101+
102+
### 3.3 gawk 崩溃残留的损坏 `options-urls.cc`
103+
即使加了 `setarch -R` 续构建,仍报:
104+
```
105+
options-urls.cc:3362:30: error: expected '}' at end of input
106+
```
107+
**第一次 gawk segfault 留下的截断 `options-urls.cc`**,make 见文件已存在不重生成,
108+
直接编译损坏文件。
109+
→ 删掉让其重生成:
110+
```bash
111+
find build -name options-urls.cc -delete
112+
find build -name options-urls.o -delete
113+
```
114+
115+
### 3.4 `--disable-decimal-float` 炸 libgcc
116+
```
117+
No rule to make target '.../libdecnumber/no/decimal32.c', needed by 'decimal32.o'
118+
make[3]: *** [all-target-libgcc] Error 2
119+
```
120+
`--disable-decimal-float` 把 decimal 格式设成 `no`,但 libgcc 仍引用 `libdecnumber/no/decimal32.c`
121+
(不存在)。已工作的交叉工具链没用这个 flag。
122+
**从 GCC_CONFIG 删掉 `--disable-decimal-float`**(改了 configure 项 → 需 `rm -rf obj_gcc` 重配 gcc)。
123+
124+
### 3.5 默认 sysroot 找不到头文件(native 布局差异)
125+
产物 g++ 编译报 `fatal error: stdio.h: No such file or directory`
126+
原因:NATIVE 构建是 **native 布局**——系统头在 `<prefix>/include`、库在 `<prefix>/lib`,
127+
gcc sysroot=`<prefix>`;但 gcc 默认在 `<sysroot>/usr/include` 找系统头。
128+
(旧交叉包是 `<prefix>/aarch64-linux-musl/include` + sysroot=该 triple 子目录,所以能找到。)
129+
**加 usr/ 相对软链**,让默认 sysroot 解析到位(无需重建):
130+
```bash
131+
cd output-native
132+
mkdir -p usr
133+
ln -sfn ../include usr/include
134+
ln -sfn ../lib usr/lib
135+
```
136+
(gcc 对不存在的目录会静默跳过,所以 `-E -v` 的搜索列表里看不到 usr/include,但建好后能用。)
137+
138+
---
139+
140+
## 4. 验证(打包前必做)
141+
142+
```bash
143+
OUT=output-native
144+
# ★ 关键:strace 必须 0 次 set_robust_list(否则 Android 13 仍 SIGSYS)
145+
qemu-aarch64 -strace $OUT/bin/aarch64-linux-musl-g++ --version 2>&1 | grep -c set_robust_list # → 0
146+
# 二进制类型 + musl 版本
147+
file $OUT/bin/aarch64-linux-musl-g++ # ARM aarch64, statically linked, stripped
148+
# C + C++ 默认 sysroot 编译 + qemu 跑
149+
printf '#include <stdio.h>\nint main(){puts("c-ok");}\n' > /tmp/t.c
150+
printf '#include <iostream>\nint main(){std::cout<<"cpp-ok\\n";}\n' > /tmp/t.cpp
151+
qemu-aarch64 $OUT/bin/aarch64-linux-musl-gcc /tmp/t.c -o /tmp/tc -static && qemu-aarch64 /tmp/tc
152+
qemu-aarch64 $OUT/bin/aarch64-linux-musl-g++ /tmp/t.cpp -o /tmp/tcpp -static && qemu-aarch64 /tmp/tcpp
153+
```
154+
155+
本次实测:`set_robust_list` 0 次;`g++ (GCC) 15.1.0`;C/C++ 均 OK。
156+
157+
---
158+
159+
## 5. 打包(套用 §5 of analysis 的 Termux 修复)
160+
161+
构建已用 `-g0 -Os -s` 内建 strip(无需再 strip)。还需 **dereference hardlink**
162+
(Android `link()` 失败,见 analysis §5):
163+
164+
```bash
165+
cd mcm-native
166+
cp -a output-native musl-gcc-15.1.0-linux-aarch64 # 规范顶层目录名
167+
tar --hard-dereference -czf musl-gcc-15.1.0-linux-aarch64.tar.gz musl-gcc-15.1.0-linux-aarch64
168+
# 校验:0 个 hardlink('h'),符号链接全相对(无 /tmp 构建路径绝对软链)
169+
tar tzvf musl-gcc-15.1.0-linux-aarch64.tar.gz | awk '{print substr($1,1,1)}' | sort | uniq -c
170+
tar tzvf musl-gcc-15.1.0-linux-aarch64.tar.gz | awk '$1~/^l/' | grep -c "/tmp/" # → 0
171+
```
172+
173+
**本次产物**:`musl-gcc-15.1.0-linux-aarch64.tar.gz`
174+
- 压缩 **80 MB** / 解压 **194 MB**(对比旧坏包 790MB / 1.86GB)。
175+
- sha256 `2277f07cd4fff2111f37182ad49dc331ccc13b6aef7dde31c704bf7dbdb0f326`
176+
- musl 1.2.5、静态、0 hardlink、usr/ sysroot 软链、14 个相对符号链接。
177+
178+
---
179+
180+
## 6. 上传 xlings-res(GLOBAL + CN)
181+
182+
`musl-gcc.lua` **无 sha pin** → 资产透明替换,免改索引。
183+
184+
```bash
185+
# GitHub(GLOBAL)— 可覆盖
186+
gh release upload 15.1.0 -R xlings-res/musl-gcc musl-gcc-15.1.0-linux-aarch64.tar.gz --clobber
187+
188+
# GitCode(CN)— 同名资产 gtc 无法覆盖(obs_callback 400),需先删旧再传
189+
# (gtc 无 delete 子命令;用 GitCode 网页/API 删 musl-gcc-15.1.0-linux-aarch64.tar.gz)
190+
gtc release upload xlings-res/musl-gcc musl-gcc-15.1.0-linux-aarch64.tar.gz --tag 15.1.0
191+
# 验证两端字节一致:
192+
curl -sL <github|gitcode 同名 url> | sha256sum # 应 = 2277f07c...
193+
```
194+
195+
---
196+
197+
## 7. 根治(已落地,防复发)
198+
199+
`xim-pkgindex/pkgs/m/musl-cross-make.lua` 的 config.mak 模板已 **显式 pin `MUSL_VER = 1.2.5`**
200+
(commit `fix(musl-cross-make): pin MUSL_VER = 1.2.5 ...`),所有后续构建(交叉 + 原生)
201+
锁定 1.2.5,不再漂到 1.2.6+。**今后任何"在 Android 上运行"的 musl-static 产物都必须 ≤1.2.5,
202+
或 patch 掉 musl 启动期的 `set_robust_list`**(robust mutex 极少用)。
203+
204+
---
205+
206+
## 8. Termux 端最终验证
207+
208+
```bash
209+
rm -rf ~/.mcpp # 清掉装坏的旧 1.2.6 工具链
210+
cd hello && mcpp build # 装新 80MB 包 → 解压(无 hardlink)→ g++ 不再 SIGSYS → 编译通过
211+
```
212+
```

.agents/docs/2026-06-23-termux-android-adaptation.md

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -247,17 +247,22 @@ Android 13 app 沙盒的 seccomp 把它 **TRAP 成 SIGSYS**(而非返回 ENOSYS)
247247
差异来源:`musl-cross-make.lua` 的 config.mak 模板**没 pin `MUSL_VER`** → 用 musl-cross-make
248248
默认版本;建交叉工具链时默认 1.2.5,后来建原生包时默认涨到 1.2.6。
249249

250-
### 修复(进行中,Plan C)
251-
**musl 1.2.5** 重建原生 aarch64 musl-gcc:`config.mak``MUSL_VER = 1.2.5`
252-
构建环境三方案:
253-
- A. 真 aarch64 机器(最稳)。
254-
- B. qemu-aarch64 模拟构建(本机可跑,gcc bootstrap 模拟 10+ 小时)。
255-
- **C. canadian-cross(本次采用)**:本机 x86_64 速度,用现成交叉工具链编译 host=aarch64
256-
的 gcc/g++,二进制链接 musl 1.2.5。
257-
258-
修复后:原生 gcc 二进制不再调 `set_robust_list` → Android 13 能跑 → `mcpp build` 在 Termux
259-
上闭环。同时应给 `musl-cross-make.lua` **显式 pin `MUSL_VER = 1.2.5`**,避免未来默认版本漂移
260-
再次引入 1.2.6(或更高)的不兼容。
250+
### 修复(✅ 已完成,Plan C)
251+
**musl 1.2.5** 重建原生 aarch64 musl-gcc。三方案:A. 真 aarch64 机器;B. qemu 模拟
252+
(10+ 小时);**C. canadian-cross(已采用,~15 分钟)**——本机 x86_64 用现成交叉工具链
253+
(musl 1.2.5)编 host=aarch64 的 gcc/g++,产物链 musl 1.2.5。
254+
255+
**完整可复现步骤、踩坑(gawk PMA segfault→`setarch -R`、损坏 options-urls.cc、
256+
`--disable-decimal-float` 炸 libgcc、usr/ sysroot 软链)、验证、打包、上传**,
257+
见独立文档 [2026-06-23-aarch64-musl-gcc-canadian-cross-rebuild.md](./2026-06-23-aarch64-musl-gcc-canadian-cross-rebuild.md)
258+
259+
**产物已上架**:`musl-gcc-15.1.0-linux-aarch64.tar.gz`,80MB/194MB,
260+
sha256 `2277f07cd4fff2111f37182ad49dc331ccc13b6aef7dde31c704bf7dbdb0f326`,
261+
musl 1.2.5、**strace 0 次 set_robust_list**、静态、dereferenced。github + gitcode
262+
xlings-res 两端字节一致。
263+
264+
**根治已落地**:`xim-pkgindex/pkgs/m/musl-cross-make.lua` 的 config.mak 模板已 **显式 pin
265+
`MUSL_VER = 1.2.5`**,所有后续工具链锁定 1.2.5,杜绝默认版本漂移再引入 1.2.6+。
261266

262267
### 经验 / 待办
263268
- 任何"在 Android 上运行"的 musl-static 二进制都必须避开 musl ≥1.2.6 的启动期

0 commit comments

Comments
 (0)