fix(devkit): M24 r1 评审 — P1 --with-sources 静默漏源码 + time64 归因更正
P1(阻断):stamp 命中时 main 提前 return,--with-sources 在 return 之后,
于是「先构建再 --with-sources」会打印成功、退出码 0、却不产出 src/。
- 把源码整理抽成 stage_sources(),stamp 命中路径先兑现 WITH_SOURCES 再返回;
整理后按钉住的 sha256 复核(sha 漂移/缺文件都重铺),任何失败即非零退出
- 新增 test_build_devkit.sh(12 项,秒级):stamp 命中下的 --with-sources、
src 缺文件/被改坏的自愈、--verify-only 的 MANIFEST 篡改检测
- skip 条件额外要求 MANIFEST 与 bin 逐条 sha 一致;--clean 同时清 out/src;
全新构建未带 --with-sources 时删除上次残留 src/(避免源码与二进制错配)
P2-a:top 排除理由改写。根因是 zig 0.17 musl 的 time64 ABI 错配(mips o32 是
ILP32 + 内核 4.4 无 time64 syscall,16B timespec 直传 32 位 syscall),不是
procps 的 bug;top 的 Mem 一栏是「百分比/总容量」不是 used GiB。新增 DEVKIT.md
§9 记录证据(vmstat -t 空列、usleep(0.5s)×10 实测 0s、sleep(1) 正常、ps lstart
正常),并说明 M16 的 patch_v2/sdk/meow_ui_time.c 可复用(本轮实测该 .o 独立
编译、仅 5 个 libc 未定义符号)但本轮不接入的取舍——需要单独 mission 做链接期
接管 + 全量回归,不是 -D 能修的。
P2-b:--with-sources 现在同时放 build_devkit.sh + DEVKIT.md(GPLv2 §3 的
"scripts used to control compilation");补 LGPL-2.1 §6 静态链接 libproc2 的
义务说明;MANIFEST/README.txt 写明 src/ 与 licenses/。
P2-c:lsof 内嵌 Termux musl 的 resolv.conf 路径记为工具链副作用(实测
lsof -i 约 3s 超时、-nP 瞬时;端口名/本机名不受影响),不换工具链。
P3:软链路径写实(/bin/ps、/usr/bin/{free,lsof,top});MANIFEST 用 zig version
而非 clang 版本;chmod 措辞改成检查挂载参数;--verify-only 增加 MANIFEST 逐条
sha256/体积比对且不再依赖 date;stamp 纳入 zig 完整版本;许可证复制失败即报错。
验证:test_build_devkit.sh 12/12 通过;--verify-only 通过(含 MANIFEST 对账);
独立工作区离线重建 85s/0 下载,六个二进制 sha256 与上一版逐字节一致;设备侧
二进制未变(sha 与 r1 真机验证过的一致)。
This commit is contained in:
1 parent
b52e6a08bc
commit
0531603779
4 files changed
+431
-143
No files matched your search
+147
-88
@@ -1,13 +1,14 @@
|
|||||||
# MeowOS devkit — 静态 MIPS32r2 调试工具集
|
# MeowOS devkit — 静态 MIPS32r2 调试工具集
|
||||||
|
|
||||||
TF 卡 `MeowOS/opt/devkit/bin/` 里那批静态二进制的构建说明、可行性实测、许可证留痕。
|
TF 卡 `MeowOS/opt/devkit/bin/` 里那批静态二进制的构建说明、可行性实测、许可证留痕。
|
||||||
构建入口:`bash scripts/build/build_devkit.sh`(产物在 `fw_apps/devkit/`,已被 `.gitignore`
|
构建入口:`bash scripts/build/build_devkit.sh`;回归测试:`bash scripts/build/test_build_devkit.sh`
|
||||||
的 `fw_apps/` 规则覆盖,不入库)。
|
(产物在 `fw_apps/devkit/`,已被 `.gitignore` 的 `fw_apps/` 规则覆盖,不入库)。
|
||||||
|
|
||||||
## 1. 为什么要有这个
|
## 1. 为什么要有这个
|
||||||
|
|
||||||
设备(HiBy R3 Pro II / Ingenic X1600 / MIPS32r2 / Linux 4.4.94+ / 单核 / 56 MB)自带
|
设备(HiBy R3 Pro II / Ingenic X1600 / MIPS32r2 / Linux 4.4.94+ / 单核 / 56 MB)自带
|
||||||
busybox 1.31.1,`free / ps / top / lsof` 都是指向 `/bin/busybox` 的软链,字段残缺;
|
busybox 1.31.1,`free / ps / top / lsof` 都是 busybox 的软链
|
||||||
|
(实测:`/bin/ps -> busybox`,`/usr/bin/{free,lsof,top} -> ../../bin/busybox`),字段残缺;
|
||||||
`vmstat`、`slabtop`、`pmap` 干脆没有。做内存分析时最缺的正是:
|
`vmstat`、`slabtop`、`pmap` 干脆没有。做内存分析时最缺的正是:
|
||||||
|
|
||||||
- `slabtop` —— Slab 总量 ~11 MB 到底被谁占了(buffer_head / dentry / squashfs_inode…)
|
- `slabtop` —— Slab 总量 ~11 MB 到底被谁占了(buffer_head / dentry / squashfs_inode…)
|
||||||
@@ -23,16 +24,17 @@ busybox 1.31.1,`free / ps / top / lsof` 都是指向 `/bin/busybox` 的软链
|
|||||||
|
|
||||||
| 工具 | 来源版本 | 许可证 | 体积(B) | 用途 / 相对 busybox 的增量 |
|
| 工具 | 来源版本 | 许可证 | 体积(B) | 用途 / 相对 busybox 的增量 |
|
||||||
|---|---|---|---|---|
|
|---|---|---|---|---|
|
||||||
| `slabtop` | procps-ng 4.0.4 | GPL-2.0-or-later | 394 408 | Slab 明细;`-o` 一次性输出不需要 TTY/terminfo |
|
| `slabtop` | procps-ng 4.0.4 | GPL-2.0-or-later(依赖 libproc2 LGPL-2.1+) | 394 408 | Slab 明细;`-o` 一次性输出不需要 TTY/terminfo |
|
||||||
| `vmstat` | procps-ng 4.0.4 | GPL-2.0-or-later | 216 924 | 系统趋势;busybox 无 |
|
| `vmstat` | procps-ng 4.0.4 | 同上 | 216 924 | 系统趋势;busybox 无;`-t` 时间戳列本工具链下为空,见 §9 |
|
||||||
| `ps` | procps-ng 4.0.4 | GPL-2.0-or-later | 324 980 | `-eo pid,rss,vsz,comm --sort=-rss` 等完整字段 |
|
| `ps` | procps-ng 4.0.4 | 同上 | 324 980 | `-eo pid,rss,vsz,comm --sort=-rss` 等完整字段 |
|
||||||
| `pmap` | procps-ng 4.0.4 | GPL-2.0-or-later | 173 460 | 地址空间映射(读 `/proc/pid/maps`);busybox 无 |
|
| `pmap` | procps-ng 4.0.4 | 同上 | 173 460 | 地址空间映射(读 `/proc/pid/maps`);busybox 无 |
|
||||||
| `free` | procps-ng 4.0.4 | GPL-2.0-or-later | 94 312 | 拆 buff/cache、available |
|
| `free` | procps-ng 4.0.4 | 同上 | 94 312 | 拆 buff/cache、available |
|
||||||
| `lsof` | lsof 4.99.4 | Purdue/BSD-style | 789 496 | SIZE/OFF、TCP 状态、NAME、`-i` 网络视图 |
|
| `lsof` | lsof 4.99.4 | Purdue/BSD-style | 789 496 | SIZE/OFF、TCP 状态、NAME、`-i` 网络视图 |
|
||||||
| | | **合计** | **1 993 580 ≈ 1.9 MB** | |
|
| | | **合计** | **1 993 580 ≈ 1.9 MB** | |
|
||||||
|
|
||||||
同目录还有构建时生成的 `MANIFEST.txt`(每个二进制的 sha256)、`licenses/`(上游 COPYING)、
|
同目录还有 `MANIFEST.txt`(每个二进制的 sha256 + 版本 + 许可证 + 体积)、
|
||||||
`README.txt`(上卡说明)。`--with-sources` 会额外生成 `src/`(源码包,GPL 合规用)。
|
`licenses/`(上游 COPYING / COPYING.LIB)、`README.txt`(上卡说明)。
|
||||||
|
`--with-sources` 会额外生成 `src/`(三份源码包 + `build_devkit.sh` + 本文件)。
|
||||||
|
|
||||||
## 3. 上卡后怎么用
|
## 3. 上卡后怎么用
|
||||||
|
|
||||||
@@ -49,69 +51,74 @@ fi
|
|||||||
|
|
||||||
**与 busybox 同名命令的先后关系**(前插 PATH 时):
|
**与 busybox 同名命令的先后关系**(前插 PATH 时):
|
||||||
|
|
||||||
| 名字 | 现状 | 前插后 |
|
| 名字 | 现状(实测软链) | 前插后 |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `free` `ps` `lsof` | `/usr/bin/*` 均是指向 `/bin/busybox` 的软链 | 解析到 devkit 版(功能更多) |
|
| `free` `lsof` `top` | `/usr/bin/x -> ../../bin/busybox` | `free`/`lsof` 解析到 devkit 版;`top` 仍是 busybox(本工具集不提供) |
|
||||||
|
| `ps` | `/bin/ps -> busybox` | 解析到 devkit 版 |
|
||||||
| `vmstat` `slabtop` `pmap` | 不存在 | 新增 |
|
| `vmstat` `slabtop` `pmap` | 不存在 | 新增 |
|
||||||
| `top` | busybox 软链;**本工具集不提供 top**(见 §7) | 仍为 busybox |
|
|
||||||
|
|
||||||
要临时用回 busybox 版:`/bin/busybox free`、`busybox ps`、`busybox lsof`。
|
要临时用回 busybox 版:`busybox free`、`busybox ps`、`busybox lsof`。
|
||||||
不要覆盖 `/usr/bin` 里的软链:rootfs 是 ubifs,随固件回刷即被还原,而且这些软链是基线的一部分。
|
不要覆盖 `/usr/bin`、`/bin` 里的软链:rootfs 是 ubifs,随固件回刷即被还原,而且这些软链是基线的一部分。
|
||||||
|
|
||||||
## 4. exFAT 语义(权限 / 软链)
|
## 4. exFAT 语义(权限 / 软链)
|
||||||
|
|
||||||
设备挂载:`/dev/mmcblk0 on /usr/data/mnt/sd_0 type exfat (rw, fmask=0022, dmask=0022, symlink=0, noexec 未设置)`。
|
设备挂载:`/dev/mmcblk0 on /usr/data/mnt/sd_0 type exfat (rw, fmask=0022, dmask=0022, symlink=0, noexec 未设置)`。
|
||||||
|
|
||||||
- **无符号链接**(`symlink=0`):所以本工具集全部是实体文件,不靠 `argv[0]` 分派,
|
- **无符号链接**(`symlink=0`):本工具集全部是实体文件,不做 `argv[0]` 分派,也不提供 symlink
|
||||||
也不提供任何 symlink(不像 busybox 那样一个多合一二进制 + 一堆软链)。
|
(不像 busybox 那样一个多合一二进制 + 一堆软链)。
|
||||||
- **无 Unix 权限位**:`fmask=0022` 让卡上新文件恒为 `0755`,因此**不需要 chmod**;
|
- **无 Unix 权限位**:`fmask=0022` 让卡上新文件恒为 `0755`,因此**不需要 chmod**——
|
||||||
反过来说,卡上也表达不了 `4755` 之类,任何需要 setuid 的工具都不适合放这。
|
反过来说 `chmod` 在这里本身是 no-op;卡上也表达不了 setuid,任何需要 setuid 的工具都不适合放这。
|
||||||
- **可执行性**:挂载参数里没有 `noexec`,且卡上现有 `MeowOS/opt/MeowOS…/meowpanel`
|
- **可执行性**:挂载参数里没有 `noexec`,且卡上现有 `MeowOS/opt/MeowPanel/meowpanel` 就是 0755 直接执行的。
|
||||||
就是 0755 直接执行的。真机验证时我们把同一批二进制放在设备 `/tmp` 跑通(见 §9)。
|
本轮真机验证是在设备 `/tmp`(同为 MIPS 目标、root 身份)做的,**没有往卡上写过任何东西**(约定:卡由塔推)。
|
||||||
未在卡上实测执行,是因为本次任务约定「不往卡上写任何东西」(塔来推)。
|
|
||||||
|
|
||||||
## 5. 重跑代价与可复现性
|
## 5. 重跑代价与可复现性
|
||||||
|
|
||||||
- **联网次数**:冷启动 **3 次**(ncurses / procps-ng / lsof 各一个 tarball,共 5.5 MB);
|
- **联网次数**:冷启动 **3 次**(ncurses / procps-ng / lsof 各一个 tarball,共 5.5 MB);
|
||||||
源码包按 sha256 校验后落在 `$MEOW_DEVKIT_WORK/src/`,此后**重跑 0 次联网**。
|
源码包按 sha256 校验后落在 `$MEOW_DEVKIT_WORK/src/`,此后**重跑 0 次联网**。
|
||||||
- **耗时**(8 核宿主实测):冷启动(含 3 次下载)**80 秒**(两次实测 80s / 86s);
|
- **耗时**(8 核宿主实测):冷启动(含 3 次下载)**80 秒**(两次实测 80s / 86s);
|
||||||
源码已缓存时全量重编约 **85 秒**;`stamp` 命中(脚本与版本都没变)时 **1 秒**直接跳过;
|
源码已缓存时全量重编约 **65–85 秒**;`stamp` 命中(脚本、版本、zig 版本都没变)**1–2 秒**;
|
||||||
`--verify-only` 秒级,且不需要 zig。
|
`--verify-only` 秒级,且只依赖 `file` / `readelf` / `sha256sum` / `awk`(不需要 zig、make、date、网络)。
|
||||||
|
- **stamp 内容**:脚本 sha256 + zig 完整版本(0.17.0 / 0.17.1 会区分)+ target + 内核版本 + 三个上游版本。
|
||||||
- **可复现(逐字节)**:在两个不同工作区各建一次,六个二进制 **sha256 完全相同**
|
- **可复现(逐字节)**:在两个不同工作区各建一次,六个二进制 **sha256 完全相同**
|
||||||
(`ps` 用 `-ffile-prefix-map` 抹掉绝对源码路径;`lsof` 用裸名 `CC=zigcc` + 相对源码路径,
|
(`ps` 用 `-ffile-prefix-map` 抹掉绝对源码路径;`lsof` 用裸名 `CC=zigcc` + 相对源码路径,
|
||||||
不再把工具链/构建目录写进 `LSOF_CC/LSOF_CCFLAGS`)。同一份 `MANIFEST.txt` 里的 sha256
|
不再把工具链/构建目录写进 `LSOF_CC/LSOF_CCFLAGS`)。`MANIFEST.txt` 里的 sha256 与设备上
|
||||||
与设备上 `sha256sum` 的结果一致,可用来核对「跑的到底是哪个二进制」。
|
`sha256sum` 的结果一致,可用来核对「跑的到底是哪个二进制」。
|
||||||
- **可复现性**:三份源码都固定 `版本 + sha256 + URL`,校验不符直接失败;`zig 0.17.x` 版本
|
- `--verify-only` 除了静态/架构/NEEDED,还会把 `bin/` 六个文件与 `MANIFEST.txt` 的 sha256/体积
|
||||||
也做硬检查。不依赖任何「这次网络恰好成功」的偶然性 —— 离线环境可先拷 `src/*.tar.*`
|
**逐条比对**(只查 static/MIPS 是看不出内容漂移的)。
|
||||||
进工作区再用 `--offline`。
|
- **回归测试**:`bash scripts/build/test_build_devkit.sh`(12 项,秒级,不重编)覆盖:
|
||||||
- 工作区默认 `~/.cache/meow-devkit`(`MEOW_DEVKIT_WORK` 可改),不污染仓库。
|
stamp 命中时 `--with-sources` 必须产出完整 `src/`(r1 P1 的回归点)、src/ 缺文件/被改坏能自愈、
|
||||||
|
`--verify-only` 能拒绝被篡改的 MANIFEST。
|
||||||
|
|
||||||
## 6. 许可证与分发合规(重点)
|
## 6. 许可证与分发合规(重点)
|
||||||
|
|
||||||
| 上游 | 许可证 | 分发二进制时的义务 |
|
| 上游 | 许可证 | 分发二进制时的义务 |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| procps-ng 4.0.4 | **GPL-2.0-or-later**(`COPYING`=GPLv2;`library/` 为 LGPL-2.1+) | **必须提供完整对应源码**(GPLv2 §3),或书面的三年有效要约 |
|
| procps-ng 4.0.4(apps) | **GPL-2.0-or-later** | **提供完整对应源码**(GPLv2 §3),含 "scripts used to control compilation and installation" |
|
||||||
| ncurses 6.5 | MIT 风格(X11 许可) | 保留版权与许可声明;不单独分发(只静态链入 slabtop) |
|
| procps `library/`(libproc2) | **LGPL-2.1+** | `ps/vmstat/slabtop/free/pmap` **静态链接**了它 → LGPL-2.1 §6 另有要求,见下 |
|
||||||
|
| ncurses 6.5 | MIT 风格(X11) | 保留版权与许可声明;只静态链入 slabtop,不单独分发 |
|
||||||
| lsof 4.99.4 | Purdue Research Foundation 许可(BSD 风格 4 条) | 文档与源码中保留作者/Purdue 署名;改过的版本要标注 |
|
| lsof 4.99.4 | Purdue Research Foundation 许可(BSD 风格 4 条) | 文档与源码中保留作者/Purdue 署名;改过的版本要标注 |
|
||||||
|
|
||||||
**结论(不要含糊)**:`build_devkit.sh` 里的固定版本 + 下载 URL **不构成 GPLv2 §3 的合规**。
|
**GPLv2 §3**:`build_devkit.sh` 里的固定版本 + 下载 URL **不构成合规**。URL 作者可能撤、
|
||||||
URL 作者随时可能撤、镜像可能消失,而且 GPL 要求的是*分发者*提供的源码或要约。所以:
|
镜像可能消失,而且 GPL 要求的是*分发者*提供的源码或书面要约。因此 `--with-sources` 会把
|
||||||
|
**三份源码包 + `build_devkit.sh` + 本文件**一起放进 `src/`(合计约 5.6 MB)。少一样都不算完整:
|
||||||
|
没有构建脚本,收卡人拿不到本轮用的 `configure`/`-D` 参数(这正是 "corresponding source" 明确包含的)。
|
||||||
|
|
||||||
1. 若这批二进制随卡交到第三方手上 → 构建时加 **`--with-sources`**,把
|
**LGPL-2.1 §6(静态链接)**:五个 procps 工具静态链入 libproc2,除 GPL 的义务外还必须
|
||||||
`ncurses-6.5.tar.gz` / `procps-ng-4.0.4.tar.xz` / `lsof-4.99.4.tar.xz` 一起放到卡上
|
「显著提示使用了该库 + 附许可证副本 + 三选一」:(a) 随作品提供该库的完整源码(含修改);
|
||||||
`MeowOS/opt/devkit/src/`(合计约 5.5 MB,TF 卡的容量代价可忽略);
|
(b) 改用共享库机制(静态交付做不到);(c) 书面要约(≥3 年)提供 (a) 的材料。
|
||||||
2. 或者随卡附**书面要约**(有效期内提供源码,GPLv2 §3(b));
|
本工具集走 **(a)**:`src/procps-ng-4.0.4.tar.xz` 里含 `library/` 全量源码,
|
||||||
3. `licenses/` 里的上游 COPYING 只是「许可声明留痕」,**不能替代源码义务**。
|
`src/build_devkit.sh` 是本轮的唯一构建描述,`licenses/procps-ng-4.0.4-COPYING.LIB` 是许可证副本。
|
||||||
|
若想更保守(收卡人不想自己重编),可以再额外提供可重链接的 `.o`(当前**未做**,属可选加固)。
|
||||||
|
|
||||||
内部自用(只有自己插卡)不触发 §3 的分发义务,但既然这台机器的产物可能被拷来拷去,
|
**结论**:内部自用不触发分发义务;但既然这批二进制可能被拷来拷去,建议一律
|
||||||
建议一律 `--with-sources`。
|
`--with-sources` 上卡。`licenses/` 只是声明留痕,**不能替代源码义务**。
|
||||||
|
|
||||||
## 7. 未交付清单(以及为什么)
|
## 7. 未交付清单(以及为什么)
|
||||||
|
|
||||||
| 候选 | 结论 | 原因 |
|
| 候选 | 结论 | 原因 |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `top`(procps 4.0.4) | **不交付** | 真机实测输出不可信:表头时长字段溢出成 `-343597384:00`,`Mem` 显示 `59.4/0.1 GiB`(MemTotal 只有 55 MB)。同时它在无 TTY 的批处理下会静默 `exit 1`(strace 显示 `ioctl(1,TIOCGWINSZ)=ENOTTY` 后直接 `exit_group(1)`),即使批处理可用也拿不到正确数据。卡上已有 htop 3.5.3,`top` 属重复且不可信 → 不凑数 |
|
| `top`(procps 4.0.4) | **不交付** | 表头时钟被工具链 time64 问题打坏(显示 `-1202590843:00` 一类),无 TTY 时还会静默 `exit 1`。**不是 procps 的 bug**(r1 评审已更正我此前的错误归因),根因见 §9。卡上已有 htop,`top` 属重复 |
|
||||||
| `htop` | 不构建 | 卡上 `MeowOS/opt/bin/htop` 已经是 **3.5.3**(673 744 B)。我们实测用 zig + 自编 ncursesw 也能编出来,但 strip 后 **756 908 B**,比现有版本更大(静态链入 musl + ncurses),没有增量价值 |
|
| `htop` | 不构建 | 卡上 `MeowOS/opt/bin/htop` 已是 **3.5.3**(673 744 B)。实测用 zig + 自编 ncursesw 也能编出 3.5.3,但 strip 后 **756 908 B**,比现有版本更大(静态链 musl+ncurses)。**且我此前只量了体积、没做运行时验证** —— 它会继承 §9 的 time64 问题(`htop -d 5`(0.5s)这类亚秒刷新会退化成忙等空转),所以「加个 build_htop() 即可」的说法不成立 |
|
||||||
| `watch` | 不构建 | busybox 1.31 已有 `watch`;procps 版 403 KB,收益不抵体积 |
|
| `watch` | 不构建 | busybox 1.31 已有 `watch`;procps 版 403 KB,收益不抵体积 |
|
||||||
| `pgrep`/`pkill` | 不构建 | busybox 已有;procps 版各 260 KB(链接整份 libproc) |
|
| `pgrep`/`pkill` | 不构建 | busybox 已有;procps 版各 260 KB(链接整份 libproc) |
|
||||||
| `uptime`/`tload`/`pidof`/`pidwait`/`w` | 不构建 | busybox 已有 `uptime`/`pidof`;`tload`/`w` 在本机无调试价值 |
|
| `uptime`/`tload`/`pidof`/`pidwait`/`w` | 不构建 | busybox 已有 `uptime`/`pidof`;`tload`/`w` 在本机无调试价值 |
|
||||||
@@ -127,14 +134,14 @@ URL 作者随时可能撤、镜像可能消失,而且 GPL 要求的是*分发
|
|||||||
宿主:Termux/Android aarch64,zig 0.17.0(自带 musl libc 与头文件),`make`、`curl`、`pkg-config`。
|
宿主:Termux/Android aarch64,zig 0.17.0(自带 musl libc 与头文件),`make`、`curl`、`pkg-config`。
|
||||||
**没有** autoconf/automake/libtool,**没有**目标内核头,sysroot 里只有 zlib(本工具集不需要它)。
|
**没有** autoconf/automake/libtool,**没有**目标内核头,sysroot 里只有 zlib(本工具集不需要它)。
|
||||||
|
|
||||||
- **procps-ng 4.0.4** ✅ 可编。两个必须处理的坑:
|
- **procps-ng 4.0.4** ✅ 可编。三个必须处理的坑:
|
||||||
1. `slabtop`(`src/slabtop.c` 直接 `#include <ncurses.h>`)与 `top` 硬依赖 ncurses;
|
1. `slabtop`(`src/slabtop.c` 直接 `#include <ncurses.h>`)硬依赖 ncurses;
|
||||||
`configure --without-ncurses` 会把它们整个跳过 → 要 `slabtop` 就必须先交叉编 ncurses。
|
`configure --without-ncurses` 会把它整个跳过 → 要 `slabtop` 就必须先交叉编 ncurses。
|
||||||
2. 交叉编译下 autoconf 的 `malloc(0)/realloc(0)` 运行期探测无法执行,不缓存
|
2. 交叉编译下 autoconf 的 `malloc(0)/realloc(0)` 运行期探测无法执行,不缓存
|
||||||
`ac_cv_func_malloc_0_nonnull=yes ac_cv_func_realloc_0_nonnull=yes` 会引入
|
`ac_cv_func_malloc_0_nonnull=yes ac_cv_func_realloc_0_nonnull=yes` 会引入
|
||||||
`rpl_malloc/rpl_realloc` 未定义引用,链接失败。
|
`rpl_malloc/rpl_realloc` 未定义引用,链接失败。
|
||||||
3. 另外必须把 `PKG_CONFIG_LIBDIR` 收紧到自编 prefix,否则会捡到宿主 aarch64 的
|
3. 必须把 `PKG_CONFIG_LIBDIR` 收紧到自编 prefix,否则会捡到宿主 aarch64 的
|
||||||
`ncursesw.pc`,结果是「musl 头 + bionic 头」混编(`watch` 直接编不过)。
|
`ncursesw.pc`,结果是「musl 头 + bionic 头」混编(`watch` 直接编不过)。脚本里有事后断言。
|
||||||
- **ncurses 6.5** ✅ 可编(`--without-shared --with-normal --enable-widec --without-progs` 等)。
|
- **ncurses 6.5** ✅ 可编(`--without-shared --with-normal --enable-widec --without-progs` 等)。
|
||||||
**必须** `--with-default-terminfo-dir=/usr/share/terminfo --with-terminfo-dirs=...`:
|
**必须** `--with-default-terminfo-dir=/usr/share/terminfo --with-terminfo-dirs=...`:
|
||||||
否则交互式 `slabtop` 会 `Error opening terminal: xterm.`(默认值是编译期 prefix,设备上不存在)。
|
否则交互式 `slabtop` 会 `Error opening terminal: xterm.`(默认值是编译期 prefix,设备上不存在)。
|
||||||
@@ -148,43 +155,78 @@ URL 作者随时可能撤、镜像可能消失,而且 GPL 要求的是*分发
|
|||||||
状态宏,`dsock.c` 会编不过 → 脚本里 `-D` 补齐(值取自 `linux/tcp.h`)。
|
状态宏,`dsock.c` 会编不过 → 脚本里 `-D` 补齐(值取自 `linux/tcp.h`)。
|
||||||
4. zig cc **不带 `-O` 时按 Debug 编**,会插入 UBSan 桩(`__ubsan_handle_negate_overflow`)
|
4. zig cc **不带 `-O` 时按 Debug 编**,会插入 UBSan 桩(`__ubsan_handle_negate_overflow`)
|
||||||
导致链接失败 → 所有编译都显式 `-O2`。
|
导致链接失败 → 所有编译都显式 `-O2`。
|
||||||
- **htop 3.5.3** ✅ 可编(用自编 ncursesw,`--disable-hwloc/sensors/delayacct`),strip 后 756 908 B —— 比卡上现有版本大,故不交付。
|
- **htop 3.5.3** ✅ 可编(用自编 ncursesw,`--disable-hwloc/sensors/delayacct`),strip 后 756 908 B ——
|
||||||
|
比卡上现有版本大,且未做运行时验证(见 §7、§9),故不交付。
|
||||||
- **perf** ❌ 不可行:依赖目标内核源码树(`tools/perf` 要按内核版本配 `perf_event_attr`),
|
- **perf** ❌ 不可行:依赖目标内核源码树(`tools/perf` 要按内核版本配 `perf_event_attr`),
|
||||||
且设备内核未必开了 `CONFIG_PERF_EVENTS` 相关选项;没有内核头也是硬阻塞。
|
且设备内核未必开了相关选项;没有内核头也是硬阻塞。
|
||||||
- **valgrind** ❌ 不可行:没有 MIPS32 后端(valgrind 官方支持 x86/amd64/arm/aarch64/ppc/s390,
|
- **valgrind** ❌ 不可行:**没有 MIPS32 后端**(官方只支持 x86/amd64/arm/aarch64/ppc/s390),
|
||||||
无 mips),不是交叉编译问题,是根本没有后端。
|
不是交叉编译问题。
|
||||||
- **gdb** ❌ 未尝试/不建议:设备已带 `gdbserver`,宿主侧可以用交叉 gdb 连;在 56 MB 单核设备上
|
- **gdb** ❌ 不建议:设备已带 `gdbserver`,宿主侧可用交叉 gdb 连;在 56 MB 单核设备上跑 gdb 本体收益极低、体积巨大。
|
||||||
跑 gdb 本体收益极低、体积巨大。
|
- **ltrace** ❌ 不可行:需要 libelf + 复杂 autoconf 探测,且本机程序多为静态/精简,投入产出不划算。
|
||||||
- **ltrace** ❌ 不可行:需要解析目标 ELF 动态符号(`PT_DYNAMIC` + PLT),本机程序多为
|
|
||||||
静态/精简,且 ltrace 的构建依赖 libelf + 复杂 autoconf 探测,投入产出不划算。
|
|
||||||
- **sysstat(sar/iostat/mpstat)** ❌ 未做:autoconf 探测多、依赖 `gettext`/`libsensors` 等,
|
- **sysstat(sar/iostat/mpstat)** ❌ 未做:autoconf 探测多、依赖 `gettext`/`libsensors` 等,
|
||||||
且本机是单核、无块设备统计(`/proc/diskstats` 对 TF 卡意义有限),收益低。
|
且本机单核、`/proc/diskstats` 对 TF 卡意义有限。
|
||||||
- **smem** ⚠️ 价值为零:依赖 `/proc/<pid>/smaps` 的 PSS,本机 `CONFIG_PROC_PAGE_MONITOR=n`,
|
- **smem** ⚠️ 价值为零:依赖 `/proc/<pid>/smaps` 的 PSS,本机没有 smaps。
|
||||||
没有 smaps → 拿不到任何它要的数据。
|
|
||||||
|
|
||||||
## 9. 真机验证证据(2026-11-06,root@10.76.208.50)
|
## 9. 已知限制:工具链的 time64 在 4.4 内核上不可用
|
||||||
|
|
||||||
产物拷到设备 `/tmp/devkit`(tmpfs)执行,验证完已删除;**没有**往 TF 卡写过任何东西。
|
**这不是 procps/htop 的 bug,是 zig 0.17 自带 musl 在 mipsel 上的 ABI 错配**(r1 评审独立定根因,
|
||||||
|
我此前把 `top` 的表头问题误判成 procps bug,此处更正)。
|
||||||
|
|
||||||
|
机制(三段,均可复验):
|
||||||
|
|
||||||
|
1. zig 0.17 的 `mipsel-linux-musleabi` 是 **time64**:`sizeof(time_t)=8`、`sizeof(long)=4`,
|
||||||
|
`struct timespec` 16 字节;同时 clang 前端给 mips o32 预定义了 `__ILP32__`。
|
||||||
|
2. zig 自带 musl(`libc/musl/src/time/clock_gettime.c`、`time/clock_nanosleep.c` 等)的守卫写成
|
||||||
|
`#if defined(SYS_*_time64) && !defined(__ILP32__)`;上游 musl 1.2.5 没有这个 `!defined(__ILP32__)`。
|
||||||
|
3. MIPS o32 是 ILP32、内核 4.4 又没有 time64 syscall → 走 `#else` 分支,把 **16 字节的 time64 结构**
|
||||||
|
直接交给 **32 位 time32 系统调用**:内核只写/只读前 8 字节,高 32 位保持未初始化。
|
||||||
|
|
||||||
|
真机实测(本轮):
|
||||||
|
|
||||||
|
| 现象 | 结果 | 影响 |
|
||||||
|
|---|---|---|
|
||||||
|
| `clock_gettime` / `time()` / `gettimeofday()` | rc=0 但值是垃圾(评审另测:`sec=2823213556008072608`,`localtime_r` 返回 NULL) | 任何按墙钟格式化时间的功能 |
|
||||||
|
| `vmstat -t` | 表头有 `-----timestamp-----`,**数据行该列整列为空**(`localtime()` 返回 NULL,`strftime` 被跳过) | `vmstat` 核心的 3 组计数**正常**;只有时间戳列不可用 |
|
||||||
|
| `top` 表头时钟 | 显示 `-1202590843:00` / `-343597384:00` 一类 | 这就是 §7 不交付 top 的原因 |
|
||||||
|
| `usleep(0.5s)` ×10 | **实测 0 秒**(应为 5 秒):`sleep()` 走 32 位 syscall,内核把 `tv_sec` 高半字当 `tv_nsec`(恒 0),亚秒被抹平 | 亚秒轮询会退化成忙等/空转 |
|
||||||
|
| `sleep(1)`(整秒) | 正常:`vmstat 1 3` 墙钟实测 2 秒 | 整秒采样周期不受影响 |
|
||||||
|
| `ps -eo lstart` | 正常 | 时间来自 `/proc/stat` 的 `btime` + jiffies,不走 libc 取时 |
|
||||||
|
| `slabtop`/`free`/`pmap`/`lsof` | 不受影响 | 不显示墙钟 |
|
||||||
|
|
||||||
|
**能否复用仓里已有的修复?** 有。M16 的 `patch_v2/sdk/meow_ui_time.c`(文档 `patch_v2/sdk/CLOCK_ABI.md`)
|
||||||
|
用「链接期强定义」接管了 `__clock_gettime` / `__clock_gettime64` / `__nanosleep_time64` /
|
||||||
|
`__clock_nanosleep(_time64)` / `__timedwait*` / `__timerfd_*` / `__clock_settime64`,
|
||||||
|
内部按内核 o32 time32 ABI 取数再升成 64 位。
|
||||||
|
|
||||||
|
- **可复用的证据(本轮实测)**:`zigcc -O2 -I. -Iinclude -c patch_v2/sdk/meow_ui_time.c` 单文件编译成功,
|
||||||
|
未定义符号只有 5 个 libc 符号(`__errno_location`、`__pthread_setcancelstate`、`__syscall_cp`、
|
||||||
|
`__udivdi3`、`syscall`),不依赖 SDK 其它目标文件。
|
||||||
|
- **代价**:必须把该 `.o` 放在 libc 之前参与链接(才会盖掉 libc 里那份),要给两套构建系统分别注入:
|
||||||
|
procps 走 libtool 的 `LDADD`、lsof 是手写 Makefile 的固定链接行;然后六个二进制全部重新真机验证。
|
||||||
|
估计 1–2 小时(含设备回归),产物每个 +几 KB。
|
||||||
|
- **本轮为什么不做**:收益只有 `vmstat -t` 一列(`top` 不交付、`ps` 本来正常、其余不打时间),
|
||||||
|
而这个改动会动到 libc 的取时/睡眠入口,风险面比收益大。**结论:可复用,但需要单独一条 mission
|
||||||
|
做「接入 + 全量回归」**,不适合塞进这次修 P1 的补丁里。
|
||||||
|
- **不加 shim 的替代方案**:给 zig 的 musl 打补丁(去掉 `!defined(__ILP32__)`)或换上游 musl 工具链。
|
||||||
|
**这不是加一个 `-D` 能修的**:守卫在 libc 源码里,编译产物(libc.a)已经固定。
|
||||||
|
|
||||||
|
## 10. 路径清洁:lsof 里有一处宿主路径(工具链副作用)
|
||||||
|
|
||||||
|
`strings lsof` 有一处 `/data/data/com.termux/files/usr/etc/resolv.conf`(其余五个产物没有宿主路径)。
|
||||||
|
来源是 **Termux 打包的 zig 自带 musl**(`libc/musl/src/network/resolvconf.c` 被改成 Termux prefix),
|
||||||
|
不是 lsof 源码,也不是本脚本的路径泄漏(源码路径已用 `-ffile-prefix-map` 抹掉)。
|
||||||
|
|
||||||
|
- 设备上该路径不存在 → **真正的 DNS 反查会失败**;`lsof -i` 不带 `-n` 时会因此卡在超时(实测约 3 秒),
|
||||||
|
带 `-nP` 瞬时返回。
|
||||||
|
- 端口名/本机名不受影响(来自 `/etc/services`、`/etc/hosts`):实测 `lsof -i` 仍显示 `TCP *:ssh`、`UDP localhost:domain`。
|
||||||
|
- **结论**:不改。换成非 Termux 的 zig/上游 musl 需要重装工具链并重做全部验证,代价大而收益仅「反向 DNS」;
|
||||||
|
文档与 `README.txt` 已写明**用 `lsof -nP`**。
|
||||||
|
|
||||||
|
## 11. 真机验证证据(2026-11-06,root@10.76.208.50)
|
||||||
|
|
||||||
|
产物拷到设备 `/tmp`(tmpfs)执行,验证完已删除;**没有**往 TF 卡写过任何东西。
|
||||||
|
|
||||||
```
|
```
|
||||||
# free -m
|
|
||||||
total used free shared buff/cache available
|
|
||||||
Mem: 55 30 2 1 27 24
|
|
||||||
Swap: 0 0 0
|
|
||||||
|
|
||||||
# vmstat 1 3
|
|
||||||
procs -----------memory---------- ---swap-- -----io---- -system-- -------cpu-------
|
|
||||||
r b swpd free buff cache si so bi bo in cs us sy id wa st gu
|
|
||||||
1 0 0 2584 8764 19388 0 0 0 0 449 6 3 3 94 0 0 0
|
|
||||||
0 0 0 2644 8764 19388 0 0 0 0 340 566 1 5 94 0 0 0
|
|
||||||
0 0 0 2644 8764 19388 0 0 0 0 332 526 1 2 97 0 0 0
|
|
||||||
|
|
||||||
# ps -eo pid,rss,vsz,comm --sort=-rss
|
|
||||||
PID RSS VSZ COMMAND
|
|
||||||
1368 4832 16516 meow_launcherd
|
|
||||||
4241 1608 3012 sh
|
|
||||||
...
|
|
||||||
|
|
||||||
# slabtop -o | head -6
|
# slabtop -o | head -6
|
||||||
Active / Total Objects (% used) : 55852 / 61357 (91.0%)
|
Active / Total Objects (% used) : 55852 / 61357 (91.0%)
|
||||||
Active / Total Slabs (% used) : 2794 / 2794 (100.0%)
|
Active / Total Slabs (% used) : 2794 / 2794 (100.0%)
|
||||||
@@ -194,13 +236,31 @@ procs -----------memory---------- ---swap-- -----io---- -system-- -------cpu----
|
|||||||
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
|
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
|
||||||
12474 10746 86% 0.06K 198 63 792K buffer_head
|
12474 10746 86% 0.06K 198 63 792K buffer_head
|
||||||
|
|
||||||
|
# vmstat 1 3 (墙钟实测 2 秒,采样间隔正常)
|
||||||
|
procs -----------memory---------- ---swap-- -----io---- -system-- -------cpu-------
|
||||||
|
r b swpd free buff cache si so bi bo in cs us sy id wa st gu
|
||||||
|
1 0 0 2584 8764 19388 0 0 0 0 449 6 3 3 94 0 0 0
|
||||||
|
0 0 0 2644 8764 19388 0 0 0 0 340 566 1 5 94 0 0 0
|
||||||
|
0 0 0 2644 8764 19388 0 0 0 0 332 526 1 2 97 0 0 0
|
||||||
|
|
||||||
|
# free -m
|
||||||
|
total used free shared buff/cache available
|
||||||
|
Mem: 55 30 2 1 27 24
|
||||||
|
Swap: 0 0 0
|
||||||
|
|
||||||
|
# ps -eo pid,rss,vsz,comm --sort=-rss
|
||||||
|
PID RSS VSZ COMMAND
|
||||||
|
1368 4832 16516 meow_launcherd
|
||||||
|
4241 1608 3012 sh
|
||||||
|
...
|
||||||
|
|
||||||
# pmap 1
|
# pmap 1
|
||||||
1: init
|
1: init
|
||||||
00400000 864K r-x-- busybox
|
00400000 864K r-x-- busybox
|
||||||
004e8000 4K rw--- busybox
|
004e8000 4K rw--- busybox
|
||||||
00969000 132K rwx-- [ anon ]
|
00969000 132K rwx-- [ anon ]
|
||||||
|
|
||||||
# lsof -nP -i
|
# lsof -nP -i (瞬时;不带 -n 约 3 秒,见 §10)
|
||||||
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
|
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
|
||||||
dropbear 1354 root 3u inet 2196 0t0 TCP *:22 (LISTEN)
|
dropbear 1354 root 3u inet 2196 0t0 TCP *:22 (LISTEN)
|
||||||
meow_netm 1372 root 5u inet 2611 0t0 UDP 127.0.0.1:53
|
meow_netm 1372 root 5u inet 2611 0t0 UDP 127.0.0.1:53
|
||||||
@@ -208,17 +268,16 @@ meow_mdns 1375 root 3u inet 2906 0t0 UDP *:5353
|
|||||||
meowpanel 1395 root 3u inet 2587 0t0 TCP *:8080 (LISTEN)
|
meowpanel 1395 root 3u inet 2587 0t0 TCP *:8080 (LISTEN)
|
||||||
```
|
```
|
||||||
|
|
||||||
- 六个二进制 `--help`/`-V` 全部 rc=0(`lsof --help` 不是合法选项,`lsof -v` 正常打印 4.99.4)。
|
- 六个二进制 `--help`/`-V` 全部正常(`lsof --help` 不是合法选项,`lsof -v` 打印 4.99.4)。
|
||||||
- 交互式 `slabtop`(无 `-o`)在 `TERM=xterm` 下正常初始化 curses(stdout 写出 1599 字节转义序列);
|
- 交互式 `slabtop`(无 `-o`)在 `TERM=xterm` 下正常初始化 curses(stdout 写出 1599 字节转义序列);
|
||||||
对照 `TERM=bogus-term` 报 `Error opening terminal: bogus-term.` —— 说明 terminfo 路径确实命中
|
对照 `TERM=bogus-term` 报 `Error opening terminal: bogus-term.` —— 说明 terminfo 路径确实命中
|
||||||
`/usr/share/terminfo`,不是内嵌 fallback。
|
`/usr/share/terminfo`,不是内嵌 fallback。
|
||||||
- 宿主侧静态/架构自检(每个产物):`file` = `statically linked, stripped`;
|
- 设备上 `sha256sum` 与 `MANIFEST.txt` 逐条一致(测的就是交付的那份字节)。
|
||||||
`readelf -h` = `ELF32` / `Machine: MIPS R3000` / `Flags: ... mips32r2`;`readelf -d` 无 `NEEDED`。
|
- 宿主侧静态/架构自检与 MANIFEST 对账:`bash scripts/build/build_devkit.sh --verify-only`。
|
||||||
可用 `bash scripts/build/build_devkit.sh --verify-only` 复跑。
|
|
||||||
|
|
||||||
## 10. 已知限制
|
## 12. 其它已知限制
|
||||||
|
|
||||||
- `pmap -x` 无 PSS(无 smaps),只有 maps 级别的段/文件信息。
|
- `pmap -x` 无 PSS(无 smaps),只有 maps 级别的段/文件信息。
|
||||||
- 不提供 `top`(原因见 §7);需要交互式总览请用卡上已有的 `htop`。
|
- 不提供 `top`(§7/§9);需要交互式总览请用卡上已有的 `htop`(注意其时钟/亚秒刷新同样受 §9 影响)。
|
||||||
- 二进制按设备内核 4.4.94 编 `LINUXV`;换内核/换卡不影响运行(这些宏只影响显示)。
|
- 二进制按设备内核 4.4.94 编 `LINUXV`;该宏只影响 `lsof -v` 显示,换内核不影响运行。
|
||||||
- 产物是 32 位 MIPS32r2(o32 ABI,软浮点/无 FPU 依赖),只适用于 X1600 这类 MIPS32r2 目标。
|
- 产物是 32 位 MIPS32r2(o32 ABI),只适用于 X1600 这类 MIPS32r2 目标。
|
||||||
@@ -13,7 +13,8 @@
|
|||||||
| `build_fw_apps.sh` | **通用打包脚本**(配置驱动)。读清单 → 组树 → repack → 校验 → 出固件。**不要改它的逻辑**,除非打包流程本身要变。 |
|
| `build_fw_apps.sh` | **通用打包脚本**(配置驱动)。读清单 → 组树 → repack → 校验 → 出固件。**不要改它的逻辑**,除非打包流程本身要变。 |
|
||||||
| `fw_content.conf` | **固件内容清单**(默认配置)。每行一条 `<src>|<dst>|<md5>|<desc>`,声明"哪个本地文件装到固件哪里"。**改固件内容只改这里。** |
|
| `fw_content.conf` | **固件内容清单**(默认配置)。每行一条 `<src>|<dst>|<md5>|<desc>`,声明"哪个本地文件装到固件哪里"。**改固件内容只改这里。** |
|
||||||
| `build_devkit.sh` | **TF 卡调试工具集**交叉编译脚本(zig → 静态 MIPS32r2):`vmstat/slabtop/free/ps/pmap/lsof` → `fw_apps/devkit/`。与固件打包无关,独立跑。详见 `DEVKIT.md`。 |
|
| `build_devkit.sh` | **TF 卡调试工具集**交叉编译脚本(zig → 静态 MIPS32r2):`vmstat/slabtop/free/ps/pmap/lsof` → `fw_apps/devkit/`。与固件打包无关,独立跑。详见 `DEVKIT.md`。 |
|
||||||
| `DEVKIT.md` | devkit 的产物清单、许可证留痕、可行性实测、上卡 PATH/busybox 关系、已知限制。 |
|
| `test_build_devkit.sh` | `build_devkit.sh` 的回归测试(不重编,秒级):`--with-sources` 在 stamp 命中时必须产出完整 `src/`、`--verify-only` 必须能查出 MANIFEST 漂移。 |
|
||||||
|
| `DEVKIT.md` | devkit 的产物清单、许可证留痕(GPLv2 §3 / LGPL-2.1 §6)、可行性实测、time64 限制、上卡 PATH/busybox 关系。 |
|
||||||
| `README.md` | 本说明。 |
|
| `README.md` | 本说明。 |
|
||||||
|
|
||||||
> 曾有一批独立脚本 `build_fw_apps_m2xx.sh`(每版复制一个、内部硬编码 md5),**已清理删除**,不再使用。它们的问题:需每版改脚本、且共享 `fw_apps/` 目录互相清空。现统一走"一个通用脚本 + 一个配置文件"。
|
> 曾有一批独立脚本 `build_fw_apps_m2xx.sh`(每版复制一个、内部硬编码 md5),**已清理删除**,不再使用。它们的问题:需每版改脚本、且共享 `fw_apps/` 目录互相清空。现统一走"一个通用脚本 + 一个配置文件"。
|
||||||
@@ -127,7 +128,7 @@ md5sum patch_v2/meow_launcherd/meow_launcherd
|
|||||||
- **改源码忘更新 md5**:清单里 md5 是强校验,源变了但 md5 没改 → 打包直接失败。**凡是动了清单里列的源文件,先 `md5sum` 更新对应行。**
|
- **改源码忘更新 md5**:清单里 md5 是强校验,源变了但 md5 没改 → 打包直接失败。**凡是动了清单里列的源文件,先 `md5sum` 更新对应行。**
|
||||||
- **SDK 库(`meow_ui.a`)不入固件**:它由 APP(如 hello)链接,走 TF 卡 `MeowAPPs/` 热更新,**不要**加进清单。
|
- **SDK 库(`meow_ui.a`)不入固件**:它由 APP(如 hello)链接,走 TF 卡 `MeowAPPs/` 热更新,**不要**加进清单。
|
||||||
- **`fw_apps/` 被 gitignore**:固件产物与组装树都是构建产物,勿提交。
|
- **`fw_apps/` 被 gitignore**:固件产物与组装树都是构建产物,勿提交。
|
||||||
- **`scripts/build/` 根目录 gitignore**:构建产物与组装树勿提交。但本目录的 **`README.md`/`build_fw_apps.sh`/`fw_content.conf`/`build_devkit.sh`/`DEVKIT.md` 已 `git add -f` 入库**(这几个是仓库侧应保留的脚本/配置/说明);其余(`fw_apps/` 产物、devkit 编译树等)不入库。
|
- **`scripts/build/` 根目录 gitignore**:构建产物与组装树勿提交。但本目录的 **`README.md`/`build_fw_apps.sh`/`fw_content.conf`/`build_devkit.sh`/`test_build_devkit.sh`/`DEVKIT.md` 已 `git add -f` 入库**(这几个是仓库侧应保留的脚本/配置/说明);其余(`fw_apps/` 产物、devkit 编译树等)不入库。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
+188
-53
@@ -12,18 +12,22 @@
|
|||||||
# fw_apps/devkit/MANIFEST.txt 版本/许可证/体积/校验摘要
|
# fw_apps/devkit/MANIFEST.txt 版本/许可证/体积/校验摘要
|
||||||
# fw_apps/devkit/licenses/ 各上游 COPYING(分发留痕)
|
# fw_apps/devkit/licenses/ 各上游 COPYING(分发留痕)
|
||||||
# fw_apps/devkit/README.txt 上卡后怎么加 PATH、和 busybox 的同名关系
|
# fw_apps/devkit/README.txt 上卡后怎么加 PATH、和 busybox 的同名关系
|
||||||
# (--with-sources 时另有 fw_apps/devkit/src/ 源码包,GPL 合规用)
|
# (--with-sources 时另有 fw_apps/devkit/src/:三份源码包 + build_devkit.sh +
|
||||||
|
# DEVKIT.md,GPLv2 §3 的“对应源码”含构建控制脚本)
|
||||||
#
|
#
|
||||||
# 源码固定为「版本 + sha256 + 固定 URL」,全部校验后才编译;缓存命中则零联网。
|
# 源码固定为「版本 + sha256 + 固定 URL」,全部校验后才编译;缓存命中则零联网。
|
||||||
#
|
#
|
||||||
# 工具链:zig cc --target=mipsel-linux-musleabi(需 zig 0.17.x)
|
# 工具链:zig cc --target=mipsel-linux-musleabi(需 zig 0.17.x)
|
||||||
# 不依赖 ~/.tools 下的私有脚本,自己生成 wrapper($WORK/bin/zigcc)。
|
# 不依赖 ~/.tools 下的私有脚本,自己生成 wrapper($WORK/bin/zigcc)。
|
||||||
# 不需要内核头(musl 头足够;只有 lsof 缺 11 个 TCP 状态宏,本脚本 -D 补上)。
|
# 不需要内核头(musl 头足够;只有 lsof 缺 11 个 TCP 状态宏,本脚本 -D 补上)。
|
||||||
|
# ⚠ 该工具链在 4.4 内核上是 time64 ABI 错配:`vmstat -t` 时间戳列会是空,
|
||||||
|
# 原因/证据/后续修法见 DEVKIT.md「已知限制:工具链 time64」。不是 -D 能修的。
|
||||||
#
|
#
|
||||||
# 许可证(二进制将来随卡分发时请保留此节):
|
# 许可证(二进制将来随卡分发时请保留此节):
|
||||||
# procps-ng 4.0.4 GPL-2.0-or-later(COPYING=GPLv2;library/ 为 LGPL-2.1+)
|
# procps-ng 4.0.4 GPL-2.0-or-later(COPYING=GPLv2)
|
||||||
# *** 分发二进制必须提供对应源码(GPLv2 §3)***
|
# *** 分发二进制必须提供对应源码(GPLv2 §3,含构建脚本)***
|
||||||
# → 用 --with-sources 把源码包一起放上卡,或随卡附书面要约。
|
# procps library/ LGPL-2.1+:ps/vmstat/slabtop/free/pmap 静态链接 libproc2,
|
||||||
|
# LGPL-2.1 §6 要求提供可重链接 object code 或书面要约(见 DEVKIT.md §6)
|
||||||
# ncurses 6.5 MIT 风格(X11 许可),保留版权声明即可
|
# ncurses 6.5 MIT 风格(X11 许可),保留版权声明即可
|
||||||
# lsof 4.99.4 Purdue Research Foundation 许可(BSD 风格 4 条),
|
# lsof 4.99.4 Purdue Research Foundation 许可(BSD 风格 4 条),
|
||||||
# 要求文档与源码中保留作者与 Purdue 的署名(COPYING 第 2 条)
|
# 要求文档与源码中保留作者与 Purdue 的署名(COPYING 第 2 条)
|
||||||
@@ -32,10 +36,14 @@
|
|||||||
# 用法:
|
# 用法:
|
||||||
# bash scripts/build/build_devkit.sh # 增量:缓存命中则不联网
|
# bash scripts/build/build_devkit.sh # 增量:缓存命中则不联网
|
||||||
# bash scripts/build/build_devkit.sh --force # 强制重编
|
# bash scripts/build/build_devkit.sh --force # 强制重编
|
||||||
# bash scripts/build/build_devkit.sh --clean # 清空工作区后重编
|
# bash scripts/build/build_devkit.sh --clean # 清空工作区与 out/src 后重编
|
||||||
# bash scripts/build/build_devkit.sh --offline # 只用已缓存的源码包(CI/离线)
|
# bash scripts/build/build_devkit.sh --offline # 只用已缓存的源码包(CI/离线)
|
||||||
# bash scripts/build/build_devkit.sh --with-sources
|
# bash scripts/build/build_devkit.sh --with-sources
|
||||||
# bash scripts/build/build_devkit.sh --verify-only # 只对现有产物做静态/架构自检
|
# # 整理 src/(三份源码包 + 本脚本 + DEVKIT.md)。**产物已是最新时也会执行**,
|
||||||
|
# # 且整理后按 sha256 复核;任何一步失败即非零退出(P1 回归点)。
|
||||||
|
# bash scripts/build/build_devkit.sh --verify-only
|
||||||
|
# # 只对现有产物自检:静态/架构/NEEDED + MANIFEST 逐条 sha256/体积比对。
|
||||||
|
# # 只需 file / readelf / sha256sum / awk;不需要 zig、make、date、网络。
|
||||||
#
|
#
|
||||||
# 环境变量:
|
# 环境变量:
|
||||||
# MEOW_DEVKIT_WORK 工作区(源码包/编译树/prefix),默认 ~/.cache/meow-devkit
|
# MEOW_DEVKIT_WORK 工作区(源码包/编译树/prefix),默认 ~/.cache/meow-devkit
|
||||||
@@ -44,6 +52,7 @@
|
|||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||||
|
SCRIPT_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/$(basename "${BASH_SOURCE[0]}")"
|
||||||
OUT_DIR="$ROOT/fw_apps/devkit"
|
OUT_DIR="$ROOT/fw_apps/devkit"
|
||||||
BIN_DIR="$OUT_DIR/bin"
|
BIN_DIR="$OUT_DIR/bin"
|
||||||
WORK="${MEOW_DEVKIT_WORK:-$HOME/.cache/meow-devkit}"
|
WORK="${MEOW_DEVKIT_WORK:-$HOME/.cache/meow-devkit}"
|
||||||
@@ -68,6 +77,14 @@ SRC_NCURSES="ncurses-${NCURSES_VER}.tar.gz|https://mirrors.tuna.tsinghua.edu.cn/
|
|||||||
SRC_PROCPS="procps-ng-${PROCPS_VER}.tar.xz|https://downloads.sourceforge.net/project/procps-ng/Production/procps-ng-${PROCPS_VER}.tar.xz|22870d6feb2478adb617ce4f09a787addaf2d260c5a8aa7b17d889a962c5e42e"
|
SRC_PROCPS="procps-ng-${PROCPS_VER}.tar.xz|https://downloads.sourceforge.net/project/procps-ng/Production/procps-ng-${PROCPS_VER}.tar.xz|22870d6feb2478adb617ce4f09a787addaf2d260c5a8aa7b17d889a962c5e42e"
|
||||||
SRC_LSOF="lsof-${LSOF_VER}.tar.xz|https://deb.debian.org/debian/pool/main/l/lsof/lsof_${LSOF_VER}+dfsg.orig.tar.xz|dc3e7f51cf03bc7fbcdd9e62d4a52825682092031bd1ae08b15fe7f4f582aebf"
|
SRC_LSOF="lsof-${LSOF_VER}.tar.xz|https://deb.debian.org/debian/pool/main/l/lsof/lsof_${LSOF_VER}+dfsg.orig.tar.xz|dc3e7f51cf03bc7fbcdd9e62d4a52825682092031bd1ae08b15fe7f4f582aebf"
|
||||||
|
|
||||||
|
# 卡上 src/ 必须包含的文件:三份源码包 + 构建脚本 + 本文档。
|
||||||
|
# GPLv2 §3 的“对应源码”明确包含 "scripts used to control compilation and
|
||||||
|
# installation",缺了脚本,收卡人拿不到本轮用的 -D/configure 参数。
|
||||||
|
SRC_STAGE_LIST="ncurses-${NCURSES_VER}.tar.gz procps-ng-${PROCPS_VER}.tar.xz lsof-${LSOF_VER}.tar.xz build_devkit.sh DEVKIT.md"
|
||||||
|
|
||||||
|
# 交付的工具——验证、MANIFEST 比对、stamp 自检都从这里取,避免多处手写漂移
|
||||||
|
TOOL_NAMES="vmstat slabtop free ps pmap lsof"
|
||||||
|
|
||||||
FORCE=0
|
FORCE=0
|
||||||
CLEAN=0
|
CLEAN=0
|
||||||
OFFLINE=0
|
OFFLINE=0
|
||||||
@@ -80,7 +97,7 @@ info() { printf ' %s\n' "$*"; }
|
|||||||
die() { printf '\n!!! %s\n' "$*" >&2; exit 1; }
|
die() { printf '\n!!! %s\n' "$*" >&2; exit 1; }
|
||||||
|
|
||||||
usage() {
|
usage() {
|
||||||
sed -n '3,40p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'
|
sed -n '3,/^# ============/p' "$SCRIPT_PATH" | sed 's/^# \{0,1\}//'
|
||||||
}
|
}
|
||||||
|
|
||||||
while [ $# -gt 0 ]; do
|
while [ $# -gt 0 ]; do
|
||||||
@@ -100,13 +117,13 @@ done
|
|||||||
# 0) 工具链与宿主依赖
|
# 0) 工具链与宿主依赖
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
check_toolchain() {
|
check_toolchain() {
|
||||||
local zig_bin zig_ver major_minor
|
local zig_bin major_minor
|
||||||
zig_bin="$(command -v zig || true)"
|
zig_bin="$(command -v zig || true)"
|
||||||
[ -n "$zig_bin" ] || die "找不到 zig。装法:pkg install zig(需 0.17.x)"
|
[ -n "$zig_bin" ] || die "找不到 zig。装法:pkg install zig(需 0.17.x)"
|
||||||
zig_ver="$("$zig_bin" version)"
|
ZIG_VERSION="$("$zig_bin" version)"
|
||||||
major_minor="${zig_ver%.*}"
|
major_minor="${ZIG_VERSION%.*}"
|
||||||
[ "$major_minor" = "$ZIG_WANT" ] || \
|
[ "$major_minor" = "$ZIG_WANT" ] || \
|
||||||
die "zig 版本是 $zig_ver,本脚本只在 $ZIG_WANT.x 上验证过(target/静态链接行为可能变)"
|
die "zig 版本是 $ZIG_VERSION,本脚本只在 $ZIG_WANT.x 上验证过(target/静态链接行为可能变)"
|
||||||
|
|
||||||
mkdir -p "$WRAP_DIR"
|
mkdir -p "$WRAP_DIR"
|
||||||
cat > "$WRAP_DIR/zigcc" <<EOF
|
cat > "$WRAP_DIR/zigcc" <<EOF
|
||||||
@@ -118,7 +135,7 @@ EOF
|
|||||||
# (lsof 会把 ${CC} 写进 version.h),换机器/换工作区也能逐字节复现。
|
# (lsof 会把 ${CC} 写进 version.h),换机器/换工作区也能逐字节复现。
|
||||||
PATH="$WRAP_DIR:$PATH"; export PATH
|
PATH="$WRAP_DIR:$PATH"; export PATH
|
||||||
ZIGCC="zigcc"
|
ZIGCC="zigcc"
|
||||||
info "zig $zig_ver → $WRAP_DIR/zigcc"
|
info "zig $ZIG_VERSION → $WRAP_DIR/zigcc"
|
||||||
|
|
||||||
for t in make curl tar sha256sum file readelf; do
|
for t in make curl tar sha256sum file readelf; do
|
||||||
command -v "$t" >/dev/null 2>&1 || die "缺宿主工具: $t"
|
command -v "$t" >/dev/null 2>&1 || die "缺宿主工具: $t"
|
||||||
@@ -166,6 +183,54 @@ unpack() { # unpack <tarball> <destdir>
|
|||||||
tar xf "$SRC_DIR/$1" -C "$2" --strip-components=1
|
tar xf "$SRC_DIR/$1" -C "$2" --strip-components=1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# 1b) 交付源码包(--with-sources):卡上 src/ 的完整性与整理
|
||||||
|
# P1 回归点:stamp 命中时也必须走这里,绝不能因为“跳过编译”就把源码静默漏掉。
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
expected_sha_for() { # expected_sha_for <tarball名> → 钉住的 sha256
|
||||||
|
case "$1" in
|
||||||
|
"ncurses-${NCURSES_VER}.tar.gz") printf '%s' "$SRC_NCURSES" | awk -F'|' '{print $3}' ;;
|
||||||
|
"procps-ng-${PROCPS_VER}.tar.xz") printf '%s' "$SRC_PROCPS" | awk -F'|' '{print $3}' ;;
|
||||||
|
"lsof-${LSOF_VER}.tar.xz") printf '%s' "$SRC_LSOF" | awk -F'|' '{print $3}' ;;
|
||||||
|
*) return 1 ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
sources_complete() {
|
||||||
|
local f got
|
||||||
|
[ -d "$OUT_DIR/src" ] || return 1
|
||||||
|
for f in $SRC_STAGE_LIST; do
|
||||||
|
[ -s "$OUT_DIR/src/$f" ] || return 1
|
||||||
|
done
|
||||||
|
# 三份源码包按钉住的 sha 逐一核对(版本漂移比缺文件更危险:看起来有源码,其实对不上)
|
||||||
|
for f in "ncurses-${NCURSES_VER}.tar.gz" "procps-ng-${PROCPS_VER}.tar.xz" "lsof-${LSOF_VER}.tar.xz"; do
|
||||||
|
got="$(sha256sum "$OUT_DIR/src/$f" | cut -d' ' -f1)"
|
||||||
|
[ "$got" = "$(expected_sha_for "$f")" ] || return 1
|
||||||
|
done
|
||||||
|
cmp -s "$SCRIPT_PATH" "$OUT_DIR/src/build_devkit.sh" || return 1
|
||||||
|
cmp -s "$ROOT/scripts/build/DEVKIT.md" "$OUT_DIR/src/DEVKIT.md" || return 1
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
stage_sources() {
|
||||||
|
local f
|
||||||
|
log "整理 $OUT_DIR/src(三份源码包 + 构建脚本 + 文档)"
|
||||||
|
fetch_src "$SRC_NCURSES"
|
||||||
|
fetch_src "$SRC_PROCPS"
|
||||||
|
fetch_src "$SRC_LSOF"
|
||||||
|
rm -rf "$OUT_DIR/src"
|
||||||
|
mkdir -p "$OUT_DIR/src"
|
||||||
|
for f in "ncurses-${NCURSES_VER}.tar.gz" "procps-ng-${PROCPS_VER}.tar.xz" "lsof-${LSOF_VER}.tar.xz"; do
|
||||||
|
cp "$SRC_DIR/$f" "$OUT_DIR/src/" || die "复制源码包失败: $f"
|
||||||
|
done
|
||||||
|
cp "$SCRIPT_PATH" "$OUT_DIR/src/build_devkit.sh" \
|
||||||
|
|| die "复制构建脚本失败: $SCRIPT_PATH(GPLv2 §3 要求带构建脚本)"
|
||||||
|
cp "$ROOT/scripts/build/DEVKIT.md" "$OUT_DIR/src/DEVKIT.md" \
|
||||||
|
|| die "复制 DEVKIT.md 失败: $ROOT/scripts/build/DEVKIT.md"
|
||||||
|
sources_complete || die "src/ 整理后仍不完整(sha256 或文件缺失)"
|
||||||
|
info "共 $(du -sh "$OUT_DIR/src" | cut -f1):$(ls "$OUT_DIR/src" | tr '\n' ' ')"
|
||||||
|
}
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# 2) ncurses:只为 slabtop 提供静态 ncursesw(不单独分发)
|
# 2) ncurses:只为 slabtop 提供静态 ncursesw(不单独分发)
|
||||||
# procps 的 slabtop/top 硬依赖 ncurses(configure 里 --without-ncurses 会把
|
# procps 的 slabtop/top 硬依赖 ncurses(configure 里 --without-ncurses 会把
|
||||||
@@ -330,14 +395,20 @@ write_meta() {
|
|||||||
log "写 MANIFEST / README / 许可证"
|
log "写 MANIFEST / README / 许可证"
|
||||||
mkdir -p "$OUT_DIR/licenses"
|
mkdir -p "$OUT_DIR/licenses"
|
||||||
|
|
||||||
cp "$BUILD_DIR/procps-src/COPYING" "$OUT_DIR/licenses/procps-ng-${PROCPS_VER}-COPYING" 2>/dev/null || true
|
# 许可证文件是分发合规的一部分:复制失败必须报错,不能 `|| true` 静默吞掉
|
||||||
cp "$BUILD_DIR/procps-src/COPYING.LIB" "$OUT_DIR/licenses/procps-ng-${PROCPS_VER}-COPYING.LIB" 2>/dev/null || true
|
cp "$BUILD_DIR/procps-src/COPYING" "$OUT_DIR/licenses/procps-ng-${PROCPS_VER}-COPYING" \
|
||||||
cp "$BUILD_DIR/ncurses-src/COPYING" "$OUT_DIR/licenses/ncurses-${NCURSES_VER}-COPYING" 2>/dev/null || true
|
|| die "复制许可证失败: procps COPYING(分发合规必需)"
|
||||||
cp "$BUILD_DIR/lsof/COPYING" "$OUT_DIR/licenses/lsof-${LSOF_VER}-COPYING" 2>/dev/null || true
|
cp "$BUILD_DIR/procps-src/COPYING.LIB" "$OUT_DIR/licenses/procps-ng-${PROCPS_VER}-COPYING.LIB" \
|
||||||
|
|| die "复制许可证失败: procps COPYING.LIB(LGPL-2.1 静态链接义务用)"
|
||||||
|
cp "$BUILD_DIR/ncurses-src/COPYING" "$OUT_DIR/licenses/ncurses-${NCURSES_VER}-COPYING" \
|
||||||
|
|| die "复制许可证失败: ncurses COPYING"
|
||||||
|
cp "$BUILD_DIR/lsof/COPYING" "$OUT_DIR/licenses/lsof-${LSOF_VER}-COPYING" \
|
||||||
|
|| die "复制许可证失败: lsof COPYING"
|
||||||
|
|
||||||
{
|
{
|
||||||
echo "MeowOS devkit — 静态 MIPS32r2 调试工具集"
|
echo "MeowOS devkit — 静态 MIPS32r2 调试工具集"
|
||||||
echo "生成时间: $(date -u '+%Y-%m-%dT%H:%M:%SZ') zig: $("${ZIGCC}" --version 2>/dev/null | head -1) target: $ZIG_TARGET"
|
# zig 版本用 `zig version`(不是 zigcc --version 的 clang 版本号)
|
||||||
|
echo "生成时间: $(date -u '+%Y-%m-%dT%H:%M:%SZ') zig: $ZIG_VERSION target: $ZIG_TARGET"
|
||||||
echo
|
echo
|
||||||
printf '%-8s %-18s %-20s %10s %s\n' "tool" "source" "license" "size(B)" "sha256"
|
printf '%-8s %-18s %-20s %10s %s\n' "tool" "source" "license" "size(B)" "sha256"
|
||||||
while IFS='|' read -r src name origin lic; do
|
while IFS='|' read -r src name origin lic; do
|
||||||
@@ -348,15 +419,18 @@ write_meta() {
|
|||||||
$(printf '%s\n' "$TOOLS" | sed '/^$/d')
|
$(printf '%s\n' "$TOOLS" | sed '/^$/d')
|
||||||
EOF
|
EOF
|
||||||
echo
|
echo
|
||||||
echo "源码(可复现性 + GPL 合规):"
|
echo "源码(可复现性 + GPL/LGPL 合规):"
|
||||||
echo " ncurses $NCURSES_VER MIT-style sha256 $(printf '%s' "$SRC_NCURSES" | awk -F'|' '{print $3}')"
|
echo " ncurses $NCURSES_VER MIT-style sha256 $(printf '%s' "$SRC_NCURSES" | awk -F'|' '{print $3}')"
|
||||||
echo " procps-ng $PROCPS_VER GPL-2.0+ sha256 $(printf '%s' "$SRC_PROCPS" | awk -F'|' '{print $3}')"
|
echo " procps-ng $PROCPS_VER GPL-2.0+ / library=LGPL-2.1+ sha256 $(printf '%s' "$SRC_PROCPS" | awk -F'|' '{print $3}')"
|
||||||
echo " lsof $LSOF_VER Purdue/BSD sha256 $(printf '%s' "$SRC_LSOF" | awk -F'|' '{print $3}')"
|
echo " lsof $LSOF_VER Purdue/BSD sha256 $(printf '%s' "$SRC_LSOF" | awk -F'|' '{print $3}')"
|
||||||
echo " 下载地址与重编方法: scripts/build/build_devkit.sh(--with-sources 可把源码包放到 src/)"
|
echo " (--with-sources 时)src/ 内还有 build_devkit.sh + DEVKIT.md(构建控制脚本,GPLv2 §3 要求)"
|
||||||
|
echo " 下载地址与重编方法: scripts/build/build_devkit.sh(--with-sources 把上述文件放进 src/)"
|
||||||
echo
|
echo
|
||||||
echo "注意: procps-ng 是 GPL-2.0-or-later。把本目录随卡交付给第三方时,"
|
echo "注意: procps-ng 是 GPL-2.0-or-later。把本目录随卡交付给第三方时,"
|
||||||
echo " GPLv2 §3 要求提供对应源码 —— 请用 --with-sources 一起带上 src/,"
|
echo " GPLv2 §3 要求提供对应源码(含构建脚本)—— 请用 --with-sources 带上 src/,"
|
||||||
echo " 或随卡附书面要约(有效期 ≥3 年)。仅给出下载 URL 不构成合规。"
|
echo " 或随卡附书面要约(有效期 ≥3 年)。仅给出下载 URL 不构成合规。"
|
||||||
|
echo " 另外 ps/vmstat/slabtop/free/pmap 静态链接了 LGPL-2.1+ 的 libproc2:"
|
||||||
|
echo " LGPL-2.1 §6 要求提供可重链接的 object code 或书面要约,详见 DEVKIT.md §6。"
|
||||||
} > "$OUT_DIR/MANIFEST.txt"
|
} > "$OUT_DIR/MANIFEST.txt"
|
||||||
|
|
||||||
cat > "$OUT_DIR/README.txt" <<'EOS'
|
cat > "$OUT_DIR/README.txt" <<'EOS'
|
||||||
@@ -372,17 +446,21 @@ MeowOS devkit — 设备端调试工具(静态 MIPS32r2)
|
|||||||
export PATH="/usr/data/mnt/sd_0/MeowOS/opt/devkit/bin:$PATH"
|
export PATH="/usr/data/mnt/sd_0/MeowOS/opt/devkit/bin:$PATH"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
exFAT 没有 Unix 权限位(挂载 fmask=0022 → 文件一律 0755),也没有符号链接。
|
源码与许可证:
|
||||||
本目录里都是实体可执行文件,拷到卡上即可执行,不需要 chmod,也不能用软链。
|
若随卡分发了源码:源码(含构建脚本 build_devkit.sh、DEVKIT.md)在 ../src/;
|
||||||
若手工从其他文件系统拷入后发现不可执行,执行一次:
|
各上游许可证原文在 ../licenses/;版本/体积/sha256 见 ../MANIFEST.txt。
|
||||||
chmod 755 /usr/data/mnt/sd_0/MeowOS/opt/devkit/bin/*
|
|
||||||
|
exFAT 没有 Unix 权限位(挂载 fmask=0022 → 新文件一律 0755),也没有符号链接。
|
||||||
|
本目录里都是实体可执行文件,拷到卡上即可执行,无需 chmod,也不能用软链。
|
||||||
|
若拷入后无法执行,请检查挂载参数(不要有 noexec;`mount | grep sd_0`),
|
||||||
|
而不是反复 chmod —— fmask=0022 下 chmod 本身是 no-op。
|
||||||
|
|
||||||
与 busybox 同名命令的关系(devkit/bin 前插 PATH 时生效):
|
与 busybox 同名命令的关系(devkit/bin 前插 PATH 时生效):
|
||||||
free ps lsof → 会被本目录版本覆盖(procps/lsof 字段更全)
|
free ps lsof → 会被本目录版本覆盖(procps/lsof 字段更全)
|
||||||
vmstat slabtop pmap → busybox 没有,直接新增
|
vmstat slabtop pmap → busybox 没有,直接新增
|
||||||
要临时用回 busybox 版:/bin/busybox free / busybox ps / busybox lsof
|
要临时用回 busybox 版:busybox free / busybox ps / busybox lsof
|
||||||
注意:/usr/bin/{free,ps,lsof,top} 目前都是指向 /bin/busybox 的软链,
|
注意:/bin/ps -> busybox,/usr/bin/{free,lsof,top} -> ../../bin/busybox,
|
||||||
所以“前插 devkit/bin”是唯一让新版本生效的方式(不要覆盖 /usr/bin 里的软链:
|
所以“前插 devkit/bin”是唯一让新版本生效的方式(不要覆盖这些软链:
|
||||||
rootfs 是 ubifs,随固件回刷会被还原,而且 busybox 软链是基线的一部分)。
|
rootfs 是 ubifs,随固件回刷会被还原,而且 busybox 软链是基线的一部分)。
|
||||||
|
|
||||||
已知限制:
|
已知限制:
|
||||||
@@ -390,7 +468,13 @@ rootfs 是 ubifs,随固件回刷会被还原,而且 busybox 软链是基线
|
|||||||
/proc/<pid>/smaps 不存在,所以 pmap -x 拿不到 PSS/私有脏页。
|
/proc/<pid>/smaps 不存在,所以 pmap -x 拿不到 PSS/私有脏页。
|
||||||
- slabtop -o(一次性输出)不需要 terminfo,也不要求 TTY;
|
- slabtop -o(一次性输出)不需要 terminfo,也不要求 TTY;
|
||||||
交互模式走 /usr/share/terminfo(设备已有 xterm 等条目;已编进 ncurses)。
|
交互模式走 /usr/share/terminfo(设备已有 xterm 等条目;已编进 ncurses)。
|
||||||
- 不提供 top:procps 4.0.4 的 top 在本机输出不可信(见仓库 scripts/build/DEVKIT.md)。
|
- 本工具链(zig 0.17 musl)在 4.4 内核上是 time64 ABI 错配:
|
||||||
|
`vmstat -t` 的时间戳列会是**空**(localtime 返回 NULL)。
|
||||||
|
vmstat 采样间隔、ps 的 lstart、slabtop/free/pmap/lsof 均正常。
|
||||||
|
原因与后续修法见 ../src/DEVKIT.md「已知限制:工具链 time64」。
|
||||||
|
- lsof 不带 -n 时会尝试反向解析(编译进 musl 的 resolv.conf 路径是构建机的,
|
||||||
|
设备上不存在)→ 实测 `lsof -i` 约 3s 超时;请用 `lsof -nP`。
|
||||||
|
- 不提供 top:见 ../src/DEVKIT.md(同样是 time64 问题,表头时钟溢出)。
|
||||||
EOS
|
EOS
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -399,23 +483,25 @@ EOS
|
|||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
stamp_value() {
|
stamp_value() {
|
||||||
{
|
{
|
||||||
sha256sum "${BASH_SOURCE[0]}"
|
sha256sum "$SCRIPT_PATH"
|
||||||
echo "$NCURSES_VER $PROCPS_VER $LSOF_VER $ZIG_TARGET $TARGET_KERNEL_VSTR"
|
# 带 zig 的完整版本(0.17.0 → 0.17.1 也要触发重建:工具链 patch 会改产物)
|
||||||
|
echo "zig=$ZIG_VERSION target=$ZIG_TARGET kernel=$TARGET_KERNEL_VSTR"
|
||||||
|
echo "ncurses=$NCURSES_VER procps=$PROCPS_VER lsof=$LSOF_VER"
|
||||||
} | sha256sum | cut -d' ' -f1
|
} | sha256sum | cut -d' ' -f1
|
||||||
}
|
}
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
local t0 t1
|
local t0 t1
|
||||||
t0=$(date +%s)
|
|
||||||
mkdir -p "$SRC_DIR" "$BUILD_DIR" "$PREFIX"
|
|
||||||
|
|
||||||
if [ "$VERIFY_ONLY" = 1 ]; then
|
if [ "$VERIFY_ONLY" = 1 ]; then
|
||||||
# 只校验现有产物:不要求 zig/make,评审者用系统自带 file/readelf 即可
|
# 只校验现有产物:不要求 zig/make/date,评审者用 file/readelf/sha256sum 即可
|
||||||
collect_verify_existing
|
collect_verify_existing
|
||||||
[ "$FAIL" = 0 ] || die "$FAIL 个产物未通过自检"
|
[ "$FAIL" = 0 ] || die "$FAIL 项未通过自检"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
t0=$(date +%s)
|
||||||
|
mkdir -p "$SRC_DIR" "$BUILD_DIR" "$PREFIX"
|
||||||
check_toolchain
|
check_toolchain
|
||||||
|
|
||||||
local cur_stamp old_stamp=""
|
local cur_stamp old_stamp=""
|
||||||
@@ -423,24 +509,41 @@ main() {
|
|||||||
[ -f "$WORK/stamp" ] && old_stamp="$(cat "$WORK/stamp")"
|
[ -f "$WORK/stamp" ] && old_stamp="$(cat "$WORK/stamp")"
|
||||||
|
|
||||||
if [ "$CLEAN" = 1 ]; then
|
if [ "$CLEAN" = 1 ]; then
|
||||||
log "清理工作区 $WORK"
|
log "清理工作区 $WORK 与输出目录的 src/"
|
||||||
rm -rf "$BUILD_DIR" "$PREFIX"
|
rm -rf "$BUILD_DIR" "$PREFIX"
|
||||||
mkdir -p "$BUILD_DIR" "$PREFIX"
|
mkdir -p "$BUILD_DIR" "$PREFIX"
|
||||||
|
if [ -d "$OUT_DIR/src" ]; then
|
||||||
|
rm -rf "$OUT_DIR/src"
|
||||||
|
fi
|
||||||
old_stamp=""
|
old_stamp=""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$FORCE" = 0 ] && [ "$cur_stamp" = "$old_stamp" ] && [ -d "$BIN_DIR" ]; then
|
local bin_ok=1 mf_ok=0 n
|
||||||
local ok=1
|
for n in $TOOL_NAMES; do
|
||||||
for n in vmstat slabtop free ps pmap lsof; do
|
[ -f "$BIN_DIR/$n" ] && verify_binary "$BIN_DIR/$n" >/dev/null 2>&1 || bin_ok=0
|
||||||
[ -f "$BIN_DIR/$n" ] && verify_binary "$BIN_DIR/$n" >/dev/null 2>&1 || ok=0
|
done
|
||||||
done
|
# 交付完整性也要一并作为 skip 条件:MANIFEST 缺失或与 bin 不符时宁可重建
|
||||||
if [ "$ok" = 1 ]; then
|
if [ -f "$OUT_DIR/MANIFEST.txt" ] && verify_manifest >/dev/null 2>&1; then
|
||||||
t1=$(date +%s)
|
mf_ok=1
|
||||||
log "产物已是最新(脚本与版本未变),跳过编译"
|
fi
|
||||||
info "输出目录: $BIN_DIR"
|
|
||||||
info "用时 $((t1 - t0))s,联网 $DOWNLOADS 次"
|
if [ "$FORCE" = 0 ] && [ "$cur_stamp" = "$old_stamp" ] && [ "$bin_ok" = 1 ] && [ "$mf_ok" = 1 ]; then
|
||||||
return 0
|
# P1 回归点:--with-sources 必须在这里就兑现,不能因为“跳过编译”而漏掉源码。
|
||||||
|
# (曾经把这段放在 return 之后,结果 stamp 命中时静默不产出 src/,退出码仍是 0。)
|
||||||
|
if [ "$WITH_SOURCES" = 1 ]; then
|
||||||
|
if sources_complete; then
|
||||||
|
info "源码包已就绪: $OUT_DIR/src"
|
||||||
|
else
|
||||||
|
stage_sources
|
||||||
|
fi
|
||||||
|
elif [ -d "$OUT_DIR/src" ] && ! sources_complete; then
|
||||||
|
info "注意: $OUT_DIR/src 与当前版本/脚本不一致;若要分发请用 --with-sources 重建"
|
||||||
fi
|
fi
|
||||||
|
t1=$(date +%s)
|
||||||
|
log "产物已是最新(脚本与版本未变),跳过编译"
|
||||||
|
info "输出目录: $BIN_DIR"
|
||||||
|
info "用时 $((t1 - t0))s,联网 $DOWNLOADS 次"
|
||||||
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
log "取源码(固定版本 + sha256 校验)"
|
log "取源码(固定版本 + sha256 校验)"
|
||||||
@@ -458,11 +561,11 @@ main() {
|
|||||||
write_meta
|
write_meta
|
||||||
|
|
||||||
if [ "$WITH_SOURCES" = 1 ]; then
|
if [ "$WITH_SOURCES" = 1 ]; then
|
||||||
log "复制源码包到 $OUT_DIR/src(GPL 合规用)"
|
stage_sources
|
||||||
mkdir -p "$OUT_DIR/src"
|
elif [ -d "$OUT_DIR/src" ]; then
|
||||||
cp "$SRC_DIR/ncurses-${NCURSES_VER}.tar.gz" "$SRC_DIR/procps-ng-${PROCPS_VER}.tar.xz" \
|
# 上次 --with-sources 的残留可能与本次二进制不对应;留着会被误当“合规源码”
|
||||||
"$SRC_DIR/lsof-${LSOF_VER}.tar.xz" "$OUT_DIR/src/"
|
info "删除上次残留的 $OUT_DIR/src(本次未请求源码,避免与二进制错配)"
|
||||||
info "共 $(du -sh "$OUT_DIR/src" | cut -f1)"
|
rm -rf "$OUT_DIR/src"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
printf '%s\n' "$cur_stamp" > "$WORK/stamp"
|
printf '%s\n' "$cur_stamp" > "$WORK/stamp"
|
||||||
@@ -471,17 +574,49 @@ main() {
|
|||||||
info "输出: $OUT_DIR"
|
info "输出: $OUT_DIR"
|
||||||
info "体积合计: $(du -sh "$BIN_DIR" | cut -f1)"
|
info "体积合计: $(du -sh "$BIN_DIR" | cut -f1)"
|
||||||
info "用时 $((t1 - t0))s,本次联网下载 $DOWNLOADS 次"
|
info "用时 $((t1 - t0))s,本次联网下载 $DOWNLOADS 次"
|
||||||
|
if [ "$WITH_SOURCES" = 1 ]; then
|
||||||
|
info "源码包: $OUT_DIR/src($(du -sh "$OUT_DIR/src" | cut -f1))"
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
collect_verify_existing() {
|
collect_verify_existing() {
|
||||||
local n bad=0
|
local n bad=0
|
||||||
for n in vmstat slabtop free ps pmap lsof; do
|
for n in $TOOL_NAMES; do
|
||||||
if [ ! -f "$BIN_DIR/$n" ]; then
|
if [ ! -f "$BIN_DIR/$n" ]; then
|
||||||
info "缺 $BIN_DIR/$n"; bad=$((bad + 1)); continue
|
info "缺 $BIN_DIR/$n"; bad=$((bad + 1)); continue
|
||||||
fi
|
fi
|
||||||
verify_binary "$BIN_DIR/$n" && info "OK $n $(wc -c < "$BIN_DIR/$n") B" || bad=$((bad + 1))
|
verify_binary "$BIN_DIR/$n" && info "OK $n $(wc -c < "$BIN_DIR/$n") B" || bad=$((bad + 1))
|
||||||
done
|
done
|
||||||
|
verify_manifest || bad=$((bad + 1))
|
||||||
FAIL=$bad
|
FAIL=$bad
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# MANIFEST.txt 的逐条 sha256/体积比对:只查“是不是静态 MIPS”看不出内容漂移
|
||||||
|
# (旧版脚本/旧工具链编出来的同样是 static/MIPS)。这里把 MANIFEST 当权威对账。
|
||||||
|
verify_manifest() {
|
||||||
|
local n line got_sha got_size bad=0
|
||||||
|
local mf="$OUT_DIR/MANIFEST.txt"
|
||||||
|
if [ ! -f "$mf" ]; then
|
||||||
|
info "FAIL 缺 $mf(无法核对产物内容)"
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
for n in $TOOL_NAMES; do
|
||||||
|
# 只认表格行:$1=工具名,$(NF-1)=纯数字体积,$NF=64 位 sha。
|
||||||
|
# (MANIFEST 末尾「源码」小节里也有以 lsof 开头的行,不加这两个约束会把两行都收进来。)
|
||||||
|
line="$(awk -v k="$n" '$1 == k && $(NF-1) ~ /^[0-9]+$/ && length($NF) == 64' "$mf")"
|
||||||
|
if [ -z "$line" ]; then
|
||||||
|
info "FAIL MANIFEST 缺 $n 的表格行"; bad=$((bad + 1)); continue
|
||||||
|
fi
|
||||||
|
got_sha="$(printf '%s\n' "$line" | awk '{print $NF}')"
|
||||||
|
got_size="$(printf '%s\n' "$line" | awk '{print $(NF-1)}')"
|
||||||
|
if [ "$got_sha" != "$(sha256sum "$BIN_DIR/$n" | cut -d' ' -f1)" ]; then
|
||||||
|
info "FAIL $n sha256 与 MANIFEST 不一致(产物被替换/旧版残留?)"; bad=$((bad + 1))
|
||||||
|
elif [ "$got_size" != "$(wc -c < "$BIN_DIR/$n")" ]; then
|
||||||
|
info "FAIL $n 体积与 MANIFEST 不一致($got_size vs $(wc -c < "$BIN_DIR/$n"))"; bad=$((bad + 1))
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
[ "$bad" = 0 ] && info "OK MANIFEST.txt 与 bin/ 六项 sha256/体积逐条一致"
|
||||||
|
return $((bad > 0))
|
||||||
|
}
|
||||||
|
|
||||||
main "$@"
|
main "$@"
|
||||||
Executable
+93
@@ -0,0 +1,93 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# ============================================================================
|
||||||
|
# test_build_devkit.sh — build_devkit.sh 的回归测试(不重编,秒级)
|
||||||
|
#
|
||||||
|
# 针对 r1 评审 P1 的回归点:**stamp 命中(跳过编译)时,--with-sources 必须
|
||||||
|
# 真正产出 src/,不能静默成功**。另覆盖 --verify-only 的 MANIFEST 漂移检测。
|
||||||
|
#
|
||||||
|
# 前置:MEOW_DEVKIT_WORK 里已有一次构建(脚本会先跑一次增量构建,命中则秒回;
|
||||||
|
# 缓存缺失时会联网下载/编译,第一次运行约 1 分钟)。
|
||||||
|
#
|
||||||
|
# 用法:bash scripts/build/test_build_devkit.sh [-v]
|
||||||
|
# 退出码 0 = 全过;非 0 = 用例失败数。
|
||||||
|
# ============================================================================
|
||||||
|
set -u
|
||||||
|
|
||||||
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||||
|
SCRIPT="$ROOT/scripts/build/build_devkit.sh"
|
||||||
|
export MEOW_DEVKIT_WORK="${MEOW_DEVKIT_WORK:-$HOME/.cache/meow-devkit}"
|
||||||
|
OUT="$ROOT/fw_apps/devkit"
|
||||||
|
TMP="$MEOW_DEVKIT_WORK/test-tmp"
|
||||||
|
|
||||||
|
VERBOSE=0
|
||||||
|
[ "${1:-}" = "-v" ] && VERBOSE=1
|
||||||
|
|
||||||
|
PASS=0
|
||||||
|
FAILN=0
|
||||||
|
pass() { PASS=$((PASS + 1)); printf 'PASS %s\n' "$*"; }
|
||||||
|
fail() { FAILN=$((FAILN + 1)); printf 'FAIL %s\n' "$*"; }
|
||||||
|
run() { # run <说明> <命令...>
|
||||||
|
local desc="$1"; shift
|
||||||
|
local log="$TMP/last.log"
|
||||||
|
if "$@" >"$log" 2>&1; then
|
||||||
|
[ "$VERBOSE" = 1 ] && sed 's/^/ | /' "$log"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
printf ' 命令失败: %s\n' "$*"
|
||||||
|
sed 's/^/ | /' "$log" | tail -20
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
mkdir -p "$TMP"
|
||||||
|
# 无论成败都恢复现场,别把测试的破坏留在产物目录里
|
||||||
|
restore() {
|
||||||
|
[ -f "$TMP/MANIFEST.txt.bak" ] && cp "$TMP/MANIFEST.txt.bak" "$OUT/MANIFEST.txt"
|
||||||
|
rm -rf "$TMP"
|
||||||
|
}
|
||||||
|
trap restore EXIT
|
||||||
|
|
||||||
|
echo "== 0) 确保基线构建(幂等;已构建则秒回)"
|
||||||
|
run "基线构建" bash "$SCRIPT" || { echo "!!! 基线构建失败,后续用例无意义"; exit 1; }
|
||||||
|
pass "基线构建"
|
||||||
|
|
||||||
|
echo "== 1) P1 回归:stamp 命中 + --with-sources 必须产出 src/"
|
||||||
|
rm -rf "$OUT/src"
|
||||||
|
run "普通重跑(应命中 stamp 且不建 src/)" bash "$SCRIPT" || fail "T1a 普通重跑"
|
||||||
|
[ ! -d "$OUT/src" ] && pass "T1a 普通重跑不创建 src/(符合预期)" || fail "T1a 普通重跑意外创建了 src/"
|
||||||
|
run "--with-sources(stamp 命中路径)" bash "$SCRIPT" --with-sources || fail "T1b --with-sources 退出码非 0"
|
||||||
|
for f in ncurses-6.5.tar.gz procps-ng-4.0.4.tar.xz lsof-4.99.4.tar.xz build_devkit.sh DEVKIT.md; do
|
||||||
|
[ -s "$OUT/src/$f" ] && pass "T1b src/$f 存在且非空" || fail "T1b 缺 src/$f(P1 未修好)"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "== 2) 缺文件自愈:删掉构建脚本后再 --with-sources"
|
||||||
|
rm -f "$OUT/src/build_devkit.sh"
|
||||||
|
run "--with-sources 补齐" bash "$SCRIPT" --with-sources || fail "T2 --with-sources 退出码非 0"
|
||||||
|
[ -s "$OUT/src/build_devkit.sh" ] && pass "T2 src/build_devkit.sh 被补回" || fail "T2 未补回 src/build_devkit.sh"
|
||||||
|
|
||||||
|
echo "== 3) 内容漂移自愈:把 src 里的源码包改坏"
|
||||||
|
printf 'tamper\n' >> "$OUT/src/ncurses-6.5.tar.gz"
|
||||||
|
run "--with-sources 重铺" bash "$SCRIPT" --with-sources || fail "T3 --with-sources 退出码非 0"
|
||||||
|
if cmp -s "$OUT/src/ncurses-6.5.tar.gz" "$MEOW_DEVKIT_WORK/src/ncurses-6.5.tar.gz"; then
|
||||||
|
pass "T3 被改坏的源码包已恢复成钉住版本"
|
||||||
|
else
|
||||||
|
fail "T3 源码包未恢复"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "== 4) --verify-only:正常通过"
|
||||||
|
run "--verify-only" bash "$SCRIPT" --verify-only && pass "T4a --verify-only 通过" || fail "T4a --verify-only 失败"
|
||||||
|
|
||||||
|
echo "== 5) --verify-only:能查出 MANIFEST 内容漂移"
|
||||||
|
cp "$OUT/MANIFEST.txt" "$TMP/MANIFEST.txt.bak"
|
||||||
|
awk 'BEGIN{done=0} { if (!done && $1=="vmstat") { $NF="0000000000000000000000000000000000000000000000000000000000000000"; done=1 } print }' \
|
||||||
|
"$TMP/MANIFEST.txt.bak" > "$OUT/MANIFEST.txt"
|
||||||
|
if run "--verify-only(MANIFEST 被篡改)" bash "$SCRIPT" --verify-only; then
|
||||||
|
fail "T5 --verify-only 未发现 MANIFEST sha 被篡改"
|
||||||
|
else
|
||||||
|
pass "T5 --verify-only 正确拒绝被篡改的 MANIFEST"
|
||||||
|
fi
|
||||||
|
cp "$TMP/MANIFEST.txt.bak" "$OUT/MANIFEST.txt"
|
||||||
|
run "--verify-only(恢复后)" bash "$SCRIPT" --verify-only && pass "T5b 恢复后重新通过" || fail "T5b 恢复后仍失败"
|
||||||
|
|
||||||
|
echo
|
||||||
|
printf '== 结果: %d 通过, %d 失败\n' "$PASS" "$FAILN"
|
||||||
|
[ "$FAILN" = 0 ]
|
||||||
Reference in new issue
Block a user