导读:你是否为 OpenHarmony 平台编译 C/C++ 三方库而头疼?面对复杂的交叉编译工具链、依赖管理、多架构适配感到无从下手?本文将带你从零开始,深入浅出地解析 lycium_plusplus 框架的设计理念与使用技巧,让你轻松掌握 OpenHarmony 生态下的三方库编译之道!

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

一、什么是 lycium_plusplus?

1.1 一句话定义

lycium_plusplus 是一个专为 OpenHarmony 系统设计的 C/C++** 三方库交叉编译自动化框架**,它能让你通过简单的配置,一键编译出能在 OpenHarmony 设备上运行的三方库。

1.2 项目背景

在 OpenHarmony 生态开发中,我们经常需要用到各种 C/C++ 三方库(如 curl、openssl、json 等)。但这些库原本是为 Linux/Windows 等成熟平台设计的,要移植到 OpenHarmony 面临以下挑战:

  • 工具链复杂:需要使用特定的交叉编译器(clang/clang++ for OHOS)
  • 依赖关系混乱:库与库之间存在复杂的依赖关系
  • 多架构适配:需要支持 armeabi-v7a、arm64-v8a 等多种架构
  • 构建系统多样:有的用 cmake,有的用 configure,有的用 make

lycium_plusplus 就是为了解决这些问题而生的!

1.3 核心能力

  • 一键构建:自动解析依赖关系树,按正确顺序编译
  • 多版本管理:支持同一库的不同版本共存
  • HNP产物生成:直接打包成 HarmonyOS 可用的 hnp 格式
  • 本机构建:支持在华为鸿蒙电脑上直接编译
  • 274+ 已适配库:涵盖主流 C/C++ 三方库

二、为什么需要这个框架?

2.1 传统编译方式 vs lycium_plusplus

让我们通过对比来理解这个框架的价值:

传统方式编译curl库
# 1. 手动下载源码
wget https://curl.se/download/curl-8.0.1.tar.gz
tar -zxvf curl-8.0.1.tar.gz

# 2. 设置交叉编译环境变量
export CC=/path/to/ohos-sdk/llvm/bin/aarch64-linux-ohos-clang
export CXX=/path/to/ohos-sdk/llvm/bin/aarch64-linux-ohos-clang++
export CFLAGS="-DOHOS_NDK -fPIC -D__MUSL__=1"

# 3. 手动处理依赖(假设依赖 openssl、zstd)
cd ../openssl && make && make install
cd ../zstd && cmake && make && make install

# 4. 配置编译
cd curl-8.0.1
./configure --host=aarch64-linux-ohos \
  --with-ssl=/path/to/openssl \
  --with-zstd=/path/to/zstd

# 5. 编译安装
make -j8
make install

问题

  • 环境变量容易设置错误
  • 依赖库需要手动先编译
  • 多架构要重复编译多次
  • 参数传递容易遗漏
使用 lycium_plusplus 编译 curl
# 1. 进入框架目录
cd lycium_plusplus/lycium

# 2. 一键编译(自动处理依赖)
./build.sh curl

优势

  • 零配置,开箱即用
  • 自动解析并编译依赖(openssl、zstd、nghttp2)
  • 自动处理多架构编译
  • 产物自动安装到标准路径

2.2 适用场景

  • OpenHarmony 应用开发:需要 C/C++ 三方库的北向应用
  • 系统开发:为 OpenHarmony 设备提供底层库支持
  • 库移植:将 Linux 库快速移植到 OpenHarmony 平台
  • 学习研究:理解交叉编译原理和 OpenHarmony 构建体系

三、框架整体架构

3.1 目录结构

lycium_plusplus/
├── community/              # 社区库(隐式依赖,不直接编译)
│   ├── CUnit/
│   ├── Catch2/
│   ├── json-c/
│   └── ... (100+ 社区库)
│
├── thirdparty/             # 核心三方库(主要工作区)
│   ├── curl/
│   │   └── HPKBUILD       # 每个库的构建配置
│   ├── json/
│   ├── openssl/
│   └── ... (274+ 已适配库)
│
├── external_deps/          # 外部适配仓配置
│   └── module.json        # 外部仓下载清单
│
└── lycium/                 # 核心编译引擎
    ├── build.sh           # 交叉编译入口
    ├── build_local.sh     # 本机构建入口
    ├── test.sh            # 测试入口
    ├── script/            # 核心脚本
    │   ├── build_hpk.sh   # 单库构建流程
    │   ├── envset.sh      # 环境配置
    │   └── load_outer_parts.py  # 外部仓加载
    └── template/          # 模板文件
        └── HPKBUILD       # HPKBUILD 模板

