mopr 0.0.57.dev1__tar.gz → 0.0.69.dev0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/.gitignore +20 -0
  2. {mopr-0.0.57.dev1/.vscode → mopr-0.0.69.dev0/.vscode-default}/settings.json +1 -9
  3. {mopr-0.0.57.dev1/.vscode → mopr-0.0.69.dev0/.vscode-default}/tasks.json +0 -9
  4. mopr-0.0.69.dev0/.vscode-macos/settings.json +5 -0
  5. mopr-0.0.69.dev0/.vscode-macos/tasks.json +14 -0
  6. {mopr-0.0.57.dev1/.vscode → mopr-0.0.69.dev0/.vscode-windows}/launch.json +8 -0
  7. mopr-0.0.69.dev0/.vscode-windows/settings.json +10 -0
  8. mopr-0.0.69.dev0/.vscode-windows/tasks.json +14 -0
  9. mopr-0.0.69.dev0/AGENTS.md +156 -0
  10. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/BUILDING.md +138 -16
  11. mopr-0.0.69.dev0/CHANGELOG.md +1997 -0
  12. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/CONTRIBUTING.md +9 -3
  13. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/MANIFEST.in +14 -2
  14. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/PKG-INFO +27 -8
  15. mopr-0.0.57.dev1/mopr.egg-info/PKG-INFO → mopr-0.0.69.dev0/README.md +138 -139
  16. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/THIRD_PARTY_NOTICES.md +65 -29
  17. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/base/__init__.py +17 -1
  18. mopr-0.0.69.dev0/base/cron.md +255 -0
  19. mopr-0.0.69.dev0/base/cron.py +345 -0
  20. mopr-0.0.69.dev0/base/dataclass_utils.py +36 -0
  21. mopr-0.0.69.dev0/base/mmap.md +150 -0
  22. mopr-0.0.69.dev0/base/mmap.py +252 -0
  23. mopr-0.0.69.dev0/base/mmap_test.py +230 -0
  24. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/base/region.md +22 -22
  25. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/base/time.py +22 -2
  26. mopr-0.0.69.dev0/base/timestamp.md +235 -0
  27. mopr-0.0.69.dev0/base/timestamp.py +388 -0
  28. mopr-0.0.69.dev0/base/types.py +8 -0
  29. mopr-0.0.69.dev0/benchmark/README.md +36 -0
  30. mopr-0.0.69.dev0/benchmark/macro/README.md +5 -0
  31. mopr-0.0.69.dev0/benchmark/regression/README.md +5 -0
  32. mopr-0.0.69.dev0/benchmark/stability/README.md +5 -0
  33. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/distributed/__init__.py +1 -1
  34. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/distributed/id/HLC.java +1 -1
  35. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/distributed/id/__init__.py +1 -1
  36. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/distributed/id/generator.py +1 -1
  37. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/distributed/id/hlc.py +1 -1
  38. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/distributed/id/id.py +2 -2
  39. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/distributed/id/option.py +1 -1
  40. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/distributed/id/queue.py +1 -1
  41. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/distributed/id/state_store.py +25 -40
  42. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/distributed/id/tests.py +1 -1
  43. mopr-0.0.69.dev0/encoding/README.md +142 -0
  44. mopr-0.0.69.dev0/encoding/__init__.py +27 -0
  45. mopr-0.0.69.dev0/encoding/charsets.py +55 -0
  46. mopr-0.0.69.dev0/encoding/csv.md +161 -0
  47. mopr-0.0.69.dev0/encoding/csv.py +141 -0
  48. mopr-0.0.69.dev0/encoding/json.md +147 -0
  49. mopr-0.0.69.dev0/encoding/yaml.md +162 -0
  50. mopr-0.0.69.dev0/encoding/yaml.py +99 -0
  51. mopr-0.0.69.dev0/finance/__init__.py +0 -0
  52. mopr-0.0.69.dev0/finance/exchange/README.md +102 -0
  53. mopr-0.0.69.dev0/finance/exchange/__init__.py +26 -0
  54. mopr-0.0.69.dev0/finance/exchange/data/ISO10383_MIC.csv +2876 -0
  55. mopr-0.0.69.dev0/finance/exchange/data/mic_codes.txt +2875 -0
  56. mopr-0.0.69.dev0/finance/exchange/exchange.py +230 -0
  57. mopr-0.0.69.dev0/finance/forex/README.md +331 -0
  58. mopr-0.0.69.dev0/finance/forex/__init__.py +128 -0
  59. mopr-0.0.69.dev0/finance/forex/allratestoday.py +403 -0
  60. mopr-0.0.69.dev0/finance/forex/bcd.py +765 -0
  61. mopr-0.0.69.dev0/finance/forex/bog.py +925 -0
  62. mopr-0.0.69.dev0/finance/forex/cfets.py +1384 -0
  63. mopr-0.0.69.dev0/finance/forex/data/cfets_cny_1994_2005.csv +3019 -0
  64. mopr-0.0.69.dev0/finance/forex/exchange_rate_api.py +319 -0
  65. mopr-0.0.69.dev0/finance/forex/fed.py +1243 -0
  66. mopr-0.0.69.dev0/finance/forex/forex.py +1812 -0
  67. mopr-0.0.69.dev0/finance/forex/hkma.py +785 -0
  68. mopr-0.0.69.dev0/finance/forex/official_source.py +193 -0
  69. mopr-0.0.69.dev0/finance/forex/xof.py +922 -0
  70. mopr-0.0.69.dev0/finance/forex/yahoo.py +202 -0
  71. mopr-0.0.57.dev1/README.md → mopr-0.0.69.dev0/mopr.egg-info/PKG-INFO +158 -122
  72. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/mopr.egg-info/SOURCES.txt +75 -8
  73. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/mopr.egg-info/requires.txt +3 -0
  74. mopr-0.0.69.dev0/mopr.egg-info/scm_file_list.json +188 -0
  75. mopr-0.0.69.dev0/mopr.egg-info/scm_version.json +8 -0
  76. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/pyproject.toml +31 -1
  77. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/python/_version.py +3 -3
  78. mopr-0.0.69.dev0/quant1x.png +0 -0
  79. mopr-0.0.69.dev0/runtime/once.md +288 -0
  80. mopr-0.0.69.dev0/runtime/once.py +146 -0
  81. mopr-0.0.69.dev0/runtime/once_test.py +328 -0
  82. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/runtime/ringbuffer.md +8 -8
  83. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/runtime/ringbuffer.py +4 -4
  84. mopr-0.0.69.dev0/runtime/scheduler.md +133 -0
  85. mopr-0.0.69.dev0/runtime/scheduler.py +1027 -0
  86. mopr-0.0.69.dev0/security/README.md +4 -0
  87. mopr-0.0.69.dev0/security/__init__.py +19 -0
  88. mopr-0.0.69.dev0/security/audit/README.md +1 -0
  89. mopr-0.0.69.dev0/security/auth/README.md +252 -0
  90. mopr-0.0.69.dev0/security/auth/__init__.py +72 -0
  91. mopr-0.0.69.dev0/security/auth/authorize.py +64 -0
  92. mopr-0.0.69.dev0/security/auth/catalog.py +195 -0
  93. mopr-0.0.69.dev0/security/auth/credential.py +137 -0
  94. mopr-0.0.69.dev0/security/auth/credential_test.py +159 -0
  95. mopr-0.0.69.dev0/security/auth/errors.py +48 -0
  96. mopr-0.0.69.dev0/security/auth/model.py +265 -0
  97. mopr-0.0.69.dev0/security/auth/principal.py +121 -0
  98. mopr-0.0.69.dev0/security/auth/rbac_test.py +340 -0
  99. mopr-0.0.69.dev0/security/auth/session.py +196 -0
  100. mopr-0.0.69.dev0/security/auth/session_test.py +222 -0
  101. mopr-0.0.69.dev0/security/auth/spi.py +114 -0
  102. mopr-0.0.69.dev0/security/auth/token.py +141 -0
  103. mopr-0.0.69.dev0/security/auth/token_test.py +115 -0
  104. mopr-0.0.69.dev0/security/compliance/README.md +1 -0
  105. mopr-0.0.69.dev0/spec/api.md +24 -0
  106. mopr-0.0.69.dev0/spec/behavior.md +24 -0
  107. mopr-0.0.69.dev0/storage/__init__.py +11 -0
  108. mopr-0.0.69.dev0/storage/storage.md +198 -0
  109. mopr-0.0.69.dev0/storage/storage.py +69 -0
  110. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/tools/license_audit/cli.py +2 -2
  111. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/tools/license_audit/handlers/java.py +2 -2
  112. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/tools/license_audit/handlers/python.py +29 -11
  113. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/tools/license_header/core.py +2 -2
  114. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/tools/license_header/project_meta.py +1 -1
  115. mopr-0.0.57.dev1/AGENTS.md +0 -110
  116. mopr-0.0.57.dev1/CHANGELOG.md +0 -852
  117. mopr-0.0.57.dev1/base/timestamp.md +0 -174
  118. mopr-0.0.57.dev1/base/timestamp.py +0 -229
  119. mopr-0.0.57.dev1/finance/forex/DESIGN.md +0 -99
  120. mopr-0.0.57.dev1/finance/forex/README.md +0 -84
  121. mopr-0.0.57.dev1/finance/forex/seed_rates.csv +0 -4
  122. mopr-0.0.57.dev1/finance/forex/seed_rates_hkd.csv +0 -4
  123. mopr-0.0.57.dev1/finance/rates/DESIGN.md +0 -126
  124. mopr-0.0.57.dev1/finance/rates/README.md +0 -63
  125. mopr-0.0.57.dev1/mopr.egg-info/scm_file_list.json +0 -88
  126. mopr-0.0.57.dev1/mopr.egg-info/scm_version.json +0 -8
  127. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/.clang-format +0 -0
  128. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/.clang-tidy +0 -0
  129. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/.clangd +0 -0
  130. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/.editorconfig +0 -0
  131. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/.gitattributes +0 -0
  132. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/.githooks/commit-msg +0 -0
  133. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/LICENSE +0 -0
  134. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/base/environment.py +0 -0
  135. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/base/filesystem.py +0 -0
  136. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/base/region.py +0 -0
  137. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/base/strings.md +0 -0
  138. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/base/strings.py +0 -0
  139. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/distributed/id/FileStateStore.java +0 -0
  140. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/distributed/id/Generator.java +0 -0
  141. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/distributed/id/Id.java +0 -0
  142. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/distributed/id/Option.java +0 -0
  143. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/distributed/id/PersistentState.java +0 -0
  144. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/distributed/id/README.md +0 -0
  145. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/distributed/id/StateStore.java +0 -0
  146. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/log/__init__.py +0 -0
  147. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/log/core.py +0 -0
  148. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/machine/__init__.py +0 -0
  149. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/machine/id.py +0 -0
  150. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/mopr.egg-info/dependency_links.txt +0 -0
  151. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/mopr.egg-info/entry_points.txt +0 -0
  152. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/mopr.egg-info/top_level.txt +0 -0
  153. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/python/__init__.py +0 -0
  154. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/runtime/__init__.py +0 -0
  155. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/runtime/ringbuffer_test.py +0 -0
  156. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/setup.cfg +0 -0
  157. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/tools/__init__.py +0 -0
  158. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/tools/__main__.py +0 -0
  159. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/tools/license_audit/__init__.py +0 -0
  160. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/tools/license_audit/__main__.py +0 -0
  161. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/tools/license_audit/handlers/__init__.py +0 -0
  162. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/tools/license_audit/handlers/cpp.py +0 -0
  163. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/tools/license_audit/handlers/go.py +0 -0
  164. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/tools/license_audit/handlers/rust.py +0 -0
  165. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/tools/license_audit/notices.py +0 -0
  166. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/tools/license_audit/report.py +0 -0
  167. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/tools/license_audit/todo.py +0 -0
  168. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/tools/license_header/__init__.py +0 -0
  169. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/tools/license_header/__main__.py +0 -0
  170. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/tools/license_header/cli.py +0 -0
  171. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/tools/license_header/handlers/__init__.py +0 -0
  172. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/tools/license_header/handlers/base.py +0 -0
  173. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/tools/license_header/handlers/cpp.py +0 -0
  174. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/tools/license_header/handlers/go.py +0 -0
  175. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/tools/license_header/handlers/java.py +0 -0
  176. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/tools/license_header/handlers/python.py +0 -0
  177. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/tools/license_header/handlers/rust.py +0 -0
  178. {mopr-0.0.57.dev1 → mopr-0.0.69.dev0}/tools/run_module.py +0 -0
