把 Typst 搬上开源鸿蒙 PC:一次“干净”的移植记录

欢迎加入开源鸿蒙 PC 社区:https://harmonypc.csdn.net/

欢迎在 PC 社区平台申请新建项目:https://atomgit.com/OpenHarmonyPCDeveloper

适配开源地址(AtomGit):https://atomgit.com/OpenHarmonyPCDeveloper/ohos_typst

目录


项目 说明
适配软件 typst(命令行排版引擎,CLI,无图形界面)
开源协议 Apache-2.0
源码版本 v0.15.1
目标平台 鸿蒙 PC(x86_64)与 arm64 设备(鸿蒙 PC / 平板 / 开发板)
交叉目标 x86_64-unknown-linux-ohos、aarch64-unknown-linux-ohos
构建宿主 Linux x86_64(Ubuntu 24)
工具链 rustup stable ≥ 1.92(实测 1.98.1)+ zig-patch 0.16.0(zig cc / zig c++ / zig ar)
上游改动 源码零修改,仅修改 Cargo.lock 以使用更高版本依赖
产物 out/x86_64/typst(strip 后约 52 MB)、out/aarch64/typst(strip 后约 48 MB)
验证方式 静态检查与实机测试
上游地址 https://github.com/typst/typst
适配仓库 https://atomgit.com/OpenHarmonyPCDeveloper/ohos_typst

Typst 简介

Typst 是一个新兴的基于标记语言 的开源排版系统。Typst 首个版本发布于 2023 年,允许使用一种类似于 Markdown 的标记语言对文档内容进行排版,并生成 PDF、SVG、PNG 和 HTML 等格式产物。

该领域过去长期使用 LaTeX,但其诸多问题已被诟病多年:报错信息可读性极差、工具链臃肿复杂、编译速度较慢、与现代编辑器集成度较差等等。Typst 极大改善了这些问题。

本次适配的目标与产物

本次适配基于 typst v0.15.1,面向 API 24~26 的鸿蒙 PC 设备,构建环境为 Linux x86_64。适配过程遵守一条约束:上游 typst 源码树保持零修改。适配内容全部放在仓库自己的脚本与配置里,升级上游版本时只需要重新走一遍构建,不需要重新合并改动。

产物 路径 说明
鸿蒙 PC out/x86_64/typst x86_64-unknown-linux-ohos,PIE,仅依赖 libc.so
arm64 设备 out/aarch64/typst aarch64-unknown-linux-ohos,同上
宿主基线 由宿主 cargo build 得到 x86_64-linux-gnu,用于对拍
设备测试包 out/typst-ohos-0.15.1-{x86_64,aarch64}-device-test.tar.gz 产物 + 中英文样例 + 随包子集字体 + run.sh 自检脚本

不需要自己编译时,也可以直接下载预构建版:

移植路线:所有修改均在构建部分

Typst 主体使用 rust 编写,源码里没有对鸿蒙进行特别适配。编译工作完全由 rustc:Rust 官方为 aarch64-unknown-linux-ohos 与 x86_64-unknown-linux-ohos 提供 Tier 2 支持,同时提供这两个目标平台预编译的标准库,无需自行构建。C/C++ 编译和链接由 zig 提供的 zig cc / zig c++,编译产物的外部依赖只有 libc.so。

层次 上游预期 鸿蒙侧的处理方式
Rust 编译 环境 rustc rustup 安装 ohos 目标平台的标准库
C/C++ 编译 环境 cc CC_<triple> / AR_<triple> 指向 build/wrapper/<arch>/zig-cc 与 zig-ar
链接 环境 cc CARGO_TARGET_<TRIPLE>_LINKER 指向 build/wrapper/<arch>/zig-c++
C 标准库 glibc 修改的 muslc,链接时附加 build/shim/shim-ohos-<arch>.o
依赖树 Cargo.lock 中锁定的版本 升级 cc 与 shlex 两个条目的版本

