Files
oak-editor/docs/zh/plans/completed/riir/M1-oakcommon.md
T
Mike-Solar 4babbf5de8
CI / Build & test (Linux) (push) Successful in 24m6s
CI / Build & test (Windows) (push) Successful in 31m14s
core: merge oak-common into oak-core
oak-common is gone; its modules (configstore, xmlutils, ocioutils,
oiioutils, colormath, colortransform, videoparams, ffmpegutils, ...)
now live in oak-core alongside the value types. The render value/GPU
types moved too: backend (wgpu context + DisplayRenderer), color
(ColorProcessor over ocio-rs), texture, frame, and the commonutil
config helpers.

Fix-ups to make the merged tree build and pass tests:

- oak-core Cargo.toml: wgpu back to 25 (the moved backend code is
  written against that API generation); add the toml/quick-xml/image
  deps oak-common carried.
- lib.rs: drop the duplicate 'pub mod error;'.
- error.rs: unified OAKCORE_* codes; restore Error::new() and
  From<OcioError> from oak-common's error type.
- backend.rs/color.rs: oak_core::/oak_render:: self-references
  rewritten to crate::; the shaderfx-dependent GPU effect test moved
  to oak-render's shaderfx tests (shaderfx depends on oak-node and
  cannot live in oak-core).
- oak-render's error module re-exports oak_core::error::{Error,
  Result}; the OAKRENDER_* codes stay as the public-code contract.
- oak-node jobs.rs: ColorProcessor imported from oak_core::color.
- Integration tests repointed at oak_core::{texture, frame, backend,
  color, colormath}.
- the display-ICC regression test treats an empty OAK_DISPLAY_ICC as
  unset, matching displayicc::env_override_icc.
2026-09-03 17:42:20 +08:00

