当前位置: 首页 > article >正文

HarmonyOS Next构建工具 lycium 原理介绍

HarmonyOS Next构建工具 lycium 原理介绍

在这里插入图片描述

背景介绍

HarmonyOS Next中很多系统API是以C++接口提供,如果要使用C++接口,必须要使用NAPI在ArkTS与C++间交互,这种场景在使用DevEco-Studio中集成的交叉编译工具,以及cmake构建工具就完全够用了。但是针对一些三方库迁移的场景,比如ffmpeg、openssl等,如果自己配置编译环境和脚本比较麻烦,进行交叉编译的过程中较关注的问题是:不同编译构建方式如何进行交叉编译、不同的编译构建平台如何配置交叉编译的环境、不同的交叉编译架构如何配置以及交叉编译后的产物如何进行测试验证。当前开源的C/C++三方库编译方式多样化,以下为主流的几种交叉编译方式:

  • cmake 编译构建。
  • configure 编译构建方式。
  • make 编译构建。
    官方提供了交叉编译构建工具lycium,帮助我们快速构建三方库。

lycium工具介绍

lycium是一款协助开发者通过shell语言实现C/C++三方库快速交叉编译,并在OpenHarmony 系统上快速验证的编译框架工具。开发者只需要设置对应C/C++三方库的编译方式以及编译参数,通过lycium就能快速的构建出能在OpenHarmony 系统运行的二进制文件。

lycium的构建原则是移植过程,不可以改源码(即不patchc/cpp文件,不patch构建脚本)。如移植必须patch,patch必须评审,给出充分理由。(不接受业务patch)

lycium构建工具地址:https://gitee.com/openharmony-sig/tpc_c_cplusplus

使用示例

  1. 编译环境准备:lycium框架支持多种构建方式的三方库,为了保障三方库能正常编译,我们需要保证编译环境中包含以下几个基本编译命令: gcc, cmake, make, pkg-config, autoconf, autoreconf, automake, 如若缺少相关命令,可通过官网下载对应版本的工具包,也可以在编译机上通过命令安装,如若Ubuntu系统上缺少cmake可以通过以下命令安装:sudo apt install cmake
  2. 修改三方库的编译方式以及编译参数,lycium框架提供了HPKBUILD文件供开发者对相应的C/C++三方库的编译配置。具体方法:
    • 在thirdparty目录下新建需要共建的三方库名字pkgname。
    • 将HPKBUILD模板文件拷贝到新建三方库目录下。
    • 根据三方库实际情况修改HPKBUILD模板,文件修改可参考minizip共建。
  3. 快速编译三方库:配置完三方库的编译方式参数后,在lycium目录执行./build.sh pkgname,进行自动编译三方库,并打包安装到当前目录的 usr/pkgname/
    ARCH 目录./build.sh # 默认编译 thirdparty 目录下的多有库,也可以:./build.sh aaa bbb ccc ... # 编译 thirdparty 目录下指定的 aaa bbb ccc ...库 当 aaa 库存在依赖时,必须保证入参中包含依赖,否则 aaa 库不会编译

lycium框架是通过linux shell脚本语言编写的,接下来我们分析构建工具的shell代码,理解构建流程,有助于帮助我们定位编译时遇到的失败问题。

构建脚本原理介绍

lycium框架主要由以下几个部分组成:

  1. HPKBUILD 构建配置
  2. 顶层构建脚本 build.sh
  3. 交叉编译工具链
  4. 测试验证环境
构建流程
1. 构建配置准备

开发者需要在 thirdparty 目录下为待编译的三方库创建目录,并编写 HPKBUILD 构建配置文件。HPKBUILD 文件定义了:

  • 源码获取方式
  • 编译参数配置
  • 依赖关系声明
  • 安装规则

HPKBUILD构建配置文件示例:

