基于 lycium 在 OpenHarmony 上交叉编译 cppDES 完整实践

欢迎加入 开源鸿蒙跨平台社区,与开发者一起共建鸿蒙三方库的开源生态。


一、背景与目标

cppDES 是 GitHub 上的 C++ 实现 Data Encryption Standard(DES/3DES) 开源库,支持 ECB、CBC 模式,采用 CMake 构建,并自带 Google Test 测试。本文记录在 OpenHarmony 三方库共建仓库(tpc_c_cplusplus) 中,使用 lycium 交叉编译框架 将 cppDES 接入、编译、打包并在设备上运行测试的完整过程,以及遇到的问题与解决方案。

目标

  • 在 Mac/Linux 宿主机上交叉编译出适用于 OpenHarmony(armeabi-v7a / arm64-v8a)的静态库与测试可执行文件;
  • 产物可被其他 Native/应用工程链接使用;
  • 测试可在开发板上通过 test.sh 或直接运行 cppDESTest 执行。

二、环境与框架简介

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

2.1 编译环境搭建

  • 宿主机:建议使用 Mac(Darwin)或 Linux。lycium 在 Windows(如 CYGWIN)上部分检查会关闭,推荐在 Linux 或 Mac 上完成编译与测试。
  • 基本工具 :需提前安装以下命令,供下载、配置与构建使用:
    • 必选:gccg++cmakemakepkg-configwget(或 curl
    • 若库使用 autotools:autoconfautoreconfautomake
    • 其他:patchunziptargitninja 等(按需)
    • 示例(Ubuntu):sudo apt install cmake make gcc g++ pkg-config wget
  • OHOS SDK
    • 从 OpenHarmony 官网或 DevEco Studio 配套渠道下载 Native 相关 SDK (需包含 native/llvmnative/build-tools/cmakenative/build/cmake/ohos.toolchain.cmake 等)。

    • 环境变量需指向 native 的父目录 (即 SDK 根目录),而非 native 本身,例如:

      bash 复制代码
      export OHOS_SDK=/path/to/OpenHarmony/Sdk/20
    • 编译前在终端执行 echo $OHOS_SDK 确认已配置;未配置时 build.sh 会提示并退出。

  • lycium 工具链 :首次执行 build.sh 时,若检测到 SDK 中缺少 *-linux-ohos-clang 等交叉编译器,会从 lycium/Buildtools/toolchain.tar.gz 解压并拷贝到 $OHOS_SDK/native/llvm/bin,无需单独安装。
  • lycium 目录角色build.sh 负责按依赖顺序调度各三方库的编译;每个库的"下载 → 解压 → 配置 → 编译 → 安装"由该库目录下的 HPKBUILD 定义,产物统一落在 lycium/usr/<pkgname>/<ARCH>/

【此处可配图:终端中执行 echo $OHOS_SDKls $OHOS_SDK/native/llvm/bin 的截图,体现 SDK 路径与工具链存在。】

2.2 cppDES 上游特点

  • 源码 :GitHub 无 release tag,使用分支归档地址 https://github.com/fffaraz/cppDES/archive/refs/heads/master.tar.gz,解压后目录名为 cppDES-master
  • 构建 :CMake,包含:
    • 静态库目标 libcppdes
    • 命令行工具 cppDES
    • 测试可执行文件 cppDESTest(依赖 FetchContent 拉取 googletest)。
  • 安装 :上游 CMakeLists.txt 未提供 install() ,需在 lycium 的 package() 中手动拷贝库与头文件。

【此处可配图:lycium 目录结构(build.sh、script/、template/、thirdparty/ 等)或 tpc_c_cplusplus 仓库结构概览。】

2.3 HPKBUILD、HPKCHECK 与 patch 简介

lycium 通过若干约定文件驱动"下载 → 解压 → 配置 → 编译 → 安装 → 设备测试",下面用通用结构说明三个部分,具体到 cppDES 的配置与完整代码在第三节「接入步骤」中展开。

HPKBUILD(构建描述)
  • 是什么 :每个三方库目录下的 HPKBUILD 是一个可被 source 的 shell 脚本,定义包元信息与若干函数 (prepare、build、package、cleanbuild 等)。build.sh 会先 source HPKBUILD 再按流程调用这些函数。
  • 重点字段:pkgname / pkgver、source、builddir / packagename、archs、buildtools、depends(依赖的其他库 pkgname)。
  • 重点函数:prepare()(打补丁/改构建脚本)、build()(cmake + make)、package()(拷贝到 usr)、cleanbuild()(清理)。

通用结构示例(以 cmake 为例):

bash 复制代码
pkgname=NAME
pkgver=VERSION
source="https://example.com/xxx.tar.gz"
builddir=xxx-${pkgver}
packagename=$builddir.tar.gz
archs=("armeabi-v7a" "arm64-v8a")
buildtools="cmake"
depends=()

prepare() {
    cd $builddir
    # 可选:patch -p0 < ../xxx.patch 或 sed/awk 修改构建脚本
    mkdir -p $ARCH-build
    cd ${OLDPWD}
}

build() {
    cd $builddir
    ${OHOS_SDK}/native/build-tools/cmake/bin/cmake "$@" -DOHOS_ARCH=$ARCH -B$ARCH-build -S./ -L
    make -j4 -C $ARCH-build
    ret=$?; cd $OLDPWD; return $ret
}

package() {
    cd $builddir
    make -C $ARCH-build install   # 上游有 install 时;无则需手动 cp 到 $LYCIUM_ROOT/usr/$pkgname/$ARCH/
    cd $OLDPWD
}

cleanbuild() {
    rm -rf ${PWD}/$builddir
}
HPKCHECK(设备侧测试)
  • 是什么 :同一三方库目录下的 HPKCHECK 也是可被 source 的 shell 脚本,供设备上的 test.sh 调用,用于定义"如何在开发板上跑该库的测试"。
  • 重点openharmonycheck() 内进入构建目录、执行测试二进制并以退出码返回;logfile 用于保存测试日志;设备上建议直接运行可执行文件,不依赖 ctest(避免宿主机路径写死)。

通用结构示例

bash 复制代码
source HPKBUILD > /dev/null 2>&1
logfile=${LYCIUM_THIRDPARTY_ROOT}/${pkgname}/${pkgname}_${ARCH}_${OHOS_SDK_VER}_test.log

checkprepare() { return 0; }

openharmonycheck() {
    res=0
    cd ${builddir}/${ARCH}-build
    [ -f ./测试可执行文件 ] && ./测试可执行文件 >> ${logfile} 2>&1 && res=$? || res=1
    cd $OLDPWD
    return $res
}
patch(补丁)
  • 是什么 :对上游源码或构建脚本的差分修改 ,以"补丁文件"形式保存,在 prepare() 中通过 patch -p0 < ../xxx.patch 应用。
  • 重点 :移植原则为不直接改 C/C++ 源码;若必须改构建脚本,用 patchsed/awk 在 prepare 中施加。格式多为 unified diff,-p0 / -p1 表示路径剥离级数。

unified diff 格式示例

diff 复制代码
--- CMakeLists.txt
+++ CMakeLists.txt
@@ -32,5 +32,8 @@
 include(GoogleTest)
-gtest_discover_tests(cppDESTest)
+if(NOT CMAKE_CROSSCOMPILING)
+  gtest_discover_tests(cppDESTest)
+endif()

三、接入步骤

3.1 创建三方库目录与模板文件

Workspace/tpc_c_cplusplus/thirdparty/ 下新建目录 cppDES ,并从 lycium 的 template 拷贝并改写以下文件:

文件 作用
HPKBUILD 定义包名、版本、源码地址、构建方式(cmake)、prepare/build/package/cleanbuild 等
HPKCHECK 定义在设备上如何执行测试(如运行 ./cppDESTest
README.OpenSource 开源协议、版权、源码来源(必填)
README_zh.md 中文说明:适配说明、编译步骤、使用方式、注意事项

【此处可配图:thirdparty/cppDES 目录下的文件列表(HPKBUILD、HPKCHECK、README.OpenSource、README_zh.md、patch 等)。】

3.2 cppDES 的 HPKBUILD / HPKCHECK 配置要点

在 2.3 的通用结构基础上,cppDES 的取值与差异如下。

cppDES 取值 / 说明
pkgname cppDES
pkgver master(上游无 tag,用分支)
source https://github.com/fffaraz/cppDES/archive/refs/heads/master.tar.gz
builddir cppDES-master
buildtools cmake
archs armeabi-v7a、arm64-v8a
depends
  • prepare() :除 mkdir -p $ARCH-build 外,需修改上游 CMakeLists.txt ,在交叉编译时跳过 gtest_discover_tests(原因见下文「问题二」)。当前用 awk 做一次性替换,等价 patch 见 0001-skip-gtest-discover-when-cross-compiling.patch
  • build() :全量 make -C $ARCH-build(不单编 libcppdes),以生成测试可执行文件 cppDESTest,供设备侧使用。
  • package() :上游无 install,需手动 拷贝 liblibcppdes.ainclude/cppdes/$LYCIUM_ROOT/usr/cppDES/$ARCH/

prepare() 中修改 CMakeLists 的写法(awk 实现):

bash 复制代码
awk '/^gtest_discover_tests\(cppDESTest\)$/{print "if(NOT CMAKE_CROSSCOMPILING)"; print "  gtest_discover_tests(cppDESTest)"; print "endif()"; next}1' CMakeLists.txt > CMakeLists.txt.tmp && mv CMakeLists.txt.tmp CMakeLists.txt

package() 中手动安装库与头文件的写法

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

HPKCHECK :设备上进入 cppDES-master/$ARCH-build 后执行 ./cppDESTest,退出码作为测试结果;完整脚本见仓库 thirdparty/cppDES/HPKBUILDHPKCHECK

3.3 交叉编译时跳过 gtest_discover_tests(prepare 中的修改)

上游 CMake 中有:

cmake 复制代码
include(GoogleTest)
gtest_discover_tests(cppDESTest)

gtest_discover_tests 会在构建阶段宿主机 上执行刚编好的 cppDESTest 以发现测试用例。而 cppDESTest 是为 arm-linux-ohos 编译的,在 Mac/Linux 上无法运行,会报 "cannot execute binary file" 并导致构建失败。因此必须在 prepare() 里对 CMakeLists.txt 做最小修改,在交叉编译时跳过该步骤(见下文"问题二")。当前实现使用 awk 将上述一行替换为:

cmake 复制代码
if(NOT CMAKE_CROSSCOMPILING)
  gtest_discover_tests(cppDESTest)
endif()

这样在 OHOS toolchain 设置 CMAKE_CROSSCOMPILING=ON 时不会执行测试发现,但 cppDESTest 仍会正常编出,供设备端使用。

3.4 HPKCHECK 设备侧测试

  • test.shcdthirdparty/cppDES,再 source HPKCHECK,因此 openharmonycheck() 中进入 ${builddir}/${ARCH}-build(即 cppDES-master/armeabi-v7a-buildarm64-v8a-build),若存在 ./cppDESTest 则直接执行并以其退出码作为测试结果,不再使用 ctest(避免设备上与宿主机路径不一致导致的 CTest 配置问题)。

四、编译流程与命令

  1. 进入 lycium 目录

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

    bash 复制代码
    ./build.sh cppDES
  3. 脚本将依次:检查 OHOS_SDK、解压/使用已有 cppDES-master.tar.gz、对每个 ARCH 执行 prepare → cmake 配置 → make → package,并写入 lycium/usr/hpk_build.csv

  4. 产物位置

    • 静态库与头文件:lycium/usr/cppDES/armeabi-v7a/lycium/usr/cppDES/arm64-v8a/(lib、include)。
    • 测试可执行文件:保留在 thirdparty/cppDES/cppDES-master/armeabi-v7a-build/cppDESTestarm64-v8a-build/cppDESTest,需随测试资源一起拷贝到设备。

【此处可配图:终端中执行 ./build.sh cppDES 后"Compileing OpenHarmony armeabi-v7a/arm64-v8a ...""Build cppDES master end!""ALL JOBS DONE!!!" 的完整输出截图。】

【此处可配图:lycium/usr/cppDES/ 下 armeabi-v7a、arm64-v8a 的 lib 与 include 目录结构(含 liblibcppdes.a、cppdes/*.h)。】


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

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

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

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

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

bash 复制代码
tr -d '\r' < thirdparty/cppDES/HPKBUILD > thirdparty/cppDES/HPKBUILD.tmp && mv thirdparty/cppDES/HPKBUILD.tmp thirdparty/cppDES/HPKBUILD

问题二:make 阶段报错 "cannot execute binary file" / GoogleTestAddTests.cmake Error

现象:cmake 配置成功,libcppdes、googletest、cppDESTest 的编译与链接也成功,但在生成 cppDESTest 之后出现类似:

text 复制代码
/Users/.../cppDES-master/armeabi-v7a-build/cppDESTest: cannot execute binary file
CMake Error at .../GoogleTestAddTests.cmake:112 (message):
  Error running test executable. Path: '.../cppDESTest' Result: 126

随后 make 报错并删除已生成的 cppDESTest。

原因gtest_discover_tests(cppDESTest) 会在构建时宿主机 上运行 cppDESTest 以发现测试。而该可执行文件是为 arm-linux-ohos 编译的,在 x86 Mac/Linux 上无法运行,因此系统返回 "cannot execute binary file"(退出码 126)。

解决 :在 prepare() 中修改上游 CMakeLists.txt,将:

cmake 复制代码
gtest_discover_tests(cppDESTest)

改为:

cmake 复制代码
if(NOT CMAKE_CROSSCOMPILING)
  gtest_discover_tests(cppDESTest)
endif()

实现方式采用 awk 在解压后的 cppDES-master/CMakeLists.txt 上做一次性替换(见 HPKBUILD 中 prepare 段),无需改 C/C++ 源码,符合"构建脚本最小改动"的移植原则。修改后交叉编译时不再执行测试发现,但 cppDESTest 仍会正常生成,供设备端运行。


问题三:设备上 ctest 报 "No test configuration file found!"

现象 :将 thirdparty/cppDES 拷贝到设备后,进入 cppDES-master 目录执行 ctest,提示 "No test configuration file found!"。

原因 :CTest 的配置文件(如 CTestTestfile.cmake)是 CMake 在构建目录 中生成的,位于 cppDES-master/armeabi-v7a-buildarm64-v8a-build,而不是源码根目录 cppDES-master。在源码根目录执行 ctest 时找不到这些文件。

解决 :在设备上先进入对应架构的构建目录再执行 ctest,例如:

bash 复制代码
cd cppDES-master/armeabi-v7a-build
ctest --output-on-failure

或直接运行测试可执行文件(推荐):

bash 复制代码
cd cppDES-master/armeabi-v7a-build
./cppDESTest

HPKCHECK 已采用"直接运行 ./cppDESTest"的方式,避免依赖 ctest 与 CTest 配置文件。

【此处可配图:在错误目录执行 ctest 报 "No test configuration file found!" 的终端截图。】


问题四:设备上 ctest 报 "include could not find requested file" 或路径为本机路径

现象 :在设备上进入 armeabi-v7a-build 后执行 ctest,报错类似:

text 复制代码
CMake Error at CTestTestfile.cmake:7 (include):
  include could not find requested file:
    /Users/lijiajun/.../thirdparty/cppDES/cppDES-master/armeabi-v7a-build/cppDESTest[1]_include.cmake

原因 :CTest 的测试列表是在宿主机 上生成的,其中的路径是宿主机绝对路径 。把构建目录拷贝到设备后,设备上并不存在该路径,因此 include 失败。这不是"缺动态库",而是路径不一致问题。

解决 :不在设备上依赖 ctest 的"发现 + include"机制,改为在 HPKCHECK 中直接执行 ./cppDESTest,用其退出码作为测试结果。这样既不依赖 CTest 配置文件中的宿主机路径,也无需在设备上做路径替换。


问题五:设备上 ctest 显示 "cppDESTest_NOT_BUILT" / "Could not find executable"

现象:设备上能进入构建目录并执行 ctest,但测试项显示为 "cppDESTest_NOT_BUILT",或 "Could not find executable cppDESTest_NOT_BUILT"。

原因 :若在 HPKBUILD 的 build() 中只编了 libcppdes (例如 make -C $ARCH-build libcppdes),则 cppDESTest 可执行文件根本没有被编译。CMake 仍会为该目标注册一条 CTest 测试,但可执行文件不存在,故标记为 NOT_BUILT。

解决 :在 build() 中做全量 make (不限定目标),即 make -C $ARCH-build,这样会同时编出 libcppdes 与 cppDESTest(并拉取、编译 googletest)。再结合"问题二"的 gtest_discover_tests 跳过逻辑,即可在宿主机上完整构建,并在设备上得到可用的 cppDESTest。


六、设备侧测试简要步骤

  1. thirdparty(或至少 thirdparty/cppDES,含 cppDES-master 及两个架构的 *-build 目录)按 lycium 文档打包为测试资源,部署到开发板,并保证设备上的目录层级与编译机一致。

  2. 在设备上进入 lycium 根目录后执行:

    bash 复制代码
    ./test.sh cppDES

    脚本会根据 CPU 架构进入对应 cppDES-master/<ARCH>-build 并执行 ./cppDESTest,结果写入日志并汇总到 check_result。

  3. 或手动进入对应构建目录执行:

    bash 复制代码
    cd /path/to/thirdparty/cppDES/cppDES-master/arm64-v8a-build   # 按实际架构选择
    ./cppDESTest

七、总结

  • cppDES 在 OpenHarmony 上的交叉编译依赖 lycium 的 HPKBUILD/HPKCHECK 机制,通过指定源码地址、builddir、buildtools=cmake,并在 prepare 中对 CMakeLists 做最小修改(跳过交叉编译时的 gtest_discover_tests),即可在宿主机完成全量构建并得到静态库与测试可执行文件。
  • 典型问题:HPKBUILD 的 CRLF 导致脚本解析错误;gtest_discover_tests 在宿主机运行目标机二进制导致 "cannot execute binary file";设备上 CTest 路径与"无 cppDESTest 可执行文件"导致的测试失败,均可通过换行符统一、CMake 条件编译和"直接运行 cppDESTest"的方式规避。
  • 最终产物:lycium/usr/cppDES/<ARCH>/ 下的静态库与头文件可供应用集成;cppDES-master/<ARCH>-build/cppDESTest 用于设备端功能验证。

若你在使用 lycium 接入其他 C/C++ 三方库时也遇到类似"测试发现"或"路径不一致"问题,可参考本文的排查思路与修改方式。更多 OpenHarmony 跨平台与三方库共建内容,欢迎在 开源鸿蒙跨平台社区 交流。


参考与相关链接

相关推荐
俩毛豆1 小时前
获得2025年度鸿蒙开发者社区贡献榜单(问答产出榜、文章产出榜)
华为·harmonyos·鸿蒙
爱搞事的程小猿2 小时前
qml自定义扩展模块
c++·qt·qml
喜欢吃燃面2 小时前
基础算法:高精度
开发语言·c++·学习·算法
new_zhou2 小时前
Windows环境c++开发dump文件生成(优化方案)
c++·windows·qt
你的冰西瓜2 小时前
C++中的queue容器详解
开发语言·c++·stl
蜡笔小马2 小时前
Boost.Polygon 库概述:高效处理平面多边形几何的利器
c++·boost
liu****2 小时前
4.镜像仓库详解
c++·docker·云原生·容器·kubernetes·镜像\
梵刹古音2 小时前
【C++】多态
开发语言·c++
前端不太难3 小时前
HarmonyOS PC 真正难的是状态一致性
华为·状态模式·harmonyos