build(ncm): 宿主交叉适配层 + 全量测试补跑(M8)
- 新增 build_ncm_cross_host.sh:同构 HOME 复用容器脚本,串起 sdk/vendor/host-mbedtls/core/tests/ncm - libs_common.sh 工具链路径改为 MEOW_R3PROII_ROOT/$HOME 可覆盖,容器默认不变 - build_mbedtls.sh 递归清理 library/ 与 3rdparty/ 旧对象,修宿主/mipsel 混架构归档 - test_ncm_core.c 改用 $TMPDIR,Termux /tmp 不可写不再导致 store/cache/tag 用例失败 - REPORT §40:构建/测试/热更结果(ncm md5 1bbd2a55…,Music du 前后恒定)
This commit is contained in:
1 parent
2c69070cc4
commit
7d4906828d
5 files changed
+226
-10
No files matched your search
@@ -3429,3 +3429,54 @@ MP3 ≤128k→标准,>128k→极高 HQ。列表显示**实际档**(如 hires
|
||||
切到「极高」档再播同名曲,会按实际档新落一份 `song_<id>_exhigh.mp3`(一次性重下,旧文件不删,
|
||||
列表按 (id,实际档,ext) 去重只显示一行,旧文件由 LRU/清空自然回收)。未对旧名做向上探测扫描
|
||||
(避免每次 miss 扫目录 + 读多份文件头);如需「旧名跨档零重下」,可作为后续优化加一次目录级兼容探测。
|
||||
|
||||
## 40. M8:交叉编译 + 真机热更(2026-11-04)
|
||||
|
||||
用户原话:「跑」(把 M5/M6 已合并代码交叉编译并热更上卡真机验证)。
|
||||
|
||||
### 40.1 宿主适配层(新增入库)
|
||||
|
||||
| 文件 | 改动 |
|
||||
|---|---|
|
||||
| `build_ncm_cross_host.sh`(新) | 不改原脚本的容器路径约定:临时布局同构 `$HOME/Project/R3ProII`(`.tools/zig-mipsel-cc`、`mipsel-linux-muslsf-cross/mipsel-linux-muslsf` → 本机 `~/.tools/mipsel-linux-musleabi-sysroot`、`zig-env/bin/zig` → 系统 `ar` 包装)+ launcher 镜像(仓库头文件 + 取回的 `meow_font.a`),导出 `CC_MIPS`/`AR_MIPS`/`TMPDIR` 后按 `sdk → vendor → host-mbedtls → core → tests → ncm` 原样执行;每步日志落 `~/.cache/meow-ncm-build/logs/`。缺省 `all`,也可单步跑。 |
|
||||
| `libs_common.sh` | `CC_MIPS`/`AR_MIPS` 由硬编码 `/home/Aska/...` 改为 `MEOW_R3PROII_ROOT`(缺省 `$HOME/Project/R3ProII`)+ 环境变量可覆盖;容器行为不变。 |
|
||||
| `build_mbedtls.sh` | 清旧对象从 `library/*.o` 改为递归清 `library/` + `3rdparty/`(everest/p256-m 的对象在 3rdparty),否则混架构对象会被归档进库。 |
|
||||
| `test/test_ncm_core.c` | 三处硬编码 `/tmp`(store/cache/tag)改为 `$TMPDIR` 优先,默认 data_dir 同改;Termux `/tmp` 不可写,否则 deviceId 持久化/机器密钥直接 FAIL。 |
|
||||
|
||||
> 任务建议的 `build_ncm_host.sh` 名称已被「宿主 UI 截图/内存 harness」占用,适配层改用 `build_ncm_cross_host.sh`。
|
||||
|
||||
### 40.2 构建结果
|
||||
|
||||
| 项 | 结果 |
|
||||
|---|---|
|
||||
| `build_sdk_host.sh --verify` | 75 成员(31 OBJS + meow_font.o + 43 freetype),全 ELF32 MIPS32 rel2(o32);`meow_ui.a` 5,701,866 B;本机约 16s |
|
||||
| mbedtls(裁剪 config,102 enabled) | mipsel:crypto text 267,933 / x509 39,074 / tls 112,485(合计 419,492 ≈ 410 KB) |
|
||||
| `build_ncm.sh` | `ncm` **1,193,464 B**;text 1,084,494 / data 1,948 / bss 1,493,360;ELF32 MIPS32 rel2、静态链接、已 strip;**0 warning**(自有代码 -Wall -Wextra) |
|
||||
| md5 | `1bbd2a5527dc992de60cdf4b0ba8656d` |
|
||||
| 耗时 | 首次整链约 13s;清空 `out/app-mipsel` 后重编 39 个对象约 5s(zig cc 进程级缓存命中) |
|
||||
|
||||
### 40.3 宿主全量测试(补齐 M5/M6 缺口)
|
||||
|
||||
| 测试 | 结果 |
|
||||
|---|---|
|
||||
| `test/test_ncm_core_host`(全量,含 M5 `test_cache_tag` / M6 `test_cache_actual_naming`) | **139 PASS / 0 FAIL / 2 SKIP**(SKIP 均为 live 网络项:Termux 环境 unikey rc=-5;计数不含 `== RESULT: PASS ==` 横幅) |
|
||||
| `test/test_ncm_tag_host`(FLAC/MP3 tag 嵌入/读回/分块/降级) | **52 PASS / 0 FAIL** |
|
||||
| `test/test_ncm_cache_host`(实际档命名/命中下探/旧名兼容/LRU) | **63 PASS / 0 FAIL** |
|
||||
| 告警 | core/tag/cache/ncm 各构建日志 `warning:` 计数均为 0 |
|
||||
| mipsel 测试二进制 | `out/test_ncm_core_mipsel` text 545,098 链接成功;本机无 `qemu-mipsel`,未执行 |
|
||||
|
||||
### 40.4 真机热更(白名单仅 MeowAPPs/dev.player.ncm/)
|
||||
|
||||
- 设备 `root@10.76.208.50`,`app.json.exec=/usr/data/mnt/sd_0/MeowAPPs/dev.player.ncm/ncm`。
|
||||
- 旧件 md5 `276b6caaf3212389f7f9dab1c289ac27`(1,160,092 B)→ 备份 `ncm.bak.276b6caaf3212389f7f9dab1c289ac27`(同目录;原有 `ncm.bak` 保留)。
|
||||
- 新件经 `ssh 'cat > ncm.new'` 流式写入 → 卡上 md5 核对一致 → `chmod 755` + `mv` → `sync`。
|
||||
- 卡上 md5 `1bbd2a5527dc992de60cdf4b0ba8656d` == 本地;大小 1,193,464 B。
|
||||
- **红线校验**:`du -s /usr/data/mnt/sd_0/Music` 写前/写后均为 **199,164,288 B**,恒定;未触碰 Music/MeowData/固件,未重启设备。
|
||||
- 生效方式:launcher 直接执行 `MeowAPPs/<pkg>/` 二进制,替换文件即生效,app 列表无需 rescan。热更时 ncm 未在运行,用户重新打开 App 即加载新件(物理验收由用户做)。
|
||||
|
||||
### 40.5 遗留
|
||||
|
||||
- **mipsel 侧未运行**:本机无 `qemu-mipsel`,`out/test_ncm_core_mipsel` 只完成编译+链接;真机功能验证依赖用户打开 App(顶栏入口/列表)。
|
||||
- **live 网络测试跳过**:Termux 环境 HTTPS 到 music.163.com 返回 rc=-5(网络/证书被拒),2 项 SKIP;加密/缓存/API 解析等离线项全部 PASS。
|
||||
- **产物不入库**:`ncm` 二进制、`meow_ui.a`、vendor、`out/` 均只在本机产出;仓库中原本被跟踪的旧 `ncm`/`test_ncm_core_host` 已恢复为 HEAD 版本,避免把本机构建产物带进提交。
|
||||
- 卡上保留两份备份(`ncm.bak` 与 `ncm.bak.<旧md5>`),需要回滚可 `cp` 任一覆盖。
|
||||
@@ -51,7 +51,9 @@ touch "$MB/library/error.c" "$MB/library/version_features.c" \
|
||||
"$MB/library/psa_crypto_driver_wrappers.h" \
|
||||
"$MB/library/psa_crypto_driver_wrappers_no_static.c"
|
||||
# 关键:config 变更不会自动触发 .c 重编,务必清掉旧对象/库再重编,否则 PEM 等新启用模块不会进库。
|
||||
rm -f "$MB/library"/*.o "$MB/library"/*.a
|
||||
# everest/ p256-m 的对象在 3rdparty/ 下,也要清,否则上一轮(如宿主 gcc)对象会被归档进 mipsel 库。
|
||||
find "$MB/library" "$MB/3rdparty" -name '*.o' -delete
|
||||
find "$MB/library" "$MB/3rdparty" -name '*.a' -delete
|
||||
|
||||
BM="$OUT/mbedtls/mipsel"; rm -rf "$BM"; mkdir -p "$BM"
|
||||
# 在 vendor 源码内建,输出到本 app 的 out 目录
|
||||
|
||||
Executable
+149
@@ -0,0 +1,149 @@
|
||||
#!/bin/bash
|
||||
# build_ncm_cross_host.sh — 在 Termux/本机(非容器)跑通 ncm 的容器交叉链路。
|
||||
#
|
||||
# 原构建脚本假定容器布局:build_ncm.sh 用 $HOME/Project/R3ProII/.tools 与
|
||||
# .tools/mipsel-linux-muslsf-cross/mipsel-linux-muslsf(libz.a);libs_common.sh 指向
|
||||
# /home/Aska/...;build_sdk.sh 从 meow_launcherd 取 meow_font.a。本脚本不改这些脚本,
|
||||
# 而是临时布局一个同构 $HOME(符号链接到本机真实工具链/仓库),再原样执行:
|
||||
# 1) .tools/zig-mipsel-cc -> ~/.tools/zig-mipsel-cc
|
||||
# 2) .tools/mipsel-linux-muslsf-cross/mipsel-linux-muslsf
|
||||
# -> ~/.tools/mipsel-linux-musleabi-sysroot(含 lib/libz.a)
|
||||
# 3) .tools/zig-env/bin/zig -> 包装器:`zig ar` 转系统 GNU ar(架构无关)
|
||||
# 4) launcher 镜像目录:仓库 meow_launcherd 头文件 + 取回的 meow_font.a(*.a 不入库)
|
||||
#
|
||||
# 依赖(均不入库):
|
||||
# ~/.tools/zig-mipsel-cc
|
||||
# ~/.tools/mipsel-linux-musleabi-sysroot
|
||||
# patch_v2/sdk/vendor/freetype-src FreeType 2.14.3 源
|
||||
# patch_v2/ncm_app/vendor/{mbedtls,jsmn,minimp3,qrcodegen,dr_flac}
|
||||
# meow_font.a:默认找 patch_v2/meow_launcherd/meow_font.a,否则 <WORK>/launcher/meow_font.a
|
||||
#
|
||||
# 用法:
|
||||
# bash patch_v2/ncm_app/build_ncm_cross_host.sh [all|prep|sdk|vendor|host-mbedtls|core|tests|ncm]
|
||||
# 缺省 all;各步日志写 <WORK>/logs/<step>.log(WORK 默认 ~/.cache/meow-ncm-build)。
|
||||
set -e
|
||||
|
||||
SELF_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
REPO_ROOT="$(cd "$SELF_DIR/../.." && pwd)"
|
||||
WORK="${NCM_CROSS_WORK:-$HOME/.cache/meow-ncm-build}"
|
||||
LOGS="$WORK/logs"
|
||||
HOMELAYOUT="$WORK/home"
|
||||
PROJ="$HOMELAYOUT/Project/R3ProII"
|
||||
TOOLS="${MEOW_TOOLS_DIR:-$HOME/.tools}"
|
||||
SYSROOT="${MEOW_SYSROOT:-$TOOLS/mipsel-linux-musleabi-sysroot}"
|
||||
FONT_A="${MEOW_FONT_A:-$REPO_ROOT/patch_v2/meow_launcherd/meow_font.a}"
|
||||
|
||||
usage() { sed -n '2,26p' "$0" | sed 's/^# \{0,1\}//'; }
|
||||
|
||||
prep() {
|
||||
mkdir -p "$PROJ/.tools/mipsel-linux-muslsf-cross" "$PROJ/.tools/zig-env/bin" "$LOGS" "$WORK/tmp"
|
||||
ln -sfn "$TOOLS/zig-mipsel-cc" "$PROJ/.tools/zig-mipsel-cc"
|
||||
ln -sfn "$SYSROOT" "$PROJ/.tools/mipsel-linux-muslsf-cross/mipsel-linux-muslsf"
|
||||
cat > "$PROJ/.tools/zig-env/bin/zig" <<'EOF'
|
||||
#!/bin/sh
|
||||
[ "$1" = ar ] && shift
|
||||
exec ar "$@"
|
||||
EOF
|
||||
chmod +x "$PROJ/.tools/zig-env/bin/zig"
|
||||
|
||||
mkdir -p "$WORK/launcher-mirror"
|
||||
for f in "$REPO_ROOT"/patch_v2/meow_launcherd/*; do
|
||||
b="$(basename "$f")"
|
||||
[ "$b" = meow_font.a ] && continue
|
||||
ln -sfn "$f" "$WORK/launcher-mirror/$b"
|
||||
done
|
||||
if [ -f "$FONT_A" ]; then
|
||||
ln -sfn "$FONT_A" "$WORK/launcher-mirror/meow_font.a"
|
||||
elif [ -f "$WORK/launcher/meow_font.a" ]; then
|
||||
ln -sfn "$WORK/launcher/meow_font.a" "$WORK/launcher-mirror/meow_font.a"
|
||||
else
|
||||
echo "缺少 meow_font.a(放 patch_v2/meow_launcherd/ 或 $WORK/launcher/,或设 MEOW_FONT_A)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
[ -x "$PROJ/.tools/zig-mipsel-cc" ] || { echo "缺少交叉编译器: $TOOLS/zig-mipsel-cc" >&2; exit 1; }
|
||||
[ -f "$PROJ/.tools/mipsel-linux-muslsf-cross/mipsel-linux-muslsf/lib/libz.a" ] || {
|
||||
echo "缺少 sysroot libz.a: $SYSROOT/lib/libz.a" >&2; exit 1; }
|
||||
echo "== prep OK:$HOMELAYOUT =="
|
||||
}
|
||||
|
||||
# 各步共用:同构 HOME + 显式 CC/AR(libs_common.sh 支持覆盖)+ Termux 可写 TMPDIR
|
||||
export HOME="$HOMELAYOUT"
|
||||
export CC_MIPS="$PROJ/.tools/zig-mipsel-cc"
|
||||
export AR_MIPS="$(command -v ar)"
|
||||
export TMPDIR="$WORK/tmp"
|
||||
|
||||
run() {
|
||||
local name="$1"; shift
|
||||
echo "== [$name] $*"
|
||||
set +e
|
||||
( "$@" ) 2>&1 | tee "$LOGS/$name.log"
|
||||
local rc=${PIPESTATUS[0]}
|
||||
set -e
|
||||
[ "$rc" -eq 0 ] || { echo "[FAIL] $name rc=$rc(日志 $LOGS/$name.log)" >&2; exit "$rc"; }
|
||||
}
|
||||
|
||||
step_sdk() {
|
||||
run sdk env LAUNCHER_DIR="$WORK/launcher-mirror" bash "$REPO_ROOT/patch_v2/sdk/build_sdk_host.sh" --verify
|
||||
}
|
||||
|
||||
step_vendor() {
|
||||
cd "$SELF_DIR"
|
||||
run vendor bash ./build_mbedtls.sh
|
||||
}
|
||||
|
||||
# 宿主 mbedtls:复用 vendor 步骤已裁剪并应用的 config,gcc 重编同一套库给宿主测试。
|
||||
step_host_mbedtls() {
|
||||
local MB="$SELF_DIR/vendor/mbedtls" BM="$SELF_DIR/out/mbedtls/host"
|
||||
[ -f "$MB/include/mbedtls/mbedtls_config.h" ] || { echo "先跑 vendor 步骤(config 未就绪)" >&2; exit 1; }
|
||||
# everest/ p256-m 的对象在 3rdparty/ 下(library/ 里只有 *.c 引子);只删 library/*.o 会留下
|
||||
# 上一轮的 mipsel 对象,归档后与宿主对象混架构(ld: incompatible with aarch64linux)。
|
||||
find "$MB/library" "$MB/3rdparty" -name '*.o' -delete
|
||||
find "$MB/library" "$MB/3rdparty" -name '*.a' -delete
|
||||
rm -rf "$BM"; mkdir -p "$BM"
|
||||
run host-mbedtls make -C "$MB" lib CC=gcc AR=ar \
|
||||
CFLAGS="-O2 -Wno-unused-parameter -fno-stack-protector"
|
||||
for a in libmbedcrypto.a libmbedx509.a libmbedtls.a; do
|
||||
[ -s "$MB/library/$a" ] && cp "$MB/library/$a" "$BM/$a"
|
||||
done
|
||||
ls -la "$BM"
|
||||
}
|
||||
|
||||
step_core() {
|
||||
cd "$SELF_DIR"
|
||||
run core bash ./build_core.sh
|
||||
local DATA="$WORK/ncm_test"
|
||||
rm -rf "$DATA"; mkdir -p "$DATA"
|
||||
run core-test ./test/test_ncm_core_host "$DATA"
|
||||
}
|
||||
|
||||
step_tests() {
|
||||
cd "$SELF_DIR"
|
||||
run tag-build bash ./build_ncm_tag_host.sh
|
||||
run tag-test ./test/test_ncm_tag_host
|
||||
run cache-build bash ./build_ncm_cache_host.sh
|
||||
run cache-test ./test/test_ncm_cache_host
|
||||
}
|
||||
|
||||
step_ncm() {
|
||||
cd "$SELF_DIR"
|
||||
run ncm bash ./build_ncm.sh
|
||||
# 只匹配编译器告警本身;build_ncm.sh 结尾的 "0 warning enforced" 总结不是告警。
|
||||
if grep -i "warning:" "$LOGS/ncm.log"; then
|
||||
echo "[FAIL] ncm 构建出现告警(要求 0 warning)" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
case "${1:-all}" in
|
||||
prep) prep ;;
|
||||
sdk) prep; step_sdk ;;
|
||||
vendor) prep; step_vendor ;;
|
||||
host-mbedtls) prep; step_host_mbedtls ;;
|
||||
core) prep; step_core ;;
|
||||
tests) prep; step_tests ;;
|
||||
ncm) prep; step_ncm ;;
|
||||
all) prep; step_sdk; step_vendor; step_host_mbedtls; step_core; step_tests; step_ncm ;;
|
||||
-h|--help) usage ;;
|
||||
*) echo "未知步骤: $1(all|prep|sdk|vendor|host-mbedtls|core|tests|ncm)" >&2; exit 2 ;;
|
||||
esac
|
||||
@@ -3,8 +3,10 @@
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
VENDOR="$ROOT/vendor"
|
||||
OUT="$ROOT/out"
|
||||
CC_MIPS="/home/Aska/Project/R3ProII/.tools/zig-mipsel-cc"
|
||||
AR_MIPS="/home/Aska/Project/R3ProII/.tools/zig-env/bin/zig ar"
|
||||
# 容器默认 $HOME/Project/R3ProII(= /home/Aska/Project/R3ProII);宿主适配层可整组覆盖
|
||||
R3ROOT="${MEOW_R3PROII_ROOT:-$HOME/Project/R3ProII}"
|
||||
CC_MIPS="${CC_MIPS:-$R3ROOT/.tools/zig-mipsel-cc}"
|
||||
AR_MIPS="${AR_MIPS:-$R3ROOT/.tools/zig-env/bin/zig ar}"
|
||||
CC_HOST="gcc"
|
||||
SZ_HOST="size"
|
||||
# 交叉 bin 是 x86_64 的,本机(aarch64)跑不了;统一用 host `size`(可读任意 ELF)+ zig ar。
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
* 缓存 LRU、设备键/cookie 加解密、二维码矩阵、以及
|
||||
* 网络接口(unikey 实拿 / 轮询 801 / 无凭据错误处理)。
|
||||
* 网络不可用时网络项按 SKIP 处理,不判失败;内部逻辑错才 FAIL。
|
||||
* 用法:test_ncm_core [data_dir](缺省 /tmp/ncm_test)
|
||||
* 用法:test_ncm_core [data_dir](缺省 $TMPDIR/ncm_test,未设则 /tmp/ncm_test)
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -87,7 +87,11 @@ static void test_crypto(void) {
|
||||
static void test_store_cookie(void) {
|
||||
printf("== store/device/cookie ==\n");
|
||||
ncm_store_t st;
|
||||
ncm_store_init(&st, NULL); /* env MEOW_DATA_DIR 或 /tmp */
|
||||
/* 不传 NULL:默认回退 /tmp(Termux 不可写 → deviceId 需持久化、机器密钥需落盘,都会失败) */
|
||||
const char *tmpbase = getenv("TMPDIR");
|
||||
char sdir[256];
|
||||
snprintf(sdir, sizeof sdir, "%s/ncm_store_test", (tmpbase && tmpbase[0]) ? tmpbase : "/tmp");
|
||||
ncm_store_init(&st, sdir);
|
||||
char id1[NCM_STORE_ID_MAX], id2[NCM_STORE_ID_MAX];
|
||||
ncm_store_get_device_id(&st, id1);
|
||||
ncm_store_get_device_id(&st, id2);
|
||||
@@ -108,10 +112,13 @@ static void test_store_cookie(void) {
|
||||
static void test_cache(void) {
|
||||
printf("== cache ==\n");
|
||||
ncm_cache_t c;
|
||||
char dir[] = "/tmp/ncm_cache_test";
|
||||
/* Termux /tmp 不可写:跟随 $TMPDIR(与 test_cache_actual_naming / tag、cache 单测一致) */
|
||||
const char *tmpbase = getenv("TMPDIR");
|
||||
char dir[256];
|
||||
snprintf(dir, sizeof dir, "%s/ncm_cache_test", (tmpbase && tmpbase[0]) ? tmpbase : "/tmp");
|
||||
/* 清空目录(须在 init 前:init 会建 songs/covers 子目录,rm -rf 会一并删掉) */
|
||||
{
|
||||
char cmd[128];
|
||||
char cmd[320];
|
||||
snprintf(cmd, sizeof cmd, "rm -rf %s; mkdir -p %s", dir, dir);
|
||||
if (system(cmd) != 0) { /* best-effort */ }
|
||||
}
|
||||
@@ -193,9 +200,11 @@ static void make_flac_bytes(unsigned char *buf, size_t *len, int bps)
|
||||
static void test_cache_tag(void) {
|
||||
printf("== cache tag embed + scan (M5) ==\n");
|
||||
ncm_cache_t c;
|
||||
char dir[] = "/tmp/ncm_tag_cache";
|
||||
const char *tmpbase = getenv("TMPDIR");
|
||||
char dir[256];
|
||||
snprintf(dir, sizeof dir, "%s/ncm_tag_cache", (tmpbase && tmpbase[0]) ? tmpbase : "/tmp");
|
||||
{
|
||||
char cmd[160];
|
||||
char cmd[320];
|
||||
snprintf(cmd, sizeof cmd, "rm -rf %s; mkdir -p %s", dir, dir);
|
||||
if (system(cmd) != 0) { /* best-effort */ }
|
||||
}
|
||||
@@ -762,7 +771,10 @@ static void test_json_unescape(void) {
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
const char *data_dir = (argc > 1) ? argv[1] : "/tmp/ncm_test";
|
||||
const char *tmpbase = getenv("TMPDIR");
|
||||
char def_dir[256];
|
||||
snprintf(def_dir, sizeof def_dir, "%s/ncm_test", (tmpbase && tmpbase[0]) ? tmpbase : "/tmp");
|
||||
const char *data_dir = (argc > 1) ? argv[1] : def_dir;
|
||||
printf("ncm_core self-test, data_dir=%s\n", data_dir);
|
||||
ncm_ctx_t ctx;
|
||||
ncm_ctx_init(&ctx, data_dir);
|
||||
|
||||
Reference in new issue
Block a user