build.sh 按以下步骤进行一次构建:

  1. 下载解压 typst v0.15.1 源代码到 typst-0.15.1/,解压 zig-patch 到 build/zig-ohos/;
  2. 应用 patches/ 下的代码补丁文件;
  3. 用 zig cc 用于编译符号补齐的 shim 代码;
  4. 执行 cargo build --release --package typst-cli --features vendor-openssl --target <triple> 编译;
  5. 将产物复制到 out/<arch>/typst,调用 build/strip.sh 移除符号;
  6. 静态核查产出的可执行文件。

准备工具链

Rust

Typst 主要使用 Rust 语言开发,编译时需要使用 rustc 和 cargo 项目管理器。这里使用 rustup 简化安装。

shell 复制代码
# 配置镜像源,后续所有涉及 rustup 的命令均需要重复配置
export RUSTUP_DIST_SERVER=https://mirrors.ustc.edu.cn/rust-static
export RUSTUP_UPDATE_ROOT=https://mirrors.ustc.edu.cn/rust-static/rustup

# 安装 rustup 与 Rust
curl --proto '=https' --tlsv1.2 -sSf https://mirrors.ustc.edu.cn/misc/rustup-install.sh | sh

为了加快下载进度,这里使用中国科学技术大学 Linux 用户协会提供的镜像源,替换 Rust 官方的链接。

Typst v0.15.1 的 workspace 声明了 rust-version = "1.92",edition 为 2024,因此宿主的 rustc 需要 1.92 或更高(本次实测 1.98.1)。Rust 默认安装只包含本机的工具链,我们还需要单独安装鸿蒙目标平台标准库(可能需要新打开一个终端以使用更新后的环境变量):

shell 复制代码
rustup target add aarch64-unknown-linux-ohos # arm64,必须
rustup target add x86_64-unknown-linux-ohos  # x86_64,鸿蒙 PC 与虚拟机使用

检查本机 Rust 环境:

bash 复制代码
rustc --version
cargo --version

若输出版本号则环境正常。

此外需要从系统包管理器安装一些包:

bash 复制代码
# Ubuntu 24
sudo apt update && sudo apt install -y git patch curl tar xz-utils perl binutils llvm

# Arch Linux
sudo pacman -Syu --noconfirm git patch curl tar xz perl binutils llvm

其中 patch 用于应用 patches/,binutils 提供 readelf 与 nm,llvm 提供 llvm-objcopy(用于移除符号)。

HarmonyOS SDK

编译过程中需要使用 HarmonyOS SDK,可从华为开发者联盟官网下载:

下载完成后,自行解压到特定目录即可。本移植版本的编译流程不使用 HarmonyOS SDK 提供的 C/C++ 编译器。HarmonyOS SDK 只用于使用 llvm-objcopy 清理编译符号,和提供鸿蒙环境中的 libc.a 用于静态检查符号覆盖。

Zig

这里使用对鸿蒙专门进行适配的 zig-patch 发行版,版本为 0.16.0:

build.sh 会自动下载到 downloads/zig-patch-0.16.0.tar.xz 并解压到 build/zig-ohos/,离线环境可以预先下载。

依赖与改动部分

Typst 主要使用 Rust ,仅少量依赖需要 C/C++ 或汇编编译器参与。具体来说(当指定 --package typst-cli --features vendor-openssl 时)只有 psm 与 openssl-src 两个依赖库需要,以及一个对编译器调用封装的 crate cc:

依赖 版本 使用到的非 rust 语言 在本次构建里承担什么 需要处理的事项
psm 0.1.24 汇编 提供上下文切换能力 CC_<triple> / AR_<triple> 需正确指向包装脚本
openssl-sys 和 openssl-src 0.9.116 / 300.4.1+3.4.0 C 包系统的网络支持 需要 perl
cc 1.4.5 无 上面两项都通过它使用编译器能力 上游默认版本较旧

其余用于压缩、字体、文件监控等等功能的依赖(flate2 + libz-rs-sys、fdeflate、fontdb、notify 等)均完全使用 Rust 实现,无需额外处理。