168 lines
7.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# M1 · oak_core 拆分手册
> 内容:`engine/common/`(41 文件通用工具集)+ `engine/config/`。
> 依赖:oakcore(2)。被依赖:几乎全员(node 31、render 24、
> codec 12、plugin 6、audio 5、task 4、timeline 4、undo 2)。
> 拆分顺序第 1 位(叶子)。
## 1. 目标形态
```
oak_core/
include/oak_core/ # 公共头(C ABI + 允许直引的纯头工具)
src/ # 现有 .cpp 原样迁入
tests/ # oak_core_gtest
```
- **纯头工具**(lerp.h、define.h、decibel.h、tohex.h、digit.h、
memorypool.h、threadsafemap.h、range.h 等无 .cpp 的):作为
oak_core 公共头直接提供给其他模块 include——拆分阶段允许
(不产生链接依赖)。RIIR 阶段这些会改写成各语言自有实现。
- **config/config.h**:单头配置存取,被全模块引用(10+)。
它是 Qt 依赖(QSettings 包装),按 §2 冻结 C ABI。
## 2. 冻结 C API(有 .cpp 实现的函数族)
命名前缀 `oak_core_`。以下按头分组(签名机械规则见 01 §3,
此处冻结函数清单与特殊约定):
### 2.1 `oak_core/config.h`(对应 config/config.h)
```c
void oak_core_config_set(const char *group, const char *key,
const char *value_utf8);
int oak_core_config_get(const char *group, const char *key,
char *buf, int buf_size); /* 两段式 */
int oak_core_config_get_int(const char *group, const char *key,
int fallback);
double oak_core_config_get_double(const char *group, const char *key,
double fallback);
void oak_core_config_set_int(const char *group, const char *key, int v);
```
### 2.2 `oak_core/xml.h`(对应 common/xmlutils.h,8 次被引)
```c
/* XMLAttributeLoop/xml_read_next_start_element 的 C 化:
* 以迭代器句柄包装 QXmlStreamReader */
typedef struct oak_coreXmlReader oak_coreXmlReader;
oak_coreXmlReader *oak_core_xml_reader_init(const char *utf8, int len);
void oak_core_xml_reader_free(oak_coreXmlReader *r);
int oak_core_xml_read_next_start_element(oak_coreXmlReader *r);
int oak_core_xml_reader_name(oak_coreXmlReader *r, char *buf, int n);
int oak_core_xml_reader_attr(oak_coreXmlReader *r, const char *attr,
char *buf, int n);
int oak_core_xml_reader_read_element_text(oak_coreXmlReader *r,
char *buf, int n);
void oak_core_xml_reader_skip_current(oak_coreXmlReader *r);
```
写出侧 `oak_core_xml_writer_*`(init_to_string/write_attribute/
write_text_element/free 得字符串,两段式)。
### 2.3 `oak_core/files.h`(common/filefunctions.h,render 7 次)
```c
int oak_core_file_exists(const char *path); /* 1/0 */
int oak_core_file_size(const char *path); /* -1 失败 */
int oak_core_file_read_all(const char *path, char *buf, int n); /* 两段式 */
int oak_core_file_write_all(const char *path, const char *data, int n);
int oak_core_dir_mkpath(const char *path);
int oak_core_get_config_path(char *buf, int n);
int oak_core_get_temp_path(char *buf, int n);
```
### 2.4 `oak_core/ocio.h`、`oak_core/oii.h`、`oak_core/ffmpeg.h`
(ocioutils/oiioutils/ffmpegutils,按 01 §3 机械 POD 化;
OAK/OIIO/FFmpeg 类型全部句柄化或拍平字段。)
### 2.5 `oak_core/misc.h`
`jobtime`(`double oak_core_jobtime_now(void)`)、`current`
(`oak_core_current_get/set` 线程局部当前对象句柄)。
## 3. 切割点(common 的 12 次反向 include,逐条)
| 现状 | 处理 |
|---|---|
| common → render/ 7 次(播放钟/自动滚动等引 render 类型) | 涉及文件(playbackaudioclock/autoscroll 等)**上移出 oak_core**:它们不是底层工具,归 oakrender(M7) |
| common → node/ 3 次 | 同上,归 oaknode(M3) |
| common → undo/ 1 次 | 同上,归 oakundo(M2) |
| common → codec/ 1 次 | 同上,归 oakcodec(M5) |
| common → pluginSupport/ 1 次 | 同上,归 oakplugin(M9) |
判据:切完后 `grep -rn '#include "' oak_core/src | grep -vE
'"(oak_core|olive/core)'` 为空(只剩 oakcore 与 Qt/系统头)。
## 4. 测试(映射 03 §2)
- config:set/get 往返、int/double fallback、两段式 buf。
- xml:reader 解析样例串、attr/text 读取、skip、writer 产出解析回读。
- files:临时目录建/写/读/尺寸/删除。
- 每函数 1 正常 + 1 错误路径;`oak_core_debug_alive_count()` 泄漏断言。
## 实施现状(2026-08-05)
M1 已落地并可独立构建、测试全绿(127 个用例:126 通过,1 个
`GTEST_SKIP`)。以下为与上文计划的实际差异。
### 最终目录结构
- `src/common/src/` — 去 Qt 化 C++ 实现(`olive::` 命名空间),target
`oak_core`(SHARED)。
- `src/common/c_api/` — 纯 C ABI 包装,通过 `target_sources` 合并进
`oak_core`,不单独成库。
- `src/common/tests/` — gtest,target `oak_core-gtest`,
`gtest_discover_tests`。
- `include/common/`(仓库根)— 公共 C 头:`commandlineparser.h`、
`current.h`、`debug.h`、`dropworkflowbehavior.h`、`error.h`、
`ffmpegutils.h`、`filefunctions.h`、`miscutils.h`、`ocioutils.h`、
`oiioutils.h`、`power.h`、`qtutils.h`、`xmlutils.h`。
- `src/common/standalone/CMakeLists.txt` — 独立构建 driver(见下)。
### 独立构建与测试
```sh
cmake -S src/common/standalone -B build-oak_core
cmake --build build-oak_core -j
ctest --test-dir build-oak_core --output-on-failure
```
driver 通过 `find_package(... CONFIG)` 使用 Homebrew 的 OCIO/OIIO/GTest
(顶层 `cmake/FindOpenColorIO.cmake`/`FindOpenImageIO.cmake` 面向
`.so`,macOS 下不适用),并把 config target 映射到 oak_core
CMakeLists 消费的 `${OCIO_LIBRARIES}` 等变量。driver 中额外处理了两点:
给 `olivecore` 补 `third_party/openfx/include` 头路径(顶层靠全局
include);禁用 OpenTimelineIO(`/opt/otio` 的 dylib 用 `@loader_path`
安装名,构建树内无法加载,且 oak_core 不需要 OTIO)。
### 实际依赖
- 第三方:EXPAT(XML 解析)、OpenColorIO、OpenImageIO、FFmpeg(经
ffmpeg_bridge 间接)、GTest(仅测试)。
- Oak 内部库:**仍链接 `olivecore` 与 `ffmpeg_bridge`**,二者均为真实
符号依赖而非纯头文件:
- `olive::core::Rational`(`core/include/olive/core/util/rational.h`)
是对 `oakcore_rational_*` C ABI 的包装,构造/析构/运算都需要
olivecore 的符号;
- `FFmpegUtils::get_compatible_bridge_pixel_format` 调用
`fb_find_best_pix_fmt_of_list`(ffmpeg_bridge 导出符号)。
- `pixelformat.h`/`sampleformat.h` 本身是 header-only,只需头路径
(`core/include`、`ffmpeg_bridge/include`,因这两个 target 的
include 目录是 PRIVATE,在 oak_core 里显式补为 PUBLIC)。
- 未按计划只链 oakcore 头;OLIVECORE_BUILD_TESTS 在独立构建中关闭。
### 与计划的主要差异
- 接口未按 §2 冻结清单逐条实现,而是按实际使用面包装:C ABI 头放在
仓库根 `include/common/`,命名 `oak_core_<模块>_<动词>`,两段式
buffer(先查询尺寸再拷入)约定统一。
- `xmlutils` 用 expat 实现(事件预先解析成队列);C API 的
`oak_core_xml_reader_read_element_text` 因底层是消费型读取,在
handle 内缓存最近一次文本以兼容两段式调用。
- 被移除/上移的类(播放钟、autoscroll 等反向 include 涉及项)见
`notes.md`。
- 计划中提到的 `switch(PixelFormat)` 编译问题实际不存在:
`olive::core::PixelFormat` 提供 `operator Format()`,可直接 switch。