3.2 三大核心目录

目录 定位 特点
thirdparty/ 主战场 274+ 已适配库,可直接编译
community/ 后勤仓库 社区贡献库,作为依赖被引用
external_deps/ 扩展接口 外部适配仓,支持动态下载

3.3 编译流程架构图

四、核心概念解读

4.1 HPKBUILD:库的身份证

每个三方库都有一个 HPKBUILD 文件,它包含了库的所有编译信息。可以理解为一个“配方”,告诉框架如何编译这个库。

核心字段速查表

字段 含义
pkgname 库名
pkgver 版本号
pkgrel 发布号
pkgdesc 库描述
url 官网
archs 支持的架构
license 许可证
depends 运行时依赖
makedepends 构建工具依赖
source 源码下载地址

4.2 构建生命周期

每个库的编译都经历以下阶段(类似工厂生产线):

各阶段职责

  1. prepare():准备阶段
    1. 下载源码包(如果 downloadpackage=true)
    2. 解压源码(如果 autounpack=true)
    3. 应用 patch 修复兼容性问题
    4. 创建构建目录
  2. build():编译阶段
    1. 执行 cmake/configure 配置
    2. 执行 make 编译
    3. 生成目标文件
  3. package():安装阶段
    1. 执行 make install
    2. 将产物安装到 L Y C I U M R O O T / u s r LYCIUM_ROOT/usr LYCIUMROOT/usrpkgname/$ARCH/
  4. archive():打包阶段(可选)
    1. 生成 tar.gz 归档
    2. 使用 hnpcli 打包成 HNP 格式
  5. check():测试阶段
    1. 在 OpenHarmony 设备上运行测试用例
    2. 验证库功能正常

4.3 依赖管理机制

退出码协议(框架的核心通信机制):

退出码 含义 框架行为
0 编译成功 标记为已完成,继续下一个
101 依赖未就绪 添加到下一轮编译队列
其他 编译失败 记录错误,跳过该库

依赖解析示例

假设我们要编译 curl,它的依赖关系是:

curl
 └── openssl
      └── zlib

编译流程:

第一轮:
  - 编译 curl → 返回 101(依赖 openssl 未编译)
  - 记录依赖:openssl

第二轮:
  - 编译 openssl → 返回 101(依赖 zlib 未编译)
  - 记录依赖:zlib

第三轮:
  - 编译 zlib → 成功(无依赖)

第四轮:
  - 编译 openssl → 成功(依赖 zlib 已就绪)

第五轮:
  - 编译 curl → 成功(依赖 openssl 已就绪)

编译完成!

4.4 多架构编译

框架会自动遍历 archs 数组,为每个架构执行一次完整的构建流程:

archs=("armeabi-v7a" "arm64-v8a")

# 伪代码
for arch in ${archs[@]}; do
    设置架构环境变量  # CC/CXX/CFLAGS 等
    prepare
    build
    package
done

环境变量示例(arm64-v8a):

export CC=aarch64-linux-ohos-clang
export CXX=aarch64-linux-ohos-clang++
export CFLAGS="-DOHOS_NDK -fPIC -D__MUSL__=1 -D__OHOS__"
export LDFLAGS="--sysroot=${SYSROOT}"

五、HPKBUILD:框架的灵魂

5.1 标准模板解析

让我们逐行拆解一个标准的 HPKBUILD 文件:

# ==================== 元数据区 ====================
pkgname=curl                        # 库名(必须与目录名一致)
pkgver=curl-8_0_1                   # 版本号
pkgrel=0                            # 发布号(用于同版本多次发布)
pkgdesc="A command line tool..."    # 描述
url="https://curl.se/"              # 官网
archs=("armeabi-v7a" "arm64-v8a")  # 支持的架构
license=("curl")                    # 许可证类型

# ==================== 依赖区 ====================
depends=("openssl" "zstd_1_5_6" "nghttp2")  # 运行时依赖
makedepends=("cmake" "pkg-config")          # 构建工具依赖

# ==================== 源码区 ====================
source="https://gitee.com/mirrors/curl/repository/archive/curl-8_0_1.zip"
downloadpackage=true    # 是否自动下载(默认true)
autounpack=true         # 是否自动解压(默认true)

# ==================== 路径区 ====================
builddir=curl-curl-8_0_1              # 解压后的目录名
packagename=$builddir.zip             # 源码包名

# ==================== 构建函数区 ====================

1. **准备阶段**
prepare() {
    cd $builddir
    # 打 patch(如果需要)
    patch -p1 < ../curl_oh_pkg.patch
    # 创建构建目录
    mkdir -p $ARCH-build
    cd $OLDPWD
}