只做一处对上游提供的文件的改动,放在 patches/0001-cargo-lock-cc-bump.patch 里,内容是升级 Cargo.lock 中的两个依赖项版本:

text 复制代码
cc     1.2.11  ->  1.4.5   (同时引入 find-msvc-tools 0.1.12)
shlex  1.3.0   ->  2.0.1

这个补丁只修改配置文件 Cargo.lock,不改上游任意源码,即「源码树零修改」。观察构建日志里确认指定的升级版本确实被采用:

text 复制代码
Compiling shlex v2.0.1
Compiling cc v1.4.5
Compiling openssl-src v300.4.1+3.4.0
Compiling psm v0.1.24

适配中遇到的问题

宿主 rustc 版本低于 typst 的要求

现象。 编译环境默认提供的 rustc 版本为 1.88.0,直接执行 cargo build 会立即终止:

text 复制代码
error: package requires rustc 1.92 or newer

原因。 typst v0.15.1 的 workspace Cargo.toml 声明了 rust-version = "1.92",同时在清单文件中指定的 edition 2024 也要求较新的工具链。

处理。 使用 rustup 更新环境 rustc 等组件:执行 rustup toolchain install stable 升级到 1.98.1,再重新 rustup target add 两个 ohos 目标平台。Rust 官方的 ohos target 都是 2 级支持,可直接下载对应平台标准库。

验证。 rustc --version 输出 1.98.1,cargo build 不再出现相关错误报告。

zig cc 的接线:三元组改写与两套环境变量

现象。 把 CC 直接指向 zig cc 之后,psm 的汇编文件仍然由宿主 cc 编译,报 error occurred in cc-rs: command did not execute successfully ... "cc";vendored OpenSSL 的 Configure 也从环境里拿到了宿主的编译器。

原因有两个。

  1. 目标平台的写法差异。rustc 与 cc-rs 传给 C 编译器的是 Rust 三元组 --target=aarch64-unknown-linux-ohos,而 zig 则要求 --target=aarch64-linux-ohos。使用一个 shell 包装脚本给 zig cc 传递其预期的参数:
bash 复制代码
# build/wrapper/aarch64/zig-cc 部分内容
for a in "$@"; do
  case "$a" in
  --target=*-unknown-linux-ohos) args+=("--target=aarch64-linux-ohos") ;;
  *) args+=("$a") ;;
  esac
done
exec "$ZIG" cc -target aarch64-linux-ohos "${args[@]}"
  1. 具体选择使用 C/C++ 编译器的流程不同。调用 C 编译器不由 Cargo 直接调用,而是在对应依赖库的构建脚本中调用构建(这里通过 cc-rs);Cargo 仅负责将链接器与归档器参数传递给 rustc。于是需要指定两部分变量:
  • Cargo 侧:CARGO_TARGET_<TRIPLE 大写>_LINKER、CARGO_TARGET_<TRIPLE 大写>_AR;
  • cc-rs 侧:CC_<triple>、AR_<triple>,其中三元组里的 - 换成 _。

处理。 build.sh 导出所有需要的变量, cc-rs 部分同时提供小写与全大写两个版本,以适应不同库的差异查找规则:

bash 复制代码
export "CC_$TRIPLE_LOWER=$CC" "CC_$TRIPLE_UPPER=$CC"
export "CXX_$TRIPLE_LOWER=$CXX" "CXX_$TRIPLE_UPPER=$CXX"
export "AR_$TRIPLE_LOWER=$AR" "AR_$TRIPLE_UPPER=$AR"
export "CARGO_TARGET_${TRIPLE_UPPER}_LINKER=$CC"
export "CARGO_TARGET_${TRIPLE_UPPER}_AR=$AR"

其中 LINKER 指向的是 zig-c++,这一点在后面还会提到。

验证。 构建日志显示 psm 与 openssl-src 正确编译完成,且 psm 相关的编译产物使用目标平台架构。

依赖库引用了 musl 不导出的 mmap64

现象。 链接阶段报错,找不到 mmap64 的定义。

