feat(devkit): M24 静态 MIPS32r2 调试工具集 — vmstat/slabtop/free/ps/pmap/lsof
TF 卡 MeowOS/opt/devkit 用的交叉编译流水线:zig 0.17 musl 静态链接,
产物 fw_apps/devkit/{bin,MANIFEST.txt,licenses,README.txt}(gitignore 内)。
- build_devkit.sh:源码固定 版本+sha256+URL(ncurses 6.5 / procps-ng 4.0.4 /
lsof 4.99.4),缓存命中零联网;冷启动 3 次下载约 80s,重跑 0 次联网约 65s,
stamp 命中 1s 跳过;--force/--clean/--offline/--with-sources/--verify-only
- 自编静态 ncursesw 只为 slabtop(procps 的 slabtop 硬依赖 ncurses);
terminfo 目录钉到设备 /usr/share/terminfo,交互式 slabtop 可用
- 逐项自检 file/readelf(static、ELF32、mips32r2、0 NEEDED),任一不过即失败
- 不交付 top(真机输出不可信)、htop(卡上已有 3.5.3 且我们的更大)
- DEVKIT.md:许可证留痕(procps=GPL-2+ 需提供源码、ncurses=MIT、lsof=Purdue)、
可行性实测、上卡 PATH 与 busybox 同名关系、真机验证输出
This commit is contained in:
1 parent
2a2e6988ae
commit
b52e6a08bc
3 files changed
+714
-1
No files matched your search
@@ -0,0 +1,224 @@
|
||||
# MeowOS devkit — 静态 MIPS32r2 调试工具集
|
||||
|
||||
TF 卡 `MeowOS/opt/devkit/bin/` 里那批静态二进制的构建说明、可行性实测、许可证留痕。
|
||||
构建入口:`bash scripts/build/build_devkit.sh`(产物在 `fw_apps/devkit/`,已被 `.gitignore`
|
||||
的 `fw_apps/` 规则覆盖,不入库)。
|
||||
|
||||
## 1. 为什么要有这个
|
||||
|
||||
设备(HiBy R3 Pro II / Ingenic X1600 / MIPS32r2 / Linux 4.4.94+ / 单核 / 56 MB)自带
|
||||
busybox 1.31.1,`free / ps / top / lsof` 都是指向 `/bin/busybox` 的软链,字段残缺;
|
||||
`vmstat`、`slabtop`、`pmap` 干脆没有。做内存分析时最缺的正是:
|
||||
|
||||
- `slabtop` —— Slab 总量 ~11 MB 到底被谁占了(buffer_head / dentry / squashfs_inode…)
|
||||
- `vmstat` —— 系统级趋势(r/b、si/so、in/cs、us/sy/id/wa),busybox 无替代
|
||||
- 真版 `lsof` —— busybox lsof 只有 pid/fd/设备号,没有 SIZE/OFF、TCP 状态、NAME
|
||||
|
||||
所以本工具集只围绕「这台机器的真实调试痛点」,不做大而全。
|
||||
|
||||
## 2. 产物清单
|
||||
|
||||
全部:`ELF 32-bit LSB executable, MIPS, MIPS32 rel2, statically linked, stripped`,
|
||||
`readelf -d` 零 `NEEDED`(musl libc 静态链入),可直接从 exFAT 卡上跑。
|
||||
|
||||
| 工具 | 来源版本 | 许可证 | 体积(B) | 用途 / 相对 busybox 的增量 |
|
||||
|---|---|---|---|---|
|
||||
| `slabtop` | procps-ng 4.0.4 | GPL-2.0-or-later | 394 408 | Slab 明细;`-o` 一次性输出不需要 TTY/terminfo |
|
||||
| `vmstat` | procps-ng 4.0.4 | GPL-2.0-or-later | 216 924 | 系统趋势;busybox 无 |
|
||||
| `ps` | procps-ng 4.0.4 | GPL-2.0-or-later | 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 无 |
|
||||
| `free` | procps-ng 4.0.4 | GPL-2.0-or-later | 94 312 | 拆 buff/cache、available |
|
||||
| `lsof` | lsof 4.99.4 | Purdue/BSD-style | 789 496 | SIZE/OFF、TCP 状态、NAME、`-i` 网络视图 |
|
||||
| | | **合计** | **1 993 580 ≈ 1.9 MB** | |
|
||||
|
||||
同目录还有构建时生成的 `MANIFEST.txt`(每个二进制的 sha256)、`licenses/`(上游 COPYING)、
|
||||
`README.txt`(上卡说明)。`--with-sources` 会额外生成 `src/`(源码包,GPL 合规用)。
|
||||
|
||||
## 3. 上卡后怎么用
|
||||
|
||||
```sh
|
||||
# 临时(SSH 会话)
|
||||
export PATH=/usr/data/mnt/sd_0/MeowOS/opt/devkit/bin:$PATH
|
||||
|
||||
# 持久化:rootfs 的 /etc/profile.d/meow_card_path.sh 只前插了 MeowOS/opt/bin,
|
||||
# devkit 是独立目录,需要再补一行(由塔/维护者决定是否进固件):
|
||||
if [ -d /usr/data/mnt/sd_0/MeowOS/opt/devkit/bin ]; then
|
||||
export PATH="/usr/data/mnt/sd_0/MeowOS/opt/devkit/bin:$PATH"
|
||||
fi
|
||||
```
|
||||
|
||||
**与 busybox 同名命令的先后关系**(前插 PATH 时):
|
||||
|
||||
| 名字 | 现状 | 前插后 |
|
||||
|---|---|---|
|
||||
| `free` `ps` `lsof` | `/usr/bin/*` 均是指向 `/bin/busybox` 的软链 | 解析到 devkit 版(功能更多) |
|
||||
| `vmstat` `slabtop` `pmap` | 不存在 | 新增 |
|
||||
| `top` | busybox 软链;**本工具集不提供 top**(见 §7) | 仍为 busybox |
|
||||
|
||||
要临时用回 busybox 版:`/bin/busybox free`、`busybox ps`、`busybox lsof`。
|
||||
不要覆盖 `/usr/bin` 里的软链:rootfs 是 ubifs,随固件回刷即被还原,而且这些软链是基线的一部分。
|
||||
|
||||
## 4. exFAT 语义(权限 / 软链)
|
||||
|
||||
设备挂载:`/dev/mmcblk0 on /usr/data/mnt/sd_0 type exfat (rw, fmask=0022, dmask=0022, symlink=0, noexec 未设置)`。
|
||||
|
||||
- **无符号链接**(`symlink=0`):所以本工具集全部是实体文件,不靠 `argv[0]` 分派,
|
||||
也不提供任何 symlink(不像 busybox 那样一个多合一二进制 + 一堆软链)。
|
||||
- **无 Unix 权限位**:`fmask=0022` 让卡上新文件恒为 `0755`,因此**不需要 chmod**;
|
||||
反过来说,卡上也表达不了 `4755` 之类,任何需要 setuid 的工具都不适合放这。
|
||||
- **可执行性**:挂载参数里没有 `noexec`,且卡上现有 `MeowOS/opt/MeowOS…/meowpanel`
|
||||
就是 0755 直接执行的。真机验证时我们把同一批二进制放在设备 `/tmp` 跑通(见 §9)。
|
||||
未在卡上实测执行,是因为本次任务约定「不往卡上写任何东西」(塔来推)。
|
||||
|
||||
## 5. 重跑代价与可复现性
|
||||
|
||||
- **联网次数**:冷启动 **3 次**(ncurses / procps-ng / lsof 各一个 tarball,共 5.5 MB);
|
||||
源码包按 sha256 校验后落在 `$MEOW_DEVKIT_WORK/src/`,此后**重跑 0 次联网**。
|
||||
- **耗时**(8 核宿主实测):冷启动(含 3 次下载)**80 秒**(两次实测 80s / 86s);
|
||||
源码已缓存时全量重编约 **85 秒**;`stamp` 命中(脚本与版本都没变)时 **1 秒**直接跳过;
|
||||
`--verify-only` 秒级,且不需要 zig。
|
||||
- **可复现(逐字节)**:在两个不同工作区各建一次,六个二进制 **sha256 完全相同**
|
||||
(`ps` 用 `-ffile-prefix-map` 抹掉绝对源码路径;`lsof` 用裸名 `CC=zigcc` + 相对源码路径,
|
||||
不再把工具链/构建目录写进 `LSOF_CC/LSOF_CCFLAGS`)。同一份 `MANIFEST.txt` 里的 sha256
|
||||
与设备上 `sha256sum` 的结果一致,可用来核对「跑的到底是哪个二进制」。
|
||||
- **可复现性**:三份源码都固定 `版本 + sha256 + URL`,校验不符直接失败;`zig 0.17.x` 版本
|
||||
也做硬检查。不依赖任何「这次网络恰好成功」的偶然性 —— 离线环境可先拷 `src/*.tar.*`
|
||||
进工作区再用 `--offline`。
|
||||
- 工作区默认 `~/.cache/meow-devkit`(`MEOW_DEVKIT_WORK` 可改),不污染仓库。
|
||||
|
||||
## 6. 许可证与分发合规(重点)
|
||||
|
||||
| 上游 | 许可证 | 分发二进制时的义务 |
|
||||
|---|---|---|
|
||||
| procps-ng 4.0.4 | **GPL-2.0-or-later**(`COPYING`=GPLv2;`library/` 为 LGPL-2.1+) | **必须提供完整对应源码**(GPLv2 §3),或书面的三年有效要约 |
|
||||
| ncurses 6.5 | MIT 风格(X11 许可) | 保留版权与许可声明;不单独分发(只静态链入 slabtop) |
|
||||
| lsof 4.99.4 | Purdue Research Foundation 许可(BSD 风格 4 条) | 文档与源码中保留作者/Purdue 署名;改过的版本要标注 |
|
||||
|
||||
**结论(不要含糊)**:`build_devkit.sh` 里的固定版本 + 下载 URL **不构成 GPLv2 §3 的合规**。
|
||||
URL 作者随时可能撤、镜像可能消失,而且 GPL 要求的是*分发者*提供的源码或要约。所以:
|
||||
|
||||
1. 若这批二进制随卡交到第三方手上 → 构建时加 **`--with-sources`**,把
|
||||
`ncurses-6.5.tar.gz` / `procps-ng-4.0.4.tar.xz` / `lsof-4.99.4.tar.xz` 一起放到卡上
|
||||
`MeowOS/opt/devkit/src/`(合计约 5.5 MB,TF 卡的容量代价可忽略);
|
||||
2. 或者随卡附**书面要约**(有效期内提供源码,GPLv2 §3(b));
|
||||
3. `licenses/` 里的上游 COPYING 只是「许可声明留痕」,**不能替代源码义务**。
|
||||
|
||||
内部自用(只有自己插卡)不触发 §3 的分发义务,但既然这台机器的产物可能被拷来拷去,
|
||||
建议一律 `--with-sources`。
|
||||
|
||||
## 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` 属重复且不可信 → 不凑数 |
|
||||
| `htop` | 不构建 | 卡上 `MeowOS/opt/bin/htop` 已经是 **3.5.3**(673 744 B)。我们实测用 zig + 自编 ncursesw 也能编出来,但 strip 后 **756 908 B**,比现有版本更大(静态链入 musl + ncurses),没有增量价值 |
|
||||
| `watch` | 不构建 | busybox 1.31 已有 `watch`;procps 版 403 KB,收益不抵体积 |
|
||||
| `pgrep`/`pkill` | 不构建 | busybox 已有;procps 版各 260 KB(链接整份 libproc) |
|
||||
| `uptime`/`tload`/`pidof`/`pidwait`/`w` | 不构建 | busybox 已有 `uptime`/`pidof`;`tload`/`w` 在本机无调试价值 |
|
||||
| `sysctl` | 不构建 | busybox 已有 `sysctl`(读写 `/proc/sys` 足够) |
|
||||
| `perf` / `valgrind` / `gdb` / `ltrace` / `sysstat` / `smem` | 不可行 | 见 §8 |
|
||||
|
||||
`pmap` 的低价值要说明白:本机 `CONFIG_PROC_PAGE_MONITOR=n`,`/proc/<pid>/smaps` 不存在,
|
||||
所以 `pmap -x` 拿不到 PSS/私有脏页。它仍有用的一点是 `/proc/<pid>/maps` **存在**,
|
||||
`pmap <pid>` 能列出地址段 + 映射文件名(busybox 没有等价物),排查「谁映射了这块内存」够用。
|
||||
|
||||
## 8. 可行性实测记录(编不出来的卡在哪)
|
||||
|
||||
宿主:Termux/Android aarch64,zig 0.17.0(自带 musl libc 与头文件),`make`、`curl`、`pkg-config`。
|
||||
**没有** autoconf/automake/libtool,**没有**目标内核头,sysroot 里只有 zlib(本工具集不需要它)。
|
||||
|
||||
- **procps-ng 4.0.4** ✅ 可编。两个必须处理的坑:
|
||||
1. `slabtop`(`src/slabtop.c` 直接 `#include <ncurses.h>`)与 `top` 硬依赖 ncurses;
|
||||
`configure --without-ncurses` 会把它们整个跳过 → 要 `slabtop` 就必须先交叉编 ncurses。
|
||||
2. 交叉编译下 autoconf 的 `malloc(0)/realloc(0)` 运行期探测无法执行,不缓存
|
||||
`ac_cv_func_malloc_0_nonnull=yes ac_cv_func_realloc_0_nonnull=yes` 会引入
|
||||
`rpl_malloc/rpl_realloc` 未定义引用,链接失败。
|
||||
3. 另外必须把 `PKG_CONFIG_LIBDIR` 收紧到自编 prefix,否则会捡到宿主 aarch64 的
|
||||
`ncursesw.pc`,结果是「musl 头 + bionic 头」混编(`watch` 直接编不过)。
|
||||
- **ncurses 6.5** ✅ 可编(`--without-shared --with-normal --enable-widec --without-progs` 等)。
|
||||
**必须** `--with-default-terminfo-dir=/usr/share/terminfo --with-terminfo-dirs=...`:
|
||||
否则交互式 `slabtop` 会 `Error opening terminal: xterm.`(默认值是编译期 prefix,设备上不存在)。
|
||||
体积代价:`libncursesw.a` 3.3 MB(未 strip,不单独分发),链进 `slabtop` 后只增加约 100 KB。
|
||||
- **lsof 4.99.4** ✅ 可编。坑:
|
||||
1. 4.99 源码包**不带** `configure`(autotools),但带老式 `Configure` 脚本,`./Configure -n linux` 可用。
|
||||
2. 版本探测读宿主 `/usr/include/linux/version.h` + `uname`,交叉时拿不到 4.4.94,
|
||||
会退化成 `LINUXV=00000 / LSOF_VSTR="0.0.0"`(Configure 打 "unsupported dialect or version")。
|
||||
这两个宏在 linux dialect 里只影响 `lsof -v` 显示,仍用 `-DLINUXV/LSOF_VSTR` 覆盖成 4.4.94。
|
||||
3. zig 的 musl 头没有 glibc 侧经由 `linux/tcp.h` 间接带来的 `TCP_ESTABLISHED` 等 11 个
|
||||
状态宏,`dsock.c` 会编不过 → 脚本里 `-D` 补齐(值取自 `linux/tcp.h`)。
|
||||
4. zig cc **不带 `-O` 时按 Debug 编**,会插入 UBSan 桩(`__ubsan_handle_negate_overflow`)
|
||||
导致链接失败 → 所有编译都显式 `-O2`。
|
||||
- **htop 3.5.3** ✅ 可编(用自编 ncursesw,`--disable-hwloc/sensors/delayacct`),strip 后 756 908 B —— 比卡上现有版本大,故不交付。
|
||||
- **perf** ❌ 不可行:依赖目标内核源码树(`tools/perf` 要按内核版本配 `perf_event_attr`),
|
||||
且设备内核未必开了 `CONFIG_PERF_EVENTS` 相关选项;没有内核头也是硬阻塞。
|
||||
- **valgrind** ❌ 不可行:没有 MIPS32 后端(valgrind 官方支持 x86/amd64/arm/aarch64/ppc/s390,
|
||||
无 mips),不是交叉编译问题,是根本没有后端。
|
||||
- **gdb** ❌ 未尝试/不建议:设备已带 `gdbserver`,宿主侧可以用交叉 gdb 连;在 56 MB 单核设备上
|
||||
跑 gdb 本体收益极低、体积巨大。
|
||||
- **ltrace** ❌ 不可行:需要解析目标 ELF 动态符号(`PT_DYNAMIC` + PLT),本机程序多为
|
||||
静态/精简,且 ltrace 的构建依赖 libelf + 复杂 autoconf 探测,投入产出不划算。
|
||||
- **sysstat(sar/iostat/mpstat)** ❌ 未做:autoconf 探测多、依赖 `gettext`/`libsensors` 等,
|
||||
且本机是单核、无块设备统计(`/proc/diskstats` 对 TF 卡意义有限),收益低。
|
||||
- **smem** ⚠️ 价值为零:依赖 `/proc/<pid>/smaps` 的 PSS,本机 `CONFIG_PROC_PAGE_MONITOR=n`,
|
||||
没有 smaps → 拿不到任何它要的数据。
|
||||
|
||||
## 9. 真机验证证据(2026-11-06,root@10.76.208.50)
|
||||
|
||||
产物拷到设备 `/tmp/devkit`(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
|
||||
Active / Total Objects (% used) : 55852 / 61357 (91.0%)
|
||||
Active / Total Slabs (% used) : 2794 / 2794 (100.0%)
|
||||
Active / Total Caches (% used) : 57 / 81 (70.4%)
|
||||
Active / Total Size (% used) : 11024.86K / 11593.48K (95.1%)
|
||||
Minimum / Average / Maximum Object : 0.02K / 0.19K / 32768.00K
|
||||
OBJS ACTIVE USE OBJ SIZE SLABS OBJ/SLAB CACHE SIZE NAME
|
||||
12474 10746 86% 0.06K 198 63 792K buffer_head
|
||||
|
||||
# pmap 1
|
||||
1: init
|
||||
00400000 864K r-x-- busybox
|
||||
004e8000 4K rw--- busybox
|
||||
00969000 132K rwx-- [ anon ]
|
||||
|
||||
# lsof -nP -i
|
||||
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
|
||||
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_mdns 1375 root 3u inet 2906 0t0 UDP *:5353
|
||||
meowpanel 1395 root 3u inet 2587 0t0 TCP *:8080 (LISTEN)
|
||||
```
|
||||
|
||||
- 六个二进制 `--help`/`-V` 全部 rc=0(`lsof --help` 不是合法选项,`lsof -v` 正常打印 4.99.4)。
|
||||
- 交互式 `slabtop`(无 `-o`)在 `TERM=xterm` 下正常初始化 curses(stdout 写出 1599 字节转义序列);
|
||||
对照 `TERM=bogus-term` 报 `Error opening terminal: bogus-term.` —— 说明 terminfo 路径确实命中
|
||||
`/usr/share/terminfo`,不是内嵌 fallback。
|
||||
- 宿主侧静态/架构自检(每个产物):`file` = `statically linked, stripped`;
|
||||
`readelf -h` = `ELF32` / `Machine: MIPS R3000` / `Flags: ... mips32r2`;`readelf -d` 无 `NEEDED`。
|
||||
可用 `bash scripts/build/build_devkit.sh --verify-only` 复跑。
|
||||
|
||||
## 10. 已知限制
|
||||
|
||||
- `pmap -x` 无 PSS(无 smaps),只有 maps 级别的段/文件信息。
|
||||
- 不提供 `top`(原因见 §7);需要交互式总览请用卡上已有的 `htop`。
|
||||
- 二进制按设备内核 4.4.94 编 `LINUXV`;换内核/换卡不影响运行(这些宏只影响显示)。
|
||||
- 产物是 32 位 MIPS32r2(o32 ABI,软浮点/无 FPU 依赖),只适用于 X1600 这类 MIPS32r2 目标。
|
||||
@@ -12,6 +12,8 @@
|
||||
|---|---|
|
||||
| `build_fw_apps.sh` | **通用打包脚本**(配置驱动)。读清单 → 组树 → repack → 校验 → 出固件。**不要改它的逻辑**,除非打包流程本身要变。 |
|
||||
| `fw_content.conf` | **固件内容清单**(默认配置)。每行一条 `<src>|<dst>|<md5>|<desc>`,声明"哪个本地文件装到固件哪里"。**改固件内容只改这里。** |
|
||||
| `build_devkit.sh` | **TF 卡调试工具集**交叉编译脚本(zig → 静态 MIPS32r2):`vmstat/slabtop/free/ps/pmap/lsof` → `fw_apps/devkit/`。与固件打包无关,独立跑。详见 `DEVKIT.md`。 |
|
||||
| `DEVKIT.md` | devkit 的产物清单、许可证留痕、可行性实测、上卡 PATH/busybox 关系、已知限制。 |
|
||||
| `README.md` | 本说明。 |
|
||||
|
||||
> 曾有一批独立脚本 `build_fw_apps_m2xx.sh`(每版复制一个、内部硬编码 md5),**已清理删除**,不再使用。它们的问题:需每版改脚本、且共享 `fw_apps/` 目录互相清空。现统一走"一个通用脚本 + 一个配置文件"。
|
||||
@@ -125,7 +127,7 @@ md5sum patch_v2/meow_launcherd/meow_launcherd
|
||||
- **改源码忘更新 md5**:清单里 md5 是强校验,源变了但 md5 没改 → 打包直接失败。**凡是动了清单里列的源文件,先 `md5sum` 更新对应行。**
|
||||
- **SDK 库(`meow_ui.a`)不入固件**:它由 APP(如 hello)链接,走 TF 卡 `MeowAPPs/` 热更新,**不要**加进清单。
|
||||
- **`fw_apps/` 被 gitignore**:固件产物与组装树都是构建产物,勿提交。
|
||||
- **`scripts/build/` 根目录 gitignore**:构建产物与组装树勿提交。但本目录的 **`README.md`/`build_fw_apps.sh`/`fw_content.conf` 已 `git add -f` 入库**(这三个是仓库侧应保留的脚本/配置/说明);其余(`fw_apps/` 产物等)不入库。
|
||||
- **`scripts/build/` 根目录 gitignore**:构建产物与组装树勿提交。但本目录的 **`README.md`/`build_fw_apps.sh`/`fw_content.conf`/`build_devkit.sh`/`DEVKIT.md` 已 `git add -f` 入库**(这几个是仓库侧应保留的脚本/配置/说明);其余(`fw_apps/` 产物、devkit 编译树等)不入库。
|
||||
|
||||
---
|
||||
|
||||
|
||||
Executable
+487
@@ -0,0 +1,487 @@
|
||||
#!/bin/bash
|
||||
# ============================================================================
|
||||
# build_devkit.sh — 交叉编译静态 MIPS32r2 调试工具集(TF 卡 MeowOS/opt/devkit)
|
||||
#
|
||||
# 为什么:设备(HiBy R3 Pro II / Ingenic X1600 / Linux 4.4.94 / MIPS32r2)上
|
||||
# busybox 提供的 free/ps/lsof 字段不全(都是 busybox 软链),且没有 vmstat/slabtop。
|
||||
# 内存分析时最缺 slabtop(拆 Slab 占用)与 vmstat(系统级趋势)。本脚本用 zig 自带
|
||||
# musl 交叉编出完全静态的二进制,放进 TF 卡供开发调试。
|
||||
#
|
||||
# 产物(全部静态链接、strip 过、无 NEEDED):
|
||||
# fw_apps/devkit/bin/{vmstat,slabtop,free,ps,pmap,lsof}
|
||||
# fw_apps/devkit/MANIFEST.txt 版本/许可证/体积/校验摘要
|
||||
# fw_apps/devkit/licenses/ 各上游 COPYING(分发留痕)
|
||||
# fw_apps/devkit/README.txt 上卡后怎么加 PATH、和 busybox 的同名关系
|
||||
# (--with-sources 时另有 fw_apps/devkit/src/ 源码包,GPL 合规用)
|
||||
#
|
||||
# 源码固定为「版本 + sha256 + 固定 URL」,全部校验后才编译;缓存命中则零联网。
|
||||
#
|
||||
# 工具链:zig cc --target=mipsel-linux-musleabi(需 zig 0.17.x)
|
||||
# 不依赖 ~/.tools 下的私有脚本,自己生成 wrapper($WORK/bin/zigcc)。
|
||||
# 不需要内核头(musl 头足够;只有 lsof 缺 11 个 TCP 状态宏,本脚本 -D 补上)。
|
||||
#
|
||||
# 许可证(二进制将来随卡分发时请保留此节):
|
||||
# procps-ng 4.0.4 GPL-2.0-or-later(COPYING=GPLv2;library/ 为 LGPL-2.1+)
|
||||
# *** 分发二进制必须提供对应源码(GPLv2 §3)***
|
||||
# → 用 --with-sources 把源码包一起放上卡,或随卡附书面要约。
|
||||
# ncurses 6.5 MIT 风格(X11 许可),保留版权声明即可
|
||||
# lsof 4.99.4 Purdue Research Foundation 许可(BSD 风格 4 条),
|
||||
# 要求文档与源码中保留作者与 Purdue 的署名(COPYING 第 2 条)
|
||||
# 本脚本链接的 ncurses 只作为 slabtop 的静态依赖进入产物,不单独分发。
|
||||
#
|
||||
# 用法:
|
||||
# bash scripts/build/build_devkit.sh # 增量:缓存命中则不联网
|
||||
# bash scripts/build/build_devkit.sh --force # 强制重编
|
||||
# bash scripts/build/build_devkit.sh --clean # 清空工作区后重编
|
||||
# bash scripts/build/build_devkit.sh --offline # 只用已缓存的源码包(CI/离线)
|
||||
# bash scripts/build/build_devkit.sh --with-sources
|
||||
# bash scripts/build/build_devkit.sh --verify-only # 只对现有产物做静态/架构自检
|
||||
#
|
||||
# 环境变量:
|
||||
# MEOW_DEVKIT_WORK 工作区(源码包/编译树/prefix),默认 ~/.cache/meow-devkit
|
||||
# MEOW_DEVKIT_JOBS 并行度,默认 nproc
|
||||
# ============================================================================
|
||||
set -eu
|
||||
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
OUT_DIR="$ROOT/fw_apps/devkit"
|
||||
BIN_DIR="$OUT_DIR/bin"
|
||||
WORK="${MEOW_DEVKIT_WORK:-$HOME/.cache/meow-devkit}"
|
||||
SRC_DIR="$WORK/src"
|
||||
BUILD_DIR="$WORK/build"
|
||||
PREFIX="$WORK/prefix"
|
||||
WRAP_DIR="$WORK/bin"
|
||||
JOBS="${MEOW_DEVKIT_JOBS:-$(nproc 2>/dev/null || echo 4)}"
|
||||
|
||||
ZIG_TARGET="mipsel-linux-musleabi"
|
||||
ZIG_WANT="0.17" # 已验证;0.18+ 参数可能变,见 check_toolchain
|
||||
|
||||
NCURSES_VER="6.5"
|
||||
PROCPS_VER="4.0.4"
|
||||
LSOF_VER="4.99.4"
|
||||
|
||||
# 设备内核版本:写进 lsof 的 LINUXV,让它按目标内核(4.4)选代码路径
|
||||
TARGET_KERNEL_VSTR="4.4.94"
|
||||
|
||||
# name|url|sha256 (sha256 是“哪份源码”的唯一权威,URL 只是取法之一)
|
||||
SRC_NCURSES="ncurses-${NCURSES_VER}.tar.gz|https://mirrors.tuna.tsinghua.edu.cn/gnu/ncurses/ncurses-${NCURSES_VER}.tar.gz|136d91bc269a9a5785e5f9e980bc76ab57428f604ce3e5a5a90cebc767971cc6"
|
||||
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"
|
||||
|
||||
FORCE=0
|
||||
CLEAN=0
|
||||
OFFLINE=0
|
||||
WITH_SOURCES=0
|
||||
VERIFY_ONLY=0
|
||||
DOWNLOADS=0
|
||||
|
||||
log() { printf '\n== %s\n' "$*"; }
|
||||
info() { printf ' %s\n' "$*"; }
|
||||
die() { printf '\n!!! %s\n' "$*" >&2; exit 1; }
|
||||
|
||||
usage() {
|
||||
sed -n '3,40p' "${BASH_SOURCE[0]}" | sed 's/^# \{0,1\}//'
|
||||
}
|
||||
|
||||
while [ $# -gt 0 ]; do
|
||||
case "$1" in
|
||||
-f|--force) FORCE=1 ;;
|
||||
--clean) CLEAN=1 ;;
|
||||
--offline) OFFLINE=1 ;;
|
||||
--with-sources) WITH_SOURCES=1 ;;
|
||||
--verify-only) VERIFY_ONLY=1 ;;
|
||||
-h|--help) usage; exit 0 ;;
|
||||
*) die "未知参数: $1(-h 看用法)" ;;
|
||||
esac
|
||||
shift
|
||||
done
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 0) 工具链与宿主依赖
|
||||
# ---------------------------------------------------------------------------
|
||||
check_toolchain() {
|
||||
local zig_bin zig_ver major_minor
|
||||
zig_bin="$(command -v zig || true)"
|
||||
[ -n "$zig_bin" ] || die "找不到 zig。装法:pkg install zig(需 0.17.x)"
|
||||
zig_ver="$("$zig_bin" version)"
|
||||
major_minor="${zig_ver%.*}"
|
||||
[ "$major_minor" = "$ZIG_WANT" ] || \
|
||||
die "zig 版本是 $zig_ver,本脚本只在 $ZIG_WANT.x 上验证过(target/静态链接行为可能变)"
|
||||
|
||||
mkdir -p "$WRAP_DIR"
|
||||
cat > "$WRAP_DIR/zigcc" <<EOF
|
||||
#!/bin/sh
|
||||
exec "$zig_bin" cc --target=$ZIG_TARGET "\$@"
|
||||
EOF
|
||||
chmod +x "$WRAP_DIR/zigcc"
|
||||
# 统一用 PATH 上的裸名 "zigcc" 当 CC:这样二进制里不会嵌进绝对工具链路径
|
||||
# (lsof 会把 ${CC} 写进 version.h),换机器/换工作区也能逐字节复现。
|
||||
PATH="$WRAP_DIR:$PATH"; export PATH
|
||||
ZIGCC="zigcc"
|
||||
info "zig $zig_ver → $WRAP_DIR/zigcc"
|
||||
|
||||
for t in make curl tar sha256sum file readelf; do
|
||||
command -v "$t" >/dev/null 2>&1 || die "缺宿主工具: $t"
|
||||
done
|
||||
# strip 必须能处理 ELF32/MIPS:优先 llvm-strip(zig 自带同源 llvm),
|
||||
# GNU strip 来自 binutils 一般也支持,但 Android 自带的那份不保证。
|
||||
if command -v llvm-strip >/dev/null 2>&1; then
|
||||
STRIP=llvm-strip
|
||||
elif command -v "$zig_bin" >/dev/null 2>&1 && [ -x "$(dirname "$zig_bin")/llvm-strip" ]; then
|
||||
STRIP="$(dirname "$zig_bin")/llvm-strip"
|
||||
else
|
||||
STRIP=strip
|
||||
fi
|
||||
info "strip → $STRIP"
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 1) 源码获取(固定版本 + sha256;缓存命中不联网)
|
||||
# ---------------------------------------------------------------------------
|
||||
fetch_src() {
|
||||
local spec="$1" name url sha got
|
||||
name="${spec%%|*}"; spec="${spec#*|}"
|
||||
url="${spec%%|*}"; sha="${spec#*|}"
|
||||
if [ -f "$SRC_DIR/$name" ]; then
|
||||
got="$(sha256sum "$SRC_DIR/$name" | cut -d' ' -f1)"
|
||||
if [ "$got" = "$sha" ]; then
|
||||
info "源码已缓存: $name"
|
||||
return 0
|
||||
fi
|
||||
info "缓存校验不符,删除重下: $name"
|
||||
rm -f "$SRC_DIR/$name"
|
||||
fi
|
||||
[ "$OFFLINE" = 1 ] && die "离线模式但缺少源码: $SRC_DIR/$name"
|
||||
info "下载 $name"
|
||||
curl -fL --retry 3 --connect-timeout 20 -o "$SRC_DIR/$name.part" "$url" \
|
||||
|| { rm -f "$SRC_DIR/$name.part"; die "下载失败: $url"; }
|
||||
got="$(sha256sum "$SRC_DIR/$name.part" | cut -d' ' -f1)"
|
||||
[ "$got" = "$sha" ] || { rm -f "$SRC_DIR/$name.part"; die "sha256 不符: $name(期望 $sha 实得 $got)"; }
|
||||
mv "$SRC_DIR/$name.part" "$SRC_DIR/$name"
|
||||
DOWNLOADS=$((DOWNLOADS + 1))
|
||||
}
|
||||
|
||||
unpack() { # unpack <tarball> <destdir>
|
||||
rm -rf "$2"; mkdir -p "$2"
|
||||
tar xf "$SRC_DIR/$1" -C "$2" --strip-components=1
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 2) ncurses:只为 slabtop 提供静态 ncursesw(不单独分发)
|
||||
# procps 的 slabtop/top 硬依赖 ncurses(configure 里 --without-ncurses 会把
|
||||
# 它们整个跳过),所以这是编 slabtop 的必要成本,不是为 htop 顺手加的。
|
||||
# terminfo 目录必须指向设备真实路径(/usr/share/terminfo),否则交互式
|
||||
# slabtop 会 "Error opening terminal":默认值是编译时 prefix,设备上没有。
|
||||
# slabtop -o(一次性输出)不初始化 curses,本来不受影响。
|
||||
# ---------------------------------------------------------------------------
|
||||
build_ncurses() {
|
||||
log "编译 ncurses $NCURSES_VER(静态 widec,无 progs/man/tests)"
|
||||
unpack "ncurses-${NCURSES_VER}.tar.gz" "$BUILD_DIR/ncurses-src"
|
||||
rm -rf "$BUILD_DIR/ncurses"; mkdir -p "$BUILD_DIR/ncurses"
|
||||
(
|
||||
cd "$BUILD_DIR/ncurses"
|
||||
CC="$ZIGCC" BUILD_CC=cc CFLAGS="-O2 -ffile-prefix-map=$BUILD_DIR/ncurses-src=/ncurses-$NCURSES_VER" \
|
||||
"$BUILD_DIR/ncurses-src/configure" \
|
||||
--host="$ZIG_TARGET" --prefix="$PREFIX/ncurses" \
|
||||
--without-shared --with-normal --without-debug --without-profile \
|
||||
--without-manpages --without-tests --without-ada \
|
||||
--without-cxx --without-cxx-binding --without-progs --without-tack \
|
||||
--enable-widec --disable-db-install \
|
||||
--enable-pc-files --with-pkg-config-libdir="$PREFIX/ncurses/lib/pkgconfig" \
|
||||
--with-default-terminfo-dir=/usr/share/terminfo \
|
||||
--with-terminfo-dirs="/usr/share/terminfo:/etc/terminfo:/lib/terminfo" \
|
||||
> "$BUILD_DIR/ncurses-configure.log" 2>&1 \
|
||||
|| { tail -20 "$BUILD_DIR/ncurses-configure.log"; die "ncurses configure 失败"; }
|
||||
make -j"$JOBS" > "$BUILD_DIR/ncurses-make.log" 2>&1 \
|
||||
|| { tail -20 "$BUILD_DIR/ncurses-make.log"; die "ncurses make 失败"; }
|
||||
make install > "$BUILD_DIR/ncurses-install.log" 2>&1 \
|
||||
|| { tail -20 "$BUILD_DIR/ncurses-install.log"; die "ncurses install 失败"; }
|
||||
)
|
||||
info "libncursesw.a 就绪: $PREFIX/ncurses/lib"
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 3) procps-ng:vmstat / slabtop / free / ps / top / pmap
|
||||
# ---------------------------------------------------------------------------
|
||||
build_procps() {
|
||||
log "编译 procps-ng $PROCPS_VER"
|
||||
unpack "procps-ng-${PROCPS_VER}.tar.xz" "$BUILD_DIR/procps-src"
|
||||
rm -rf "$BUILD_DIR/procps"; mkdir -p "$BUILD_DIR/procps"
|
||||
(
|
||||
cd "$BUILD_DIR/procps"
|
||||
# PKG_CONFIG_LIBDIR 必须收紧:否则会捡到宿主(Termux/aarch64)的 ncursesw.pc,
|
||||
# 结果是一边用 musl 头一边混进 bionic 头,watch/top 直接编不过。
|
||||
# 注意:下面这段环境变量赋值必须写成“无注释的连续续行”,
|
||||
# 注释行会截断续行链,导致变量只作用于一条空命令。
|
||||
#
|
||||
# ac_cv_func_malloc_0_nonnull / realloc:交叉编译时 autoconf 的运行期探测
|
||||
# 无法执行,不缓存这两个值会生成 rpl_malloc/rpl_realloc 引用而链接失败。
|
||||
PKG_CONFIG_PATH="$PREFIX/ncurses/lib/pkgconfig" \
|
||||
PKG_CONFIG_LIBDIR="$PREFIX/ncurses/lib/pkgconfig" \
|
||||
ac_cv_func_malloc_0_nonnull=yes ac_cv_func_realloc_0_nonnull=yes \
|
||||
CC="$ZIGCC" CFLAGS="-O2 -ffunction-sections -fdata-sections -ffile-prefix-map=$BUILD_DIR/procps-src=/procps-ng-$PROCPS_VER" \
|
||||
LDFLAGS="-static -Wl,--gc-sections" \
|
||||
"$BUILD_DIR/procps-src/configure" \
|
||||
--host="$ZIG_TARGET" --prefix="$PREFIX/procps" \
|
||||
--disable-shared --enable-static --disable-nls --disable-kill \
|
||||
> "$BUILD_DIR/procps-configure.log" 2>&1 \
|
||||
|| { tail -20 "$BUILD_DIR/procps-configure.log"; die "procps configure 失败"; }
|
||||
# 防呆:确认 ncurses 来自本 devkit 的 prefix,而不是宿主 Termux 的那份
|
||||
grep -q "$PREFIX/ncurses" "$BUILD_DIR/procps/Makefile" \
|
||||
|| die "procps 的 NCURSES_CFLAGS/LIBS 没指向 devkit prefix(pkg-config 串到宿主了)"
|
||||
make -j"$JOBS" > "$BUILD_DIR/procps-make.log" 2>&1 \
|
||||
|| { tail -20 "$BUILD_DIR/procps-make.log"; die "procps make 失败"; }
|
||||
)
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 4) lsof:真版 lsof(busybox lsof 只有 pid/fd/设备号,没有 size/offset/协议)
|
||||
# lsof 4.99.4 自带老式 Configure(不需要 autoconf),但版本探测读的是宿主
|
||||
# /usr/include/linux/version.h + uname,在 Termux/aarch64 上拿不到目标内核版本,
|
||||
# 于是 Makefile 里退化成 -DLINUXV=00000 -DLSOF_VSTR="0.0.0"(Configure 会打
|
||||
# "unsupported dialect or version")。这两个宏在 linux dialect 里只影响
|
||||
# `lsof -v` 的显示,不影响代码分支 —— 但仍显式覆盖成目标内核 4.4.94,便于事后对账。
|
||||
# zig 的 musl 头没有 glibc 侧 linux/tcp.h 间接带来的 TCP 状态宏(TCP_ESTABLISHED
|
||||
# 等 11 个),这里按 linux/tcp.h 的定义补齐;不补则 dsock.c 编译失败。
|
||||
# ---------------------------------------------------------------------------
|
||||
build_lsof() {
|
||||
log "编译 lsof $LSOF_VER"
|
||||
rm -rf "$BUILD_DIR/lsof"
|
||||
mkdir -p "$BUILD_DIR/lsof"
|
||||
tar xf "$SRC_DIR/lsof-${LSOF_VER}.tar.xz" -C "$BUILD_DIR/lsof" --strip-components=1
|
||||
(
|
||||
cd "$BUILD_DIR/lsof"
|
||||
CC="$ZIGCC" ./Configure -n linux > "$BUILD_DIR/lsof-configure.log" 2>&1 \
|
||||
|| { tail -20 "$BUILD_DIR/lsof-configure.log"; die "lsof Configure 失败"; }
|
||||
grep -q 'unsupported dialect' "$BUILD_DIR/lsof-configure.log" \
|
||||
&& info "注意:Configure 报 unsupported dialect(宿主 uname 6.x),版本宏下面用 -D 覆盖"
|
||||
# lsof 的 Makefile 里 CFLAGS = CDEFS INCL DEP DEBUG;额外宏走 DEBUG 注入。
|
||||
# -O2 必须显式给:zig cc 无 -O 时按 Debug 编,会插入 UBSan 桩导致链接失败。
|
||||
make -j"$JOBS" CC="$ZIGCC" \
|
||||
DEBUG="-O2 -DLINUXV=44094 -DLSOF_VSTR=\"$TARGET_KERNEL_VSTR\" -DTCP_ESTABLISHED=1 -DTCP_SYN_SENT=2 -DTCP_SYN_RECV=3 -DTCP_FIN_WAIT1=4 -DTCP_FIN_WAIT2=5 -DTCP_TIME_WAIT=6 -DTCP_CLOSE=7 -DTCP_CLOSE_WAIT=8 -DTCP_LAST_ACK=9 -DTCP_LISTEN=10 -DTCP_CLOSING=11" \
|
||||
> "$BUILD_DIR/lsof-make.log" 2>&1 \
|
||||
|| { tail -20 "$BUILD_DIR/lsof-make.log"; die "lsof make 失败"; }
|
||||
)
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 5) 收集 + strip + 逐项验证
|
||||
# ---------------------------------------------------------------------------
|
||||
# 产出清单:<源路径>|<目标名>|<出处>|<许可证>
|
||||
# 只放「真机实测能跑且真有价值」的:vmstat/slabtop(busybox 没有)、
|
||||
# free/ps/pmap(busybox 版字段残缺)、lsof(busybox 版只有 pid/fd)。
|
||||
# 不交付 top:本机(32 位 MIPS + 4.4.94)上 procps 4.0.4 的 top 表头/内存单位
|
||||
# 输出明显错误(时长字段溢出、Mem 显示 59.4 GiB 而 MemTotal 只有 55 MB),
|
||||
# 且卡上已有 htop 3.5.3(673KB),top 属重复且不可信 → 见 DEVKIT.md「未交付清单」。
|
||||
TOOLS="
|
||||
$BUILD_DIR/procps/src/vmstat|vmstat|procps-ng $PROCPS_VER|GPL-2.0-or-later
|
||||
$BUILD_DIR/procps/src/slabtop|slabtop|procps-ng $PROCPS_VER|GPL-2.0-or-later
|
||||
$BUILD_DIR/procps/src/free|free|procps-ng $PROCPS_VER|GPL-2.0-or-later
|
||||
$BUILD_DIR/procps/src/ps/pscommand|ps|procps-ng $PROCPS_VER|GPL-2.0-or-later
|
||||
$BUILD_DIR/procps/src/pmap|pmap|procps-ng $PROCPS_VER|GPL-2.0-or-later
|
||||
$BUILD_DIR/lsof/lsof|lsof|lsof $LSOF_VER|Purdue/BSD-style
|
||||
"
|
||||
|
||||
FAIL=0
|
||||
collect_and_verify() {
|
||||
log "收集产物并验证"
|
||||
rm -rf "$BIN_DIR"; mkdir -p "$BIN_DIR"
|
||||
printf '%-8s %10s %s\n' "工具" "体积(B)" "静态/架构"
|
||||
printf '%-8s %10s %s\n' "--------" "----------" "--------------------"
|
||||
while IFS='|' read -r src name origin lic; do
|
||||
[ -n "$src" ] || continue
|
||||
[ -f "$src" ] || die "缺产物: $src(编译没成功?)"
|
||||
cp "$src" "$BIN_DIR/$name"
|
||||
chmod 755 "$BIN_DIR/$name"
|
||||
"$STRIP" --strip-all "$BIN_DIR/$name"
|
||||
if verify_binary "$BIN_DIR/$name"; then
|
||||
printf '%-8s %10s %s\n' "$name" "$(wc -c < "$BIN_DIR/$name")" "OK: static/ELF32/MIPS32r2/0 NEEDED"
|
||||
else
|
||||
FAIL=$((FAIL + 1))
|
||||
fi
|
||||
done <<EOF
|
||||
$(printf '%s\n' "$TOOLS" | sed '/^$/d')
|
||||
EOF
|
||||
}
|
||||
|
||||
verify_binary() {
|
||||
local f="$1" desc cls mach flags needed
|
||||
desc="$(file -b "$f")"
|
||||
cls="$(readelf -h "$f" | sed -n 's/^ *Class: *//p')"
|
||||
mach="$(readelf -h "$f" | sed -n 's/^ *Machine: *//p')"
|
||||
flags="$(readelf -h "$f" | sed -n 's/^ *Flags: *//p')"
|
||||
needed="$(readelf -d "$f" 2>/dev/null | grep -c NEEDED || true)"
|
||||
case "$desc" in
|
||||
*"statically linked"*) ;;
|
||||
*) info "FAIL $(basename "$f"): 非静态 → $desc"; return 1 ;;
|
||||
esac
|
||||
[ "$cls" = "ELF32" ] || { info "FAIL $(basename "$f"): Class=$cls"; return 1; }
|
||||
case "$mach" in *MIPS*) ;; *) info "FAIL $(basename "$f"): Machine=$mach"; return 1 ;; esac
|
||||
case "$flags" in *mips32r2*) ;; *) info "FAIL $(basename "$f"): Flags=$flags"; return 1 ;; esac
|
||||
[ "$needed" = "0" ] || { info "FAIL $(basename "$f"): 有 $needed 条 NEEDED"; return 1; }
|
||||
case "$desc" in *"not stripped"*) info "警告 $(basename "$f"): 未 strip";; esac
|
||||
return 0
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 6) MANIFEST / README / 许可证 / (可选)源码
|
||||
# ---------------------------------------------------------------------------
|
||||
write_meta() {
|
||||
log "写 MANIFEST / README / 许可证"
|
||||
mkdir -p "$OUT_DIR/licenses"
|
||||
|
||||
cp "$BUILD_DIR/procps-src/COPYING" "$OUT_DIR/licenses/procps-ng-${PROCPS_VER}-COPYING" 2>/dev/null || true
|
||||
cp "$BUILD_DIR/procps-src/COPYING.LIB" "$OUT_DIR/licenses/procps-ng-${PROCPS_VER}-COPYING.LIB" 2>/dev/null || true
|
||||
cp "$BUILD_DIR/ncurses-src/COPYING" "$OUT_DIR/licenses/ncurses-${NCURSES_VER}-COPYING" 2>/dev/null || true
|
||||
cp "$BUILD_DIR/lsof/COPYING" "$OUT_DIR/licenses/lsof-${LSOF_VER}-COPYING" 2>/dev/null || true
|
||||
|
||||
{
|
||||
echo "MeowOS devkit — 静态 MIPS32r2 调试工具集"
|
||||
echo "生成时间: $(date -u '+%Y-%m-%dT%H:%M:%SZ') zig: $("${ZIGCC}" --version 2>/dev/null | head -1) target: $ZIG_TARGET"
|
||||
echo
|
||||
printf '%-8s %-18s %-20s %10s %s\n' "tool" "source" "license" "size(B)" "sha256"
|
||||
while IFS='|' read -r src name origin lic; do
|
||||
[ -n "$src" ] || continue
|
||||
printf '%-8s %-18s %-20s %10s %s\n' "$name" "$origin" "$lic" \
|
||||
"$(wc -c < "$BIN_DIR/$name")" "$(sha256sum "$BIN_DIR/$name" | cut -d' ' -f1)"
|
||||
done <<EOF
|
||||
$(printf '%s\n' "$TOOLS" | sed '/^$/d')
|
||||
EOF
|
||||
echo
|
||||
echo "源码(可复现性 + GPL 合规):"
|
||||
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 " lsof $LSOF_VER Purdue/BSD sha256 $(printf '%s' "$SRC_LSOF" | awk -F'|' '{print $3}')"
|
||||
echo " 下载地址与重编方法: scripts/build/build_devkit.sh(--with-sources 可把源码包放到 src/)"
|
||||
echo
|
||||
echo "注意: procps-ng 是 GPL-2.0-or-later。把本目录随卡交付给第三方时,"
|
||||
echo " GPLv2 §3 要求提供对应源码 —— 请用 --with-sources 一起带上 src/,"
|
||||
echo " 或随卡附书面要约(有效期 ≥3 年)。仅给出下载 URL 不构成合规。"
|
||||
} > "$OUT_DIR/MANIFEST.txt"
|
||||
|
||||
cat > "$OUT_DIR/README.txt" <<'EOS'
|
||||
MeowOS devkit — 设备端调试工具(静态 MIPS32r2)
|
||||
================================================
|
||||
|
||||
加到 PATH(SSH 会话,临时):
|
||||
export PATH=/usr/data/mnt/sd_0/MeowOS/opt/devkit/bin:$PATH
|
||||
|
||||
持久化(rootfs 的 /etc/profile.d/meow_card_path.sh 已把 MeowOS/opt/bin 前插,
|
||||
但 devkit 是独立目录,需要再加一行):
|
||||
if [ -d /usr/data/mnt/sd_0/MeowOS/opt/devkit/bin ]; then
|
||||
export PATH="/usr/data/mnt/sd_0/MeowOS/opt/devkit/bin:$PATH"
|
||||
fi
|
||||
|
||||
exFAT 没有 Unix 权限位(挂载 fmask=0022 → 文件一律 0755),也没有符号链接。
|
||||
本目录里都是实体可执行文件,拷到卡上即可执行,不需要 chmod,也不能用软链。
|
||||
若手工从其他文件系统拷入后发现不可执行,执行一次:
|
||||
chmod 755 /usr/data/mnt/sd_0/MeowOS/opt/devkit/bin/*
|
||||
|
||||
与 busybox 同名命令的关系(devkit/bin 前插 PATH 时生效):
|
||||
free ps lsof → 会被本目录版本覆盖(procps/lsof 字段更全)
|
||||
vmstat slabtop pmap → busybox 没有,直接新增
|
||||
要临时用回 busybox 版:/bin/busybox free / busybox ps / busybox lsof
|
||||
注意:/usr/bin/{free,ps,lsof,top} 目前都是指向 /bin/busybox 的软链,
|
||||
所以“前插 devkit/bin”是唯一让新版本生效的方式(不要覆盖 /usr/bin 里的软链:
|
||||
rootfs 是 ubifs,随固件回刷会被还原,而且 busybox 软链是基线的一部分)。
|
||||
|
||||
已知限制:
|
||||
- pmap 只能读 /proc/<pid>/maps;本机 CONFIG_PROC_PAGE_MONITOR=n,
|
||||
/proc/<pid>/smaps 不存在,所以 pmap -x 拿不到 PSS/私有脏页。
|
||||
- slabtop -o(一次性输出)不需要 terminfo,也不要求 TTY;
|
||||
交互模式走 /usr/share/terminfo(设备已有 xterm 等条目;已编进 ncurses)。
|
||||
- 不提供 top:procps 4.0.4 的 top 在本机输出不可信(见仓库 scripts/build/DEVKIT.md)。
|
||||
EOS
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# 主流程
|
||||
# ---------------------------------------------------------------------------
|
||||
stamp_value() {
|
||||
{
|
||||
sha256sum "${BASH_SOURCE[0]}"
|
||||
echo "$NCURSES_VER $PROCPS_VER $LSOF_VER $ZIG_TARGET $TARGET_KERNEL_VSTR"
|
||||
} | sha256sum | cut -d' ' -f1
|
||||
}
|
||||
|
||||
main() {
|
||||
local t0 t1
|
||||
t0=$(date +%s)
|
||||
mkdir -p "$SRC_DIR" "$BUILD_DIR" "$PREFIX"
|
||||
|
||||
if [ "$VERIFY_ONLY" = 1 ]; then
|
||||
# 只校验现有产物:不要求 zig/make,评审者用系统自带 file/readelf 即可
|
||||
collect_verify_existing
|
||||
[ "$FAIL" = 0 ] || die "$FAIL 个产物未通过自检"
|
||||
return 0
|
||||
fi
|
||||
|
||||
check_toolchain
|
||||
|
||||
local cur_stamp old_stamp=""
|
||||
cur_stamp="$(stamp_value)"
|
||||
[ -f "$WORK/stamp" ] && old_stamp="$(cat "$WORK/stamp")"
|
||||
|
||||
if [ "$CLEAN" = 1 ]; then
|
||||
log "清理工作区 $WORK"
|
||||
rm -rf "$BUILD_DIR" "$PREFIX"
|
||||
mkdir -p "$BUILD_DIR" "$PREFIX"
|
||||
old_stamp=""
|
||||
fi
|
||||
|
||||
if [ "$FORCE" = 0 ] && [ "$cur_stamp" = "$old_stamp" ] && [ -d "$BIN_DIR" ]; then
|
||||
local ok=1
|
||||
for n in vmstat slabtop free ps pmap lsof; do
|
||||
[ -f "$BIN_DIR/$n" ] && verify_binary "$BIN_DIR/$n" >/dev/null 2>&1 || ok=0
|
||||
done
|
||||
if [ "$ok" = 1 ]; then
|
||||
t1=$(date +%s)
|
||||
log "产物已是最新(脚本与版本未变),跳过编译"
|
||||
info "输出目录: $BIN_DIR"
|
||||
info "用时 $((t1 - t0))s,联网 $DOWNLOADS 次"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
log "取源码(固定版本 + sha256 校验)"
|
||||
fetch_src "$SRC_NCURSES"
|
||||
fetch_src "$SRC_PROCPS"
|
||||
fetch_src "$SRC_LSOF"
|
||||
|
||||
build_ncurses
|
||||
build_procps
|
||||
build_lsof
|
||||
|
||||
collect_and_verify
|
||||
[ "$FAIL" = 0 ] || die "$FAIL 个产物未通过静态/架构自检(见上)"
|
||||
|
||||
write_meta
|
||||
|
||||
if [ "$WITH_SOURCES" = 1 ]; then
|
||||
log "复制源码包到 $OUT_DIR/src(GPL 合规用)"
|
||||
mkdir -p "$OUT_DIR/src"
|
||||
cp "$SRC_DIR/ncurses-${NCURSES_VER}.tar.gz" "$SRC_DIR/procps-ng-${PROCPS_VER}.tar.xz" \
|
||||
"$SRC_DIR/lsof-${LSOF_VER}.tar.xz" "$OUT_DIR/src/"
|
||||
info "共 $(du -sh "$OUT_DIR/src" | cut -f1)"
|
||||
fi
|
||||
|
||||
printf '%s\n' "$cur_stamp" > "$WORK/stamp"
|
||||
t1=$(date +%s)
|
||||
log "完成"
|
||||
info "输出: $OUT_DIR"
|
||||
info "体积合计: $(du -sh "$BIN_DIR" | cut -f1)"
|
||||
info "用时 $((t1 - t0))s,本次联网下载 $DOWNLOADS 次"
|
||||
}
|
||||
|
||||
collect_verify_existing() {
|
||||
local n bad=0
|
||||
for n in vmstat slabtop free ps pmap lsof; do
|
||||
if [ ! -f "$BIN_DIR/$n" ]; then
|
||||
info "缺 $BIN_DIR/$n"; bad=$((bad + 1)); continue
|
||||
fi
|
||||
verify_binary "$BIN_DIR/$n" && info "OK $n $(wc -c < "$BIN_DIR/$n") B" || bad=$((bad + 1))
|
||||
done
|
||||
FAIL=$bad
|
||||
}
|
||||
|
||||
main "$@"
|
||||
Reference in new issue
Block a user