Skip to content

Commit 5e5c5d0

Browse files
committed
doc: add jieba plugin architecture and rollout plan
also incude Windows and WinGet plan for jieba plugin
1 parent 8c83f64 commit 5e5c5d0

File tree

2 files changed

+307
-0
lines changed

2 files changed

+307
-0
lines changed
Lines changed: 305 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,305 @@
1+
# OpenCC Jieba 外掛化架構重設計與執行方案
2+
3+
> 目標:讓 OpenCC 不再將 Jieba 靜態編譯進核心,而是於讀到 `"segmentation": {"type": "jieba"}` 時,動態尋找並載入 `libopencc-jieba.so`(或平台對應名稱),以便發行版可拆分成 `opencc``opencc-jieba` 套件。
4+
5+
## 1. 問題與目標
6+
7+
### 1.1 目前痛點
8+
9+
- Jieba 目前需在編譯期透過 `ENABLE_JIEBA` 決定是否納入,導致:
10+
- 核心套件與可選分詞能力耦合。
11+
- 發行版不易做「最小核心 + 可選擴充」打包。
12+
- 使用者拿到 `jieba` 配置時,若核心未編進 Jieba,僅能得到 `Unknown segmentation type: jieba`
13+
14+
### 1.2 重設計目標
15+
16+
- 核心(`libopencc`)維持「分詞介面 + 轉換鏈」能力,不含 cppjieba 直接依賴。
17+
- Jieba 由獨立外掛(建議 `libopencc-jieba.so`)提供,採動態載入。
18+
- 配置層面保持相容:既有 `type = "jieba"` 配置可直接使用。
19+
- 發行版可拆包:
20+
- `opencc`:核心 + mmseg
21+
- `opencc-jieba`:Jieba 外掛 + Jieba 字典
22+
23+
---
24+
25+
## 2. 新架構概觀
26+
27+
```
28+
+------------------------+
29+
| 應用程式/API |
30+
+-----------+------------+
31+
|
32+
v
33+
+------------------------+
34+
| libopencc |
35+
| - Config Parser |
36+
| - SegmentationFactory |
37+
| - PluginManager |
38+
+-----------+------------+
39+
|
40+
dlopen/dlsym (POSIX)
41+
|
42+
v
43+
+------------------------+ +---------------------------+
44+
| libopencc-jieba.so | -----> | cppjieba + jieba_dict |
45+
| - plugin entrypoint | | (由 opencc-jieba 套件提供) |
46+
| - JiebaSegmentation | +---------------------------+
47+
+------------------------+
48+
```
49+
50+
核心只負責:
51+
1. 解析配置辨識 `segmentation.type`
52+
2. 對未知(或非內建)分詞器,走外掛解析流程。
53+
3. 驗證外掛 API 版本並建立 `Segmentation` 實例。
54+
55+
---
56+
57+
## 3. 核心介面設計(ABI/API)
58+
59+
為兼顧 C++ 內部物件與動態載入穩定性,建議採 **C ABI + 函式表**
60+
61+
### 3.1 Plugin Descriptor(C ABI)
62+
63+
新增(示意)標頭:`src/plugin/OpenCCPlugin.h`
64+
65+
```c
66+
#define OPENCC_PLUGIN_ABI_VERSION 1
67+
68+
typedef struct {
69+
const char* key; // 例如 "dict_path"
70+
const char* value; // UTF-8
71+
} opencc_kv_pair_t;
72+
73+
typedef struct opencc_segmentation_handle opencc_segmentation_handle_t;
74+
75+
typedef struct {
76+
uint32_t abi_version;
77+
const char* plugin_name; // "opencc-jieba"
78+
const char* segmentation_type; // "jieba"
79+
80+
// 建立分詞器實例;config 來自 segmentation 區塊
81+
int (*create)(const opencc_kv_pair_t* config,
82+
size_t config_size,
83+
opencc_segmentation_handle_t** out,
84+
char** err_msg);
85+
86+
// 執行分詞,回傳 UTF-8 token 陣列
87+
int (*segment)(opencc_segmentation_handle_t* h,
88+
const char* utf8_text,
89+
char*** tokens,
90+
size_t* token_count,
91+
char** err_msg);
92+
93+
void (*free_tokens)(char** tokens, size_t token_count);
94+
void (*destroy)(opencc_segmentation_handle_t* h);
95+
void (*free_error)(char* err_msg);
96+
} opencc_segmentation_plugin_v1;
97+
98+
// 外掛必須導出此符號
99+
const opencc_segmentation_plugin_v1* opencc_get_segmentation_plugin_v1(void);
100+
```
101+
102+
### 3.2 核心端 C++ 包裝
103+
104+
- 在核心新增 `PluginSegmentationAdapter : public Segmentation`。
105+
- `Segment()` 內部呼叫 plugin `segment()`,再轉成 `Segments`。
106+
- 由 `PluginManager` 管理 `.so` 生命週期(`dlopen` handle、descriptor 快取、銷毀順序)。
107+
108+
### 3.3 錯誤語意
109+
110+
- 外掛錯誤統一映射為 OpenCC 例外(如 `RuntimeError` / `InvalidFormat`)。
111+
- `err_msg` 由外掛配置 allocator,核心透過 `free_error()` 釋放,避免跨 CRT 釋放問題。
112+
113+
---
114+
115+
## 4. 配置與載入策略
116+
117+
### 4.1 配置相容
118+
119+
`type = "jieba"` 維持不變:
120+
121+
```json
122+
"segmentation": {
123+
"type": "jieba",
124+
"dict_path": "jieba_dict/jieba.dict.utf8",
125+
"model_path": "jieba_dict/hmm_model.utf8",
126+
"user_dict_path": "jieba_dict/user.dict.utf8"
127+
}
128+
```
129+
130+
### 4.2 外掛搜尋順序(建議)
131+
132+
`type = "jieba"`
133+
134+
1. 明確環境變數:`OPENCC_SEGMENTATION_PLUGIN_PATH`(可含多路徑)。
135+
2. 編譯期預設路徑(如 `${libdir}/opencc/plugins`)。
136+
3. 同目錄回退:`libopencc` 所在目錄。
137+
4. 系統 linker 預設路徑。
138+
139+
檔名規則:
140+
- Linux: `libopencc-jieba.so`
141+
- macOS: `libopencc-jieba.dylib`
142+
- Windows: `opencc-jieba.dll`
143+
144+
### 4.3 安全與可控性
145+
146+
- 可加入 `OPENCC_DISABLE_PLUGINS=1` 供高安全場景停用動態載入。
147+
- 僅接受檔名白名單(Linux/macOS:`libopencc-*.so` / `libopencc-*.dylib`,Windows:`opencc-*.dll`)以降低任意動態庫注入風險。
148+
- 驗證 `abi_version`,不符立即拒載。
149+
150+
---
151+
152+
## 5. 建置與打包重構
153+
154+
## 5.1 CMake(建議)
155+
156+
新增選項:
157+
- `ENABLE_SEGMENTATION_PLUGINS`(預設 ON)
158+
- `BUILD_OPENCC_JIEBA_PLUGIN`(預設 OFF,可由發行版啟用)
159+
160+
目標拆分:
161+
- `opencc` 核心:不連結 cppjieba
162+
- `opencc-jieba` 外掛:連結 cppjieba,輸出到 plugin 目錄
163+
164+
## 5.2 Bazel(建議)
165+
166+
- 增加 `cc_binary(..., linkshared = True)` 產生 `libopencc-jieba.so`
167+
-`//deps/libcppjieba``//data/jieba_dict` 移至外掛打包規則。
168+
169+
## 5.3 發行版打包
170+
171+
- `opencc`
172+
- `libopencc.so`
173+
- 內建 config(不含 jieba 亦可,或保留並於缺 plugin 時報明確錯)
174+
- `opencc-jieba`
175+
- `libopencc-jieba.so`
176+
- `jieba_dict/*`
177+
- 可選:`s2twp_jieba.json` / `tw2sp_jieba.json`
178+
179+
## 5.4 Windows 平台與 WinGet 生態(重點補充)
180+
181+
### 5.4.1 Windows 動態載入實作
182+
183+
-`LoadLibraryExW` + `GetProcAddress` 實作 `SharedLibrary`,避免在 Windows 分支額外分散邏輯。
184+
- 優先使用 `LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR`(或等價策略),降低 DLL Hijacking 風險。
185+
- 可在初始化階段呼叫 `SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_DEFAULT_DIRS)`(若可行)統一搜尋行為。
186+
187+
### 5.4.2 Windows 安裝路徑建議
188+
189+
- `opencc` 套件(核心):
190+
- `opencc.dll` / `opencc.exe`
191+
- `%ProgramFiles%\OpenCC\bin`
192+
- `opencc-jieba` 套件(外掛):
193+
- `opencc-jieba.dll`
194+
- `%ProgramFiles%\OpenCC\plugins`
195+
- `%ProgramFiles%\OpenCC\share\opencc\jieba_dict\*`
196+
- 核心預設外掛搜尋路徑可加入 `%ProgramFiles%\OpenCC\plugins`,並允許以 `OPENCC_SEGMENTATION_PLUGIN_PATH` 覆蓋。
197+
198+
### 5.4.3 WinGet 打包建議
199+
200+
- 建議拆成兩個 package ID:
201+
- `OpenCC.OpenCC`(核心)
202+
- `OpenCC.OpenCC.Jieba`(外掛)
203+
- `OpenCC.OpenCC.Jieba` manifest 可宣告對 `OpenCC.OpenCC` 的相依,確保安裝順序。
204+
- `winget install OpenCC.OpenCC`:預設最小安裝(不含 Jieba)。
205+
- `winget install OpenCC.OpenCC.Jieba`:補齊 Jieba plugin 與字典。
206+
- 若使用者嘗試 `jieba` 配置但缺外掛,錯誤訊息應明確提示:`Please install package OpenCC.OpenCC.Jieba (winget install OpenCC.OpenCC.Jieba)`
207+
208+
### 5.4.4 Windows CI / 驗證
209+
210+
- 在 Windows runner 建立兩組測試:
211+
1. 僅安裝核心(確認 `jieba` 配置報錯且訊息可行動)。
212+
2. 安裝核心 + 外掛(確認 `s2twp_jieba.json` 正常)。
213+
- 增加一個 DLL 搜尋路徑安全測試:確認不會從 CWD 誤載未知同名 DLL。
214+
215+
---
216+
217+
## 6. 相容性策略
218+
219+
### 6.1 向後相容
220+
221+
- 若系統未安裝 plugin:
222+
- 錯誤訊息改為可行動建議,例如:
223+
- `Segmentation plugin 'jieba' not found. Please install package 'opencc-jieba'.`
224+
- 若有 plugin 且 ABI 相容:既有配置直接可用。
225+
226+
### 6.2 漸進式遷移
227+
228+
- 第一階段可保留 `ENABLE_JIEBA`(舊路徑)與 plugin(新路徑)並存。
229+
- 第二階段 deprecate 靜態編譯路徑,CI 改以 plugin 為主。
230+
- 第三階段移除核心直連 cppjieba。
231+
232+
---
233+
234+
## 7. 測試與驗證方案
235+
236+
### 7.1 單元測試
237+
238+
- `PluginManagerTest`
239+
- 找不到檔案
240+
- 缺符號 `opencc_get_segmentation_plugin_v1`
241+
- ABI mismatch
242+
- `PluginSegmentationAdapterTest`
243+
- token 回傳正確
244+
- 外掛錯誤傳遞
245+
246+
### 7.2 整合測試
247+
248+
- 有安裝 `opencc-jieba``s2twp_jieba.json` 轉換成功。
249+
- 無安裝 `opencc-jieba`:得到預期錯誤字串(含安裝建議)。
250+
251+
### 7.3 打包測試(發行版關鍵)
252+
253+
- 僅安裝 `opencc`:一般 mmseg 配置可用,jieba 配置失敗但錯誤可理解。
254+
- 安裝 `opencc + opencc-jieba`:jieba 配置恢復正常。
255+
256+
---
257+
258+
## 8. 實作里程碑(可直接排期)
259+
260+
### M1:核心 plugin 基礎設施(1~2 週)
261+
262+
- 定義 C ABI 與 `PluginManager`
263+
- `Config``type != mmseg` 時可嘗試 plugin 解析。
264+
- 加入基本錯誤訊息與路徑搜尋。
265+
266+
### M2:Jieba 外掛實作(1 週)
267+
268+
- 將現有 `JiebaSegmentation` 邏輯遷入外掛。
269+
- 完成 `libopencc-jieba` 產物與安裝路徑。
270+
271+
### M3:測試與 CI(1 週)
272+
273+
- 新增 plugin 模式單元/整合測試。
274+
- CI matrix:
275+
- 核心 only
276+
- 核心 + jieba plugin
277+
278+
### M4:文件與發行版指南(0.5 週)
279+
280+
- 更新 `JIEBA_USAGE.md`:從「編譯期功能」改為「可選插件」。
281+
- 新增 distro 打包建議(Deb/RPM/Homebrew/Nix)。
282+
283+
---
284+
285+
## 9. 風險與對策
286+
287+
- **ABI 穩定性風險**:以版本化函式表(v1/v2)演進,避免破壞舊 plugin。
288+
- **跨平台動態載入差異**:封裝一層 `SharedLibrary` 抽象(dlopen/LoadLibrary)。
289+
- **效能疑慮**:plugin 載入只在初始化發生一次;分詞時透過函式指標呼叫,額外開銷可忽略。
290+
- **除錯成本**:強化啟動日誌(可選 debug env)與明確錯誤碼。
291+
292+
---
293+
294+
## 10. 建議最終落地形式
295+
296+
- OpenCC 主倉:
297+
- 提供 plugin host 能力 + 官方 `opencc-jieba` plugin 原始碼。
298+
- 套件管理層:
299+
- 預設安裝 `opencc`
300+
- 使用者需要 `jieba` 時再安裝 `opencc-jieba`
301+
302+
這樣可以同時達成:
303+
1. 核心精簡。
304+
2. 發行版可選依賴。
305+
3. 使用者配置體驗不變(仍然 `type: "jieba"`)。

doc/JIEBA_USAGE.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
本文档说明如何在 OpenCC 中启用和使用 Jieba 中文分词功能。
44

5+
> 架構重設計提案(Jieba 外掛化)請見:`doc/JIEBA_PLUGIN_ARCHITECTURE_PLAN.md`
6+
57
## 概述
68

79
OpenCC 默认使用最大正向匹配(mmseg)算法进行分词。从版本 X.X.X 开始,我们引入了对 **Jieba 分词**的实验性支持。

0 commit comments

Comments
 (0)