ohos_KDiff3:基于 OpenHarmony 的 Qt 源码文件对比合并工具项目

移植 OpenHarmony 的 Qt 源码文件对比合并工具。

分支1Tags0
文件最后提交记录最后更新时间
16 天前
16 天前
16 天前
16 天前
16 天前
16 天前
16 天前
16 天前
12 天前
12 天前
16 天前
16 天前
16 天前
16 天前

KDiff3 的 OpenHarmony 适配记录

这份文档记录我们把 KDiff3(一个文本/源码差异比较与合并工具,能做两文件/三文件逐行对比、三路合并、目录递归比较)搬到 OpenHarmony / HarmonyOS PC 上的过程:鸿蒙工程怎么组织、环境怎么搭、HAP 怎么编出来、业务库怎么交叉编译,以及最后哪些功能能用、哪些受平台限制或 KDE 依赖剥离影响没做。原项目是一个标准的 KDE 桌面 Qt Widgets 应用,上游主页:https://invent.kde.org/sdk/kdiff3,版本 0.9.98

这次走的是 Qt-for-OpenHarmony 这条路:用一个 ArkTS 壳工程起 UIAbility,铺 XComponent 承载 Qt 窗口,通过 libqohos.so(Qt-OHOS QPA 平台插件)加载外部交叉编译好的 libkdiff3.so。KDiff3 的 C++/Qt 源码编译成独立共享库,由 QPA 插件 dlopen 后调用其 main 入口。

需要说明一点:KDiff3 上游是个 KDE 应用,强依赖 KF5 全家桶(KIO / KCrash / KXmlGui / KConfig / KI18n 等)。鸿蒙第一版的策略是「先把 KDE 桌面集成全剥掉,保核心 diff/merge」——所以远程文件、崩溃上报、KDE 菜单/工具栏体系、完整国际化等全被主动砍掉了。这不是 bug,是第一版取舍。下面会逐项讲清楚。


一、工程结构 / 鸿蒙工程在哪

鸿蒙工程就是仓库根目录,主模块为 entry/,另带一个 qEmbeddedUiExtensionHost/ 特性模块。用 DevEco Studio 打开仓库根目录即可。