# Contributor: Jeff Han <hanjinfei@foxmail.com>
# Maintainer: Jeff Han <hanjinfei@foxmail.com>
pkgname=FFmpeg
pkgver=n6.0
pkgrel=0
pkgdesc="FFmpeg is a collection of libraries and tools to process multimedia content such as audio, video, subtitles and related metadata."
url="https://github.com/FFmpeg/FFmpeg/"
archs=("armeabi-v7a" "arm64-v8a")
license=("GPL2" "GPL3" "LGPL3" "MIT" "X11" "BSD-styl")
depends=("rtmpdump" "openssl_1_0_2u")
makedepends=()
source="https://github.com/FFmpeg/$pkgname/archive/refs/tags/$pkgver.tar.gz"

autounpack=false
downloadpackage=true
buildtools="configure"

builddir=$pkgname-${pkgver}
packagename=$builddir.tar.gz
source envset.sh
buildhost=true
arch=
ldflags=

prepare() {
    if [ "$LYCIUM_BUILD_OS" == "Linux" ]
    then
        hostosname=linux
    elif [ "$LYCIUM_BUILD_OS" == "Darwi" ]
    then
        hostosname=darwin
    else
        echo "System cannot recognize, exiting"
        return -1
    fi
    if [ $buildhost == true ]
    then
        tar -zxf $packagename
        cd $builddir
        ./configure --enable-static --enable-shared --disable-doc --disable-htmlpages \
            --target-os=$hostosname --disable-optimizations --prefix=`pwd`/hostbuild > $publicbuildlog 2>&1
        $MAKE >> $publicbuildlog 2>&1
        $MAKE install >> $publicbuildlog 2>&1
        export LD_LIBRARY_PATH=`pwd`/hostbuild/lib:$LD_LIBRARY_PATH
        sed -i.bak 's/include $(SRC_PATH)\/tests\/fate\/source.mak/#include $(SRC_PATH)\/tests\/fate\/source.mak/g' tests/Makefile
        $MAKE check >> $publicbuildlog 2>&1
        ret=$?
        buildhost=false
        cd $OLDPWD
    fi

    mkdir $pkgname-$ARCH-build
    tar -zxf $packagename -C $pkgname-$ARCH-build
    cd  $pkgname-$ARCH-build/$builddir
    patch -p1 < ../../FFmpeg_oh_test.patch
    cd $OLDPWD

    if [ $ARCH == "armeabi-v7a" ]
    then
        setarm32ENV
        arch=arm
        ldflags="-L${OHOS_SDK}/native/sysroot/usr/lib/arm-linux-ohos"
    elif [ $ARCH == "arm64-v8a" ]
    then
        setarm64ENV
        arch=aarch64
        ldflags="-L${OHOS_SDK}/native/sysroot/usr/lib/aarch64-linux-ohos"
    else
        echo "${ARCH} not support"
        return -1
    fi

    return $ret
}

build() {
    cd $pkgname-$ARCH-build/$builddir
    PKG_CONFIG_LIBDIR="${pkgconfigpath}" ./configure "$@" --enable-neon --enable-asm --enable-network \
    --disable-vulkan --enable-cross-compile --enable-librtmp --disable-x86asm --enable-openssl --enable-protocols \
    --enable-static --enable-shared --disable-doc --disable-htmlpages --target-os=linux --arch=$arch \
    --cc=${CC} --ld=${CC} --strip=${STRIP} --host-cc="${CC}" --host-ld="${CC}" --host-os=linux \
    --host-ldflags=${ldflags} --sysroot=${OHOS_SDK}/native/sysroot > $buildlog 2>&1
    $MAKE >> $buildlog 2>&1
    ret=$?
    cd $OLDPWD
    return $ret
}

package() {
    cd $pkgname-$ARCH-build/$builddir
    $MAKE install >> $buildlog 2>&1
    cd $OLDPWD
}

checktestfiles() {
    cd $pkgname-$ARCH-build/$builddir/tests/ref

    tmpdir=("fate" "acodec" "lavf" "lavf-fate" "pixfmt" "seek" "vsynth")
    for dir in ${tmpdir[*]}
    do
        for file in `ls $dir`
        do
            if [ ! -f $dir/$file ]; then
                continue
            fi
            str=`cat $dir/$file | grep "\*tests"`
            if [ ! -z "$str" ]
            then
                sed -i.bak 's/\*tests/tests/g' $dir/$file
            fi
        done
    done

    cd $OLDPWD
}