原因。 Typst 间接依赖了 memmap2 库 的 v0.9.5 版本。在 src/unix.rs 里,其使用下面判定决定具体调用符号:

rust 复制代码
#[cfg(any(
    target_os = "android",
    all(target_os = "linux", not(target_env = "musl"))
))]
use libc::{mmap64 as mmap, off64_t as off_t};

Rust 的 ohos 目标平台的编译信息为 target_os = "linux"、target_env = "ohos",没有被条件编译选项排除,于是 memmap2 把鸿蒙视为 glibc 环境,使用 libc::mmap64。而鸿蒙实际使用 musl ,其只导出 mmap,mmap64 没有提供。参考 alpine 的 muslc 信息:

text 复制代码
$ readelf -Ws downloads/alpine-x64-root/lib/ld-musl-x86_64.so.1 | grep -w mmap
   471: 00000000000564e7   197 FUNC    WEAK   DEFAULT   11 mmap

处理。 编译一个 C shim 把 mmap64 转发到 mmap:

c 复制代码
#include <sys/mman.h>

void *mmap64(void *addr, size_t length, int prot, int flags, int fd, long long offset) {
    return mmap(addr, length, prot, flags, fd, (off_t)offset);
}

关键细节:这个 shim 通过封装脚本参与链接。 build/wrapper/<arch>/zig-c++ 把编译好的 shim 目标文件追加进链接参数,zig-cc 则没有:

bash 复制代码
# build/wrapper/aarch64/zig-c++(节选)
SHIM="$SELF/../../shim/shim-ohos-aarch64.o"
extra=()
[ -f "$SHIM" ] && extra+=("$SHIM")
exec "$ZIG" c++ -target aarch64-linux-ohos "${extra[@]}" "${args[@]}"

之所以只在 zig-c++ 封装脚本中参与,原因是 build.sh 把 CARGO_TARGET_<TRIPLE>_LINKER 指向了这个脚本,整个程序的链接通过该脚本完成,缺失符号也会在这步导致链接失败。

验证。 链接完成后,产物里 mmap64 不再是未定义符号,只剩 musl 提供的 mmap:

text 复制代码
$ readelf -Ws out/aarch64/typst | grep -wE "mmap64|mmap"
     2: 0000000000000000     0 FUNC    GLOBAL DEFAULT  UND mmap

这条经验可以推广。 依赖中所有 not(target_env = "musl") 形式的平台判定,在鸿蒙上都会判别为 glibc 分支,因为 ohos 的 target_env 取值是 ohos,与 gnu、musl 都不相同。遇到链接阶段缺符号时,先尝试检索存不存在相同问题。

Zig SDK 不提供 objcopy,转为使用 HarmonyOS SDK 提供的 strip 能力

现象。 zig-patch 的发行目录内有 zig、lib 与文档,没有 llvm-objcopy,缺失移除符号的能力。

处理。 build/strip.sh 按顺序尝试搜索:HarmonyOS SDK 自带的 llvm-objcopy、宿主 PATH 里的 llvm-objcopy、objcopy,若存在任一可用项就执行 --strip-all。

验证。 strip 之后 file 检查输出含 stripped 标记,产物体积(48 MB / 52 MB)极大减小。

Cargo.lock 里 cc 与 shlex 的版本

现象。 上游 v0.15.1 锁定的 cc 版本是 1.2.11,shlex 版本是 1.3.0。

处理。 补丁把 cc 升为 1.4.5(同时引入 find-msvc-tools 0.1.12)、shlex 升到 2.0.1,只改 Cargo.lock。

验证。 构建日志中出现 Compiling shlex v2.0.1 与 Compiling cc v1.4.5 说明确实使用升级后的版本。

产物的静态核查

交叉编译产物真的在鸿蒙平台上可以运行吗?在编译环境通过几个方法快速检查:build.sh 在结束处打印架构、NEEDED 与 interpreter,同时 build/check-symbols.sh 提供完整的完全静态的符号检查。

