CharLS 无损 JPEG-LS 库在 OpenHarmony 的 lycium 适配与 ctest 验证

欢迎加入 开源鸿蒙跨平台社区,与开发者一起共建「一次开发,多端部署」的开源生态。


一、背景与目标

CharLSteam-charls/charls)是 JPEG-LS 标准的 C++ 实现,支持无损与近无损图像压缩与解压。JPEG-LS 复杂度低、压缩比高(接近 JPEG 2000 无损比),被 DICOM 等医疗影像标准采用。CharLS 无第三方依赖,仅需 C++14 与 CMake,适合作为 OpenHarmony 上的图像编解码基础库。本文记录在 OpenHarmony 三方库共建仓库(tpc_c_cplusplus) 中,使用 lycium 交叉编译框架 将 CharLS 2.4.2 接入、编译静态库与测试可执行文件,并在设备上通过 ctest 或直接运行 charlstest -unittest 完成验证的完整过程,以及 CRLF 换行符等常见问题的处理。

目标

  • 在 Mac/Linux 宿主机上交叉编译出适用于 OpenHarmony(armeabi-v7a / arm64-v8a)的 libcharls.a 与头文件;
  • 开启上游测试,编出 charlstest,供设备端验证;
  • 产物可被其他 Native/应用工程链接使用;设备上可用 ctest 或 ./test/charlstest -unittest 跑测试。

二、环境与框架简介

环境搭建 更详细的步骤(SDK 下载、环境变量、依赖工具安装等)可参考:OpenHarmony 交叉编译环境配置。下文仅列出与本文直接相关的要点。

2.1 编译环境搭建

  • 宿主机 :建议 Mac(Darwin)或 Linux;需安装 gccg++cmakemakepkg-configwget 等。

  • OHOS SDK :需包含 native/llvmnative/build-tools/cmakenative/build/cmake/ohos.toolchain.cmake 等;环境变量指向 SDK 根目录,例如:

    bash 复制代码
    export OHOS_SDK=/path/to/OpenHarmony/Sdk/20
  • lycium :每个三方库由目录下的 HPKBUILD 定义"下载 → 解压 → prepare → 编译 → 安装";产物落在 lycium/usr/<pkgname>/<ARCH>/;设备侧测试由 HPKCHECK 中的 openharmonycheck() 定义。

2.2 CharLS 上游特点

  • 源码 :使用 release 归档 https://github.com/team-charls/charls/archive/refs/tags/2.4.2.tar.gz,解压后目录名为 charls-2.4.2
  • 构建 :CMake,包含:
    • 静态库目标 charls(产物为 libcharls.a);
    • 可选测试可执行文件 charlstest (在 CHARLS_BUILD_TESTS=ON 时编出,位于 test/charlstest);
    • 可选示例与 Fuzz 等,本适配中关闭。
  • 依赖:无第三方库,仅 C++14 与 CMake 3.13+。
  • 安装 :上游 CMake 有 CHARLS_INSTALL 选项;本适配在 package() 中手动 拷贝库与头文件到 usr/charls/<ARCH>/,不依赖上游 install。
  • 测试 :上游仅注册一个 CTest 用例 basic-test,对应命令 charlstest -unittest。charlstest 还支持 -bitstreamdamage-performance-legacy 等模式,但 CMake 中未为它们单独 add_test,因此 ctest 默认只显示 1 个测试。

2.3 HPKBUILD / HPKCHECK 在本库中的角色

  • HPKBUILD :定义 pkgname=charls、pkgver=2.4.2、source、builddir=charls-2.4.2、buildtools=cmake;prepare() 中仅 mkdir -p $ARCH-buildbuild() 中 cmake 打开 CHARLS_BUILD_TESTS=ON、关闭 SAMPLES/FUZZ/INSTALL,并全量 make;package() 中拷贝 libcharls.ainclude/charls/usr/charls/$ARCH/
  • HPKCHECK :设备上进入 ${builddir}/${ARCH}-build,若有 ctest 则执行 ctest,否则直接运行 ./test/charlstest -unittest,以退出码作为测试结果。

三、接入步骤

3.1 创建三方库目录与文件

Workspace/tpc_c_cplusplus/thirdparty/ 下新建目录 charls,并准备:

