第 27 篇:收尾——双版本验证、文档补齐与 PR 提交
本系列第 27 篇,也是最后一篇。26 篇下来,170 个测试全绿,代码翻译终于完成。但"写完代码"离"提交 PR"还有一段路:双版本验证、文档补齐、打包制品、填写 PR 模板……这篇记录收尾阶段的全部过程和踩过的坑。
一、收尾阶段要做什么
代码写完并不意味着能直接提 PR。对照共建计划的要求,还需要:
- 双版本验证:LTS 1.0.5 和 STS 1.1.3 都要能编译、测试通过
- 文档补齐:LICENSE、CHANGELOG.md、设计文档、API 文档、README
- 制品打包:用
cjpm bundle生成 .cjp 制品 - PR 提交:填写模板、推送到官方仓库
一个一个来。
二、双版本验证——LTS 1.0.5
问题:两个版本怎么共存?
我一开始装的是 STS 1.1.3(第 2 篇),开发全程用的也是 1.1.3。现在要验证 LTS 1.0.5 也能跑,但两个版本的 SDK 安装器会互相覆盖——不能同时装两个。
解决方案:NSIS 免安装解压
查了一下,仓颉 SDK 安装包是 NSIS 格式。NSIS 安装包支持静默解压到指定目录,不写入注册表,不和已安装版本冲突:
# 假设安装包在 d:\2.Project\cj-awesome\仓颉工具\
# /S 表示静默,/D= 指定解压目录
.\cangjie-sdk-windows-x64-1.0.5.exe /S "/D=d:\2.Project\cj-awesome\仓颉工具\cangjie-sdk-1.0.5"等几秒就解压完了。进去一看,结构跟正式安装一样,cjpm.exe 在 tools\bin\ 目录下。
💡 坑 1:1.0.5 的
cjpm.exe在tools\bin\而不是bin\。不同版本的目录结构有细微差异,别想当然。
切换版本测试
不能直接把 1.0.5 加到系统 PATH(会和 1.1.3 冲突)。我的做法是在 PowerShell 里临时设置环境变量:
$env:CANGJIE_HOME = "d:\2.Project\cj-awesome\仓颉工具\cangjie-sdk-1.0.5"
$env:PATH = "$env:CANGJIE_HOME\tools\bin;$env:CANGJIE_HOME\bin;$env:CANGJIE_HOME\runtime\lib;$env:PATH"然后验证版本:
cjpm --version
# Cangjie Project Manager: 1.0.5坑 2:cjpm 缓存不兼容
第一次用 1.0.5 跑 cjpm test,直接报错:
DataModelException: This data is not DataModelString一头雾水。后来想到:之前用 1.1.3 编译过,target/ 目录里缓存的是 1.1.3 格式的数据。两个版本的缓存格式不兼容。
解决办法很简单——清掉 target/ 目录:
Remove-Item -Recurse -Force target\
cjpm test清完重跑,170/170 PASSED ✅。
💡 经验:切换 SDK 版本后,一定要先清
target/。两个版本的编译缓存格式不同,混用会报各种奇怪的错。
三、双版本验证——STS 1.1.3 分支
LTS 验证通过后,还需要为 STS 1.1.3 创建一个独立分支。原因是 cjpm.toml 里的 cjc-version 字段不同:
main分支:cjc-version = "1.0.5"(兼容 LTS)feat/plist4cj-1.1.3分支:cjc-version = "1.1.3"(STS 专用)
创建分支
git checkout -b feat/plist4cj-1.1.3然后修改 cjpm.toml 里的版本号:
[package]
cjc-version = "1.1.3" # 改为 STS 版本切回 STS 1.1.3 环境,清 target/,跑测试:
Remove-Item -Recurse -Force target\
cjpm test170/170 PASSED ✅。提交。
至此,双版本验证全部完成:
| 分支 | SDK 版本 | 测试结果 |
|---|---|---|
main | LTS 1.0.5 | 170/170 PASSED |
feat/plist4cj-1.1.3 | STS 1.1.3 | 170/170 PASSED |
四、制品打包——cjpm bundle
STS 1.1.3 打包
STS 1.1.3 的 cjpm 支持 bundle 命令,可以把库打包成 .cjp 文件(类似 Java 的 .jar):
cjpm bundle成功生成了 plist4cj-1.0.0.cjp(49KB)。但紧接着报了个错:
Can not load openssl library or function SHA256_Init坑 3:cjpm bundle 与 OpenSSL 4.0 不兼容
cjpm bundle 在打包后需要用 SHA256 生成校验和。它调用的是 OpenSSL 的 SHA256_Init 函数——但这个函数在 OpenSSL 4.0 中已经被移除了(属于旧版 API 废弃)。
我尝试安装了两个 OpenSSL 发行版:
winget install ShiningLight.OpenSSL.Light # OpenSSL 4.0.1
winget install FireDaemon.OpenSSL # 也是 4.0.1都是 4.0.x,SHA256_Init 已经不存在了。
💡 坑:cjpm 目前只兼容 OpenSSL 3.x,不兼容 4.0。但 Windows 上通过 winget 能装到的基本都是 4.0 了。
解决办法:PowerShell 手动补校验和
既然 cjpm bundle 只是缺一个 SHA256 校验文件,那用 PowerShell 自己算一个就行:
$hash = (Get-FileHash -Algorithm SHA256 "target\bundle\plist4cj-1.0.0.cjp").Hash.ToLower()
"$hash plist4cj-1.0.0.cjp" | Out-File -Encoding utf8 "target\bundle\plist4cj-1.0.0.cjp.sha256"这样就有了 .cjp + .sha256 两个文件,效果等同于 cjpm bundle 完整的输出。
LTS 1.0.5 打包
LTS 1.0.5 的 cjpm 没有 bundle 命令(这是 1.1.3 新增的功能)。所以 LTS 分支无法生成 .cjp 制品,这是已知限制。
五、文档补齐
对照共建计划的目录结构要求,发现缺好几个文件:
| 文件 | 要求 | 状态 |
|---|---|---|
| LICENSE | 必须 | ❌ 缺失 |
| CHANGELOG.md | 必须 | ❌ 缺失 |
| doc/design.md | 必须 | ❌ 缺失 |
| doc/feature_api.md | 建议 | ❌ 缺失 |
| README.md | 必须 | ⚠️ 内容不完整 |
1. LICENSE
上游 dd-plist 用的是 MIT 协议,我们也保持一致。注意要保留上游版权声明:
plist4cj - A Cangjie port of dd-plist to parse and generate property lists
Copyright (C) 2026 plist4cj contributors
Based on dd-plist:
Copyright (C) 2016 Daniel Dreibrodt
Permission is hereby granted, free of charge, ...
[MIT 协议全文]2. CHANGELOG.md
记录 v1.0.0 的变更,包含所有已完成模块和已知限制:
## [1.0.0] - 2026-07-23
### Added
- 完整移植 dd-plist 1.30 全部公开 API,170/170 单元测试通过
- 数据模型:NSObject、NSString、NSNumber、NSData、NSDate、UID、NSNull、NSArray、NSDictionary、NSSet
- 解析器:Binary / XML / ASCII
- 写出器:XML / Binary / ASCII
- 双版本适配:LTS 1.0.5 与 STS 1.1.3
### Known Limitations
- toJavaObject / fromJavaObject 反射胶水不可移植
- UID BigInteger 用 Int64 替代
- XMLLocationFilter / ByteOrderMarkFilterInputStream 已跳过3. doc/design.md
设计文档,包含架构分层图、核心设计决策、测试策略、平台差异说明。重点解释为什么这样做:
| 决策 | 原因 |
|---|---|
| 手写递归下降解析器 | 仓颉标准库无 XML DOM、无 SAX |
Array<Rune> 替代 char[] | 仓颉 Rune 是 Unicode 标量值 |
Int64 替代 BigInteger | 仓颉无 BigInteger |
跳过 toJavaObject | 依赖 Java 反射,仓颉无等价能力 |
4. doc/feature_api.md
所有公开 API 的方法签名表格,方便使用者查阅。
5. README.md 重写
按共建模板重写,包含:项目信息、快速开始、环境要求、API 文档、使用示例、已知限制等。
💡 坑 4:README 更新后出现了内容重复——新版内容追加在旧版后面,变成了两份 README 拼在一起。提交前一定要检查文件内容。
双分支同步
以上文档都在 main 分支创建。别忘了用 cherry-pick 同步到 feat/plist4cj-1.1.3 分支:
git checkout feat/plist4cj-1.1.3
git cherry-pick <main上的commit>💡 坑 5:cherry-pick 可能冲突(尤其是 README.md 两个分支都有改动时)。冲突了就手动解决,或者直接
git checkout main -- README.md覆盖过去。
六、PR 模板填写与提交
确认提交流程
共建计划的 PR 提交流程:
- Fork 官方仓库(AtomGit 平台
cj-awesome组织) - 从 fork 的分支向官方仓库发起 PR
- PR 标题必须带
【共建】前缀
PR 信息
按模板填写关键信息:
| 字段 | 内容 |
|---|---|
| 仓颉版本 | LTS 1.0.5 / STS 1.1.3 |
| 三方库名称 | plist4cj |
| 上游版本 | 1.30 |
| 上游仓库 | https://github.com/3breadt/dd-plist |
| 适配路径 | 共建 |
测试用例对比
| 测试类型 | 上游用例数 | 仓颉版用例数 |
|---|---|---|
| 单元测试 | 约 120+ | 170 |
| 通过率 | — | 100% |
两个分支分别提 PR
因为有两个分支,需要分别提两个 PR:
| PR | 分支 | 仓颉版本 |
|---|---|---|
| PR 1 | main → 官方 main | LTS 1.0.5 |
| PR 2 | feat/plist4cj-1.1.3 → 官方对应分支 | STS 1.1.3 |
推送代码
git push origin main
git push origin feat/plist4cj-1.1.3💡 提示:PR 绑定的是分支而不是某次 commit。如果 PR 审核期间需要修改,直接往同一个分支 push 新 commit,PR 会自动包含最新变更。
七、收尾阶段的踩坑总结
| 坑 | 现象 | 解决 |
|---|---|---|
| SDK 安装冲突 | 两个版本不能同时正式安装 | NSIS 静默解压到独立目录 |
| cjpm 缓存不兼容 | 切换版本后报 DataModelException | 清 target/ 目录 |
| OpenSSL 4.0 不兼容 | SHA256_Init 函数已移除 | PowerShell Get-FileHash 手动补校验和 |
| LTS 无 bundle 命令 | unknown command 'bundle' | 已知限制,LTS 不生成 .cjp |
| README 内容重复 | 多次编辑后新旧内容拼接 | 检查并删除旧版残留 |
| cherry-pick 冲突 | 两分支 README 不同 | 直接 checkout 覆盖 |
八、项目成果回顾
从第 1 篇到第 27 篇,整个过程回顾:
| 阶段 | 篇目 | 做了什么 |
|---|---|---|
| 准备 | 1-5 | 读懂规则、搭环境、认识库、规划路线、搭工程 |
| 叶子类型 | 6-11 | NSObject、NSString、NSNumber、NSData、NSDate、UID、NSNull |
| 容器类型 | 12-14 | NSArray、NSDictionary、NSSet |
| 工具与写出器 | 15-22 | 位置信息、BOM、三个写出器 |
| 解析器 | 23-26 | 格式检测、Binary/XML/ASCII 解析器 |
| 收尾 | 27 | 双版本验证、文档补齐、PR 提交(本篇) |
最终交付:
| 指标 | 数据 |
|---|---|
| 移植模块 | 13 个类 + 3 个解析器 + 3 个写出器 |
| 单元测试 | 170/170 PASSED |
| LTS 1.0.5 | ✅ 170/170 |
| STS 1.1.3 | ✅ 170/170 |
| 共建文章 | 27 篇 |
| 文档 | LICENSE / CHANGELOG / design / feature_api / README |
| 当前状态 | 🟡 PR 已提交,等待审核 |
九、最后的话
回头看,这件事最难的部分不是翻译代码本身,而是从头到尾搞清楚"到底要做什么"。
一开始连仓颉是什么都不知道,到能读懂 Java 源码、能写出仓颉代码、能跑通 170 个测试、能把一个完整的开源库移植过来——这个过程虽然慢,但每一步都是实的。
给后来者的建议:
- 别怕慢,怕的是方向错。先把规则读懂(第 1 篇),后面才不会返工。
- 小步验证。每翻译一个类就跑一遍测试,别攒一堆一起编译。
- 善用文档。仓颉的官方文档(CangjieCorpus)是最权威的参考。
- 平台差异不可怕。Java 有但仓颉没有的东西(反射、BigInteger、SAX),想办法用等价方式补上或标注清楚就行。
本系列到此完结。如果对你有帮助,欢迎分享给同样想入门仓颉的朋友。PR 审核通过后,plist4cj 就会正式进入仓颉三方库生态,成为仓颉开发者可以使用的工具库。