[鸿蒙三方库适配实战] 多媒体信息工具 MediaInfo CLI 的 OpenHarmony 平台迁移实践

摘要:本文详细介绍了如何将多媒体信息分析工具 MediaInfo CLI 适配到 鸿蒙PC 平台。文章将系统性地讲解如何利用 lycium_plusplus 构建框架,处理 C/C++ 项目在鸿蒙环境下的交叉编译流程,展示如何处理 musl libc 兼容性问题、CMake 构建配置优化以及 HNP 包生成的完整实践。

本文是软件鸿蒙化迁移实践系列文章之一,专注于 C/C++ 原生库的鸿蒙 PC 适配,为开发者提供完整的迁移指南。

AtomGit仓库地址:https://atomgit.com/OpenHarmonyPCDeveloper/ohos_mediainfo

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

项目信息说明

项目 说明
名称 MediaInfo CLI
开源协议 BSD-2-Clause
源码版本 25.03
目标平台 鸿蒙 PC
依赖项 CMake, ZenLib, MediaInfoLib, zlib
操作系统平台 WSL Ubuntu 24.04

一、背景介绍

1.0 功能与效果

MediaInfo CLI 在本实践中的预期能力如下:

功能:提供跨平台的视频和音频文件技术信息分析功能,支持多种媒体格式(MP4、MKV、AVI、MP3、FLAC 等),输出详细的技术参数(编码格式、分辨率、比特率、帧率、采样率等)。

效果:在鸿蒙 PC 上提供与标准 Linux 环境相近的 MediaInfo CLI 使用体验,便于在鸿蒙应用开发中实现媒体文件分析、元数据提取、媒体库管理等场景的多媒体处理功能。

1.1 什么是 鸿蒙PC HNP 生态

HNP(Harmony Native Package)是 鸿蒙PC 的原生包格式,lycium 是增强型构建框架,支持自动下载源码、交叉编译(arm64-v8a、armeabi-v7a)、一键生成 HNP 包以及开源声明聚合。C/C++ 原生库的适配是鸿蒙系统生态建设中的重要一环。

1.2 为什么适配 C/C++ 原生库会有难度

常见挑战包括:

  • 构建系统差异:C/C++ 项目通常使用 CMake、Autotools 等构建系统,需要配置交叉编译工具链(aarch64-linux-ohos-clang/clang++)。
  • musl libc 兼容性:鸿蒙PC使用 musl libc,不支持某些 glibc 特有的函数(如 pthread_cancel),需要修改源码或注释掉不兼容的调用。
  • 依赖管理复杂:项目可能依赖多个第三方库(如 MediaInfo 依赖 ZenLib、MediaInfoLib、zlib),需要正确配置依赖路径和编译选项。
  • 产物体积优化:默认的 make install 会安装所有文件(头文件、库文件、文档等),需要优化只保留可执行文件以减小产物体积。
  • Windows 元数据干扰:从 Windows 环境复制的源码可能包含 :Zone.Identifier 等区域标识文件,需要在打包前清理。
  • 构建缓存问题:lycium 使用 hpk_build.csv 跟踪构建状态,需要正确清理缓存才能重新构建。

1.3 MediaInfo 简介

MediaInfo 是一款由 MediaArea 开发的方便统一显示视频和音频文件最相关技术和标签数据的工具。其主要特点包括:

  • 多格式支持:支持视频(MP4、MKV、AVI、MOV、WMV 等)和音频(MP3、FLAC、AAC、OGG 等)格式。
  • 详细技术分析:提供编码格式、分辨率、比特率、帧率、采样率、声道数等技术参数。
  • 多种输出格式:支持文本、HTML、XML、JSON、CSV 等输出格式。
  • 跨平台特性:原生支持 Windows、macOS、Linux,本次适配扩展到 鸿蒙PC 平台。
  • 开源地址

二、环境准备

2.0 系统要求

  • 开发环境:Ubuntu 24.04(推荐 WSL 2)
  • 核心工具:CMake(v3.16+)、GCC/G++、Git、Python3
  • 构建框架:lycium_plusplus
  • 鸿蒙 SDK:OpenHarmony SDK(提供交叉编译工具链 aarch64-linux-ohos-clang/clang++)
  • 目标架构:arm64-v8a(AArch64)

2.0.1 扩展阅读与参考教程

下方汇总展示了多位老师在鸿蒙 OpenHarmony 适配方面的高质量教程。若在前提准备(环境、工具链、框架)部分还有不清楚的地方,可参考这些文章进一步学习。 以下资源不分先后顺序,均具有参考价值。