@@ -34,6 +34,19 @@
34
34
  # Test data
35
35
  data/
36
36
 
37
+ # 例外: 随包分发的数据资产(不是测试数据) —— finance/forex/data/ 下的 cfets 头部归档
38
+ # (1994-2005, 官网区间接口取不到的那一段), 必须入库并随 mopr.finance.forex 分发;
39
+ # 需先解除目录级忽略, 再放行其中的 CSV(pyproject 的 package-data 与 MANIFEST.in 同步收录)。
40
+ !finance/forex/data/
41
+ !finance/forex/data/*.csv
42
+
43
+ # 例外: 同上的第二处 —— finance/exchange/data/ 下的 ISO 10383 MIC 官方全量清单原文(CSV)
44
+ # 与由其提取的四字码表(TXT), 必须入库并随 mopr.finance.exchange 分发;
45
+ # 同样先解除目录级忽略, 再放行其中的 CSV / TXT(package-data 与 MANIFEST.in 同步收录)。
46
+ !finance/exchange/data/
47
+ !finance/exchange/data/*.csv
48
+ !finance/exchange/data/*.txt
49
+
37
50
  # Python
38
51
 
39
52
  # Byte-compiled / optimized / DLL files
@@ -199,3 +212,10 @@ THIRD_PARTY_TODO.md
199
212
 
200
213
  # 仓库根的 compile_commands.json 软链(指向 build/Release 下由 CMake 导出的产物)
201
214
  compile_commands.json
215
+
216
+ # --- 编辑器/IDE 本地配置 ---
217
+
218
+ # VS Code 工作区配置由 scripts/vscode_sync.py 按操作系统分层生成:
219
+ # 入库的是 .vscode-default/(共享层)与 .vscode-<platform>/(平台覆盖层),
220
+ # 产物 .vscode/ 含与本机/平台相关的取值,不入库(本地文件保留)。
221
+ .vscode/
@@ -1,12 +1,4 @@
1
1
  {
2
- "terminal.integrated.profiles.windows": {
3
- "PowerShell": {
4
- "source": "PowerShell",
5
- "icon": "terminal-powershell",
6
- "args": ["-NoExit", "-Command", "chcp 65001 > $null"]
7
- }
8
- },
9
- "terminal.integrated.defaultProfile.windows": "PowerShell",
10
2
  "C_Cpp.intelliSenseEngine": "disabled",
11
3
  "cmake.configureOnOpen": false,
12
4
  "cmake.useCMakePresets": "never",
@@ -23,6 +15,6 @@
23
15
  "code-runner.runInTerminal": true,
24
16
  "java.diagnostic.filter": [
25
17
  "**/base/*.java",
26
- "**/distributed/id/*.java",
18
+ "**/distributed/id/*.java"
27
19
  ]
28
20
  }
@@ -41,15 +41,6 @@
41
41
  "problemMatcher": [
42
42
  "$msCompile"
43
43
  ]
44
- },
45
- {
46
- "label": "refresh clangd db (ninja-debug)",
47
- "type": "shell",
48
- "command": "powershell -NoProfile -ExecutionPolicy Bypass -File refresh-clangd.ps1",
49
- "options": {
50
- "cwd": "${workspaceFolder}"
51
- },
52
- "problemMatcher": []
53
44
  }
54
45
  ]
55
46
  }
@@ -0,0 +1,5 @@
1
+ {
2
+ "code-runner.executorMap": {
3
+ "python": "python3 tools/run_module.py $fullFileName"
4
+ }
5
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "version": "2.0.0",
3
+ "tasks": [
4
+ {
5
+ "label": "refresh clangd db (ninja-debug)",
6
+ "type": "shell",
7
+ "command": "bash refresh-clangd.sh",
8
+ "options": {
9
+ "cwd": "${workspaceFolder}"
10
+ },
11
+ "problemMatcher": []
12
+ }
13
+ ]
14
+ }
@@ -14,6 +14,14 @@
14
14
  "preLaunchTask": "mopr: build (debug-dynamic)",
15
15
  "stopAtEntry": false,
16
16
  "environment": []
17
+ },
18
+ {
19
+ "type": "cmake",
20
+ "request": "launch",
21
+ "name": "Debug portfile(s)",
22
+ "cmakeDebugType": "external",
23
+ "pipeName": "\\\\.\\pipe\\vcpkg_ext_portfile_dbg",
24
+ "preLaunchTask": "Debug vcpkg commands"
17
25
  }
18
26
  ]
19
27
  }
@@ -0,0 +1,10 @@
1
+ {
2
+ "terminal.integrated.profiles.windows": {
3
+ "PowerShell": {
4
+ "source": "PowerShell",
5
+ "icon": "terminal-powershell",
6
+ "args": ["-NoExit", "-Command", "chcp 65001 > $null"]
7
+ }
8
+ },
9
+ "terminal.integrated.defaultProfile.windows": "PowerShell"
10
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "version": "2.0.0",
3
+ "tasks": [
4
+ {
5
+ "label": "refresh clangd db (ninja-debug)",
6
+ "type": "shell",
7
+ "command": "powershell -NoProfile -ExecutionPolicy Bypass -File refresh-clangd.ps1",
8
+ "options": {
9
+ "cwd": "${workspaceFolder}"
10
+ },
11
+ "problemMatcher": []
12
+ }
13
+ ]
14
+ }
@@ -0,0 +1,156 @@
1
+ # AGENTS.md — 仓库协作规范
2
+
3
+ 本文件面向在本仓库工作的自动化 Agent 与协作者,列出必须遵守的约定。遇到与本文件冲突的做法时,以本文件为准。
4
+
5
+ ## 语言与版本要求
6
+
7
+ mopr 是单仓多语言库(monolibrary),同一语义将来可能有多种语言实现。各语言最低版本由本项目独立维护,不要求与同系列 `quant1x` 仓库同步:
8
+
9
+ | 语言 | 最低版本 | 说明 |
10
+ | --- | --- | --- |
11
+ | Python | 3.12+ | 3.12.x |
12
+ | C++ | C++20 | GCC 13+ / Clang 17+ / MSVC 14.3+ |
13
+ | Rust | 1.98.0+ | 2024 edition |
14
+ | Go | 1.27+ | 1.27.x |
15
+ | Java | 8+ | `pom.xml` 的 `java.version`(JDK 8 及以上) |
16
+
17
+ - 编写各语言实现时,不得使用低于上表基线的语言特性与 API(含第三方依赖的最低版本要求)。
18
+ - 版本基线变更由本项目独立评估;README.md「语言与版本要求」为对外文档,两者保持一致。
19
+ - 当前仓库以 C++20 + MSVC v143 + CMake/Conan 2 为主验证。
20
+
21
+ ### 语言角色与演进顺序
22
+
23
+ mopr 同一语义的多语言实现遵循固定的**角色与演进顺序**,与"主验证语言"无关:
24
+
25
+ 1. **Python 为 spec**:先行实现,确定语义、API 与默认行为(含解析/输出格式面),是其余语言的语义参照;
26
+ 2. **C++ 为生产实现**:Python spec 确定后落地,同时是仓库主验证语言(C++20 + MSVC v143 + CMake/Conan 2);
27
+ 3. **Rust / Go 为扩展**:随后跟进,与 Python spec 保持 API/语义对齐。
28
+
29
+ 配套约定:
30
+
31
+ - 文档、注释与 API 对照表描述语言时,遵循 `python → c++ → rust → go` 的演进顺序;**不得先入为主地以 C++ 为全部语言的语义源头**(反例:文档开头写"以 C++ 为基准 / 参考实现")。语义判断以 Python(spec)为准绳。
32
+ - 跨语言差异处理先从 Python(spec)侧定案,再推广至 C++(生产)与 Rust/Go(扩展);若 Python 缺少某能力而其他语言已有,应先补 Python spec。
33
+ - 语言最低版本表(上文)与 README.md「语言与版本要求」不因角色调整而改变。
34
+
35
+ ## 文件命名与物理命名空间约定
36
+
37
+ 同一功能拆分为多个源文件时,文件名统一采用「**功能名前缀 + 下划线 + 角色/平台名**」,用前缀在目录内构成**物理层面的命名空间**:
38
+
39
+ - **前缀即命名空间**:同族文件按前缀自然聚拢,按前缀即可检索到该功能的全部实现:
40
+ - `base/strings_camel.go` / `strings_snake.go` / `strings_kebab.go` / `strings_helper.go`;
41
+ - `distributed/id/state_lock_unix.go` / `state_lock_windows.go` / `state_lock_shared.go` / `state_lock_other.go`;
42
+ - `base/mmap/mmap_posix.go` / `mmap_windows.go` / `mmap_unsupported.go`;
43
+ - `benchmark/micro/ringbuffer_mpmc_probe.cpp` / `ringbuffer_sched_cost_probe.cpp` / `ringbuffer_single_thread_ablation.cpp`。
44
+ - **两级正交**:前缀承载功能维度,后缀承载语言与角色维度——语言后缀沿用各语言惯例(`.py` / `.h` / `.cpp` / `.rs` / `.go` / `.md`),角色后缀用于平台分支(`_posix` / `_windows` / `_unsupported`)与测试(`_test`);同一功能的跨语言实现因此同名不同后缀、同处一目录。
45
+ - **适用边界**:前缀只用于同一功能的文件分组,不为无关文件强加公共前缀;功能名已唯一的文件直接以功能名命名(`region.go` / `cron.rs` / `crc32.h`),不画蛇添足。
46
+ - **同目录优先,不按语言分目录**:语言工具链要求「目录即成包」时(Go 的 `package`、Java 的包路径),在**该功能目录内**加同名二级目录与其它语言对齐(`base/mmap/mmap.go` ↔ `base/mmap.py`);**不得**在仓库根按语言拆分语言级目录,把同一功能的各语言实现物理隔离——同目录并列才能形成「看到 `mmap.py` 顺手去看 `mmap.h` / `mmap.rs` / `mmap/mmap.go`」的对照与主动学习。
47
+ - 与「仓库根即实现根」配合:目录承载模块级命名空间,文件名前缀承载模块内的功能级命名空间,二者共同决定 C++ 命名空间与各语言模块路径(见下文与 [CONTRIBUTING.md](CONTRIBUTING.md)「目录与多语言布局约定」)。
48
+ - 设计意图(同目录对照的收益、按语言分目录为何是反例、对 AI 的友好之处)见 [docs/directory-layout-rationale.md](docs/directory-layout-rationale.md)。
49
+
50
+ ## Python 包形态与导入约定
51
+
52
+ - mopr 的 Python 代码经 `pyproject.toml` package-dir 注册为 `mopr.*` 子包:`python/` → `mopr`(包入口,导出 `__version__`),`base/` → `mopr.base`,`log/` → `mopr.log`,`machine/` → `mopr.machine`,`runtime/` → `mopr.runtime`,`distributed/` → `mopr.distributed`,`tools/` → `mopr.tools`。仓库根目录无 `__init__.py`,源码形态下 `mopr` 是 PEP 420 隐式命名空间包。
53
+ - 库模块以 `mopr.<子包>.<模块>` 导入;子包间存在跨子包相对导入(如 `log/core.py` 的 `from ..base import ...`),要求按包化名称导入——**禁止**在仓库根以顶层形态验证库模块(`from log.core import logger`、`python -m log.core` 会因相对导入越界报 `attempted relative import beyond top-level package`)。源码形态需在仓库根的父目录运行(或把仓库根加入 `PYTHONPATH`);冒烟写法示例:`python -c "from mopr.log import logger"`。
54
+ - 内置工具 `tools/` 无跨子包相对导入,可顶层 `python -m tools.*`,也可包化 `python -m mopr.tools.*`;提交信息「验证方式」优先采用包化形态。
55
+ - 发现文档/产物中过时或错误的导入命令时,在 AGENTS.md / BUILDING.md 等人工维护文档中修正;CHANGELOG.md 由 autochangelog 自动生成/刷新,其内容(含历史验证命令)**禁止手工编辑**。
56
+
57
+ ## C++ 头文件引用约定
58
+
59
+ - **公共头文件之间的跨目录引用一律用「相对当前文件的相对路径」**(引号形式):`runtime/once.h` 引 `base/cron.h` 必须写 `#include "../base/cron.h"`;**禁止**仓库根相对路径(`"base/cron.h"`)与尖括号形式(`<base/cron.h>`)。
60
+ - 原因:mopr 公共头文件随安装统一放入 `include/mopr/<模块>/`(如 `include/mopr/base/cron.h`),安装后 include 根为 `include/`,仓库根相对路径与尖括号形式均搜索不到;相对路径的目录关系在源码树与安装后保持一致。
61
+ - 同目录引用写 `#include "error.h"`;第三方头文件仍用尖括号(`#include <spdlog/spdlog.h>`)。
62
+ - `.cpp`、`tests/`、`benchmark/` 等不随安装分发的文件可用仓库根相对路径(构建期由 `$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}>` 提供 include 根)。
63
+ - 使用方包含安装后的头文件写 `<mopr/<模块>/<头文件>.h>`(如 `<mopr/runtime/once.h>`)。
64
+
65
+ ## C++ 命名空间与头文件宏约定
66
+
67
+ - **命名空间**:以项目名 `mopr` 为根,**仓库根路径下的子目录为第二级**,多级目录依次下探:
68
+ - `base/timestamp.h` → `mopr::base`;`storage/storage.h` → `mopr::storage`;
69
+ - `distributed/id/hlc.h` → `mopr::distributed::id`;`encoding/csv.h` → `mopr::encoding`。
70
+ - 同一模块内可按文件/职责再设下一级子命名空间(如 `base/strings.h` → `mopr::base::strings`;`encoding/csv.h` → `mopr::encoding::csv`;`encoding/json.h` → `mopr::encoding::json`,含 `mopr::encoding::json_detail` / `mopr::encoding::safe_json` / `mopr::encoding::unsafe_json`;`encoding/yaml.h` → `mopr::encoding::yaml` / `mopr::encoding::safe_yaml`)。
71
+ - **禁止**使用未挂 `mopr` 根的顶层命名空间(如 `namespace encoding`、`namespace runtime`)。第三方库自身的顶层命名空间(如 csv-parser 的 `csv`、yaml-cpp 的 `YAML`)不得作为本项目的命名空间根,与本项目命名空间冲突时一律以全局限定形式书写(`::csv::`)。
72
+ - **头文件宏(`#ifndef` 守卫)**:`MOPR_{大写的目录名}_{文件名}_H`,目录层级用下划线连接,文件名取去扩展名的主体:
73
+ - `encoding/csv.h` → `MOPR_ENCODING_CSV_H`;`encoding/charsets.h` → `MOPR_ENCODING_CHARSETS_H`;
74
+ - `distributed/id/hlc.h` → `MOPR_DISTRIBUTED_ID_HLC_H`;`base/strings.h` → `MOPR_BASE_STRINGS_H`。
75
+ - 守卫宏与 `#pragma once` 并存;`#endif` 行以注释回写宏名(如 `#endif // MOPR_ENCODING_CSV_H`)。
76
+ - 新增公共头文件一律遵循上述规则。既有不合规处按模块逐个收敛(`runtime::*` → `mopr::runtime::*`、`base/filesystem.h` 的 `filesystem` → `mopr::base::filesystem`、`base/except.h` 的 `quant1x` → `mopr::base`、`base/mmap.h` 的全局 `file_mmap` / `mmap_open` / `mmap_flush` / `mmap_close` → `mopr::base` 内的 `MmapHandle` / `mmap_open` / `mmap_flush` / `mmap_close`),不做一次性大范围改名。
77
+ - **公开符号命名跨语言一致**(同一语义在各语言同名,便于跨语言对照与回溯):
78
+ - **公开函数名一致**:Python 与 C++ 使用同一函数名(如 Python `mmap_open` ↔ C++ `mmap_open`),不因语言差异改名;Rust / Go 沿用本语言惯例的,须在模块文档的 API 对照表中给出对应关系。
79
+ - **函数名带模块前缀时不套同名命名空间**:函数名已含模块前缀(如 `mmap_`)时,C++ 侧不再套一层同名命名空间——`mmap_open` 直接位于 `mopr::base`,而非 `mopr::base::mmap::mmap_open`(同风格参考 `base/region.h` 的 `region_currency` / `region_timezone`)。
80
+ - **公开结构体 typedef 统一 `mopr_` 前缀**:结构体标签与 typedef 用同名风格,如 `typedef struct mopr_xxx mopr_xxx_t;`;但跨语言共享的**句柄类型除外**——句柄跨语言同名,C++ 侧直接定义 `struct MmapHandle`(与 Python / Rust / Go 的 `MmapHandle` 一字不差),不套 `mopr_xxx_t` 风格。
81
+ - **句柄类型不得命名 `File`**:句柄承载的是映射而不是文件(文件句柄只是其内部成员之一),`File` 会与 `os.File` / 文件流混淆;跨语言统一用 `MmapHandle`(C++ 为 `struct MmapHandle`)。
82
+ - **句柄操作遵循语言惯例**:Python / Rust / Go 用句柄方法(`flush` / `close`、`Flush` / `Close`),C++ 句柄是 POD,用同名自由函数(`mmap_flush` / `mmap_close`)与之一一对应。
83
+ - **同一语义可同时提供「公开 API + RAII 类」两层**:第一层为跨平台公开 API(如 `mmap_open` / `mmap_flush` / `mmap_close` + 句柄),资源由调用方显式管理;第二层为跨语言同名的 RAII 类(如 `MappedMemory`:`MappedMemory.open` 打开,析构 / `Drop` / `with` / `defer` 自动释放)。两层共用同一实现、语义必须一致,区别仅在释放时机;模块文档须给出两层对照表(示例见 `base/mmap.md`「1. 分层与命名」)。
84
+ - **RAII 类名不得与模块名重复**:类名不叫 `mmap` / `Mmap`(与模块名、包名重复,且易被误读为句柄),统一用其语义名(如 `MappedMemory`),并跨语言同名;句柄另用 `XxxHandle`(如 `MmapHandle`,四语言同名,C++ 亦为 `struct MmapHandle`)。
85
+ - 已知遗留(需按模块逐一评估,勿批量替换):`base/common.h` 的全局 typedef 与常量(`i8` / `u8` / … 为标量别名、非结构体 typedef,不适用 `mopr_` 前缀约定),`base/format.h` 的全局探测模板与 `std::vector` 的 `operator<<`(依赖 ADL / 非限定查找,移入命名空间会导致使用方找不到),`tests/` 下 `*_test_types` 等测试辅助命名空间。
86
+
87
+ ## git 提交规范
88
+
89
+ ### 1. 提交信息规范(含上级仓库约定)
90
+
91
+ 以下约定与上级 `quant1x` 仓库的提交规范保持一致:
92
+
93
+ - **提交标题与正文必须使用中文**,准确说明本次变更内容;必要时可保留英文术语(如 `fmt`、`VcpkgEnabled`、`conan_toolchain`)作为对象标识。
94
+ - **主题统一模板**:`<type>[<language>]:<summary>`(注意冒号为全角 `:`)。
95
+ - `<type>` 取值:`feat`(新特性)、`fix`(修复)、`refactor`(重构)、`perf`(性能)、`docs`(文档)、`test`(测试)、`chore`(例行维护)。
96
+ - `<language>` 取值:`python`、`c++`、`rust`、`go`、`java`、`multi`。mopr 是单仓多语言库(monolibrary),同一语义将来可能有多种语言实现,必须如实标注;本仓库当前以 `c++` 为主。多语言组合用半角逗号 `,` 分隔并按语义顺序书写(如 `python,c++`、`c++,rust`、`python,c++,rust,go,java`)——注意 `c++` 自身含 `+`,不用 `+` 连接以免出现 `c+++rust` 这类难读形式;变更仅涉及构建/工具/文档等不含代码语言的杂项时,标注其影响的实现语言,或使用 `multi`。
97
+ - **主题禁止仅写空泛描述**(如 `update` / `optimize` / `fix` 这类无对象的词),必须指明对象与语言,例如:
98
+ - `fix[c++]:修正 conan 静态运行时链接被 vcpkg 集成劫持的问题`
99
+ - `feat[c++]:重构 conan/cmake 多配置构建体系`
100
+ - `docs[c++]:更新 BUILDING.md 构建矩阵`
101
+ - **正文**在标题后空一行,以 `- ` 分条列出要点;**跨语言同步改动**(本仓库如引入 `c++,rust` 等)正文必须补充:
102
+ 1. 变更概述;
103
+ 2. 涉及语言与文件范围;
104
+ 3. 语义一致性说明;
105
+ 4. 验证方式/测试命令。
106
+
107
+ ```
108
+ feat[c++]:新增按 build_type/runtime 分目录的构建布局
109
+
110
+ - conanfile.layout 按 build_type 与 compiler.runtime 推导独立目录
111
+ - 验证:conan install . --build=missing && cmake --preset release-dynamic
112
+ ```
113
+
114
+ - **提交信息不得包含版本号、Git Tag 或发布相关信息**;tag 与版本号管理如另有工具负责(如 [autochangelog](https://gitee.com/quant1x/autochangelog)),不得手动干预。
115
+ - 提交前必须逐项核对清单(Checklist):
116
+ - [ ] 主题是否符合 `type[language]:summary` 模板?
117
+ - [ ] `type` 是否真实反映本次变更类型?
118
+ - [ ] `language` 是否准确标注本次涉及的开发语言,未标注或误标注视为不合规?
119
+ - [ ] 标题是否避免空泛描述、明确对象和影响?
120
+ - [ ] 正文是否包含要点(跨语言时含变更概述、文件范围、语义一致性、验证方式)?
121
+ - [ ] 是否未包含版本号 / Git Tag / 发布相关字符串?
122
+ - [ ] 是否以中文为主,能按语言维度快速过滤和回溯?
123
+
124
+ 任一项未满足,必须在提交前修正,不能直接提交。
125
+
126
+ ### 2. Windows 下提交信息的字符集约定(重要)
127
+
128
+ **背景**:Windows PowerShell 下在命令行内直接内嵌中文提交信息,会因 GBK/UTF-8 编码错乱导致解析失败(报错形如"字符串缺少终止符"或中文乱码),且此类失败发生在命令解析阶段,`&&` 前序命令(如 `git add`)也不会执行。
129
+
130
+ **标准做法**:涉及中文的提交信息不得直接写入命令行参数,必须按以下流程执行:
131
+
132
+ 1. 用工具(write_to_file)将提交信息写入 UTF-8 编码的临时文件,例如 `<仓库根>/.git/commit-msg.tmp`(放在 `.git/` 内,不污染工作树):
133
+ ```
134
+ chore: 中文标题
135
+
136
+ - 正文要点一
137
+ - 正文要点二
138
+ ```
139
+ 2. 依次执行暂存与提交:
140
+ ```
141
+ git add <文件>
142
+ git commit -F .git/commit-msg.tmp
143
+ ```
144
+ 3. 提交成功后删除临时文件:
145
+ ```
146
+ Remove-Item .git/commit-msg.tmp
147
+ ```
148
+
149
+ **推论**:任何需要在 Windows 命令行传递的中文内容(提交信息、`-m` 参数、脚本输入等)都应优先改用文件传递(`-F`、`--file` 等参数),规避编码问题。
150
+
151
+ ### 3. 其他
152
+
153
+ - 除非用户明确要求,不得执行 `git commit`、`git push`、`git rebase` 等写操作。
154
+ - 不做破坏性 git 操作(`push --force`、`reset --hard` 等)。
155
+ - tag 与版本号管理如另有工具负责(如 [autochangelog](https://gitee.com/quant1x/autochangelog)),不得手动干预。
156
+ - autochangelog 安装方法见 [BUILDING.md](BUILDING.md)「版本发布(autochangelog)」。
@@ -1,6 +1,6 @@
1
1
  # 构建与编译指南
2
2
 
3
- mopr 是单仓多语言库(monolibrary),同一语义提供 Python、C++、Rust、Java 多种实现;各语言的构建、编译与发布相互独立,不共享发布包。本文档按 **Python → C++ → Rust → Java → Go** 的顺序分别介绍各语言的构建与运行方式。
3
+ mopr 是单仓多语言库(monolibrary),同一语义提供 Python、C++、Rust、Go、Java 多种实现;各语言的构建、编译与发布相互独立,不共享发布包。本文档按 **Python → C++ → Rust → Go → Java** 的顺序分别介绍各语言的构建与运行方式。
4
4
 
5
5
  第三方组件的声明与许可证归档(`THIRD_PARTY_NOTICES.md` + `third_party/licenses/`)是各语言发布前的公共合规步骤,见 6「第三方声明与许可证归档」。
6
6
 
@@ -9,8 +9,8 @@ mopr 是单仓多语言库(monolibrary),同一语义提供 Python、C++、
9
9
  | Python | `python/`(包入口)、`base/`、`log/`、`machine/`、`runtime/`、`distributed/`、`tools/` 中的 `*.py` | 源码树直接运行(核心模块仅标准库;`log/core.py` 用运行时第三方依赖 loguru,见 `pyproject.toml`);包形态与导入方式见 1.1 |
10
10
  | C++ | 仓库根 `main.cpp`,`base/`、`runtime/`、`distributed/id/` 的 `*.cpp/*.h` | Conan 2 + CMake(当前构建主线) |
11
11
  | Rust | 仓库根 `Cargo.toml` / `lib.rs` / `main.rs`,`runtime/`、`distributed/` 的 `*.rs` | Cargo |
12
- | Java | `distributed/id/*.java`,测试/基准 `tests/runtime/*.java` | Maven(`mvn test` 运行 JUnit 5 测试/基准)/ javac |
13
12
  | Go | `base/`、`runtime/`、`distributed/` 的 `*.go` | `go build ./...`(模块内多包,无独立 main) |
13
+ | Java | `distributed/id/*.java`,测试/基准 `tests/runtime/*.java` | Maven(`mvn test` 运行 JUnit 5 测试/基准)/ javac |
14
14
 
15
15
  ## 1. Python 构建
16
16
 
@@ -49,7 +49,7 @@ python .\distributed\id\tests.py
49
49
 
50
50
  ## 2. C++ 构建
51
51
 
52
- > C++ 是仓库当前构建主线(Conan 2 + CMake),验证环境:**Windows + MSVC**,工程入口为仓库根 `main.cpp`;与 Rust、Python、Java 各语言构建相互独立,不共享发布包。
52
+ > C++ 是仓库当前构建主线(Conan 2 + CMake),验证环境:**Windows + MSVC**,工程入口为仓库根 `main.cpp`;与 Python、Rust、Java 各语言构建相互独立,不共享发布包。
53
53
 
54
54
  本节描述 C++ 工程从零构建、编译、运行的完整步骤,其它平台差异见 2.9「平台差异」。
55
55
 
@@ -74,7 +74,7 @@ conan --version
74
74
 
75
75
  ```
76
76
  conan install -s build_type=<Release|Debug> -s compiler.runtime=<dynamic|static>
77
- │ ① 按参数解析/安装 fmt 依赖(CMakeToolchain + CMakeDeps 生成器)
77
+ │ ① 按参数解析/安装 conanfile.py 声明的依赖(fmt/backward-cpp 等,CMakeToolchain + CMakeDeps 生成器)
78
78
  │ ② conanfile.layout 按 build_type-runtime 推导独立目录 build/<bt>-<rt>/generators
79
79
  ▼
80
80
  cmake --preset <bt>-<rt> ← 仓库根 CMakePresets.json(手写、入库)
@@ -136,9 +136,11 @@ cmake --build --preset debug-static
136
136
 
137
137
  | 文件 | 作用 | 入库 |
138
138
  | --- | --- | --- |
139
- | `conanfile.py` | 依赖声明 + 生成器;`configure()` 固化 cppstd(MSVC→`20`,gcc/clang→`gnu20`);`layout()` 按 build_type-runtime 分目录 | ✅ |
139
+ | `conanfile.py` | 依赖声明 + 生成器;`configure()` 固化 cppstd(MSVC→`20`,gcc/clang→`gnu20`);`layout()` 按 build_type-runtime 分目录;`package_type` / `exports_sources` / `build()` / `package()` / `package_info()` 供 `conan create` 出包(见 2.11) | ✅ |
140
140
  | `CMakePresets.json` | 手写 4 组合 preset,`${presetName}` 自动对齐目录 | ✅ |
141
- | `CMakeLists.txt` | `CMAKE_CXX_STANDARD 20`;`CMAKE_CONFIGURATION_TYPES` 默认单 `Release`(可被 preset/命令行覆盖);target 级 `VS_GLOBAL_VcpkgEnabled=false`(见 2.10「常见问题」) | ✅ |
141
+ | `CMakeLists.txt` | `CMAKE_CXX_STANDARD 20`;`CMAKE_CONFIGURATION_TYPES` 默认单 `Release`(可被 preset/命令行覆盖);`MOPR_BUILD_TESTS` / `MOPR_BUILD_BENCHMARK` 构建范围开关(默认 ON);target 级 `VS_GLOBAL_VcpkgEnabled=false`(见 2.10「常见问题」) | ✅ |
142
+ | `cmake/mopr-config.cmake.in` | CMake 包配置模板(`find_package(mopr)` 的依赖转发与目标引入,见 2.11) | ✅ |
143
+ | `test_package/` | `conan create` 的使用方验收用例(只 `find_package(mopr)` + `mopr::mopr_core`,见 2.11 ②) | ✅ |
142
144
  | `build/`、`CMakeUserPresets.json` | conan/cmake 自动生成的可再生物(`.gitignore`) | ❌ |
143
145
 
144
146
  `CMakeUserPresets.json` 由每次 `conan install` 生成/累积(include conan 的 preset);项目已自带手写 `CMakePresets.json`,**不需要依赖它**。若累积导致 `Duplicate preset` 报错,直接删除该文件即可。
@@ -230,7 +232,7 @@ powershell -ExecutionPolicy Bypass -File .\refresh-clangd.ps1
230
232
  # VS Code 内也可:终端 → 运行任务 → "refresh clangd db (ninja-debug)"
231
233
  ```
232
234
 
233
- 脚本自动完成:激活 VS x64 环境 → `conan install`(debug-dynamic 依赖,已装则秒过)→ 清理 conan 生成的 `CMakeUserPresets.json`(避免 `Duplicate preset` 冲突)→ `cmake --preset ninja-debug`。
235
+ 脚本自动完成:屏蔽 vcpkg 用户级 MSBuild 集成(仅在本机存在该集成时生效,见 2.10——否则 conan 编译 `spdlog` 时会被 vcpkg 的动态 fmt 11 污染)→ 若缓存里的 `spdlog` 已被污染则强制重建 → 激活 VS x64 环境 → `conan install`(debug-dynamic 依赖,已装则秒过)→ 清理 conan 生成的 `CMakeUserPresets.json`(避免 `Duplicate preset` 冲突)→ `cmake --preset ninja-debug`。
234
236
 
235
237
  - `ninja-debug` 是仓库 `CMakePresets.json` 里的 configure preset(Ninja 生成器 + 仓库根 `ninja-toolchain.cmake`);
236
238
  - `ninja-toolchain.cmake` 是 wrapper:`include()` VS 构建的 conan toolchain 后清空 `CMAKE_GENERATOR_PLATFORM`/`CMAKE_GENERATOR_TOOLSET`(否则 Ninja 报 "does not support platform/toolset specification"),并复用 debug-dynamic 已装的依赖,无需单独安装;
@@ -272,6 +274,19 @@ go install gitee.com/quant1x/autochangelog@latest
272
274
  - 多为**只装了某一种配置的依赖**而 VS 多配置生成器校验其它配置。本工程 preset 已收敛单配置(`CMAKE_CONFIGURATION_TYPES`),应不再出现;
273
275
  - 若仍出现:`build/<组合>/generators/` 里残留了其它 build_type 的数据文件(conan 二次安装不清理),删除该组合目录后重跑 `conan install`。
274
276
 
277
+ **Q:configure 报 `find_package(Backward)` 失败 / 找不到新增依赖的 `*Config.cmake`**
278
+ - 原因:`build/<组合>/generators/` 是**旧版 `conanfile.py`** 生成的产物,停留在新增/更换依赖之前的依赖集。conan 二次安装会按**当前** conanfile 全量重生成 generators,但不会自动触发——升级 `conanfile.py` 后,既有组合目录**不会自行补装**新增包。典型现场:generators 里只有 `fmt`/`spdlog`/`benchmark` 等旧 `*Config.cmake`,缺新增包的配置(如 `BackwardConfig.cmake`),configure 在对应 `find_package` 处中断;
279
+ - 处理:按 2.3「构建矩阵」重跑**该组合对应参数**的依赖安装,再重新 configure:
280
+ ```powershell
281
+ conan install . --build=missing -s build_type=Debug -s compiler.runtime=static # 参数与 preset 一一对应
282
+ cmake --preset debug-static --fresh
283
+ ```
284
+ `--build=missing` 会就地编译缓存中缺失的源码包(首次可能较长,如 openssl/curl)。核对方法:configure 日志应列出全部依赖的 `find_package(...)` 声明,`generators/` 目录应含对应的 `*Config.cmake`。
285
+
286
+ **Q:configure 日志 `MOPR_CHRONO_TZ_OK - Failed`(MSVC 构建被误链入 date 库)**
287
+ - 背景:`CMakeLists.txt` 用编译探针实测 `locate_zone`/`zoned_time` 是否可用——探针**通过**(MSVC STL / libstdc++ 已实现)则用标准库 C++20 chrono、不链 date;**失败**才链 `date` 作回退(设计上服务于标准库缺 chrono 时区的平台,如 macOS 的 libc++,`time.cpp` 同时以 `__cpp_lib_chrono < 201907` 走 date 分支,两者判定一致)。原探针写法 `zoned_time<milliseconds> zt{z, system_clock::now()}` 在 MSVC STL 下不可移植:MSVC 的 `zoned_time` 构造要求时间点**精确**为类模板的 `Duration`,而 `system_clock::time_point` 是 100ns 步进,到 `milliseconds` 属截断转换、不能隐式绑定,故在 MSVC 上必然失败、Windows 构建被误判多链 date(libstdc++/libc++ 的该构造是模板、内部自动转换,可编译);
288
+ - 处理:探针已改为先 `time_point_cast<milliseconds>` 的可移植写法(对其它 STL 同样成立)。探针结果缓存在 `CMakeCache.txt`,拉取/升级代码后需 `cmake --preset <组合> --fresh`(或删除 CMakeCache)重新配置,确认日志为 `MOPR_CHRONO_TZ_OK - Success`。
289
+
275
290
  **Q:`Duplicate preset ...`**
276
291
  - `CMakeUserPresets.json` 被多次 `conan install` 累积 include。删除该文件即可(手写 `CMakePresets.json` 不受影响)。
277
292
 
@@ -279,15 +294,122 @@ go install gitee.com/quant1x/autochangelog@latest
279
294
  - 机器上若有 vcpkg 的用户级 MSBuild 集成(`%LOCALAPPDATA%\vcpkg\vcpkg.user.props` 等),会劫持链接(用 vcpkg 动态 `fmt.lib` 抢占 conan 静态库)。仓库已在 `CMakeLists.txt` 给 target 注入 `VcpkgEnabled=false` 阻断,仅对本工程生效、不影响其它项目;
280
295
  - 若发现该文件缺失或早期产物残留,删除产物旁的 `fmt.dll` 重建即可。
281
296
 
297
+ **Q:链接报 `LNK2019` / `LNK2001`,未解析符号里同时出现 `fmt::v11` 与 `fmt::v12`**
298
+ - 现场:`mopr_core.lib`、各 `*_test.obj` 引用 `fmt::v12::...`(本工程用 conan 的 fmt 12 静态),而 `spdlogd.lib` 里却是 `__declspec(dllimport) ... fmt::v11::...`,两者无法对上;
299
+ - 原因:**vcpkg 用户级 MSBuild 集成劫持的不只是本工程的 target,还包括 conan 编译依赖包的过程**。`vcpkg.user.props` / `vcpkg.user.targets` 会把 `$(VCPKG_ROOT)\installed\<triplet>\include`(及 lib)注入**所有** MSBuild 工程;`CMakeLists.txt` 的 `VcpkgEnabled=false` 只加在 mopr 自身 target 上,conan 构建 `spdlog` 时不受保护,于是 spdlog 被编成 vcpkg 的**动态 fmt 11**(`fmtd.dll`),与 conan 的静态 fmt 12 ABI 不兼容。此现象与 `build/` 目录新旧无关,重跑 `conan install` 也不会自愈(conan 认为该包已存在,直接复用);
300
+ - 判定(任选其一):
301
+ - 查 conan 缓存里该 spdlog 包的静态库引用了哪个 fmt 内联命名空间——`@v11@fmt@@` 出现、`@v12@fmt@@` 为 0 即为被污染;对应包目录可由 `build/<组合>/generators/spdlog-*-data.cmake` 的 `spdlog_PACKAGE_FOLDER_*` 定位;
302
+ - 查该包的 conan 构建目录(`conan cache path spdlog/1.17.0 --folder=build`)下 `*.tlog` 是否出现 `vcpkg\installed` 路径;
303
+ - 处理:让 conan **强制重建**受影响的包,并在重建时跳过 vcpkg 集成。该逃生开关由 vcpkg 自身的 props 导入条件提供(`'$(VCPkgLocalAppDataDisabled)' == ''`),设置后本次 MSBuild 调用即不再导入 vcpkg:
304
+ ```powershell
305
+ $env:VCPkgLocalAppDataDisabled = '1' # 仅影响当前终端内的 MSBuild 调用
306
+ conan install . --build=missing --build=spdlog/* -s build_type=Debug -s compiler.runtime=dynamic
307
+ cmake --preset debug-dynamic --fresh
308
+ ```
309
+ 重建后缓存中该 spdlog 包即为正确版本,后续构建无需重复;**每个组合(见 2.3 构建矩阵)各跑一次**。通常只需重建 `spdlog`——`fmt` 包本身由 conan 自行构建、不受该劫持影响,可用上面的符号检查确认;
310
+ - 注:只做 `conan install`(不带 `--build=spdlog/*`)或 `cmake --preset ... --fresh` 都无法修复,因为问题出在**依赖包的二进制**里,不是 generators 或 CMakeCache。
311
+
282
312
  **Q:`fmt/format.h file not found`(编辑器内标红)**
283
313
  - 编辑器报红是**语言服务器问题**,不代表编译失败——以构建结果为准。clangd 已通过 Ninja 旁路(`build/ninja-debug` 编译数据库)接入,配置方法见 2.7.6;若旁路目录尚未配置或依赖更新后未刷新,就会出现标红,重跑 `cmake --preset ninja-debug` 即可。
284
314
 
285
315
  **Q:`conan install` 报 cppstd / profile 错误**
286
316
  - 工程已在 `conanfile.py` 固化 cppstd(MSVC→`20`,gcc/clang→`gnu20`),正常无需 `-s`;若仍报错,检查本机 default profile(`conan profile show`)与编译器是否匹配。
287
317
 
318
+ **Q:`conan create` 在缓存内报缺源文件 / `string sub-command REPLACE requires at least four arguments`**
319
+ - 缺源文件:`conan create` 只把 `conanfile.py` 的 `exports_sources` 列出的文件导出到缓存。新增 C++ 源文件、公共头或 `cmake/` 脚本后,若未同步补模式,缓存内构建就会缺文件;按 `CMakeLists.txt` 的 `add_library` / `install(FILES)` 清单同步更新 `exports_sources`(见 2.11 ②);
320
+ - `git_tag_info` 报错:缓存内的源树不是 git 仓库。`build()` 会传 `-DMOPR_VERSION_OVERRIDE=<包版本>`(由 `conanfile.py` 的 `set_version` 从 git tag 得到),`cmake/git_tag_info.cmake` 收到该变量后直接采用、不再探测 git;若在其它非 git 源树(源码包/导出目录)手工 configure 且未传该变量,脚本会回退版本 `0.0.0` 并把 git 元信息置空。
321
+
322
+ ### 2.11 安装与使用方消费(find_package)
323
+
324
+ `mopr_core` 对外只有一种写法,两种获取途径:
325
+
326
+ ```cmake
327
+ find_package(mopr CONFIG REQUIRED)
328
+ target_link_libraries(<tgt> PRIVATE mopr::mopr_core)
329
+ ```
330
+
331
+ ```cpp
332
+ #include <mopr/<模块>/<头文件>.h> // 例:<mopr/runtime/once.h>
333
+ ```
334
+
335
+ | 途径 | 获取方式 | `mopr-config.cmake` 来源 | 第三方依赖 |
336
+ | --- | --- | --- | --- |
337
+ | ① 安装前缀(不走 conan 的下游) | `cmake --install build/<组合> --config <Debug\|Release> --prefix <P>` | 随安装写入 `<P>/lib/cmake/mopr/`(仓库自带,可整体搬迁) | 使用方自备(config 内 `find_dependency` 转发) |
338
+ | ② conan 包 | `conan create .` 出包后,使用方 `requires("mopr/<版本>")` | 使用方 `conan install` 时由 CMakeDeps 生成;包内同时携带 ① 的同一套 config | 由 conan 自动解析并转发 |
339
+
340
+ 两种途径的 target 名(`mopr::mopr_core`)与 include 形态一致,切换途径无需改源码。
341
+
342
+ #### 2.11.1 ① cmake --install(不使用 conan 的下游)
343
+
344
+ ```powershell
345
+ cd <仓库根>
346
+ conan install . --build=missing # 提供第三方依赖(fmt/spdlog/...,也可换 vcpkg 或系统包)
347
+ cmake --preset release-dynamic
348
+ cmake --build --preset release-dynamic
349
+ cmake --install build/release-dynamic --config Release --prefix D:\sdk\mopr
350
+ ```
351
+
352
+ 安装布局:
353
+
354
+ ```
355
+ <P>/include/mopr/<模块>/<头文件>.h 公共头文件(使用方 include 根 = <P>/include)
356
+ <P>/lib/mopr_core.lib 静态库(类 Unix 为 libmopr_core.a)
357
+ <P>/lib/cmake/mopr/ mopr-config.cmake、mopr-config-version.cmake、mopr-targets*.cmake
358
+ <P>/share/licenses/mopr/ THIRD_PARTY_NOTICES.md + C++ 侧许可证全文
359
+ ```
360
+
361
+ 使用方:
362
+
363
+ ```cmake
364
+ list(APPEND CMAKE_PREFIX_PATH "D:/sdk/mopr") # 或 -Dmopr_DIR=D:/sdk/mopr/lib/cmake/mopr
365
+ find_package(mopr CONFIG REQUIRED)
366
+ target_link_libraries(app PRIVATE mopr::mopr_core)
367
+ ```
368
+
369
+ - `mopr-config.cmake` 会转发 `mopr_core` 的全部第三方依赖(fmt、spdlog、tsl-robin-map、magic_enum、pfr、bshoshany-thread-pool、Backward、libiconv、rapidjson、csv-parser、yaml-cpp;平台缺 C++20 chrono tz/parse 时另有 date),使用方需能自行解析这些包:沿用 conan 时把 `build/<组合>/generators` 加进 `CMAKE_PREFIX_PATH` 即可(该目录已含各依赖的 `*config.cmake`);
370
+ - `mopr_core` 是**单配置**产物(`CMAKE_CONFIGURATION_TYPES` 收敛,见 2.6),使用方须用与安装时相同的 `build_type`,否则报 `IMPORTED_LOCATION not set`;
371
+ - 依赖清单在上述 `.in` 模板与 `CMakeLists.txt` 顶部 `find_package` 两处同步维护(见文件内注释)。
372
+
373
+ #### 2.11.2 ② conan 包
374
+
375
+ ```powershell
376
+ cd <仓库根>
377
+ conan create . --build=missing -s build_type=Release # 或 -s build_type=Debug -s compiler.runtime=static 等,参数与 2.3「构建矩阵」同款
378
+ ```
379
+
380
+ `conan create` 在 conan 缓存内按 profile 构建并打包,包内容:
381
+
382
+ ```
383
+ include/mopr/<模块>/<头文件>.h 公共头文件
384
+ lib/mopr_core.lib 静态库
385
+ lib/cmake/mopr/ 仓库自带的同一套 config(版本号 = 包版本 = git tag)
386
+ share/licenses/mopr/ 第三方声明与许可证全文
387
+ ```
388
+
389
+ 要点:
390
+
391
+ - 包构建只产出 `mopr_core` 与安装物:`conanfile.py` 的 `build()` 按 `MOPR_BUILD_TESTS=OFF`、`MOPR_BUILD_BENCHMARK=OFF` 配置,`tests/`、`benchmark/` 及其 GoogleTest / Google Benchmark 依赖(`test_requires`)不参与包构建,也不传播给使用方;
392
+ - 包构建的源文件白名单是 `conanfile.py` 的 `exports_sources`(不含 `tests/`、`benchmark/` 与其它语言实现),新增 C++ 源文件 / 公共头 / `cmake/` 脚本后需同步补模式(见 2.10 对应条目);
393
+ - 包的 target 名与仓库自带 config 一致(`package_info()` 的 `cmake_file_name=mopr`、`cmake_target_name=mopr::mopr_core`),使用方写法与 2.11.1 相同;
394
+ - `test_package/` 是包验收用例:`conan create` 打完包后会**以使用方姿态**(`requires(mopr/<版本>)` + `find_package(mopr CONFIG REQUIRED)` + `mopr::mopr_core`,无任何手工路径注入)编译并运行一个最小可执行文件,验证头文件安装位置、库链接与第三方依赖转发都成立;该用例在仓库内构建(产物在 `test_package/build/`,已被 `.gitignore` 的 `build/` 规则覆盖),不需要时用 `-tf ""` 跳过该阶段——编辑器把 `#include <mopr/...>` 标红属语言服务器未接入包路径,以 `conan create` 结果为准(同 2.10 的编辑器标红条目);
395
+ - **不影响日常开发**:平时仍按 2.4 走 `conan install .` + `cmake --preset`,`conan create` 只在出包时执行。
396
+
397
+ 使用方(conan 侧):
398
+
399
+ ```python
400
+ # conanfile.py
401
+ def requirements(self):
402
+ self.requires("mopr/0.0.60")
403
+ ```
404
+
405
+ ```cmake
406
+ find_package(mopr CONFIG REQUIRED)
407
+ target_link_libraries(app PRIVATE mopr::mopr_core)
408
+ ```
409
+
288
410
  ## 3. Rust 构建与发布
289
411
 
290
- > 本仓库是单仓多语言 monorepo,Rust 相关构建与发布必须按 Rust 视角单独维护,不能把 C++ / Python / Java 的实现混进 Rust crate。
412
+ > 本仓库是单仓多语言 monorepo,Rust 相关构建与发布必须按 Rust 视角单独维护,不能把 Python / C++ / Java 的实现混进 Rust crate。
291
413
 
292
414
  Rust crate 的根目录是仓库根,入口文件为:
293
415
 
@@ -332,7 +454,7 @@ cargo publish --dry-run --allow-dirty
332
454
 
333
455
  - `Cargo.toml` 里 `publish = true`
334
456
  - `include` 仅保留 Rust 源文件、README 与必要元数据,并显式纳入 `THIRD_PARTY_NOTICES.md` 与 `third_party/licenses/rust/**`(第三方合规物随 .crate 一并分发,见 CHANGELOG 0.0.31)
335
- - Go / Java / Python / C++ 的实现不进入 Rust 包
457
+ - Python / C++ / Go / Java 的实现不进入 Rust 包
336
458
  - 发布前先按 6「第三方声明与许可证归档」运行 `python -m tools.license_audit rust`,确认无「缺失 / 待人工补录」项后再发版;外部合规检查工具的清单、安装、使用与产出物见 3.5
337
459
 
338
460
  ### 3.3 发布
@@ -479,7 +601,7 @@ mvn test
479
601
 
480
602
  ## 5. Go 构建
481
603
 
482
- > Go 实现为模块内多包形态(无独立可执行入口),代码位于 `base/`、`runtime/`、`distributed/` 下的 `*.go`(`go.mod`:`module github.com/quant1x/mopr`);与 C++(当前构建主线)、Rust、Python、Java 各语言构建相互独立,不共享发布包。
604
+ > Go 实现为模块内多包形态(无独立可执行入口),代码位于 `base/`、`runtime/`、`distributed/` 下的 `*.go`(`go.mod`:`module github.com/quant1x/mopr`);与 Python、C++(当前构建主线)、Rust、Java 各语言构建相互独立,不共享发布包。
483
605
 
484
606
  ### 5.1 版本要求
485
607
 
@@ -503,7 +625,7 @@ go build ./...
503
625
  go test ./...
504
626
  ```
505
627
 
506
- 现有包:`base/cache`(内存映射缓存)、`base/mem`(页与大小换算)、`runtime`(环形缓冲)、`distributed/id`(分布式 ID,含 `state_lock_windows.go` 等平台分文件)。也可按目录定向运行:
628
+ 现有包:`base/cache`(泛型内存映射缓存)、`base/mem`(页与大小换算)、`base/mmap`(文件内存映射)、`runtime`(环形缓冲)、`distributed/id`(分布式 ID,含 `state_lock_windows.go` 等平台分文件)。也可按目录定向运行:
507
629
 
508
630
  ```powershell
509
631
  go test ./runtime/... ./distributed/id/...
@@ -515,14 +637,14 @@ Go 侧唯一运行时第三方依赖为 `golang.org/x/sys` v0.47.0(声明于 `
515
637
 
516
638
  ### 5.4 平台分文件与许可证头
517
639
 
518
- `base/cache` 的 mmap 与 `distributed/id` 的 state_lock 均按平台拆分实现:`mmap_windows.go` / `mmap_posix.go` / `mmap_unsupported.go`、`state_lock_windows.go` / `state_lock_unix.go` / `state_lock_other.go`。平台分文件必须保留 `//go:build` 构建约束:许可证头位于其前(均为行注释,Go 允许 build constraint 被行注释与空行前置),批量写入版权/许可证头时不得删除 build tag;`mapFile`、`processAlive` 等平台符号由 build tag 决定唯一编译。平台分文件改动不得引入低于 Go 1.27.0 的特性。当前验证环境(Windows + `go1.27.0`)下 `go build ./...` 与 `go test ./...` 全绿(`base/cache`、`base/mem`、`distributed/id`、`runtime` 四个包)。
640
+ `base/mmap` 的映射实现与 `distributed/id` 的 state_lock 均按平台拆分实现:`mmap_windows.go` / `mmap_posix.go` / `mmap_unsupported.go`、`state_lock_windows.go` / `state_lock_unix.go` / `state_lock_other.go`。平台分文件必须保留 `//go:build` 构建约束:许可证头位于其前(均为行注释,Go 允许 build constraint 被行注释与空行前置),批量写入版权/许可证头时不得删除 build tag;`Map`、`processAlive` 等平台符号由 build tag 决定唯一编译。平台分文件改动不得引入低于 Go 1.27.0 的特性。当前验证环境(Windows + `go1.27.0`)下 `go build ./...` 与 `go test ./...` 全绿(`base/cache`、`base/mem`、`base/mmap`、`distributed/id`、`runtime` 五个包)。
519
641
 
520
642
  ## 6. 第三方声明与许可证归档
521
643
 
522
- 发布(源码 / 二进制产物分发)会引入第三方组件:C++ 的 conan 依赖、Rust 的 cargo 依赖、Go 的模块依赖、Python 的 pip 依赖、Java 的 maven 依赖。各许可证普遍要求随分发物附带声明与许可证全文,本仓库以仓库级合规物统一维护,与各语言构建相互独立:
644
+ 发布(源码 / 二进制产物分发)会引入第三方组件:Python 的 pip 依赖、C++ 的 conan 依赖、Rust 的 cargo 依赖、Go 的模块依赖、Java 的 maven 依赖。各许可证普遍要求随分发物附带声明与许可证全文,本仓库以仓库级合规物统一维护,与各语言构建相互独立:
523
645
 
524
- - `THIRD_PARTY_NOTICES.md`(仓库根):第三方组件清单,按语言分节列出组件、版本、许可证与版权;C++ / Rust 直接依赖 / Go / Python / Java 组件表格与 Rust 完整依赖闭包为机器区段(`<!--..._START-->` / `<!--..._END-->` 注释之间),由 6.2 工具每次运行自动刷新(表格「版权 / 主页」列等人工内容按旧文件继承,不随刷新丢失),围栏外段落(头部说明、表外注记、归档目录、更新流程等)保持人工维护;
525
- - `third_party/licenses/`:许可证全文归档,按语言拆分 `third_party/licenses/rust/`、`third_party/licenses/cpp/`、`third_party/licenses/go/`、`third_party/licenses/python/`、`third_party/licenses/java/`;
646
+ - `THIRD_PARTY_NOTICES.md`(仓库根):第三方组件清单,按语言分节列出组件、版本、许可证与版权;Python / C++ / Rust 直接依赖 / Go / Java 组件表格与 Rust 完整依赖闭包为机器区段(`<!--..._START-->` / `<!--..._END-->` 注释之间),由 6.2 工具每次运行自动刷新(表格「版权 / 主页」列等人工内容按旧文件继承,不随刷新丢失),围栏外段落(头部说明、表外注记、归档目录、更新流程等)保持人工维护;
647
+ - `third_party/licenses/`:许可证全文归档,按语言拆分 `third_party/licenses/python/`、`third_party/licenses/cpp/`、`third_party/licenses/rust/`、`third_party/licenses/go/`、`third_party/licenses/java/`;
526
648
  - `tools/license_audit/`:第三方依赖声明生成工具(`mopr.tools.license_audit`,仅 Python 标准库,仓库根执行),按语言子模块扫描依赖并刷新上述文件;
527
649
  - `THIRD_PARTY_TODO.md`(仓库根,运行期生成):每次审计收尾把机器无法自动确定的事项(缺失许可证文本、新增组件版权/主页、许可类型未标注等)写入待办清单;无待办自动删除,不随版本控制(见 `.gitignore`),发布前必须清零;
528
650
  - Python 运行时第三方依赖目前仅 loguru(声明于 `pyproject.toml [project].dependencies`):`python` 子命令核验声明与源码 import 交叉核对,并把许可证文本归档到 `third_party/licenses/python/`;Java 主代码(`distributed/id/`)仅 import JDK 内置包、`mopr` jar 运行时无第三方依赖,其 dev/test 依赖 junit-jupiter/disruptor(仅被 `tests/` 基准代码引用)由 `java` 子命令按源码引用证据推定角色并归档到 `third_party/licenses/java/`;Java 的 Maven 插件与 Python 的构建工具(build-system.requires)仅构建期使用,不随产物分发。
@@ -550,7 +672,7 @@ python -m tools.license_audit # 缺省:依次运行 python/cpp/rust/go
550
672
 
551
673
  ### 6.3 「缺失 / 待人工补录」语义
552
674
 
553
- 脚本输出「缺失 / 待人工补录」表示本地缓存取不到该组件的许可证文本(上游不随包分发、或本地从未下载),脚本不会自动生成该归档并返回非 0。发布前**必须补齐**这些项(可参照既有做法人工补录,如 Rust 侧 r-efi 与两个 winapi 占位子 crate 按 MIT 文本补录)。当前归档 274 个许可证文件(rust 256 + cpp 7 + go 7 + python 1 + java 3),无缺失项(Python 侧 loguru 0.7.3 与 Java 侧 disruptor 3.4.4 的上游产物未随附许可证文件,已按官方文本人工补录;Java 的 dev/test 依赖 junit-jupiter/disruptor 归档见 `third_party/licenses/java/`)。
675
+ 脚本输出「缺失 / 待人工补录」表示本地缓存取不到该组件的许可证文本(上游不随包分发、或本地从未下载),脚本不会自动生成该归档并返回非 0。发布前**必须补齐**这些项(可参照既有做法人工补录,如 Rust 侧 r-efi 与两个 winapi 占位子 crate 按 MIT 文本补录)。当前归档 330 个许可证文件(python 5 + cpp 22 + rust 293 + go 7 + java 3),无缺失项(Python 侧 loguru 0.7.3 与 Java 侧 disruptor 3.4.4 的上游产物未随附许可证文件,已按官方文本人工补录;Java 的 dev/test 依赖 junit-jupiter/disruptor 归档见 `third_party/licenses/java/`)。
554
676
 
555
677
  ### 6.4 依赖变更后的更新流程
556
678