开源鸿蒙PC三方库:vcpkg 实战——把 ZenLib 和 MediaInfo 搬到鸿蒙 PC

欢迎加入开源鸿蒙 PC 社区:https://harmonypc.csdn.net/

开源仓库地址:https://atomgit.com/OpenHarmonyPCDeveloper/ohos_vcpkg

上一篇讲了 vcpkg 的环境搭建和 curl 验证,这一篇来次真刀真枪的实战——用 vcpkg 移植 ZenLib(一个 C++ 跨平台基础库),再基于它安装 libmediainfo。这个案例恰好能验证 vcpkg 处理「依赖链」的能力:A 库依赖 B 库,B 库需要 musl 补丁,vcpkg 能不能搞定?

本篇基于社区作者 展菲 的《HarmonyOS 鸿蒙PC平台三方库移植:使用 vcpkg 移植 libzen》整理,结合我自己的实操复现重新讲述。

背景:为什么选 ZenLib + MediaInfo 这个组合

ZenLib 是 MediaArea 维护的 C++ 跨平台基础库,提供字符串、线程、文件 I/O、网络等工具的封装,版本 0.4.41。它是 libmediainfo(MediaInfo 库)的直接依赖。

这个组合对验证 vcpkg 来说刚刚好:依赖链简单(libmediainfo → ZenLib)、有 musl 兼容问题(ZenLib 在 OHOS 上编译会因 pthread_cancel 挂掉)、补丁逻辑典型(条件编译加宏判断),而且产物有实际用途——MediaInfo 的鸿蒙适配是三方库移植的经典案例。
在这里插入图片描述

前置条件

确保搭好的环境还在:

export OHOS_SDK_ROOT=/path/to/ohos-sdk/linux
ls "$OHOS_SDK_ROOT/native/llvm/bin/clang++"   # 确认编译器存在

triplet 用 arm64-ohos,OHOS SDK API 12+。

第一部分:移植 ZenLib——踩着 musl 的坑过去

第一次编译尝试

按照 vcpkg 标准流程,我直接执行:

vcpkg install libzen:arm64-ohos

但编译在到达 ZenLib 的线程相关代码时报错了:

error: use of undeclared identifier 'pthread_cancel'

这个报错对我们来说应该已经不陌生了——我们在前面 MediaInfo 系列里反复遇到过。复习一下根因:

  1. pthread_cancel 不是 POSIX 强制接口,它属于 glibc 的扩展;
  2. 鸿蒙的 C 标准库是 musl,而 musl 没有实现 pthread_cancel
  3. OHOS 编译时通常带有 -D__MUSL__ 宏,理论上可以通过这个宏做条件编译,但原始代码里没有对应的 #ifdef 保护。

补丁思路

关键问题不是「缺了这个函数怎么办」——ZenLib 用 pthread_cancel 的地方实际上是在尝试优雅地终止线程,如果操作系统不支持线程取消,直接不做就行。所以我们不需要实现它,只需要在 OHOS/musl 环境下跳过这个调用:

#if !defined(__ANDROID_API__) && !defined(__OHOS__) && !defined(__MUSL__)
    pthread_cancel((pthread_t)ThreadPointer);
#else
    (void)ThreadPointer;   // 消掉"未使用变量"的编译警告
#endif

这段代码同时覆盖了三个场景:Android(__ANDROID_API__)、鸿蒙(__OHOS__)、以及任何 musl 环境(__MUSL__)。思路是「三个条件只要有一个成立,就不调 pthread_cancel」,非常稳健。

补丁生效的注意事项

改完补丁后,有两点必须做:

  1. 提升 port-version:在 ports/libzen/vcpkg.json 里把 port-version 加 1。vcpkg 会对比 port-version 判断 port 内容是否变化,如果不升级,vcpkg 会认为 port 没变而直接用旧的缓存产物,根本不会应用你的补丁。这是一个极其隐蔽的坑。
  2. 清理构建缓存:删除 buildtrees 下 ZenLib 的旧编译产物,确保重新从源码开始构建:
rm -rf /path/to/vcpkg/buildtrees/libzen
vcpkg install libzen:arm64-ohos

在这里插入图片描述

验证

构建成功后,产物应该在 installed/arm64-ohos/ 下:

installed/arm64-ohos/
├── include/ZenLib/          ← 头文件
├── lib/libzen.a             ← 静态库(vcpkg OHOS triplet 默认产生的形态)
└── share/zenlib/            ← CMake 包配置、版权声明

可以通过检查编译日志来二次确认补丁真的生效了:日志中应该能看到 --target=aarch64-linux-ohos--sysroot=…/native/sysroot,这两个参数证明编译器确实在用鸿蒙的工具链和系统库。

第二部分:移植 libmediainfo——依赖链的通路验证

ZenLib 就位后,libmediainfo 的安装就顺畅多了:

vcpkg install libmediainfo:arm64-ohos

因为 vcpkg 已经知道 ZenLib 已安装(在 installed 目录下),libmediainfo 的 portfile 里 depends 声明了 libzen,所以构建时会自动找到它。vcpkg 的依赖解析机制在这里发挥了作用:不需要手动指定 PKG_CONFIG_PATH 或 -I/-L 参数,工具链内部已经串好了路径

这跟上一篇 lycium_plusplus 路线里手写十多个库的 PKG_CONFIG_PATH 形成了鲜明对比——对应用开发者来说,这种「透明」的体验就是 vcpkg 路线的核心价值。
在这里插入图片描述

完整排障清单

我在移植过程中实际遇到的几个状况:

现象 判断流程 处理
改了补丁但编译输出还是旧的报错 vcpkg 缓存了旧 port,没重新编译 buildtrees/libzen,确认 port-version 已升
编译能过但链接时报 undefined symbol libc 差异,可能有其他 glibc-only API 逐个比对报错的符号,参考 glibc vs musl 差异表
编译命令里没出现 --target=…-ohos toolchain 没正确加载 OHOS triplet 检查 OHOS_SDK_ROOT 和 triplet 文件路径
找不到 sysroot 头文件 OHOS SDK 路径不对或不完整 ls $OHOS_SDK_ROOT/native/sysroot/usr/include 验证

小结

这一篇用 ZenLib + libmediainfo 这个有实际依赖关系的组合,把 vcpkg 路线的核心能力验证通了:

  1. musl 兼容补丁——通过 #if defined 条件编译优雅地处理平台差异;
  2. 依赖链自动解析——libmediainfo 自动找到已安装的 libzen;
  3. port-version 缓存机制——补丁修改后必须升版本号,这是 vcpkg 特有的「仪式感」;
  4. 编译日志验证——--target--sysroot 是确认交叉编译正确性的关键指标。

如果你之前在 lycium_plusplus 里反复打 pthread_cancel 补丁已经形成了肌肉记忆,那么在 vcpkg 里,这份补丁被写进了 portfile 并跟随仓库版本,一次修复、永久生效、所有人共享——这是包管理器在知识复用层面的真正优势。

感谢原创作者 展菲 的开源分享。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