资源类型 描述 链接
三方库交叉编译环境(Ubuntu) 在 Ubuntu 中搭建鸿蒙PC 三方库交叉编译构建开发环境 👉 点击查看
三方库交叉编译环境(macOS) 在 macOS 中搭建鸿蒙PC 三方库交叉编译开发环境 👉 点击查看
基础环境搭建 Windows 10 上安装和使用 WSL 2、安装 Ubuntu 24 详细指南 👉 点击查看
Mac 移植指南 鸿蒙PC命令行适配指南(Mac 版) 👉 点击查看
Win 移植指南 鸿蒙PC 生态三方软件移植:开发环境搭建及三方库移植指南 👉 点击查看
全流程适配指南 OpenHarmony Linux 命令行工具适配实战:基于 Cursor × WSL 的 tree 2.2.1 交叉编译与 HNP 打包全流程指南 👉 点击查看
官方构建文档 新脚手架:社区维护的鸿蒙PC 生态命令行工具构建框架 lycium_plusplus(原 build 仓库为旧方式,请以本仓库为准) 👉 点击查看

2.1 lycium_plusplus 框架

lycium_plusplus 是本次适配工作的核心工具,主要用于统一管理各类第三方库的构建流程,通过规范编译、依赖与打包逻辑,实现三方库在目标平台上高效、稳定地编译与集成,是整个适配环节中保障构建一致性与可维护性的关键支撑。

plain 复制代码
# 克隆 lycium_plusplus 项目
git clone https://gitcode.com/OpenHarmonyPCDeveloper/lycium_plusplus.git
cd lycium_plusplus

2.2 CMake 与交叉编译环境

由于 MediaInfo 是 C/C++ 项目,需要 CMake 和 鸿蒙 SDK 提供的交叉编译工具链。

plain 复制代码
# 安装 CMake
sudo apt-get install -y cmake

# 验证安装
cmake --version

# 配置 鸿蒙 SDK 环境变量
export OHOS_SDK=/home/weishuo/ohos-sdk/linux

三、实战:以 MediaInfo 为例的适配步骤

本章节将为新人开发者提供完整的、可复现的适配步骤。我们将从零开始,逐步完成 MediaInfo CLI 的鸿蒙适配工作。每个步骤都包含详细的说明、命令示例和注意事项。

我们主要需要创建HPKBUILD、hnp.json、README.OpenSource、HPKCHECK四个核心文件

HPKBUILD:三方库编译构建脚本,下载、补丁、交叉编译、打包全流程管控

hnp.json:鸿蒙 HNP 安装包元信息,系统识别安装、路径依赖配置

README.OpenSource:开源版权溯源、协议声明,合规审计必备文档

HPKCHECK:编译产物真机校验脚本,检测库可用性、兼容性与运行异常

鸿蒙 Lycium++ 三方库 标准完整流程

Tip:AI 全面渗透的技术时代,开发不再等同于亲手写码。核心在于掌握全流程的适配逻辑与框架,用精准的 Prompt 与 AI 工具协同调试,高效达成目标

比如:学习鸿蒙适配框架lycium_plusplus,参考已经适配完成的三方库命令,适配三方库命令MediaInfo,lycium_plusplus/thirdparty/ 创建库目录,编写HPKBUILD、hnp.json、README.OpenSource、HPKCHECK,编译产物需要生成在output/目录下

  1. 创建目录

在 lycium_plusplus/thirdparty/ 下新建库名目录

  1. 放入 4 个必备文件 + 补丁(按需)
  • HPKBUILD:定义信息 + 下载 / 编译 / 安装 / 打包
  • hnp.json:HNP 包元数据,系统识别配置
  • README.OpenSource:开源合规、版权协议声明
  • HPKCHECK:真机运行校验、兼容性测试
  • 适配补丁文件(*.patch)
  1. 一键构建

执行:./build.sh 库名

  1. 框架全自动执行

下载源码 → 打补丁 → 交叉编译 → 安装 → 生成 HNP → 真机校验

  1. 获取产物
  • usr/:二进制库、头文件
  • output/:鸿蒙 HNP 安装包

3.1 创建项目目录结构

步骤说明

在 lycium_plusplus 框架中,每个三方库都需要在 thirdparty/ 目录下拥有独立的目录。这个目录将存放该库的所有构建配置文件(HPKBUILD、hnp.json、README.OpenSource、HPKCHECK 等)。

详细操作流程

plain 复制代码
# 1. 进入 lycium_plusplus 项目根目录
cd /home/weishuo/lycium_plusplus

# 2. 进入 thirdparty 目录
cd thirdparty

# 3. 创建 mediainfo 目录
mkdir -p mediainfo

# 4. 进入新创建的目录
cd mediainfo

# 5. 验证目录创建成功
pwd
# 输出:/home/weishuo/lycium_plusplus/thirdparty/mediainfo

# 6. 查看目录结构
ls -la

目录结构说明