copyhostbin() {
    file=$1
    if [[ -f tests/$file ]] && [[ ! -f tests/$file.${ARCH} ]]
    then
        mv tests/$file tests/$file.${ARCH}
        cp ../../$builddir/tests/$file tests/$file
    fi
}

check() {
    cd $pkgname-$ARCH-build/$builddir
    # disable running cmd
    sed -i.bak 's/	$(Q)$(SRC_PATH)\/tests\/fate-run.sh/#	$(Q)$(SRC_PATH)\/tests\/fate-run.sh/g' tests/Makefile
    # disable check git sources
    sed -i.bak 's/include $(SRC_PATH)\/tests\/fate\/source.mak/#include $(SRC_PATH)\/tests\/fate\/source.mak/g' tests/Makefile
    # disable check ffprobe,this use xmllint command, which ohos is not support
    sed -i.bak 's/include $(SRC_PATH)\/tests\/fate\/ffprobe.mak/#include $(SRC_PATH)\/tests\/fate\/ffprobe.mak/g' tests/Makefile

    # change x86 cmd for generate test target
    mv ffmpeg ffmpeg.${ARCH}
    cp ../../$builddir/ffmpeg ./
    retrytimes=0
    ret=0
    while true
    do
        $MAKE check >> $buildlog 2>&1
        if [ $? -eq 0 ]
        then
            break;
        fi

        copyhostbin base64
        copyhostbin audiomatch
        copyhostbin audiogen
        copyhostbin videogen
        copyhostbin tiny_psnr
        copyhostbin tiny_ssim
        copyhostbin rotozoom

        let retrytimes=$retrytimes+1
        if [ $retrytimes -gt 4 ]
        then
            ret=1
            break
        fi
    done

    mv ffmpeg.${ARCH} ffmpeg
    for file in `ls tests/*.${ARCH}`
    do
        tmpfile=${file%.*}
        mv $file $tmpfile
    done

    # reduction running cmd for real test
    sed -i.bak 's/#	$(Q)$(SRC_PATH)\/tests\/fate-run.sh/	$(Q)$(SRC_PATH)\/tests\/fate-run.sh/g' tests/Makefile
    cd $OLDPWD
    checktestfiles

    echo "The test must be on an OpenHarmony device!"
    # skip running test on host
    # real test CMD
    # make check

    return $ret
}

recoverpkgbuildenv() {
    unset arch
    unset ldflags
    if [ $ARCH == "armeabi-v7a" ]
    then
        unsetarm32ENV
    elif [ $ARCH == "arm64-v8a" ]
    then
        unsetarm64ENV
    else
        echo "${ARCH} not support"
        return -1
    fi
}

# 清理环境
cleanbuild() {
    rm -rf ${PWD}/${builddir} ${PWD}/$pkgname-arm64-v8a-build ${PWD}/$pkgname-armeabi-v7a-build #${PWD}/$packagename
}
2. 构建过程

主入口 build.sh 脚本执行以下步骤:

  1. 解析命令行参数,确定要编译的目标库
  2. 检查编译环境(编译工具链等)
  3. 读取目标库的 HPKBUILD 配置
  4. 按照依赖关系顺序编译各个库
  5. 对每个库执行:
    • 获取源码
    • 配置编译参数
    • 执行编译
    • 安装到指定目录

检查编译环境代码:

# 检测操作系统类型
unames=`uname -s`
osname=${unames:0:5}

# 设置根目录
LYCIUM_ROOT=$(cd $(dirname ${BASH_SOURCE[0]}); pwd)

# 检查 OHOS_SDK 环境
if [ -z ${OHOS_SDK} ]
then
    echo "OHOS_SDK 未设置..."
    exit 1
fi

依赖管理检测:

# 依赖库暂存文件
depend_tmp_file="/tmp/$USER-lycium_deps-$build_time"
export LYCIUM_DEPEND_PKGNAMES=$depend_tmp_file

# 已完成库列表
donelist=()
donelibs=()