ohos_KDiff3-main/
├── AppScope/                              # 应用级配置(包名、图标、版本)
│   ├── app.json5                          # bundleName = com.example.kdiff3ohos
│   └── resources/base/
│       ├── element/string.json            # 应用名 "KDiff3"
│       └── media/                         # app_icon / startIcon
│
├── entry/                                 # 主模块(HAP 业务壳)
│   ├── libs/arm64-v8a/                    # 预编译 native 库 ⭐
│   │   ├── libkdiff3.so                   # KDiff3 业务库(交叉编译产物)
│   │   ├── libqohos.so                    # Qt-OHOS QPA 桥接库
│   │   ├── libQt5*.so                     # Qt 5.12.12 运行时
│   │   ├── libQt5PrintSupport.so          # Qt 打印支持(运行时缺这个会闪退,见下文)
│   │   ├── platforms/libqohos.so          # QPA 平台插件
│   │   ├── styles/libqohosstyle.so        # QStyle 插件
│   │   ├── imageformats/*.so              # 图片格式插件
│   │   └── libc++_shared.so               # OHOS NDK C++ 运行时
│   ├── src/main/
│   │   ├── module.json5                   # Ability / 权限 / 设备类型 / 文件关联
│   │   ├── cpp/                           # Native 构建入口(示例 libentry.so)
│   │   │   ├── CMakeLists.txt
│   │   │   └── hello.cpp
│   │   ├── ets/
│   │   │   ├── qabilitystage/
│   │   │   │   └── QAbilityStage.ets      # 应用入口(初始化 Qt、加载 libkdiff3.so)
│   │   │   ├── qability/
│   │   │   │   ├── QAbility.ets           # 主 UIAbility(生命周期委托 libqohos)
│   │   │   │   ├── OhosExportModules.ts   # 导出 43 个鸿蒙系统 API 给 Qt
│   │   │   │   └── QEmbeddedUiExtensionAbility.ets
│   │   │   ├── pages/
│   │   │   │   ├── MainWindowNativeNode.ets   # 主窗口 XComponent
│   │   │   │   ├── SubWindowNativeNode.ets    # 子窗口
│   │   │   │   ├── FloatWindowNativeNode.ets  # 浮动窗口
│   │   │   │   └── UiExtensionNativeNode.ets  # UI 扩展窗口
│   │   │   └── common/
│   │   │       └── QtAppConstants.ets         # APP_LIBRARY_NAME = libkdiff3.so
│   │   └── resources/
│   │       └── rawfile/kdiff3/               # 自检样例文本
│   │           ├── left.txt                    # 左侧对比文件
│   │           └── right.txt                   # 右侧对比文件
│   ├── build-profile.json5                # CMake + arm64-v8a ABI
│   └── oh-package.json5
│
├── qEmbeddedUiExtensionHost/              # EmbeddedUI 扩展宿主模块
├── build-profile.json5                    # 顶层构建配置
├── oh-package.json5                       # 工程级 ohpm 依赖
└── README.md

关键一点:鸿蒙工程不包含 KDiff3 业务源码。业务逻辑全部在外部 libkdiff3.so 中,由 libqohos.so 通过 dlopen / dlsym("main") 加载。entry/src/main/cpp/CMakeLists.txt 只编译一个示例性质的 libentry.so,不涉及 KDiff3 本体。


二、环境要求

项目 要求 备注
DevEco Studio 支持 HarmonyOS PC(Stage 模型)的版本 命令行构建用 hvigorw / ohpm
HarmonyOS SDK compatibleSdkVersion / targetSdkVersion = 6.1.0(23) build-profile.json5
Qt for OpenHarmony 5.12.12(arm64-v8a) ArkTS 侧通过 libqohos.so 接入
目标设备 2in1 / tablet(arm64-v8a) module.json5deviceTypes
启动业务库 libkdiff3.so QtAppConstants.ets
签名 用自己的调试 / 发布证书 仓库里 signingConfigs 是本机配置,换机器要重配

应用信息(取自 AppScope/app.json5):

  • bundleNamecom.example.kdiff3ohos
  • 显示名:KDiff3
  • 版本:versionName 1.0.0 / versionCode 1000000

三、编译与运行

前置准备:放入 Qt 依赖库

entry/libs/arm64-v8a/ 目录需要放入以下交叉编译产物:

entry/libs/arm64-v8a/
├── libkdiff3.so                # KDiff3 业务库
├── libqohos.so                # Qt-OHOS QPA 桥接库
├── libQt5Core.so / libQt5Gui.so / libQt5Widgets.so / ...
├── libQt5PrintSupport.so      # Qt 打印支持(缺这个会闪退,见下文)
├── libc++_shared.so
├── platforms/libqohos.so
├── imageformats/
└── styles/

构建 HAP

# 1. 安装 ohpm 依赖
ohpm install

# 2. 用 DevEco Studio 打开仓库根目录
#    File → Project Structure → Signing Configs 配好签名

# 3. 构建
#    Build → Build Hap(s)/APP(s) → Build Hap(s)

# 产物路径
# entry/build/default/outputs/default/entry-default-signed.hap

命令行构建:

hvigorw --mode module -p module=entry@default -p product=default assembleHap

推送到设备

hdc install entry/build/default/outputs/default/entry-default-signed.hap
hdc shell aa start -a QAbility -b com.example.kdiff3ohos

业务库交叉编译(参考)

cd ~/ohos-qt-port/kdiff3/kdiff3-0.9.98/src-QT4
mkdir -p build-ohos && cd build-ohos

cmake .. \
  -DCMAKE_TOOLCHAIN_FILE=$OHOS_SDK_ROOT/native/build/cmake/ohos.toolchain.cmake \
  -DOHOS_ARCH=arm64-v8a \
  -DOHOS_PLATFORM=OHOS \
  -DCMAKE_PREFIX_PATH=/opt/qt-ohos/qt-5.12.12-ohos/qt-5.12.12-ohos

ninja

# 裁剪 + 4KB 对齐修复
$OHOS_SDK_ROOT/native/llvm/bin/llvm-strip --strip-unneeded libkdiff3.so
python3 fix_elf_align_v2.py libkdiff3.so

# 部署到工程
scp libkdiff3.so mac:~/Downloads/Kdiff3Ohos/entry/libs/arm64-v8a/

四、这个项目是怎么适配的

适配思路一句话:ArkTS 壳层负责生命周期和窗口承载,KDiff3 业务逻辑不动,由 Qt-OHOS 桥接层把两者连起来;KDE 桌面集成全部剥掉,保核心 diff/merge。

1. 启动链路

HarmonyOS 拉起 com.example.kdiff3ohos(QAbility)
  → QAbilityStage.onCreate() 初始化 Qt-OHOS QPA
  → qpa.setupQtApplication({ appName: 'libkdiff3.so' })
  → QAbility.onWindowStageCreate() 加载 MainWindowNativeNode
  → MainWindowNativeNode 起 XComponent(libraryname: 'qohos')
  → QPA 插件在 XComponent 上建 surface,dlopen("libkdiff3.so")
  → 调用 main(argc, argv)
  → KDiff3 Qt 主窗口渲染到 XComponent

2. ArkTS 桥接层(entry/src/main/ets/

  • QAbilityStage.etsonCreate 里调 qpa.handleAbilityStageOnCreate(this),初始化 Qt 应用上下文。onAcceptWant / onNewProcessRequest 负责多实例 / 多进程的 key 分配。
  • QAbility.etslaunchType 设成 specifiedisolationProcess: true(独立进程)。生命周期回调全部委托给 libqohos.soonCreate / onDestroy / onWindowStageCreate / onNewWant / onForeground / onBackground / onContinue
  • MainWindowNativeNode.ets:一块 XComponenttype: XComponentType.NODElibraryname: 'qohos'——KDiff3 的 Qt 界面最终渲染到这块 surface 上。
  • OhosExportModules.ts:把 43 个鸿蒙系统 API(文件访问、剪贴板、i18n、window、display 等)打包导出给 Qt 侧使用。

3. KDE 依赖剥离

KDiff3 上游是 KDE 应用,强依赖 KF5 全家桶。这次交叉编译时做了以下剥离:

上游 KDE 组件 功能 剥离方式 替代
KIO 远程文件比较(FTP/SFTP/SMB) 宏屏蔽 / 编译排除 砍掉,只支持本地文件
KCrash 崩溃收集上报 宏屏蔽 不接
KXmlGui KDE 风格菜单 / 工具栏 / 快捷键体系 编译排除 简化为 Qt 原生菜单
KConfig KDE 配置系统 编译排除 替换为 QSettings
KI18n 完整多语言支持 编译排除 降为 QObject::tr 或硬编码英文
KDE Widgets KDE 风格对话框 / 向导 编译排除 全换成标准 Qt Widgets
KRecentFilesAction 打开最近项目 没迁移
KStatusNotifier 系统托盘 / 通知 砍掉

4. 文件关联(module.json5

QAbility 注册了 file:// + general.text 的技能声明,支持 ohos.want.action.sendDatamaxFileSupported: 10。从鸿蒙系统的文件管理器里用「打开方式」选 KDiff3 打开文本文件是有接入路径的。rawfile/kdiff3/ 里还带了两个自检样例文件(left.txt / right.txt),方便快速验证对比功能。

5. 权限声明(module.json5

权限 用途
ohos.permission.SYSTEM_FLOAT_WINDOW 浮动窗口显示
ohos.permission.FILE_ACCESS_PERSIST 持久化文件访问
ohos.permission.PRINT 打印功能
ohos.permission.PREPARE_APP_TERMINATE 应用终止前保存状态
ohos.permission.STORE_PERSISTENT_DATA 持久化存储
ohos.permission.READ_PASTEBOARD 读取剪贴板
ohos.permission.GET_FILE_ICON 获取文件图标

6. 已知运行时 bug:缺 libQt5PrintSupport.so 闪退

装到真机上第一次启动闪退,hilog 抓到的是 dlopen: library "libQt5PrintSupport.so" not found。原因是 libkdiff3.so 的 NEEDED 依赖闭包里包含了 libQt5PrintSupport.so,但 entry/libs/arm64-v8a/ 下没放这个 .so。把缺的 .so 从 Qt-OHOS 编译产物拷过来就解决了。编译和运行时都是能跑通的。


五、功能支持情况(T0 / T1 / T2)

先把口径说清楚:

  • 分档:T0 是「装、起、最低限度能用」,T1 是「KDiff3 的日常核心」,T2 是「远程文件、打印、KDE 桌面集成这些增强项,多依赖 KDE 组件或桌面平台能力」。
  • 状态只有两个:能用 指功能正常;未适配 指桌面端特有或平台没有对应概念的能力,按平台特点或第一版策略主动砍掉,是取舍不是没做完。

T0 — 基础能力

能力 状态 说明
编译打包成 HAP 能用 hvigorw assembleHap / DevEco 都能构建;需先放入 native 库
安装 / 启动 / 进主界面 能用 ArkTS 起 UIAbility + XComponent,QPA 插件加载 libkdiff3.so,拉起 KDiff3 主窗口
主窗口渲染 能用 Qt Widgets 经 XComponent 宿主渲染,主窗口界面正常显示
从系统「打开方式」接收文本文件 能用 module.json5 注册了 file:// + general.text 文件关联
自检样例文件 能用 rawfile/kdiff3/ 内置 left.txt / right.txt,方便快速验证对比
进程隔离 能用 isolationProcess: true,业务崩溃不影响壳

小结:装、起、进界面、从文件管理器接收文件这条主链路是通的。运行时缺 libQt5PrintSupport.so 闪退的问题已定位并解决。

T1 — 核心比较能力

能力 状态 说明
本地两个文件比较 能用 KDiff3 核心功能,逐行对比、高亮差异
三方合并 能用 共同祖先 + 两个派生版本的智能合并
冲突解决 能用 手动编辑冲突区域,逐块选择保留版本
本地目录比较 能用 递归扫描目录,列出差异文件
语法高亮 能用 C/C++/Python/JavaScript 等多语言
Qt 原生菜单 / 工具栏 能用 从 KXmlGui 简化为 Qt 原生菜单,功能等价但不是 KDE 风格

小结:文件差异对比、三方合并、目录比较这些 KDiff3 的日常核心功能,代码路径都齐了,libkdiff3.so 交叉编译已通过。菜单/工具栏从 KDE 体系换成 Qt 原生,功能等价。

T2 — 增强能力(KDE 桌面集成 / 平台限制)

能力 状态 说明
远程文件比较(FTP/SFTP/SMB) 未适配 上游用 KIO 实现,鸿蒙版砍掉 KIO 依赖,只支持本地文件
崩溃收集上报 未适配 上游用 KCrash,鸿蒙版宏屏蔽,不接
KDE 风格菜单 / 工具栏 / 快捷键 未适配 上游用 KXmlGui,鸿蒙版简化为 Qt 原生菜单
KDE 配置系统 未适配 上游用 KConfig,鸿蒙版替换为 QSettings
完整多语言支持 未适配 上游用 KI18n,鸿蒙版降为 QObject::tr 或硬编码英文
KDE 风格对话框 / 向导 未适配 上游用 KDE Widgets,鸿蒙版全换成标准 Qt Widgets
打开最近项目 未适配 上游用 KRecentFilesAction,鸿蒙版没迁移
系统托盘 / 通知 未适配 上游用 KStatusNotifier,鸿蒙版砍掉
打印 未适配 module.json5 声明了 PRINT 权限,也打包了 libQt5PrintSupport.so;但鸿蒙 PC 没有 CUPS 打印子系统,Qt-OHOS 的 PrintSupport 大概率是空壳或未启用,点打印大概率没反应或失败
复杂子窗口 / 模态对话框 未适配 Qt-OHOS 平台插件的子窗口 / 模态对话框实现不完整,涉及弹窗的路径有崩溃风险
Embedded UI 未适配 桥接代码已预留,但宿主页仍是模板内容(Hello from EmbeddedComponentImpl),不是成熟功能
x86_64 模拟器 未适配 构建配置只开了 arm64-v8a

小结:T2 这批里,最值得说的是两点。第一,KDE 全家桶全部被主动砍掉了。 KDiff3 上游强依赖 KF5——远程文件靠 KIO、崩溃上报靠 KCrash、菜单/工具栏靠 KXmlGui、配置靠 KConfig、国际化靠 KI18n。鸿蒙第一版的策略是「先把 KDE 桌面集成全剥掉,保核心 diff/merge」,所以远程文件、崩溃上报、KDE 菜单体系、完整国际化全没了。这不是 bug,是第一版取舍——先把核心功能掏出来,KDE 桌面集成以后再补。第二,打印大概率不可用。 虽然声明了 PRINT 权限、也打包了 libQt5PrintSupport.so(甚至缺了它还会闪退),但鸿蒙 PC 没有 CUPS 打印子系统,Qt-OHOS 的 PrintSupport 大概率是空壳。这两个都卡在平台能力边界或 KDE 依赖剥离上,不是代码没写。


六、整体到什么程度

把三档合起来看:

  • T0 基础能力:宿主工程结构、启动链路、主窗口承载、文件关联、自检样例都到位,能编能装能起。运行时缺 libQt5PrintSupport.so 闪退的问题已定位并解决。
  • T1 核心比较能力:文件差异对比、三方合并、冲突解决、目录比较、语法高亮——这些是 KDiff3 的日常核心,代码路径都齐了,libkdiff3.so 交叉编译已通过。菜单/工具栏从 KDE 体系换成 Qt 原生,功能等价。
  • T2 增强能力:远程文件、崩溃上报、KDE 菜单/配置/国际化、打开最近项目、系统托盘、打印——这些大多因为 KDE 依赖剥离或平台能力边界而未适配。远程文件是因为砍了 KIO、只支持本地文件;打印是因为鸿蒙没有 CUPS 打印栈;KDE 菜单/配置/国际化是第一版主动剥掉的,以后可以补。

一句话总结:这次把「ArkTS → XComponent → Qt QPA → libkdiff3.so」这条管线在鸿蒙 PC 上接通了,KDiff3 的主窗口能起来,本地文件差异对比、三方合并、目录比较这些核心功能有完整的代码路径。KDE 全家桶(远程文件、崩溃上报、KDE 菜单、完整国际化、系统托盘)全部被主动砍掉——这是第一版策略,先把核心功能掏出来,KDE 桌面集成以后再补。打印虽然声明了权限也打包了库,但鸿蒙没有 CUPS 打印栈,大概率不可用。

项目介绍

移植 OpenHarmony 的 Qt 源码文件对比合并工具。

定制我的领域