# 编译阶段
build() {
    cd $builddir
    # 配置("$@" 包含依赖路径和工具链参数)
    cmake "$@" -DCURL_CA_BUNDLE="/etc/ssl/certs/cacert.pem" \
               -DCURL_ZSTD=ON \
               -B$ARCH-build -S./
    # 编译
    $MAKE -C $ARCH-build
    ret=$?
    cd $OLDPWD
    return $ret  # 必须返回退出码
}

# 安装阶段
package() {
    cd $builddir
    make -C $ARCH-build install  # 安装到 $LYCIUM_ROOT/usr/curl/$ARCH/
    cd $OLDPWD
}

# 测试阶段
check() {
    echo "The test must be on an OpenHarmony device!"
    # 实际测试命令(需在 OHOS 设备上运行)
}

# 清理阶段
cleanbuild() {
    rm -rf ${PWD}/$builddir
}

5.2 关键变量说明

变量 作用域 说明
$ARCH 全局 当前编译架构(如 arm64-v8a)
$LYCIUM_ROOT 全局 框架根目录
$OHOS_SDK 全局 OpenHarmony SDK 路径
$MAKE 全局 make 命令(已设置 -j8 并行)
“$@” build() cmake 参数(依赖路径、工具链等)
$buildlog build() 编译日志文件路径

5.3 构建工具类型

根据库的构建系统,buildtools 字段可设置为:

适用场景 配置方式
cmake CMakeLists.txt 项目 默认值,无需额外配置
configure autotools 项目 自动设置 --prefix 等参数
make 纯 Makefile 项目 直接执行 make
其他 需要在 build() 中自定义

六、实战演练:从入门到精通

提示:本章提供三个循序渐进的实战案例,帮助读者快速掌握 HPKBUILD 编写与三方库适配技巧。读者可参考下面鸿蒙 PC 三方库适配相关文章深入学习:

序号 文章标题 核心内容 适合阶段 阅读链接
1 从零开始写 HPKBUILD:以 MediaInfo 为例的三方库 OpenHarmony 适配实战 HPKBUILD 编写全流程、字段详解、实战演练 入门 CSDN链接
2 [鸿蒙三方库适配实战] 多媒体信息工具 MediaInfo CLI 的 OpenHarmony 平台迁移实践 复杂依赖处理、Patch 应用、编译问题排查 进阶 CSDN链接
3 Windows 鸿蒙 PC 应用开发:DevEco Studio 集成与调用三方 Native 库实战指南 产物使用、DevEco Studio 集成、北向应用调用 实战 CSDN链接

学习路径建议

第一步:阅读文章1 → 理解 HPKBUILD 基本结构与编写方法
         ↓
第二步:阅读文章2 → 掌握复杂库适配技巧与问题排查
         ↓
第三步:阅读文章3 → 学习如何在应用中使用编译好的三方库
         ↓
第四步:回到本文  → 系统理解框架整体架构与设计思想

三篇文章核心知识点

文章1 - 从零开始写 HPKBUILD

  • HPKBUILD 文件完整结构解析
  • 元数据字段、依赖声明、源码配置
  • prepare/build/package/check 函数编写
  • MediaInfo 适配完整案例演示
  • 常见错误与解决方案

文章2 - MediaInfo CLI 迁移实践

  • 复杂依赖链处理(libzen + libcurl + zlib)
  • Patch 文件编写与应用技巧
  • configure/cmake 混合项目适配
  • musl libc 兼容性问题处理
  • 编译日志分析与调试方法

文章3 - DevEco Studio 集成调用

  • 编译产物在 DevEco Studio 中的配置
  • CMakeLists.txt 中引入三方库
  • 北向应用调用 Native 库的完整流程
  • 权限配置与打包发布
  • 真机调试与性能优化

七、进阶特性:外部适配仓

7.1 什么是外部适配仓?

外部适配仓是 lycium_plusplus 的创新设计,允许将适配代码独立于主仓库管理。

优势

  • 解耦发布:适配仓可独立更新,无需修改主仓
  • 多版本管理:同一库的不同版本可有不同的适配
  • 社区协作:不同开发者可维护不同库的适配

7.2 配置方法

步骤1:编辑 module.json

cd ../external_deps
cat module.json
{
    "module": [
        {
            "name": "tree",
            "branch": "ohos_2.2.1",
            "version": "2.2.1",
            "type": "git",
            "url": "https://gitcode.com/OpenHarmonyPCDeveloper/ohos_tree.git"
        }
    ]
}

