欢迎加入 开源鸿蒙跨平台社区,与开发者一起共建「一次开发,多端部署」的开源生态。
一、背景与目标
CharLS (team-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;需安装
gcc、g++、cmake、make、pkg-config、wget等。 -
OHOS SDK :需包含
native/llvm、native/build-tools/cmake、native/build/cmake/ohos.toolchain.cmake等;环境变量指向 SDK 根目录,例如:bashexport 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-build;build() 中 cmake 打开CHARLS_BUILD_TESTS=ON、关闭 SAMPLES/FUZZ/INSTALL,并全量 make;package() 中拷贝libcharls.a与include/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.gz、charls-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 $builddir后mkdir -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.a到usr/charls/$ARCH/lib/,拷贝include/charls到usr/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-build 或 arm64-v8a-build):
- 若存在 ctest 命令,则直接执行
ctest; - 若无 ctest,则执行
./test/charlstest -unittest,以可执行文件退出码作为测试结果。
这样既支持"多测试项"的 ctest 展示(当前上游只注册了 1 个 basic-test),也保证在无 ctest 环境下仍能跑通功能测试。
四、编译流程与命令
-
进入 lycium 目录:
bashcd /path/to/tpc_c_cplusplus/lycium -
执行编译(仅编译 charls):
bash./build.sh charls -
脚本将依次:检查 OHOS_SDK、下载/解压 charls-2.4.2、对每个 ARCH 执行 prepare → cmake → make → package,并写入
lycium/usr/hpk_build.csv。 -
产物位置:
-
静态库与头文件:
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 进行测试。
-
将编译产物中的 构建目录
thirdparty/charls/charls-2.4.2/armeabi-v7a-build连同其中的test/charlstest、CTestTestfile.cmake等一并拷贝到开发板,保持目录结构不变。 -
在设备上进入该构建目录,直接执行 ctest(无需带超时参数):
bashcd /path/to/charls-2.4.2/armeabi-v7a-build ctest -
通过即表示 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-build 或 charls-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 跨平台与三方库共建内容,欢迎在 开源鸿蒙跨平台社区 交流。
参考与相关链接
- CharLS 上游:https://github.com/team-charls/charls(2.4.2 版本,BSD-3-Clause)
- tpc_c_cplusplus / lycium:OpenHarmony 三方库 C/C++ 共建仓库及交叉编译框架
- 环境搭建 :OpenHarmony 交叉编译环境配置
- 开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net/