需要在 HarmonyOS / OHOS(arm64-ohos) 上编译 MediaArea ZenLib(vcpkg 包名:libzen) ,已经会用 vcpkg 做交叉编译,但遇到 musl / libc 能力差异 导致的编译失败。
本文基于 vcpkg 的 libzen port(版本 0.4.41)与 OHOS LLVM 工具链的实际踩坑记录整理。

一、背景:libzen 是什么,为什么在 OHOS 上容易踩坑
libzen(ZenLib)是 MediaInfo 生态里常用的 C++ 基础库,提供字符串、线程、工具类等能力。
在 OHOS 上交叉编译时,常见挑战并不在"依赖很多",而在:
- 工具链与 sysroot 对齐 (Clang +
--target+--sysroot) - libc 行为差异(OHOS 侧常见 musl 取向;部分 glibc 习惯 API 不存在或不可用)
其中最容易卡住的一点是:pthread_cancel。
二、典型报错:pthread_cancel 未声明
1) 现象
编译 Source/ZenLib/Thread.cpp 时出现:
text
error: use of undeclared identifier 'pthread_cancel'
2) 根因
pthread_cancel 不是 POSIX 必选 API 。在 musl 一类实现中通常不可用;而 OHOS 工具链编译参数里常见:
text
-D__MUSL__
ZenLib 源码里原本的策略是:
- Android:不走
pthread_cancel - 其它 Unix:走
pthread_cancel
OHOS/musl 更接近"需要走 Android 同类策略"的平台,而不是传统 glibc Linux。
三、vcpkg 侧解决方案(推荐做法)
1) 在 port 中引入补丁(最小侵入)
本仓库已提供补丁文件:
ports/libzen/ohos-musl-no-pthread-cancel.patch
并在 ports/libzen/portfile.cmake 的 vcpkg_from_github 中通过 PATCHES 自动应用。
补丁核心思路:
- 在
__ANDROID_API__、__OHOS__、__MUSL__任一成立时,不调用pthread_cancel - 用
(void)ThreadPointer;避免未使用变量告警
2) 提升 port-version
为避免二进制缓存/旧构建树"误以为没变",ports/libzen/vcpkg.json 已增加:
"port-version": 1
3) 完整 portfile.cmake文件
ohos-musl-no-pthread-cancel.patch补丁文件
cpp
diff --git a/Source/ZenLib/Thread.cpp b/Source/ZenLib/Thread.cpp
--- a/Source/ZenLib/Thread.cpp
+++ b/Source/ZenLib/Thread.cpp
@@ -519,11 +519,15 @@ Thread::returnvalue Thread::ForceTerminate()
{
//Terminating (not clean)
- #if !defined(__ANDROID_API__)
+ // pthread_cancel is not available on some libc implementations (e.g. musl,
+ // OpenHarmony). Android already excludes it; extend the same policy.
+ #if !defined(__ANDROID_API__) && !defined(__OHOS__) && !defined(__MUSL__)
pthread_cancel((pthread_t)ThreadPointer);
+ #else
+ (void)ThreadPointer;
#endif
//Configuring
State=State_Terminated;
return Ok;
}
bash
if(VCPKG_TARGET_IS_WINDOWS)
vcpkg_check_linkage(ONLY_STATIC_LIBRARY)
endif()
vcpkg_from_github(
OUT_SOURCE_PATH SOURCE_PATH
REPO MediaArea/ZenLib
REF "v${VERSION}"
SHA512 4232eb6e73e9b380f6fe2ce3cfeb9fe343936362a35ca8d088c783dc6277332df762d689efe023e3f1418c2e6d2629e0b82ac93df9cce3ae0ab346c2ed1911f1
HEAD_REF master
PATCHES
ohos-musl-no-pthread-cancel.patch
)
vcpkg_find_acquire_program(PKGCONFIG)
vcpkg_cmake_configure(
SOURCE_PATH "${SOURCE_PATH}/Project/CMake"
OPTIONS
"-DPKG_CONFIG_EXECUTABLE=${PKGCONFIG}"
-DCMAKE_REQUIRE_FIND_PACKAGE_PkgConfig=1
)
vcpkg_cmake_install()
vcpkg_cmake_config_fixup(PACKAGE_NAME zenlib)
vcpkg_fixup_pkgconfig()
if(NOT VCPKG_BUILD_TYPE AND VCPKG_TARGET_IS_WINDOWS)
vcpkg_replace_string("${CURRENT_PACKAGES_DIR}/debug/lib/pkgconfig/libzen.pc" " -lzen" " -lzend")
endif()
file(REMOVE_RECURSE "${CURRENT_PACKAGES_DIR}/debug/include" "${CURRENT_PACKAGES_DIR}/debug/share")
vcpkg_install_copyright(FILE_LIST "${SOURCE_PATH}/License.txt")
vcpkg.json文件:
bash
{
"name": "libzen",
"version": "0.4.41",
"port-version": 1,
"description": "ZenLib is a C++ utility library for easiest cross-platform development",
"homepage": "https://github.com/MediaArea/ZenLib",
"license": "Zlib",
"dependencies": [
{
"name": "vcpkg-cmake",
"host": true
},
{
"name": "vcpkg-cmake-config",
"host": true
}
]
}
四、环境与安装步骤
1) 必备环境变量
bash
export OHOS_SDK_ROOT=/path/to/ohos-sdk/linux
并确认工具链存在:
bash
ls "$OHOS_SDK_ROOT/native/llvm/bin/clang++"
2) 安装 triplet
本文以 arm64-ohos 为例(你本地 triplet 名称需与实际一致)。
3) 安装命令
bash
# 建议改 port 后清理旧源码树,避免补丁未重新应用
rm -rf /path/to/vcpkg/buildtrees/libzen
vcpkg install libzen:arm64-ohos
4) 产物位置(典型)
安装成功后,常见输出位于:
installed/arm64-ohos/lib/(静态/动态库,取决于 triplet 与 linkage)installed/arm64-ohos/include/(头文件)installed/arm64-ohos/share/zenlib/(CMake package 配置,具体以生成结果为准)
五、接入使用(CMake)
1) 通过 vcpkg toolchain 注入
确保你的工程 CMake 配置使用 vcpkg 提供的 toolchain,例如:
cmake
-DCMAKE_TOOLCHAIN_FILE=/path/to/vcpkg/scripts/buildsystems/vcpkg.cmake
2) find_package 示例
ZenLib 在 vcpkg 中通常以 zenlib 包名做 config fixup(以你安装后的 share/zenlib/*.cmake 为准)。常见写法类似:
cmake
find_package(zenlib CONFIG REQUIRED)
target_link_libraries(main PRIVATE zenlib::zenlib)
说明:不同版本/不同 triplet 下导出的 target 名称可能略有差异,请以
installed/<triplet>/share/zenlib/目录中的 CMake 配置文件为准。
六、行为变化与风险评估(必须读)
1) Thread::ForceTerminate() 语义变化
禁用 pthread_cancel 后,ForceTerminate() 不再具备"向目标线程投递取消点并强制结束" 的能力(与 Android 分支策略更接近)。
2) 什么时候可以接受
- 业务主要使用 ZenLib 的字符串/解析工具,不依赖"硬杀线程"语义
- 线程退出路径本身是协作式的(可 join / 可自然结束)
3) 什么时候需要额外设计
- 你确实依赖"强制终止线程"来完成超时/取消
- 需要引入:取消标志位、
pthread_kill(SIGUSR)协作退出、或重构线程生命周期
七、排障清单(按优先级)
- 确认补丁已应用 :清理
buildtrees/libzen后重装 - 确认 triplet 与 sysroot :编译命令里应出现
--target=...-ohos与--sysroot=.../native/sysroot - 确认 OHOS_SDK_ROOT :避免路径拼接出现
//或缺失目录 - 若仍遇到 libc 差异:优先对比是否还有其它 glibc-only API(按报错逐个补丁或换实现)
上面移植成功libzen后,移植libinfo变得很简单了:

八、结语
将 libzen 移植到 HarmonyOS/OHOS,本质上是 "交叉编译 + libc 能力对齐" 。
pthread_cancel 属于高频雷点:它看起来是"标准 pthread",但在 musl/OHOS 场景下并不成立。
通过 vcpkg port 补丁把平台差异收敛在包管理层面,可以让业务工程保持干净,同时便于团队复用与版本升级维护。
https://atomgit.com/weixin_62765017/ohos_mediainfo
最后,欢迎加入开源鸿蒙开发者社区交流:https://harmonypc.csdn.net/