plain 复制代码
lycium_plusplus/
├── thirdparty/
│   ├── mediainfo/          ← 我们刚创建的目录
│   │   ├── HPKBUILD        ← 将要创建的构建脚本
│   │   ├── hnp.json        ← 将要创建的包元数据
│   │   ├── README.OpenSource  ← 将要创建的开源声明
│   │   └── HPKCHECK        ← 将要创建的检查脚本
│   ├── fuse3/              ← 其他三方库示例
│   ├── glib/               ← 其他三方库示例
│   └── ...
├── lycium/
│   ├── build.sh            ← lycium 构建入口脚本
│   └── usr/                ← 构建产物输出目录
└── Projects/
    └── MediaInfo/          ← MediaInfo 源码目录(需提前准备)

注意事项

  • 目录名称必须与 pkgname 变量保持一致(本例中为 mediainfo)
  • 确保 Projects/MediaInfo/ 目录中已经有 MediaInfo 的源码
  • 如果源码还未准备,需要先下载或克隆源码到 Projects/MediaInfo/ 目录

3.2 创建 HPKBUILD 文件

步骤说明

HPKBUILD 是 lycium 框架的核心构建脚本,它定义了三方库的元信息配置及下载、编译、打包等全流程构建逻辑。可以理解为一个"构建配方",告诉 lycium 框架如何编译和打包这个库。

HPKBUILD 的核心作用

  1. 元信息定义:库名、版本、描述、许可证、目标架构等
  2. 依赖管理:声明编译时和运行时依赖
  3. 构建流程:prepare() → build() → package() → archive()
  4. 环境配置:交叉编译工具链、CMake 参数、安装路径等

详细操作流程

前提准备,需要提前准备源码放在Projects目录下 MediaInfo源码GitHub地址: https://github.com/MediaArea/MediaInfo

plain 复制代码
# 1. 确保当前在 mediainfo 目录
cd /home/weishuo/lycium_plusplus/thirdparty/mediainfo

# 2. 创建 HPKBUILD 文件
# 方法 1:使用 vim 编辑器
vim HPKBUILD

# 方法 2:使用 nano 编辑器(对新人更友好)
nano HPKBUILD

# 方法 3:使用 Windows 编辑器创建后复制到 WSL(需要注意 CRLF 问题)
# 在 Windows 上创建 HPKBUILD 文件,然后复制到 WSL
# 注意:必须使用 LF 换行符,不能使用 CRLF

HPKBUILD 文件内容详解

plain 复制代码
#!/bin/bash
# 编译构建脚本:MediaInfo CLI 工具 (适配鸿蒙系统)
# 贡献者/维护者信息
# Contributor: Your Name <youremail@domain.com>
# Maintainer: Your Name <youremail@domain.com>

# 基础包配置
# 包名
pkgname=mediainfo
# 包版本
pkgver=25.03
# 包发布版本号
pkgrel=0
# 包描述:音视频文件技术信息和标签数据查看工具(命令行版)
pkgdesc="A convenient unified display of the most relevant technical and tag data for video and audio files (CLI version)"
# 项目源码地址
url="https://github.com/MediaArea/MediaInfo"
# 支持的架构:32位ARM / 64位ARM
archs=("armeabi-v7a" "arm64-v8a")
# 开源协议
license=("BSD-2-Clause")
# 运行依赖(无)
depends=()
# 编译依赖:需要cmake
makedepends=("cmake")

# 源码配置
# 使用本地源码,不自动解压
autounpack=false
# 不自动下载源码包
downloadpackage=false

# 编译工具
buildtools="cmake"

# 本地源码路径(从环境变量 LYCIUM_ROOT 指向项目目录)
srcpath="${LYCIUM_ROOT}/../Projects/MediaInfo"
# 编译目录名称 = 包名+版本
builddir=${pkgname}-${pkgver}