核查项 aarch64 产物 x86_64 产物
file 命令输出 ELF 64-bit LSB pie executable, ARM aarch64, stripped ELF 64-bit LSB pie executable, x86-64, stripped
interpreter /lib/ld-musl-aarch64.so.1 /lib/ld-musl-x86_64.so.1
NEEDED 仅 libc.so 仅 libc.so
RUNPATH / RPATH 无 无
ELF 标志 BIND_NOW、NOW PIE 同
首个 LOAD 段的页边界 0x10000 0x1000
动态未定义符号总数 234 229
其中 HarmonyOS SDK libc.a 不存在的 0 0
其中 Alpine musl 不存在的 0 0
弱引用外部符号 4 4

符号覆盖检查的具体方法:获取产物符号表里所有 UND 符号,检查在 OHOS SDK sysroot 里的 libc.a、 Alpine musl 1.2.5 中是否存在。所有符号均存在,说明产物需要的外部符号,设备端与验证环境两端都具备。四个弱引用未定义符号是 copy_file_range、getentropy、getrandom、gettid,装载器找不到时按可选处理:

bash 复制代码
$ OHOS_SDK=/opt/ohos-sdk/sdk/default/openharmony ./build/check-symbols.sh out/aarch64/typst
UND 符号数: 234
== 缺失于 OHOS SDK libc.a: 0 ==
== 缺失于 Alpine musl 1.2.5(qemu 运行环境): 0 ==
== WEAK UND 符号数: 4 ==
copy_file_range
getentropy
getrandom
gettid

NEEDED 只有 libc.so,说明 libc++、compiler-rt 与 OpenSSL 都是静态链接的,不依赖设备上预装其它运行库。两个架构的首个 LOAD 段页边界不同(aarch64 是 0x10000,x86_64 是 0x1000),为指令集各自的默认页大小,均为 4096 的整数倍。

功能验证:与上游版本 9 项比对

Typst 的行为是否与其它平台一致,靠逐项比较验证来判定。做法是在编译环境上额外构建一份 x86_64-linux-gnu 产物作为参照版,OHOS 产物放在 qemu-user + Alpine musl 1.2.5 的运行环境里执行,两者跑同一批样例,比对输出。

鸿蒙设备环境模拟使用 qemu-user 9.2.1 与 Alpine musl 1.2.5 的 rootfs,本次复用自同机的前置适配项目,放在 downloads/ 下,不纳入版本管理;换到别的机器上需要比照时,准备同样的 qemu-aarch64 / qemu-x86_64 与 Alpine rootfs 即可。

对拍前做了两处修改,避免把无关的随机量算成差异:

  • 样例文档里加 #set document(date: none),消除编译时间戳;
  • PDF 的 XMP InstanceID / DocumentID 每次编译都会重新生成,比对前替换成占位符。

SVG、PNG 与文本输出不做归一化,逐字节比对。验证脚本与样例文档(baseline/run-alignment.sh 与 test-project/ 里的拉丁样例、中文样例、查询样例与随包子集字体)随适配工作目录提供,本节列出的输出都由它产生。

序号 比对项 比对方式 aarch64 x86_64
1 --version 逐字节 PASS PASS
2 --help 逐字节 PASS PASS
3 fonts --ignore-system-fonts 逐字节 PASS PASS
4 拉丁样例导出 PDF / SVG / PNG SVG、PNG 逐字节;PDF 归一化随机 ID PASS PASS
5 中文样例导出 PDF(随包子集字体) 归一化随机 ID PASS PASS
6 eval 查询(heading / figure) 逐字节 PASS PASS
7 错误路径(即编译不存在的文件) 退出码 + 报错文本 PASS PASS
8 无 HOME 环境下的行为 退出码 + 输出 PASS PASS
9 包系统实际工作:真实下载 @preview 包 日志 + 缓存落位 + 编译结果 PASS PASS

第 4、5 项:产物完全一致。 拉丁样例两页的 SVG 与 PNG 在两个平台上的摘要完全一致:

