refactor(common): de-Qt oakcommon and wrap it in a pure C ABI

- de-Qt all classes under src/common (std::string/vector/mutex,
  std::filesystem, expat-based XmlStreamReader/Writer)
- add pure C ABI in include/common + src/common/c_api: opaque handles,
  init returns NULL on failure, free(NULL) is a no-op, out-params with
  negative OAKCOMMON_E_* error codes (include/common/error.h)
- remove single-consumer classes from oakcommon (html, jobtime,
  otioutils, playbackaudioclock, tohex, util, avframeptr,
  crashpadinterface/crashpadutils, autoscroll, digit, range); their
  destinations are recorded in docs/zh/plans/riir/notes.md
- add gtest suites under src/common/tests (127 cases), standalone
  build driver in src/common/standalone
This commit is contained in:
2026-08-05 17:20:19 +08:00
parent bb09872a2f
commit bad52feda3
73 changed files with 8851 additions and 2 deletions
+64
View File
@@ -101,3 +101,67 @@ OAK/OIIO/FFmpeg 类型全部句柄化或拍平字段。)
- xmlreader 解析样例串、attr/text 读取、skip、writer 产出解析回读。
- files:临时目录建/写/读/尺寸/删除。
- 每函数 1 正常 + 1 错误路径;`oakcommon_debug_alive_count()` 泄漏断言。
## 实施现状(2026-08-05
M1 已落地并可独立构建、测试全绿(127 个用例:126 通过,1 个
`GTEST_SKIP`)。以下为与上文计划的实际差异。
### 最终目录结构
- `src/common/src/` — 去 Qt 化 C++ 实现(`olive::` 命名空间),target
`oakcommon`SHARED)。
- `src/common/c_api/` — 纯 C ABI 包装,通过 `target_sources` 合并进
`oakcommon`,不单独成库。
- `src/common/tests/` — gtesttarget `oakcommon-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-oakcommon
cmake --build build-oakcommon -j
ctest --test-dir build-oakcommon --output-on-failure
```
driver 通过 `find_package(... CONFIG)` 使用 Homebrew 的 OCIO/OIIO/GTest
(顶层 `cmake/FindOpenColorIO.cmake`/`FindOpenImageIO.cmake` 面向
`.so`,macOS 下不适用),并把 config target 映射到 oakcommon
CMakeLists 消费的 `${OCIO_LIBRARIES}` 等变量。driver 中额外处理了两点:
`olivecore``third_party/openfx/include` 头路径(顶层靠全局
include);禁用 OpenTimelineIO`/opt/otio` 的 dylib 用 `@loader_path`
安装名,构建树内无法加载,且 oakcommon 不需要 OTIO)。
### 实际依赖
- 第三方:EXPATXML 解析)、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,在 oakcommon 里显式补为 PUBLIC)。
- 未按计划只链 oakcore 头;OLIVECORE_BUILD_TESTS 在独立构建中关闭。
### 与计划的主要差异
- 接口未按 §2 冻结清单逐条实现,而是按实际使用面包装:C ABI 头放在
仓库根 `include/common/`,命名 `oakcommon_<模块>_<动词>`,两段式
buffer(先查询尺寸再拷入)约定统一。
- `xmlutils` 用 expat 实现(事件预先解析成队列);C API 的
`oakcommon_xml_reader_read_element_text` 因底层是消费型读取,在
handle 内缓存最近一次文本以兼容两段式调用。
- 被移除/上移的类(播放钟、autoscroll 等反向 include 涉及项)见
`notes.md`
- 计划中提到的 `switch(PixelFormat)` 编译问题实际不存在:
`olive::core::PixelFormat` 提供 `operator Format()`,可直接 switch。
+82
View File
@@ -0,0 +1,82 @@
# 记录项
## common
CancelableObject只在render和task处有🚰,移入对应模块。
## 从 oakcommonsrc/common)移除的类(2026-08-05
判据:不严重依赖 common 其他类,且只有一个非 common 模块使用它
tests/gtest 不计入使用方)。以下类已从 `src/common/` 移除,
拆分时应放到对应模块:
| 类 | 唯一使用方 | 应放到 |
|---|---|---|
| `Html`html.h/.cpp | engine/node | oaknodeM3)。注意它依赖 common 的 xmlutils,迁移时需连同 XML 辅助或改为调用 oakcommon C API |
| `JobTime`jobtime.h/.cpp | engine/render | oakrenderM7 |
| `OTIOUtils`otioutils.h | engine/task | oaktaskM8 |
| `PlaybackAudioClock`playbackaudioclock.h | engine/audio | oakaudioM6 |
| `to_hex`tohex.h | engine/node | oaknodeM3 |
| `mid()`util.h | engine/node | oaknodeM3 |
| `AVFramePtr`avframeptr.h | engine/render | oakrenderM7 |
| `CrashpadInterface`crashpadinterface.h/.cpp | app/main.cpp | appcrashhandler 相关) |
| crashpadutils.h | app/crashhandler | app/crashhandler |
| `AutoScroll`autoscroll.hoakutil shim | app/dialog、app/widget | app |
| `digit.h`oakutil shim | app/dialog | app |
| `range.h`oakutil shim | app/widget | app |
另:`power.h``memorypool.h``threadsafemap.h` 当前没有任何
common 模块外的使用方(零用户),不满足移除判据,暂保留在
oakcommon;后续若确认无用途可直接删除。
## oakcommon 去Qt化的删除与语义变更(2026-08-05)
去Qt化过程中以下函数被删除或语义变化,迁移调用方时需注意:
- `CommandLineParser::print_help()`:不再自动读取
`QCoreApplication::applicationName()/applicationVersion()`,需先调
`set_app_info()`C API`oakcommon_commandlineparser_set_app_info`),
否则打印默认 `"oak"` + 空版本。
- `FileFunctions::get_unique_file_identifier`:哈希由 SHA-1 改为
FNV-1a 64-bit,旧缓存 key 全部失效(需一次重建)。
`get_configuration_location`/`get_application_path`/
`get_temp_file_path`/`get_auto_recovery_root` 的标准路径改为手写
平台实现,路径与原 Qt 版不同。`read_file_as_string(":/...")`
qrc 资源路径不再可用,shader 等资源调用方需改为磁盘路径或内嵌。
- xmlutils`xml_read_next_start_element(reader, CancelAtom*)`
重载与 cancel_atom 参数删除(依赖 render/cancelatom.h),取消语义
由调用方在循环外自行检查;`XMLAttributeLoop` 宏删除,由
`XmlStreamReader::attributes()` + range-for 替代;
`QXmlStreamReader/Writer` 由基于 expat 的
`olive::XmlStreamReader/Writer` 替代(不支持 XML 命名空间)。
- `OIIOUtils::frame_to_buffer/buffer_to_frame`:未进 C APIC++ 侧签名
拍平为 `(const void *data, int64_t linesize_bytes, OIIO::ImageBuf *)`
engine/codec/frame.cpp 迁移时传成员即可。`OakCommonPixelFormat` 枚举
目前定义在 include/common/ocioutils.hoiioutils 复用,后续可抽成
独立的 include/common/pixelformat.h。
- `MemoryPool`:删除 QTimer 每 5 秒自动回收空 arena,改为公有
`clear_empty_arenas()` 由调用方周期调用;不再继承 QObject。
memorypool/threadsafemap 零使用方且为模板/多态基类,未包 C API。
- `debug_handler`:丢失 `QMessageLogContext`(文件/行号)参数(原实现
本就未用);`qInstallMessageHandler` 无对应物。
- `Current::set_current_video_params/audio_params`:由按值拷贝改为持有
`std::shared_ptr<void>`(类型擦除),调用方需自行管理生命周期并用
`static_pointer_cast` 还原(调用点:olivehost.cpp、
timebasedwidget.cpp、plugin.cpp 等 6 处)。
- qtutilsengine 未使用的纯 UI 函数(`q_font_metrics_width`
`create_horizontal/vertical_line``set_combo_box_data`
`word_wrap_string``flip_control_and_shift_modifiers`
`get_formatted_date_time``to_q_color``core::qHash`
`Q_DECLARE_METATYPE` 宏组)未迁入 oakcommonapp 层继续用 Qt 版。
`ptr_to_value/value_to_ptr` 载体由 QVariant 改为 `uintptr_t`
迁移时调用点需同步改(renderprocessor.cpp、rendermanager.cpp、
previewautocacher.cpp、src/capi/worker.cpp)。`get_parent_of_type`
依赖 C++ 模板+RTTI,未进 C API。
- define.h:删除 `MACRO_NAME_AS_STR`/`MACRO_VAL_AS_STR`/
`OLIVE_NS_CONST_ARG`/`OLIVE_NS_ARG`/`OLIVE_NS_RETURN_ARG`
(依赖 Qt QArgument,全仓无使用)。
- decibel.h:删除 `ALLOW_RETURNING_INFINITY` 编译开关分支(代码库
未定义该宏,行为不变)。
- `FFmpegUtils`:新增类内常量 `k_rgb_channel_count/k_rgba_channel_count`
3/4)取代对 `VideoParams` 同名常量的引用,消除 common→render
反向依赖。