`vendor/MetasequoiaImeEngine` submodule 改为 `engine/` 目录,导入的是 product-lock.json 原本钉住的提交 c810d201,逐文件核对过 blob,因此这是一次 搬迁而不是引擎升级。引擎自己的嵌套 submodule(googlepinyinime-rev、utfcpp、 miniaudio)按各自 gitlink 一并展开,来源与提交见 engine/UPSTREAM.md。 Windows 专门化裁掉了不属于本产品的部分:whisper.cpp 与本地推理 provider、 macOS 示例宿主、整个 dictionary/ 建库流水线、上游 CI 与 release-please 配置。 词库仍按 product-lock.json 在构建时取发布产物。 引擎不再进 product-lock.json:没有 gitlink 就没有可比对的东西,锁里写一个上游 commit 等于宣称这棵树仍等于上游,而第一个 Windows 专门化改动落地时这句话就假了。 verify-contracts / verify-checkout 随之移除,verify-published 保留。 CI 与工具链:引擎源码并入根 scripts/format.sh(删掉引擎自己的那份,避免两套排除 列表分叉);引擎 voice.yml 里的 silero_vad.onnx 摘要校验移到本仓 lock job; engine-bump-triage 工作流与其测试删除;gitsubmodule 的 dependabot 频率由 daily 改为 monthly。 README、README.en、AGENTS.md、CONTRIBUTING、docs/product-release.md 及各子目录 文档同步说明新的位置与边界。
6.4 KiB
参与 MSIME-Windows 开发
组织级的通用约定(行为准则、PR 要求、安全上报)见组织贡献指南。这份文档只讲本仓特有的东西:环境、怎么把它编出来、改哪一层、以及提交前要跑什么。
想找活干的话先看招募开源开发者和 good first issue。不写代码也有事情可做:词库条目、文档、图标资源、兼容性测试都在 no-code 标签下。
环境
- Windows 10 / 11
- Visual Studio 2026(需要 C++ 桌面开发工作负载)
- CMake 3.25+
- vcpkg,并把
VCPKG_ROOT设进环境变量 - Python 3.10+
- Inno Setup 6.6+(只有要打安装包时才需要)
Boost 按 -DBoost_ROOT=... → 环境变量 BOOST_ROOT → %USERPROFILE%\scoop\apps\boost\current 的顺序解析。preset 里的 vcpkg 路径取自 $env{VCPKG_ROOT},不需要改文件。
取代码
git clone --recursive https://github.com/metasequoiaime/MSIME-Windows.git
cd MSIME-Windows
忘了 --recursive 的话补一句 git submodule update --init --recursive。vendor/ 下是 opencc 和 cpp-pinyin,缺了它们 Server 编不过。输入引擎在 engine/,是本仓的目录而不是 submodule,普通 clone 就有。
词库不在版本库里,构建时从 dict-* release 按锁定的 tag 和摘要取用:
python scripts/product_lock.py fetch-dictionaries --staging-root .
构建
没有顶层聚合的 CMakeLists.txt,这是有意的:TSF DLL 用静态 CRT、Server 用动态 CRT,两者的 vcpkg manifest 与编译选项互不兼容,合成一个 build tree 会互相污染。每个组件是独立的 CMake 工程,从仓库根目录指定 -S:
cmake -S windows -B windows/build64 -A x64 # TSF 文本服务 DLL
cmake -S server -B server/build -A x64 # Server
cmake -S ui -B ui/build -A x64 # 自研 GUI 框架 msimeui
server/ 通过 add_subdirectory(../ui ...) 把 msimeui 拉进自己的构建,这是唯一的跨组件构建引用。
每个组件也各自带了本地脚本,比手敲 cmake 省事:
.\windows\scripts\prepare_env.py # 生成 .clangd 并把 preset 指向本机 vcpkg/Boost
.\windows\scripts\lcompile.ps1 64 # Debug;换 32 编 32 位
.\server\scripts\lcompile.ps1
各组件更细的说明在各自的 README 与 AGENTS.md 里,那两份文件写给人和 AI 都一样有效:
windows/AGENTS.md— TSF 层的构建、注册与手工回归清单(这份清单是本仓最难替代的知识,改 TSF 前先读)server/README.md— Server 的开发构建与本地词库准备ui/README.md— GUI 框架的构建与边界约束installer/README.md— 打包AGENTS.md— 跨组件契约:协议只有一份来源,改哪边要同时改哪边
打一个可安装的包
从仓库根开始,严格按顺序。任一步失败先修,不要拿旧产物继续打包:
Set-Location .\windows
.\scripts\lcompile-release-both.ps1
Set-Location ..\server
.\scripts\lcompile-release.ps1
Set-Location ..\installer
.\Prepare-PackageFiles.ps1 -RepoRoot .. -TsfDirectory windows -ServerDirectory server -UiHtmlDirectory ui-html -NoticesDirectory .
.\Sign-PackageBinaries-Local.ps1
.\Compile-Installer.ps1
Sign-PackageBinaries-Local.ps1 用的是本机测试证书,只用于内部安装验证;不要把本机证书指纹或私钥提交进仓库。
改动前要知道的几条边界
- 协议的唯一来源是
engine/contracts/。 IPC 线格式、opcode、语音分帧和 WebView 消息定义都在那里,两侧引用同一份头文件,不要在任何一侧另写一份。 engine/是本仓的一等代码。 要为 Windows 改引擎就直接改,和改server/一样评审和测试;引擎和调用它的代码可以、也应该在同一个 PR 里。例外是engine/下的googlepinyinime-rev/、utfcpp/、voice/third_party/,那是上游副本。见 engine/UPSTREAM.md。ui/不许反向依赖产品。 它不读 Server 配置、IPC、引擎、词库或全局输入状态。ui/scripts/check-boundary.py在 CI 里检查。- 窗口归
server/,页面归ui-html/。 改消息type、JSON 字段或页面导出的 JS 函数时两侧一起改。 ui-html/webview2/shared/是生成物,由ui-html/scripts/sync-contracts.py从engine/contracts/webview/同步,CI 用--check校验。要改契约就去改engine/contracts/,然后在同一个提交里重新生成。- 候选与输入状态的权威在 Server 和引擎,页面只负责展示。
提交前
ctest --test-dir server/build --output-on-failure # Server 单元测试(引擎随 Server 一起构建)
python -m unittest discover -s tests # 产品级组合验证
bash scripts/format.sh --check # 格式,覆盖 server/windows/ui/log/engine
bash scripts/ci/check-developer-paths.sh # 构建输入里不许出现个人目录路径
改了 TSF 层就照 windows/AGENTS.md 的手工回归清单跑一遍。输入法很难靠读代码判断对错,PR 里必须写清你怎么验证的:系统版本、宿主程序、操作步骤、观察到的结果、跑过的测试命令。
git status --short 确认只暂存本次任务涉及的路径,不要 git add -A。提交信息用 type(scope): 摘要,不要加 Co-Authored-By 或任何 AI 生成标记。
分支从 develop 切,PR 也合回 develop——它是本仓默认分支,开 PR 时不用改 base。main 是发布分支,只在发版时由维护者从 develop 合入;特性分支直接提到 main 会被 Branch guard 检查拦下,把 base 改回 develop 即可。发布链条见 docs/product-release.md。
不要在 PR、Issue、截图或日志里泄露 API Key。仓库开了 secret scanning 和 push protection,但那是最后一道防线不是第一道。