text 复制代码
$ cd baseline/align-out
$ md5sum host/latin-1.png aarch64/latin-1.png
6a85352873d5944047220ca0be15e390  host/latin-1.png
6a85352873d5944047220ca0be15e390  aarch64/latin-1.png

$ md5sum host/latin-2.svg aarch64/latin-2.svg
f3f2e103325d3e1dc4ec0de1b845a0d5  host/latin-2.svg
f3f2e103325d3e1dc4ec0de1b845a0d5  aarch64/latin-2.svg

PDF 在去除随机 ID 影响后同样一致,说明字体子集、坐标与结构树都是逐项相同的。

第 9 项:包系统实际运行测试。 样例引用 @preview/a2c-nums:0.0.1,编译时 Typst 会发起请求请求下载该包:

bash 复制代码
typst compile pkg-test.typ pkg.pdf

这一项同时验证了 typst 网络部分模块能正常工作,输出:

text 复制代码
downloading @preview/a2c-nums:0.0.1

  0 B /   2.5 KiB (  0 %),  24.7 KiB/s, ETA: 0 s
  2.5 KiB /   2.5 KiB (100 %),  24.7 KiB/s, ETA: 0 s

下载完成后包被写入 ~/.cache/typst/packages/preview/a2c-nums/0.0.1/,文档里 int-to-cn-num(123456789) 渲染出 一亿二千三百四十五万六千七百八十九。两个架构在这一项上都是通过。

功能划分

状态依据适配仓库里的功能核查记录与上面测试结果填写。

T0 基础

功能 状态 备注
CLI 参数解析与子命令分发 支持
源码解析与求值(typst-syntax / typst-eval) 支持
排版引擎(typst-layout) 支持
内嵌字体(typst-assets) 支持 随二进制分发,无需外部字体文件
PDF / SVG / PNG 导出 支持 SVG 与 PNG 与宿主位级一致
错误诊断输出 支持 退出码与报错文本与宿主一致
标准输入与标准输出(-) 支持 stdin → stdout 导出 PDF 正常

T1 核心

功能 状态 备注
中文(CJK)排版 支持 需要 --font-path 或 TYPST_FONT_PATHS 指定中文字体
数学排版、表格、图形、交叉引用、脚注 支持
eval 子命令与查询 支持
包系统(@preview 下载) 支持 依赖 HOME 或 TYPST_PACKAGE_CACHE_PATH
包缓存与数据目录 支持 无 HOME 时的行为与其它平台一致
watch 模式 支持 inotify 后端
自定义字体路径 支持 --font-path / TYPST_FONT_PATHS
模板初始化(init) 支持 与包系统共用下载与缓存路径

T2 其它与边界

功能 状态 备注
系统字体自动扫描 不支持 fontdb 扫描的是标准 Linux 字体目录,鸿蒙的系统字体位于 /system/fonts,需要用 --font-path /system/fonts 或 TYPST_FONT_PATHS 显式指定
--open 打开外部查看器 不支持 鸿蒙系统不支持
shell 补全(completions) 支持 bash 补全脚本生成正常
info 子命令 支持 输出正常,含特性开关状态
PDF 标准与 tagged PDF 支持
HTML 与 bundle 导出 支持
编译性能参数(-j / --timings / --deps) 支持
自定义 CA 证书(--cert) 支持

在鸿蒙 PC 上验证

以下内容在鸿蒙 PC 真机上执行(设备型号、分辨率与系统版本待填)。

准备

在系统设置应用「隐私和安全 > 高级」中开启「运行外部来源的扩展程序」开关,并从应用商店安装【BiShengJDK17-OH】与【DevBox】。

执行文件签名

鸿蒙 PC 要求所有可执行文件在执行前都必须签名,这里使用调试签名。把可执行文件传输到设备后:

shell 复制代码
# 假设传输的可执行文件名为 typst_unsign
binary-sign-tool sign -inFile typst_unsign -outFile typst -selfSign "1"
chmod 755 ./typst
# typst 为签名后的可运行的可执行文件

真机快速核查