核心函数 buildhpk() 实现了构建流程控制:

  1. 任务分轮次执行
  2. 处理依赖关系
  3. 错误处理机制
    主要变量:
  • nextroundlist: 下一轮待构建项目
  • notdonelist: 未完成项目列表
  • buildfalselist: 构建失败项目列表

关键函数说明如下:
checkbuildenv()
检查必要的构建工具是否安装:

  • gcc, cmake, make 等基础工具

  • autoconf, automake 等自动化工具

  • git, curl 等辅助工具 prepareshell()
    为每个构建目录准备必要的脚本:

  • build_hpk.sh: 项目构建脚本

  • envset.sh: 环境设置脚本 makelibsdir()
    管理构建目录:

  • 检查目录有效性

  • 过滤已构建项目

  • 添加到构建队列

3. 交叉编译支持

框架通过以下方式实现交叉编译:

  1. 使用 OpenHarmony NDK 提供的交叉编译工具链
  2. 在 HPKBUILD 中配置交叉编译相关参数
  3. 支持 arm32/arm64/x86 等多架构编译
4. 产物输出

编译产物按照如下结构组织:

usr/
  └── ${pkgname}/
       └── ${ARCH}/
            ├── lib/      # 库文件
            ├── include/  # 头文件
            └── bin/      # 可执行文件
build_hpk.sh构建脚本说明

核心构建函数说明:

1. prepare()

准备构建环境:

  • 宿主机构建(buildhost=true时)
  • 解压源码包
  • 应用补丁
  • 设置交叉编译环境
2. build()

执行构建过程:

  • 配置构建参数
  • 执行configure配置
  • 执行make编译
  • 返回构建结果
3. package()

安装打包:

  • 执行make install
  • 生成最终安装包
4. check()

测试验证:

  • 修改测试配置
  • 准备测试环境
  • 执行测试用例
  • 处理测试结果
5. 环境管理函数
  • recoverpkgbuildenv()
    • 清理编译环境变量
    • 恢复原始环境
  • cleanbuild()
    • 清理构建目录
    • 删除临时文件

总结

本文介绍了HarmonyOS Next跨平台构建脚本功能、使用、以及原理,介绍了构建脚本相关的shell代码等。


http://www.kler.cn/a/517762.html

相关文章:

  • Windows本地部署(DeepSeek-R1-Distill-Qwen-1.5B)模型
  • PHP EOF (Heredoc) 详解
  • ThinkPhp伪静态设置后,访问静态资源也提示找不到Controller
  • 高速光模块中的并行光学和WDM波分光学技术
  • 数据库SQLite和SCADA DIAView应用教程
  • 2025美赛C题完整代码+建模过程
  • uniapp商城之商品分类
  • 【C++高并发服务器WebServer】-3:进程控制(退出进程、孤儿进程、僵尸进程、进程回收)
  • 大模型GUI系列论文阅读 DAY3续4:《TREE SEARCH FOR LANGUAGE MODEL AGENTS》
  • 【机器学习】自定义数据集使用框架的线性回归方法对其进行拟合
  • Linux挂载samba共享文件夹
  • RubyFPV开源代码之系统简介
  • 【加密算法】简单区分HS、RSA、ES 和 ED,与对应go实现案例
  • C# OpenCV机器视觉:实现农作物病害检测
  • 【转帖】eclipse-24-09版本后,怎么还原原来版本的搜索功能
  • vulshare/nginx-php-flag命令执行漏洞
  • 8、提升用户体验的技巧
  • STM32新建不同工程的方式
  • 如何运用python爬虫获取大型资讯类网站文章,并同时导出pdf或word格式文本?
  • 【图文详解】lnmp架构搭建Discuz论坛
  • 纯css实现div宽度可调整
  • 为什么 TCP 挥手需要有 TIME_WAIT 状态?
  • 论文阅读的附录(七):Understanding Diffusion Models: A Unified Perspective(二):公式46的推导
  • 计算机图形学:实验三 光照与阴影
  • IBM 后端开发(二)
  • 【Project】CupFox电影网站数据爬取分析与可视化