# 准备阶段:复制源码、打补丁
prepare() {
    # 判断本地源码目录是否存在
    if [ -d "$srcpath" ]; then
        # 创建编译目录
        mkdir -p "$builddir"
        # 复制本地所有源码到编译目录
        cp -rf "$srcpath"/* "$builddir/"
        # 删除备份文件 .bak
        find "$builddir" -name "*.bak" -type f -delete 2>/dev/null || true
        # 删除 Windows 系统遗留的区域标识符文件
        find "$builddir" -name "*:Zone.Identifier" -type f -delete 2>/dev/null || true
        
        # 如果存在musl兼容补丁,则自动打补丁
        if [ -f "../mediainfo-zenlib-musl.patch" ]; then
            cd "$builddir"
            patch -p1 < "../mediainfo-zenlib-musl.patch"
            cd "$OLDPWD"
        fi
    else
        # 源码不存在则报错退出
        echo "ERROR: Source not found at $srcpath"
        exit 1
    fi
}

# 编译阶段:cmake + make
build() {
    # 进入编译目录
    cd "$builddir"
    
    # cmake 配置
    cmake "$@" \
        -B"$ARCH-build" \          # 按架构区分构建目录
        -S./Project/CMake/CLI/ \    # CLI 版源码路径
        -D CMAKE_BUILD_TYPE=Release \ # 编译 Release 版本
        -D CMAKE_INSTALL_PREFIX="/usr" \ # 安装路径前缀
        -D BUILD_ZENLIB=ON \         # 编译依赖库 ZenLib
        -D BUILD_MEDIAINFOLIB=ON \   # 编译核心库 MediaInfoLib
        -D BUILD_ZLIB=ON \           # 编译 zlib
        -D ZLIB_BUILD_SHARED=OFF \   # zlib 编译为静态库
        -D ZLIB_BUILD_TESTING=OFF \   # 不编译 zlib 测试程序
        -D MediaInfoLib_BUILD_STATIC=ON # MediaInfoLib 编译为静态库
    
    # 多线程编译(4线程)
    make -j4 -C "$ARCH-build"
    # 记录 make 执行结果
    ret=$?
    
    # 返回原目录
    cd "$OLDPWD"
    # 返回编译结果状态码
    return $ret
}

# 安装阶段:将编译产物安装到指定目录
package() {
    cd "$builddir"
    # 安装到目标架构目录(用于后续打包)
    make -C "$ARCH-build" install DESTDIR="${LYCIUM_ROOT}/usr/${pkgname}/${ARCH}"
    cd "$OLDPWD"
}

# 测试阶段:提示需在真机/设备上运行
check() {
    echo "The test must be on an OpenHarmony device!"
}

# 归档打包阶段:生成 .tar.gz + .hnp 鸿蒙安装包
archive() {
    # 指定 hnp 工具路径(鸿蒙 SDK 工具链)
    export HNP_TOOL="${HNP_TOOL:-${OHOS_SDK}/toolchains/hnpcli}"
    
    # 创建输出目录
    mkdir -p "${LYCIUM_ROOT}/output/${ARCH}"
    
    # 进入安装目录并打包成 tar.gz
    pushd "${LYCIUM_ROOT}/usr/${pkgname}/${ARCH}" > /dev/null 2>&1
    tar -zcf "${LYCIUM_ROOT}/output/${ARCH}/${pkgname}_${pkgver}.tar.gz" .
    echo "Archive completed: ${LYCIUM_ROOT}/output/${ARCH}/${pkgname}_${pkgver}.tar.gz"
    popd > /dev/null 2>&1
    
    # 如果 hnpcli 工具存在,则生成鸿蒙 .hnp 包
    if [ -f "${HNP_TOOL}" ]; then
        cp "${LYCIUM_ROOT}/../thirdparty/${pkgname}/hnp.json" "${LYCIUM_ROOT}/usr/${pkgname}/${ARCH}/"
        ${HNP_TOOL} pack -i "${LYCIUM_ROOT}/usr/${pkgname}/${ARCH}" -o "${LYCIUM_ROOT}/output/${ARCH}/"
        echo "Archive completed: ${LYCIUM_ROOT}/output/${ARCH}/${pkgname}.hnp"
    else
        # 缺少工具则跳过 hnp 打包
        echo "Warning: hnpcli not found at ${HNP_TOOL}, skipping HNP generation"
    fi
}

# 清理构建目录
cleanbuild() {
    rm -rf "${PWD}/$builddir"
}

构建流程说明

plain 复制代码
HPKBUILD 执行流程:

1. prepare()   ← 准备阶段:复制源码、清理文件
       ↓
2. build()     ← 构建阶段:CMake 配置、编译
       ↓
3. package()   ← 打包阶段:安装产物到指定目录
       ↓
4. archive()   ← 归档阶段:生成 tar.gz 和 hnp 包
       ↓
5. cleanbuild() ← 清理阶段:清除构建产物(可选)

3.3 创建 hnp.json(包元数据)

步骤说明

hnp.json 文件用于描述 HNP 包的元信息,类似于 Node.js 的 package.json 或 Python 的 setup.py。它告诉鸿蒙系统这个包是什么、包含哪些文件、如何安装等信息。

hnp.json 的作用

  1. 包信息描述:名称、版本、描述、许可证
  2. 架构信息:目标架构(arm64-v8a、armeabi-v7a)
  3. 安装规则:哪些文件安装到哪些目录
  4. 依赖声明:运行时依赖的其他 HNP 包

详细操作流程

plain 复制代码
# 1. 确保当前在 mediainfo 目录
cd /home/weishuo/lycium_plusplus/thirdparty/mediainfo

# 2. 创建 hnp.json 文件
vim hnp.json
# 或
nano hnp.json

# 3. 验证 JSON 格式是否正确
python3 -m json.tool hnp.json > /dev/null && echo "JSON 格式正确" || echo "JSON 格式错误"

hnp.json 文件内容详解

plain 复制代码
{
    "type": "hnp-config",
    "name": "mediainfo",
    "version": "25.03",
    "description": "A convenient unified display of the most relevant technical and tag data for video and audio files (CLI version)",
    "license": "BSD-2-Clause",
    "arch": "arm64-v8a",
    "install": {
        "bin": ["usr/bin/mediainfo"]
    }
}

3.4 创建 README.OpenSource(开源声明)

步骤说明

README.OpenSource 是为了满足开源合规性要求而创建的文件。它声明了 MediaInfo 及其所有依赖库的许可证信息、上游地址和版本信息。这是鸿蒙生态开源合规的必要文件。

为什么需要 README.OpenSource

  1. 开源合规:声明所有使用的开源组件及其许可证
  2. 许可证追踪:记录每个组件的许可证文件和上游地址
  3. 版本管理:明确每个依赖库的版本号
  4. 法律风险规避:避免侵犯开源许可证条款

详细操作流程

plain 复制代码
# 1. 确保当前在 mediainfo 目录
cd /home/weishuo/lycium_plusplus/thirdparty/mediainfo

# 2. 创建 README.OpenSource 文件
vim README.OpenSource
# 或
nano README.OpenSource

# 3. 验证 JSON 格式是否正确
python3 -m json.tool README.OpenSource > /dev/null && echo "JSON 格式正确" || echo "JSON 格式错误"

README.OpenSource 文件内容详解

plain 复制代码
[
    {
        "Name": "MediaInfo",
        "License": "BSD-2-Clause",
        "License File": "https://github.com/MediaArea/MediaInfo/blob/master/LICENSE",
        "Version Number": "25.03",
        "Owner": "your-email@example.com",
        "Upstream URL": "https://github.com/MediaArea/MediaInfo/releases/download/v25.03/MediaInfo_CLI_25.03_GNU_FromSource.tar.xz",
        "Description": "MediaInfo is a convenient unified display of the most relevant technical and tag data for video and audio files."
    },
    {
        "Name": "ZenLib",
        "License": "zlib/libpng",
        "License File": "https://github.com/MediaArea/ZenLib/blob/master/License.txt",
        "Version Number": "0.4.41",
        "Owner": "your-email@example.com",
        "Upstream URL": "https://github.com/MediaArea/ZenLib/archive/refs/tags/v0.4.41.tar.gz",
        "Description": "ZenLib is a C++ library for cross-platform development, used by MediaInfo."
    },
    {
        "Name": "MediaInfoLib",
        "License": "BSD-2-Clause",
        "License File": "https://github.com/MediaArea/MediaInfoLib/blob/master/LICENSE",
        "Version Number": "25.03",
        "Owner": "your-email@example.com",
        "Upstream URL": "https://github.com/MediaArea/MediaInfoLib/releases/download/v25.03/MediaInfoLib_25.03_GNU_FromSource.tar.xz",
        "Description": "MediaInfoLib is the library for MediaInfo, providing media file analysis capabilities."
    },
    {
        "Name": "zlib",
        "License": "Zlib",
        "License File": "https://github.com/madler/zlib/blob/master/LICENSE",
        "Version Number": "1.3.1",
        "Owner": "your-email@example.com",
        "Upstream URL": "https://github.com/madler/zlib/releases/download/v1.3.1/zlib-1.3.1.tar.gz",
        "Description": "zlib is a software library used for data compression."
    }
]

3.5 创建 HPKCHECK 检查脚本

步骤说明

HPKCHECK 是 lycium 框架的构建检查脚本,用于在编译前验证环境是否满足构建要求,以及在编译后验证产物是否正确。它相当于一个"自动化测试脚本",确保构建质量。

HPKCHECK 的作用

  1. 环境验证:检查编译环境是否满足要求
  2. 产物验证:验证生成的可执行文件是否存在且可执行
  3. 功能测试:运行基本的功能测试(如 --version、--help)
  4. 日志记录:记录测试结果到日志文件

详细操作流程

plain 复制代码
# 1. 确保当前在 mediainfo 目录
cd /home/weishuo/lycium_plusplus/thirdparty/mediainfo

# 2. 创建 HPKCHECK 文件
vim HPKCHECK
# 或
nano HPKCHECK

# 3. 添加可执行权限
chmod +x HPKCHECK

# 4. 验证脚本语法
bash -n HPKCHECK && echo "脚本语法正确" || echo "脚本语法错误"

HPKCHECK 文件内容详解

plain 复制代码
#!/bin/bash
# HPKCHECK for MediaInfo CLI

HPK_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "${HPK_DIR}" || exit 1
source ./HPKBUILD > /dev/null 2>&1

logfile="${HPK_DIR}/${pkgname}_${ARCH}_test.log"

checkprepare() {
    return 0
}

openharmonycheck() {
    res=0
    inst_bin="${LYCIUM_ROOT}/usr/${pkgname}/${ARCH}/bin"
    
    if [ -x "${inst_bin}/mediainfo" ]; then
        cd "$inst_bin" || return 1
    else
        echo "no mediainfo binary in ${inst_bin}" >&2
        return 1
    fi
    
    {
        echo "start test times: $(date)"
        
        echo "=== MediaInfo CLI version check ==="
        if [ -x ./mediainfo ]; then
            ./mediainfo --version
            res=$(( res | $? ))
        else
            echo "missing ./mediainfo"
            res=1
        fi
        
        echo "=== MediaInfo CLI help check ==="
        if [ -x ./mediainfo ]; then
            ./mediainfo --help | head -20
            res=$(( res | $? ))
        else
            echo "missing ./mediainfo"
            res=1
        fi
        
        echo "end test times: $(date)"
    } >> "${logfile}" 2>&1
    
    if [ $res -ne 0 ] && [ -n "${LYCIUM_FAULT_PATH}" ]; then
        mkdir -p "${LYCIUM_FAULT_PATH}/${pkgname}"
    fi
    
    cd "${OLDPWD}"
    return $res
}

3.6 创建 mediainfo-zenlib-musl.patch(musl 兼容性补丁)

步骤说明

mediainfo-zenlib-musl.patch 是修复 musl libc 兼容性的关键补丁文件。MediaInfo 依赖的 ZenLib 库使用了 pthread_cancel 函数,但 OpenHarmony 使用的 musl libc 不支持该函数,会导致编译失败。

为什么需要这个补丁

  1. pthread_cancel 缺失:ZenLib 的 Thread.cpp 中调用了 pthread_cancel 来取消线程
  2. musl libc 限制:musl libc(OpenHarmony 使用的 C 库)出于简化设计,不提供 pthread_cancel 实现
  3. 编译阻断:不修复会导致链接错误 undefined reference to 'pthread_cancel'
  4. 功能安全:MediaInfo CLI 实际上不需要线程取消功能,注释掉不影响正常使用
plain 复制代码
--- a/ZenLib/Source/ZenLib/Thread.cpp
+++ b/ZenLib/Source/ZenLib/Thread.cpp
@@ -520,7 +520,7 @@
     {
         #ifdef __unix__
-            pthread_cancel((pthread_t)ThreadPointer);
+            // pthread_cancel not supported in musl libc (OpenHarmony)
         #endif
         #ifdef _WIN32
             #ifdef UNICODE

补丁修改说明

  • 修改位置:ZenLib/Source/ZenLib/Thread.cpp 第 520 行附近
  • 修改内容:将 pthread_cancel 函数调用替换为注释
  • 影响范围:仅影响线程取消功能,MediaInfo CLI 不依赖此功能

HPKBUILD 中的使用方式

补丁在 prepare() 函数中自动应用(见 3.2 节 HPKBUILD 的 prepare() 函数):

plain 复制代码
# 应用 musl 兼容性 patch(修复 pthread_cancel 不可用问题)
if [ -f "../mediainfo-zenlib-musl.patch" ]; then
    echo "Applying musl compatibility patch..."
    cd "$builddir"
    patch -p1 < "../mediainfo-zenlib-musl.patch"
    if [ $? -eq 0 ]; then
        echo "  Patch applied successfully"
    else
        echo "  Patch may have already been applied or failed"
    fi
    cd "$OLDPWD"
fi

注意事项

  • patch 文件放在 thirdparty/mediainfo/ 目录,与 HPKBUILD 同级
  • 使用 patch -p1 参数,因为 patch 文件中的路径以 a/ 和 b/ 开头
  • 如果 patch 已经应用过,patch 命令会提示失败,脚本中会忽略此错误
  • 这是标准做法,比直接在 HPKBUILD 中用 sed 或 python 修改源码更规范

四、编译流程与完整示例

4.1 环境准备

配置用于前置环境检查与变量设置,通过指定 鸿蒙SDK 路径、验证 CMake 环境,为 lycium_plusplus 构建三方库提供基础运行环境

plain 复制代码
# 1. 确保鸿蒙 SDK 已安装
export OHOS_SDK=/home/weishuo/ohos-sdk/linux

# 2. 确保 CMake 已安装
cmake --version

4.2 创建项目结构并执行编译

通过目录操作、脚本创建、清理缓存、执行构建指令,完成 lycium_plusplus 中 MediaInfo 三方库的从零构建全流程

plain 复制代码
cd lycium_plusplus/thirdparty
mkdir -p mediainfo
cd mediainfo
# 创建 HPKBUILD 文件(内容见第三章)
vim HPKBUILD

cd ../../lycium
# 清理历史构建记录(可选,但推荐)
grep -v 'mediainfo' usr/hpk_build.csv > usr/hpk_build.csv.tmp
mv usr/hpk_build.csv.tmp usr/hpk_build.csv
rm -rf ../thirdparty/mediainfo/mediainfo-25.03
rm -rf output/*/mediainfo*

# 开始构建
./build.sh mediainfo

4.3 构建成功输出示例

4.4 验证产物

构建成功后,编译产物会统一输出至 output 目录,包含标准 tar 压缩包 与鸿蒙专用 hnp 格式包

五、鸿蒙PC 上验证结果(测试)

解压并进入目录,并且查看二进制文件并添加执行权限,执行签名操作

plain 复制代码
# 解压到鸿蒙 PC 桌面(路径示例)
tar -zxf arm64-v8a.tar.gz

# 进入对应目录
cd arm64-v8a/bin

# 查看文件
ls -l

# 在鸿蒙 PC 上若策略要求,可对二进制签名(示例)
binary-sign-tool sign -inFile mediainfo -outFile mediainfo -selfSign "1"

# 按需添加执行权限
chmod +x mediainfo

# 执行测试
./mediainfo --version

MediaInfo help 命令测试

plain 复制代码
./mediainfo --help

MediaInfo 媒体文件分析测试

plain 复制代码
./mediainfo test.mp4

六、常见问题与解决方案(FAQ)

Q1:构建时报错 $'\r': command not found?

A:这是 Windows 换行符(CRLF)导致的问题。在 WSL + Windows 共享目录环境下,使用 create_file 工具创建的文件会自动带有 CRLF 换行符。解决方案是使用 Python 脚本在 Linux 环境中重新创建文件。

plain 复制代码
# 使用 Python 二进制模式转换(推荐)
python3 << 'EOF'
import os

files = [
    "/path/to/HPKBUILD",
    "/path/to/HPKCHECK"
]

for filepath in files:
    with open(filepath, "rb") as f:
        content = f.read()
    content = content.replace(b"\r\n", b"\n").replace(b"\r", b"\n")
    with open(filepath, "wb") as f:
        f.write(content)
    print(f"Fixed: {filepath}")

print("All files fixed!")
EOF

Q2:执行 ./build.sh mediainfo 后,日志显示 ALL JOBS DONE!!! 但 output 目录为空?

A:这通常是因为 hpk_build.csv 中已有该包的构建记录,导致构建被跳过。需要手动清理构建记录和缓存。

plain 复制代码
cd lycium_plusplus/lycium
grep -v 'mediainfo' usr/hpk_build.csv > usr/hpk_build.csv.tmp
mv usr/hpk_build.csv.tmp usr/hpk_build.csv
rm -rf ../thirdparty/mediainfo/mediainfo-25.03
rm -rf output/*/mediainfo*
./build.sh mediainfo

Q3:编译时报错 use of undeclared identifier 'pthread_cancel'?

A:原因是 鸿蒙 使用 musl libc,不支持 pthread_cancel 函数。HPKBUILD 中已包含自动修复逻辑,会在 CMake 配置后检测并注释掉该函数调用。

plain 复制代码
--- a/ZenLib/Source/ZenLib/Thread.cpp
+++ b/ZenLib/Source/ZenLib/Thread.cpp
@@ -520,7 +520,7 @@
     {
         #ifdef __unix__
-            pthread_cancel((pthread_t)ThreadPointer);
+            // pthread_cancel not supported in musl libc (OpenHarmony)
         #endif
         #ifdef _WIN32
             #ifdef UNICODE

Q4:如何在鸿蒙 PC 上使用 MediaInfo CLI?

A:安装 HNP 包后,可以直接运行 mediainfo 命令。

plain 复制代码
# 查看版本
mediainfo --version

# 查看帮助
mediainfo --help

# 分析媒体文件
mediainfo video.mp4

# 输出 JSON 格式
mediainfo --Output=JSON audio.mp3

# 完整技术参数
mediainfo --Full movie.mkv

# 批量分析
mediainfo *.mp4 *.mkv

Q5:构建产物中包含 Windows 区域标识文件(:Zone.Identifier)?

A:原因是源码从 Windows 环境复制时带来了这些元数据文件。解决方案是在 prepare() 和 package() 阶段都添加清理命令。

plain 复制代码
# 在 prepare() 中清理
find "$builddir" -name "*:Zone.Identifier" -type f -delete

# 在 package() 中清理
find "${destdir}" -name "*:Zone.Identifier" -type f -delete

Q6:CMake 配置时报错找不到 ZenLib 或 MediaInfoLib?

A:MediaInfo 使用 CMake 的 FetchContent 机制自动下载依赖。确保网络连接正常(GitHub 可访问),已初始化子模块。

plain 复制代码
# 手动初始化子模块
cd ~/lycium_plusplus/Projects/MediaInfo
git submodule update --init --recursive

Q7:如何验证生成的可执行文件是否正确?

A:使用 file 命令检查 ELF 文件格式。

plain 复制代码
file ~/lycium_plusplus/lycium/usr/mediainfo/arm64-v8a/usr/bin/mediainfo

# 正确输出:
# ELF 64-bit LSB pie executable, ARM aarch64, version 1 (SYSV), 
# dynamically linked, interpreter /lib/ld-musl-aarch64.so.1, 
# with debug_info, not stripped

**Q8:**如何系统排查构建错误?

A:按以下步骤排查:

plain 复制代码
# 1. 查看完整日志
./build.sh mediainfo 2>&1 | tee build.log

# 2. 确认失败阶段:prepare / build / package / archive

# 3. 检查 prepare()
ls -la thirdparty/mediainfo/mediainfo-25.03/

# 4. 检查 build()
cat thirdparty/mediainfo/mediainfo-25.03/build.log

# 5. 检查 package() - 确认 destdir 路径和可执行文件是否存在

# 6. 检查 archive() - 确认打包路径是否正确

Q9:为什么选择本地源码而非 Git 下载?

A:本地源码模式更适合快速迭代开发,避免每次构建都重新下载。MediaInfo 包含多个子模块(ZenLib、MediaInfoLib、zlib),本地源码可以确保版本一致性。对于已经验证过的稳定版本,可以改为从 GitHub 下载。

plain 复制代码
# 改为从 GitHub 下载(修改 HPKBUILD)
source="https://github.com/MediaArea/MediaInfo/releases/download/v${pkgver}/MediaInfo_CLI_${pkgver}_GNU_FromSource.tar.xz"
autounpack=true
downloadpackage=true

# 需要提取准备源码放在Projects
# 本地源码路径(从环境变量 LYCIUM_ROOT 指向项目目录)
srcpath="${LYCIUM_ROOT}/../Projects/MediaInfo"
autounpack=false
downloadpackage=false

七、技术总结

本次将 MediaInfo CLI 适配至 鸿蒙PC 平台,完整验证了 C/C++ 原生项目在鸿蒙环境下的交叉编译、构建打包与体积优化流程,形成了可复用的适配范式。通过规范 HPKBUILD 配置、兼容 musl libc、清理 Windows 元数据、精简打包产物等关键处理,实现了工具正常编译运行与轻量化部署,相关思路可广泛迁移至各类开源 C/C++ 库的鸿蒙移植工作。

  • 建立了 CMake 类项目标准化的 HPKBUILD 适配模板,明确交叉编译与依赖管理要点
  • 解决 musl libc 兼容性、Windows 换行与元数据、CMake 目录规范等常见适配问题
  • 通过产物裁剪实现包体积显著优化,提升在鸿蒙设备上的部署效率
  • 适配方案具备通用性,可直接用于 FFmpeg、7-Zip、curl 等同类工具移植
  • 为后续多架构扩展、动态链接优化、自动化适配工具开发奠定基础

八、结语

本次实践成功将 MediaInfo CLI 移植至 鸿蒙PC 平台,充分体现了 lycium_plusplus 框架对 C/C++ 项目交叉编译的支撑能力。通过合理运用 HPKBUILD 构建流程、适配 musl libc 环境、规范 CMake 编译配置、优化产物体积及自动管理依赖等关键措施,有效解决了适配中的兼容性与构建问题,为同类开源 C/C++ 项目迁移至鸿蒙生态提供了可复用的思路与实践参考,也助力开源鸿蒙原生工具生态的完善与发展。

提示:本文基于 MediaInfo CLI 25.03 版本进行适配。不同版本的依赖和构建脚本可能有所差异,建议在适配前先熟悉目标项目的 CMakeLists.txt 和构建配置文件。

相关推荐
wei_shuo12 小时前
鸿蒙 PC CodeArts 实战:libplacebo 三方 Native 库编译、签名与调用全流程
鸿蒙pc·三方库适配
特立独行的猫a12 小时前
鸿蒙PC的包管理工具 Homebrew 正式上线,Harmonybrew介绍及使用指南
华为·harmonyos·homebrew·鸿蒙pc·harmonybrew
wei_shuo12 小时前
从零开始写 HPKBUILD:以 MediaInfo 为例的三方库鸿蒙PC适配实战
鸿蒙pc·三方库适配
wei_shuo12 小时前
[鸿蒙三方库适配实战] 高性能视频渲染库 libplacebo 的 鸿蒙PC 平台迁移实践
鸿蒙pc·三方库适配
wei_shuo3 天前
Windows 鸿蒙 PC 应用开发:DevEco Studio 集成与调用三方 Native 库实战指南
鸿蒙·鸿蒙pc·三方库适配
特立独行的猫a6 天前
鸿蒙 PC 命令行工具迁移实战直播课 · pngquant命令行移植实战
华为·ai·harmonyos·vcpkg·鸿蒙pc·lycim
特立独行的猫a7 天前
鸿蒙 PC 命令行工具迁移实战 · 直播PPT
android·华为·harmonyos·vcpkg·三方库移植·鸿蒙pc
特立独行的猫a7 天前
鸿蒙 PC 三方库移植实战 · 直播课件(详细教案)
华为·harmonyos·移植·鸿蒙pc·opendesk
特立独行的猫a9 天前
鸿蒙 PC 命令行工具迁移实战 · 内部课件(详细配套版)
华为·harmonyos·移植·鸿蒙pc