步骤2:外部仓结构

ohos_tree/
├── HPKBUILD              # 适配后的构建配置
├── 0001-ports-for-ohos.patch  # 兼容性补丁
└── hnp.json              # HNP 打包配置

步骤3:编译

cd ../lycium
./build.sh tree  # 自动从外部仓下载并编译

7.3 HNP 打包配置

如果需要生成 HNP 产物,在 HPKBUILD 中添加 archive() 函数:

archive() {
    mkdir -p ${LYCIUM_ROOT}/output/$ARCH
    pushd $LYCIUM_ROOT/usr/$pkgname/$ARCH
        tar -zvcf ${LYCIUM_ROOT}/output/$ARCH/${pkgname}_${pkgver}.tar.gz *
    popd
    cp hnp.json $LYCIUM_ROOT/usr/$pkgname/$ARCH
    ${HNP_TOOL} pack -i ${LYCIUM_ROOT}/usr/$pkgname/$ARCH \
                     -o ${LYCIUM_ROOT}/output/$ARCH/
}

hnp.json 示例

{
    "type": "hnp-config",
    "name": "tree",
    "version": "2.2.1",
    "install": {}
}

八、常见问题与调试技巧

8.1 编译失败排查

问题1:依赖未找到

ERROR: openssl not found

解决方法

# 检查依赖是否已编译
ls ../lycium/usr/ | grep openssl

# 手动编译依赖
./build.sh openssl

# 检查 HPKBUILD 中 depends 字段
cat ../thirdparty/curl/HPKBUILD | grep depends

问题2:工具链缺失

aarch64-linux-ohos-clang: command not found

解决方法

# 检查 OHOS_SDK 环境变量
echo $OHOS_SDK

# 检查工具链是否存在
ls $OHOS_SDK/native/llvm/bin/ | grep clang

# 如果不存在,框架会自动从 Buildtools 解压
ls ../lycium/Buildtools/toolchain.tar.gz

问题3:架构不支持

configure: error: cannot guess build type

解决方法

某些库的 configure 脚本不认识 OpenHarmony 架构,需要传递 --host 参数:

# 在 build() 中添加
./configure --host=aarch64-linux-ohos \
  --build=x86_64-linux-gnu

8.2 日志查看

编译日志位置

# 单库编译日志
ls ../thirdparty/curl/
├── curl-curl-8_0_1-arm64-v8a-lycium_build.log
└── curl-public-lycium_build.log

# 框架总日志
cat ../lycium/lycium_build_intl.log

实时查看日志

# 另开一个终端
tail -f ../thirdparty/curl/*-lycium_build.log

8.3 调试技巧

技巧1:跳过下载

如果源码已下载,可以跳过下载阶段:

# 在 HPKBUILD 中设置
downloadpackage=false

技巧2:保留构建目录

调试时可以保留构建目录:

# 注释掉 cleanbuild 中的删除命令
cleanbuild() {
    # rm -rf ${PWD}/$builddir  # 临时注释
}

技巧3:手动执行编译

进入构建目录手动调试:

cd ../thirdparty/curl/curl-curl-8_0_1/arm64-v8a-build
cat CMakeCache.txt  # 查看 cmake 配置
make VERBOSE=1      # 显示详细编译命令

8.4 经验之谈:musl libc 兼容性

OpenHarmony 使用 musl libc,与常见的 glibc 有部分差异:

问题1:缺少 strverscmp 函数

undefined reference to `strverscmp'

解决:链接 muslc_gext 库

# 在 HPKBUILD 的 build() 中添加
export LDFLAGS="$LDFLAGS -lmuslc_gext -L$LYCIUM_ROOT/usr/muslc_gext/$ARCH/lib"

问题2:getwd 函数已废弃

warning: the `getwd' function is dangerous

解决:替换为 getcwd

// 错误
char *dir = getwd(buf);

// 正确
char *dir = getcwd(buf, sizeof(buf));

九、框架设计思想总结

1. 约定优于配置(Convention over Configuration)

  • 标准化 HPKBUILD 接口
  • 固定的目录结构
  • 统一的产物输出路径

2. 声明式构建(Declarative Build)

# 你只需要声明"是什么"
pkgname=curl
depends=("openssl")

# 框架负责处理"怎么做"
自动下载 → 自动编译依赖 → 自动传递路径

3. 依赖驱动(Dependency-Driven)

通过退出码协议实现依赖自动解析,无需手动指定编译顺序。

4. 环境隔离(Environment Isolation)

每个架构独立的构建目录,避免交叉污染:

builddir/
├── armeabi-v7a-build/
└── arm64-v8a-build/
Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