设备测试目录里提供测试脚本 run.sh,运行该脚本即可进行完全测试:

shell 复制代码
tar xzf typst-ohos-0.15.1-x86_64-device-test.tar.gz
cd typst-ohos-device-test
sh run.sh ./typst

脚本覆盖:产物版本、内嵌字体列表、拉丁样例导出 PDF/SVG/PNG、中文样例导出 PDF、eval 查询、产物目录清单。

图中终端窗口顶部是设备桌面与任务栏,可以看到签名命令与自检脚本从 --version 一路执行到 DEVICE TEST DONE,out/ 目录下生成了 sample-cjk.pdf、sample-latin-1.svg、sample-latin-1.png、sample-latin-2.svg、sample-latin-2.png 与 sample-latin.pdf。

签名完成之后,即可参考官网文档开始排版工作。

常见问题(FAQ)

Q1:产物拷到设备上执行报权限错误(Operation not permitted)。

鸿蒙 PC 要求可执行文件先签名。用 binary-sign-tool sign -selfSign "1" 做一次调试签名,并对文件执行 chmod 755。

Q2: 产物在第三方终端中签名后运行仍报错权限错误。

鸿蒙 PC 对自签类型可执行文件的限制,建议使用系统内置终端应用。

Q3:含中文项目编译出来汉字不显示。

默认只使用内嵌字体,内嵌字体不含中文字形。加 --font-path fonts 指定随包子集字体,或 TYPST_FONT_PATHS=/system/fonts 使用设备系统字体。

Q4:包里引用的 @preview 包下载失败。

确认正确设置 HOME环境变量。需要网络代理时设置 http_proxy / https_proxy,包系统会读取这两个环境变量。

Q5:产物在本机 qemu 里运行失败。

产物动态链接的是 musl 的 libc.so,用 qemu-user 执行时需要提供对应的 musl 运行环境,靠 -L 指定根目录:

bash 复制代码
./downloads/qemu-u92-root/usr/bin/qemu-aarch64 -L ./downloads/alpine-root out/aarch64/typst --version

未准备好 Alpine rootfs 时,运行会失败,这与产物本身无关;按上面的命令准备好 rootfs,或者直接到真机上验证。

后续

后续拟继续推进的方向:

  • 系统字体自动扫描 :目前中文排版要显式给出字体路径。fontdb 扫描的是标准 Linux 字体目录,拟推动支持 /system/fonts。
  • --open 的外部查看器 :鸿蒙设备目前不向终端应用开放类似 xdg-open 的权限。

参考资料:

相关推荐
梦想不只是梦与想3 小时前
鸿蒙 预览数据模拟:Hamock
harmonyos·模拟数据·hamock
鶴哥只手遮天4 小时前
Spring Boot 4.1.1 深度源码解析-第 29 章 · 测试体系:`@SpringBootTest`、切片测试、Testcontainers
java·后端·开源
老牛日常随笔4 小时前
Meta 开源 8160 亿参数模型,官方给的方案是两台 Mac Studio
macos·开源
miofly4 小时前
OpenCode控制台密钥泄露事件:1.4%用户受影响,多方说法现分歧
开源·github
miofly4 小时前
GitHub 周榜趋势速报 | 2026-10-18
开源·github
鶴哥只手遮天5 小时前
Spring Boot 4.1.1 深度源码解析-第 15 章 · 条件注解体系:全部 `@ConditionalOnXxx` 的实现原理
java·后端·开源
鶴哥只手遮天5 小时前
Spring Boot 4.1.1 深度源码解析-第 30 章 · 基础设施能力:SSL Bundle、Task 与虚拟线程、Retry
java·后端·开源
鶴哥只手遮天5 小时前
Spring Boot 4.1.1 深度源码解析-第 26 章 · 指标、观测与链路追踪:Micrometer 与 OpenTelemetry
java·后端·开源
鶴哥只手遮天5 小时前
Spring Boot 4.1.1 深度源码解析-第 19 章 · Spring MVC 自动配置:DispatcherServlet、消息转换
java·后端·开源