文件 作用
HPKBUILD 包名、版本、源码、prepare/build/package/cleanbuild;build 中打开 CHARLS_BUILD_TESTS
HPKCHECK 设备上优先 ctest,否则执行 ./test/charlstest -unittest
README.OpenSource 开源协议(BSD-3-Clause)、上游地址、版本(JSON 多行格式)
README_zh.md 中文说明:简介、产物、编译、测试、链接方式等
.gitignore 忽略 charls-2.4.2.tar.gzcharls-2.4.2/*-lycium_build.log

3.2 CharLS 的 HPKBUILD 配置要点

charls 取值 / 说明
pkgname charls
pkgver 2.4.2
source https://github.com/team-charls/charls/archive/refs/tags/2.4.2.tar.gz
builddir charls-2.4.2
buildtools cmake
archs armeabi-v7a、arm64-v8a
depends
  • prepare() :仅 cd $builddirmkdir -p $ARCH-build,无需打补丁或改 CMake。
  • build() :关键 CMake 选项如下,其余由 build.sh 传入(如 toolchain、OHOS_ARCH):
    • -DCHARLS_BUILD_TESTS=ON:编出 charlstest;
    • -DCHARLS_BUILD_FUZZ_TEST=OFF-DCHARLS_BUILD_SAMPLES=OFF-DCHARLS_INSTALL=OFF-DBUILD_SHARED_LIBS=OFF
  • package() :拷贝 $ARCH-build/libcharls.ausr/charls/$ARCH/lib/,拷贝 include/charlsusr/charls/$ARCH/include/

build() 核心片段

bash 复制代码
PKG_CONFIG_LIBDIR="${pkgconfigpath}" ${OHOS_SDK}/native/build-tools/cmake/bin/cmake "$@" \
    -DOHOS_ARCH=$ARCH -B$ARCH-build -S. \
    -DCHARLS_BUILD_TESTS=ON \
    -DCHARLS_BUILD_FUZZ_TEST=OFF \
    -DCHARLS_BUILD_SAMPLES=OFF \
    -DCHARLS_INSTALL=OFF \
    -DBUILD_SHARED_LIBS=OFF \
    -L > $buildlog 2>&1
$MAKE VERBOSE=1 -C $ARCH-build >> $buildlog 2>&1

package() 核心片段

bash 复制代码
mkdir -p $LYCIUM_ROOT/usr/$pkgname/$ARCH/lib $LYCIUM_ROOT/usr/$pkgname/$ARCH/include
[ -f $ARCH-build/libcharls.a ] && cp -f $ARCH-build/libcharls.a $LYCIUM_ROOT/usr/$pkgname/$ARCH/lib/
[ -d include/charls ] && cp -r include/charls $LYCIUM_ROOT/usr/$pkgname/$ARCH/include/

3.3 HPKCHECK 设备侧测试逻辑

设备上进入 ${builddir}/${ARCH}-build(即 charls-2.4.2/armeabi-v7a-buildarm64-v8a-build):

  • 若存在 ctest 命令,则直接执行 ctest
  • 若无 ctest,则执行 ./test/charlstest -unittest,以可执行文件退出码作为测试结果。

这样既支持"多测试项"的 ctest 展示(当前上游只注册了 1 个 basic-test),也保证在无 ctest 环境下仍能跑通功能测试。


四、编译流程与命令

  1. 进入 lycium 目录

    bash 复制代码
    cd /path/to/tpc_c_cplusplus/lycium
  2. 执行编译(仅编译 charls):

    bash 复制代码
    ./build.sh charls
  3. 脚本将依次:检查 OHOS_SDK、下载/解压 charls-2.4.2、对每个 ARCH 执行 prepare → cmake → make → package,并写入 lycium/usr/hpk_build.csv

  4. 产物位置

    • 静态库与头文件:lycium/usr/charls/armeabi-v7a/lycium/usr/charls/arm64-v8a/(lib/libcharls.a、include/charls/)。

    • 测试可执行文件:thirdparty/charls/charls-2.4.2/<ARCH>-build/test/charlstest,需随测试资源拷贝到设备对应构建目录下运行。


五、设备侧测试(直接使用 ctest)

本文在 32 位开发板 上使用 armeabi-v7a-build 进行测试。

  1. 将编译产物中的 构建目录 thirdparty/charls/charls-2.4.2/armeabi-v7a-build 连同其中的 test/charlstestCTestTestfile.cmake 等一并拷贝到开发板,保持目录结构不变。

  2. 在设备上进入该构建目录,直接执行 ctest(无需带超时参数):

    bash 复制代码
    cd /path/to/charls-2.4.2/armeabi-v7a-build
    ctest
  3. 通过即表示 CharLS 单元测试通过(如输出 1/1 Test #1: basic-test ... Passed)。


六、遇到的问题与解决方案

问题一:HPKBUILD 在 source 时报 "command not found" / "syntax error near unexpected token"

现象 :执行 ./build.sh charls 时出现多行 "line N: : command not found" 以及 "syntax error near unexpected token {"(如 prepare() 附近),导致 cleanbuild 等未定义。

原因 :HPKBUILD 文件使用了 Windows 换行符(CRLF,\r\n) 。在 bash 中,行尾的 \r 会导致该行被错误解析,从而触发上述报错。

解决 :将 HPKBUILD(以及 HPKCHECK、README 等)统一为 Unix 换行(LF)。例如:

bash 复制代码
cd thirdparty/charls
tr -d '\r' < HPKBUILD > HPKBUILD.tmp && mv HPKBUILD.tmp HPKBUILD
# 同理处理 HPKCHECK、README_zh.md、README.OpenSource、.gitignore

问题二:为什么 ctest 只显示 1 个测试(basic-test)?

现象 :设备上执行 ctest 后,输出为 "1/1 Test #1: basic-test ... Passed",与 cJSON 的 19 个测试不同。

原因上游 CharLS 的 CMake 只注册了一个 CTest 。在根目录 CMakeLists.txt 中,当 CHARLS_BUILD_TESTS=ON 时仅有:

cmake 复制代码
add_test(NAME basic-test COMMAND charlstest -unittest WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR})

charlstest 虽支持多种运行模式(如 -bitstreamdamage-performance-legacy),但上游并未为每种模式单独写 add_test,因此从 CTest 角度看只有 1 个测试。若要像 cJSON 那样出现多个测试项,需通过补丁在 CMake 中增加多条 add_test(对应不同 charlstest 参数),本适配暂未加补丁,保持与上游一致。


问题三:设备上应在哪个目录执行 ctest?

现象:在 thirdparty/charls 或 charls-2.4.2 根目录执行 ctest,提示 "No test configuration file found!"。

原因 :CTest 的配置文件在构建目录 中生成,即 charls-2.4.2/armeabi-v7a-buildcharls-2.4.2/arm64-v8a-build

解决:在设备上先进入对应架构的构建目录再执行 ctest 或 charlstest。例如 32 位开发板进入 armeabi-v7a-build 后直接执行:

bash 复制代码
cd charls-2.4.2/armeabi-v7a-build
ctest
# 或
./test/charlstest -unittest

HPKCHECK 已采用"先 cd 到 b u i l d d i r / {builddir}/ builddir/{ARCH}-build"再执行 ctest 或 charlstest 的方式。


七、总结

  • CharLS 在 OpenHarmony 上的交叉编译依赖 lycium 的 HPKBUILD/HPKCHECK 机制,通过指定 2.4.2 源码地址、builddir、buildtools=cmake,并打开 CHARLS_BUILD_TESTS=ON ,即可在宿主机完成全量构建,得到 libcharls.a 、头文件与 charlstest
  • 典型问题 :HPKBUILD 的 CRLF 导致脚本解析错误,需统一为 LF;ctest 仅 1 个测试是上游设计如此;设备上测试需在构建目录内执行 ctest 或 charlstest。
  • 最终产物:lycium/usr/charls/<ARCH>/ 下的静态库与头文件可供应用集成;charls-2.4.2/<ARCH>-build/test/charlstest 用于设备端功能验证,支持 ctest 或直接运行 -unittest

若你在使用 lycium 接入其他无依赖的 C++ 库时也遇到 CRLF 或 ctest 单测试项问题,可参考本文的排查与处理方式。更多 OpenHarmony 跨平台与三方库共建内容,欢迎在 开源鸿蒙跨平台社区 交流。


参考与相关链接

相关推荐
寻寻觅觅☆5 小时前
东华OJ-基础题-106-大整数相加(C++)
开发语言·c++·算法
fpcc5 小时前
并行编程实战——CUDA编程的Parallel Task类型
c++·cuda
ceclar1236 小时前
C++使用format
开发语言·c++·算法
lanhuazui107 小时前
C++ 中什么时候用::(作用域解析运算符)
c++
charlee447 小时前
从零实现一个生产级 RAG 语义搜索系统:C++ + ONNX + FAISS 实战
c++·faiss·onnx·rag·语义搜索
老约家的可汗7 小时前
初识C++
开发语言·c++
crescent_悦7 小时前
C++:Product of Polynomials
开发语言·c++
小坏坏的大世界8 小时前
CMakeList.txt模板与 Visual Studio IDE 操作对比表
c++·visual studio
乐观勇敢坚强的老彭8 小时前
c++寒假营day03
java·开发语言·c++
愚者游世9 小时前
brace-or-equal initializers(花括号或等号初始化器)各版本异同
开发语言·c++·程序人生·面试·visual studio