Files
MeowOS-For-R3P2/patch_v2/reader_app/build_reader.sh
T
AskaEth 409fd1edf7 feat(reader): M27 书架按目录分组(ui.shelf_group=folder|format,默认 format 不变)
- 新增 shelf_model.c/.h:扫描/行序列从 shelf.c 拆出(纯 C,宿主可测);shelf_book 加 group[96](相对 Books/ 的目录路径,根下空串),path 语义/内容完全不变(进度键仍为 rdprog_hash(path))
- folder 模式:目录段头(根下=未分类),未分类置顶、其余按目录名排序;组内沿用最近阅读优先/其次书名;空目录不产生段头
- format 模式逐行保持旧行为;新增 reader.conf ui.shelf_group,缺键默认 format
- 上限 256→2048(SHELF_MAX_ROWS=2N=4096,段头≤书数),超限置可读提示,不再静默截断
- 顶栏加「目录/格式」切换,设置页加「书架分组」;UTF-8 安全截断长中文目录名
- 单测 test/shelf_group_smoke.c(38 断言)+ 计时 test/shelf_scan_bench.c
- build_reader.sh:链 meow_ui.a 解析冒烟 stbi_*;无 qemu 时跳过执行而非失败
2026-11-09 21:55:33 +08:00

173 lines
10 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# build_reader.sh — os.meow.reader R2 可复现构建:
# vendor: freetype(静态)/miniz/libmobi/stb/zlib 头 → 交叉 mipsel 编 reader 二进制
# + 宿主 core 单测(R1+loaders) + qemu-mipsel 冒烟(rdft/book/formats)。
#
# 产物:
# reader mipsel 静态 ELF(链 meow_ui.a + freetype + miniz + libmobi + zlib)
# test/test_reader_core_host 宿主 core 单测(enc/layout/txt)
# test/loaders_smoke_host 宿主四格式 loader 单测
# test/rdft_smoke_mipsel qemu-mipsel FreeType 冒烟
# test/book_smoke_mipsel qemu-mipsel TXT 书桥冒烟
# test/formats_smoke_mipsel qemu-mipsel 四格式书桥冒烟
#
# 约束:只写本目录(patch_v2/reader_app/);不改 sdk/;-Wall -Wextra 0 warning(自有代码)。
# vendor/(第三方源码+构建产物)gitignore,不入仓;build 脚本可复现。
set -e
cd "$(dirname "$0")"
ROOT="$HOME/Project/R3ProII"
CC="$ROOT/.tools/zig-mipsel-cc"
SYSROOT="$ROOT/.tools/mipsel-linux-muslsf-cross/mipsel-linux-muslsf"
HOST_CC="${HOST_CC:-gcc}"
VENDOR="$PWD/vendor"
OBJ="$VENDOR/build"
# qemu-mipsel 运行时冒烟:宿主没装 qemu(如 Termux 无 mipsel user-mode 包)时,
# 仍编译 mipsel 冒烟二进制,只跳过执行;设 QEMU_BIN=<路径> 可指定其它模拟器。
QEMU_BIN="${QEMU_BIN:-qemu-mipsel}"
run_qemu() {
if [ "${SKIP_QEMU:-0}" = 1 ] || ! command -v "$QEMU_BIN" >/dev/null 2>&1; then
shift
echo " SKIP qemu 执行(未找到 $QEMU_BIN):$*"
return 0
fi
timeout "$@"
}
mkdir -p "$OBJ"
# ---------- 1) vendor 拉取/对齐 ----------
FT_VER="2.14.3"; MINIZ_URL="https://codeload.github.com/richgel999/miniz/tar.gz/refs/heads/master"
# libmobi 版本锁定:见 NOTICE「Locked version (commit)」。LGPL-3.0 §4(d) 要求「已分发二进制
# 对应的 libmobi 源码」与公开源码一致可复现,故不用 refs/heads/master(移动分支),改锁到精确
# commit SHA(2024-10-29 的 9062742...,与上级代理 agent-332 复验/NOTICE 声明一致,已验证可拉取)。
LM_URL="https://codeload.github.com/bfabiszewski/libmobi/tar.gz/906274205c11944b628da1c553b255acb1af7c55"
mkdir -p "$VENDOR"
fetch_freetype() {
if [ -n "$FREETYPE_SRC" ] && [ -f "$FREETYPE_SRC/CMakeLists.txt" ]; then cp -r "$FREETYPE_SRC" vendor/freetype-src;
elif [ ! -d "$VENDOR/freetype-src" ] && [ -f /tmp/freetype/CMakeLists.txt ]; then cp -r /tmp/freetype "$VENDOR/freetype-src";
elif [ ! -d "$VENDOR/freetype-src" ]; then
( cd "$VENDOR" && curl -fsSL -o ft.tar.xz "https://download.savannah.gnu.org/releases/freetype/freetype-$FT_VER.tar.xz" \
&& mkdir -p freetype-src && tar xf ft.tar.xz -C freetype-src --strip-components=1 && rm ft.tar.xz )
fi
[ -f "$VENDOR/freetype-src/CMakeLists.txt" ] || { echo "freetype 不可用"; exit 1; }
}
fetch_miniz() {
if [ ! -f "$VENDOR/miniz/miniz.c" ]; then
( cd /tmp && curl -fsSL -o miniz.tgz "$MINIZ_URL" && mkdir -p miniz_m && tar xzf miniz.tgz -C miniz_m --strip-components=1 \
&& cp miniz_m/miniz.c miniz_m/miniz.h miniz_m/miniz_common.h miniz_m/miniz_tdef.c miniz_m/miniz_tdef.h \
miniz_m/miniz_tinfl.c miniz_m/miniz_tinfl.h miniz_m/miniz_zip.c miniz_m/miniz_zip.h "$VENDOR/miniz/" )
fi
[ -f "$VENDOR/miniz/miniz.c" ] || { echo "miniz 不可用"; exit 1; }
}
fetch_libmobi() {
# 若 vendor/libmobi 来自旧版(LM_URL 改 pin 前抓的 master),请先删 vendor/libmobi 再重跑,
# 以确保取到下方锁定的 commit。此处仅在其缺失时拉取。
if [ ! -f "$VENDOR/libmobi/src/mobi.h" ]; then
( cd /tmp && curl -fsSL -o lm.tgz "$LM_URL" && mkdir -p lm_m && tar xzf lm.tgz -C lm_m --strip-components=1 \
&& mkdir -p "$VENDOR/libmobi" && cp -r lm_m/src "$VENDOR/libmobi/src" && cp lm_m/COPYING "$VENDOR/libmobi/COPYING" )
fi
[ -f "$VENDOR/libmobi/src/mobi.h" ] || { echo "libmobi 不可用"; exit 1; }
}
fetch_stb() { [ -f "$VENDOR/stb/stb_image.h" ] || { mkdir -p "$VENDOR/stb"; cp "$ROOT/patch_v2/sdk/stb_image.h" "$VENDOR/stb/stb_image.h"; }; }
fetch_freetype; fetch_miniz; fetch_libmobi; fetch_stb
if [ ! -f "$VENDOR/zlib/zlib.h" ]; then mkdir -p "$VENDOR/zlib"; cp /usr/include/zlib.h /usr/include/zconf.h "$VENDOR/zlib/" 2>/dev/null || true; fi
# ---------- 2) FreeType mipsel 静态构建 ----------
FT_SRC="$VENDOR/freetype-src"; FT_BUILD="$VENDOR/freetype-build"
if [ ! -f "$FT_BUILD/libfreetype.a" ] || [ -n "$FORCE_FT" ]; then
rm -rf "$FT_BUILD"
cmake -S "$FT_SRC" -B "$FT_BUILD" -DCMAKE_SYSTEM_NAME=Linux -DCMAKE_C_COMPILER="$CC" \
-DCMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=OFF \
-DFT_DISABLE_ZLIB=TRUE -DFT_DISABLE_BZIP2=TRUE -DFT_DISABLE_PNG=TRUE -DFT_DISABLE_HARFBUZZ=TRUE -DFT_DISABLE_BROTLI=TRUE >/dev/null
cmake --build "$FT_BUILD" -j"$(nproc)" >/dev/null 2>&1
fi
FT_INCS="-I$FT_BUILD -I$FT_BUILD/include -I$FT_SRC/include"
COREINC="-Icore -Ivendor/miniz -Ivendor/stb -Ivendor/libmobi/src -Ivendor/zlib"
MZFLAGS="-DMINIZ_NO_ZLIB_COMPATIBLE_NAMES -DMINIZ_NO_TIME"
# ---------- 3) miniz + libmobi 对象(mipsel) ----------
build_mipsel_libs() {
for f in vendor/miniz/miniz_tinfl.c vendor/miniz/miniz_tdef.c vendor/miniz/miniz_zip.c vendor/miniz/miniz.c; do
b="$(basename "$f" .c)"; [ -f "$OBJ/mz_$b.o" ] || $CC -Os -static -Wall -Wextra -Ivendor/miniz $MZFLAGS -c "$f" -o "$OBJ/mz_$b.o"
done
for f in vendor/libmobi/src/*.c; do b="$(basename "$f" .c)"; [ "$b" = "miniz" ] && continue
[ -f "$OBJ/lm_$b.o" ] || $CC -Os -static -w -Ivendor/libmobi/src -Ivendor/zlib -c "$f" -o "$OBJ/lm_$b.o"
done
# stb_image 的实现由 meow_ui.a 提供(SDK 自 M6.45 收编 stb_image.c.o);此处只编封装,
# 否则链接 meow_ui.a 时 stbi_* 会与归档内 stb_image.o 重复定义。
[ -f "$OBJ/rdimg.o" ] || $CC -Os -static -Wall -Wextra -Ivendor/stb -c engine/rdimg.c -o "$OBJ/rdimg.o"
}
build_mipsel_libs
# ---------- 4) 宿主 loader 单测(miniz/libmobi 用宿主编一遍) ----------
echo "==> host core test (R1)"
$HOST_CC -O2 -Wall -Wextra -Icore -I. test/test_reader_core.c core/rdenc.c core/rdlayout.c core/rdtxt.c -o test/test_reader_core_host -lm
./test/test_reader_core_host
echo "==> host seg test (R3.2)"
$HOST_CC -O2 -Wall -Wextra -Icore test/seg_smoke.c core/seg.c core/rdenc.c -o test/seg_smoke_host -lm
./test/seg_smoke_host
echo "==> host chapter test (R3.3)"
$HOST_CC -O2 -Wall -Wextra -Icore test/chapter_smoke.c core/rdchapter.c core/seg.c core/rdenc.c -o test/chapter_smoke_host -lm
./test/chapter_smoke_host
echo "==> host shelf group test (M27)"
$HOST_CC -O2 -Wall -Wextra -Iapp -I../sdk test/shelf_group_smoke.c app/shelf_model.c app/progress.c app/reader_conf.c -o test/shelf_group_smoke_host
./test/shelf_group_smoke_host
echo "==> host shelf scan bench (M27,只编不跑;用法 ./test/shelf_scan_bench_host <Books目录> [progress|noop] [轮数])"
$HOST_CC -O2 -Wall -Wextra -Iapp -I../sdk test/shelf_scan_bench.c app/shelf_model.c app/progress.c -o test/shelf_scan_bench_host
echo "==> host loaders test"
HOBJ="$OBJ/host"; mkdir -p "$HOBJ"
for f in vendor/miniz/miniz_tinfl.c vendor/miniz/miniz_tdef.c vendor/miniz/miniz_zip.c vendor/miniz/miniz.c; do
b="$(basename "$f" .c)"; [ -f "$HOBJ/mz_$b.o" ] || $HOST_CC -O2 -Ivendor/miniz $MZFLAGS -c "$f" -o "$HOBJ/mz_$b.o"
done
for f in vendor/libmobi/src/*.c; do b="$(basename "$f" .c)"; [ "$b" = "miniz" ] && continue
[ -f "$HOBJ/lm_$b.o" ] || $HOST_CC -O2 -w -Ivendor/libmobi/src -Ivendor/zlib -c "$f" -o "$HOBJ/lm_$b.o"
done
HCORE=""
for f in rdxml rdhtml rdsb rdzip rdsrc rdepub rdfb2 rdmobi rdcbz rdenc rdtxt; do
$HOST_CC -O2 -Wall -Wextra $COREINC -c core/$f.c -o "$HOBJ/core_$f.o"
done
python3 tools/gen_samples.py >/dev/null
$HOST_CC -O2 -Wall -Wextra $COREINC test/loaders_smoke.c "$HOBJ"/*.o -lz -lm -o test/loaders_smoke_host
./test/loaders_smoke_host /tmp/rd_samples
# ---------- 5) qemu-mipsel FreeType 冒烟 ----------
echo "==> mipsel ft smoke"
$CC -Os -static -Wall -Wextra -Iengine $FT_INCS test/rdft_smoke.c engine/rdft.c "$FT_BUILD/libfreetype.a" -o test/rdft_smoke_mipsel
run_qemu 120 "$QEMU_BIN" ./test/rdft_smoke_mipsel "${FONT:-$ROOT/font/src/MiSans-Regular.otf}"
# ---------- 6) qemu-mipsel 书桥冒烟(TXT + 四格式) ----------
# rdimg.o 引用 stbi_*,实现只在 sdk/meow_ui.a 里(见步骤 3 注释);冒烟不链 UI 主体,
# 但必须链该归档才能解析 stbi_*(归档按需只拉 stb_image.o)。
echo "==> mipsel book smoke (TXT)"
$CC -Os -static -Wall -Wextra -Iapp -Icore -Iengine $FT_INCS $COREINC test/book_smoke.c \
app/book.c core/rdenc.c core/rdlayout.c core/rdtxt.c core/seg.c core/rdchapter.c core/rdxml.c core/rdhtml.c core/rdsb.c core/rdzip.c \
core/rdsrc.c core/rdepub.c core/rdfb2.c core/rdmobi.c core/rdcbz.c engine/rdft.c \
"$OBJ"/mz_*.o "$OBJ"/lm_*.o "$OBJ"/rdimg.o ../sdk/meow_ui.a "$SYSROOT/lib/libz.a" "$FT_BUILD/libfreetype.a" -o test/book_smoke_mipsel
run_qemu 120 "$QEMU_BIN" ./test/book_smoke_mipsel "${FONT:-$ROOT/font/src/MiSans-Regular.otf}"
echo "==> mipsel formats smoke"
$CC -Os -static -Wall -Wextra -Iapp -Icore -Iengine $FT_INCS $COREINC test/formats_smoke.c \
app/book.c core/rdenc.c core/rdlayout.c core/rdtxt.c core/seg.c core/rdchapter.c core/rdxml.c core/rdhtml.c core/rdsb.c core/rdzip.c \
core/rdsrc.c core/rdepub.c core/rdfb2.c core/rdmobi.c core/rdcbz.c engine/rdft.c \
"$OBJ"/mz_*.o "$OBJ"/lm_*.o "$OBJ"/rdimg.o ../sdk/meow_ui.a "$SYSROOT/lib/libz.a" "$FT_BUILD/libfreetype.a" -o test/formats_smoke_mipsel
run_qemu 150 "$QEMU_BIN" ./test/formats_smoke_mipsel "${FONT:-$ROOT/font/src/MiSans-Regular.otf}" /tmp/rd_samples
# ---------- 7) reader 二进制(mipsel 静态) ----------
echo "==> reader binary"
CORE_L="core/rdenc.c core/rdlayout.c core/rdtxt.c core/seg.c core/rdchapter.c core/rdxml.c core/rdhtml.c core/rdsb.c core/rdzip.c core/rdsrc.c core/rdepub.c core/rdfb2.c core/rdmobi.c core/rdcbz.c"
ENGINE_L="engine/rdft.c"
APP_L="app.c app/shelf.c app/shelf_model.c app/reader.c app/book.c app/progress.c app/settings.c app/reader_conf.c app/reader_ipc.c"
$CC -Os -static -Wall -Wextra -I../sdk -I../meow_launcherd -I. -Icore -Iapp -Iengine $FT_INCS $COREINC \
$CORE_L $APP_L $ENGINE_L "$OBJ"/mz_*.o "$OBJ"/lm_*.o "$OBJ"/rdimg.o \
../sdk/meow_ui.a "$SYSROOT/lib/libz.a" "$FT_BUILD/libfreetype.a" -lpthread -o reader
ls -la reader
file reader
md5sum reader
echo " 运行(qemu): qemu-mipsel ./reader"
echo "build_reader OK"