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


一、背景与目标

rudpevercomer/rudp)是 C 实现的 Reliable UDP 库,接口类似 POSIX socket(RUDPListenRUDPAcceptRUDPSendRUDPRecv 等),支持双逻辑通道、多线程安全,可在 Linux/Windows 上编译。上游仅提供 Makefile(无 CMake/autotools),无第三方依赖,仅需系统库 pthreadrt。本文记录在 OpenHarmony 三方库共建仓库(tpc_c_cplusplus) 中,使用 lycium 交叉编译框架 将 rudp 接入、通过 make 命令行传入 CC/AR 覆盖工具链完成 OHOS 交叉编译、在 prepare() 中生成 CRC32 测试用例(4 条,不依赖 socket),并在设备上通过 HPKCHECK 执行 ./rel/rudp_test 完成验证的完整过程。

目标

  • 在 Mac/Linux 宿主机上交叉编译出适用于 OpenHarmony(armeabi-v7a / arm64-v8a / x86_64)的 librudp.a 与头文件;
  • 提供与上游 API 一致的 basetype.hplatform_adpt.hrudp.h,供应用集成;
  • 编写不依赖网络的 CRC32 测试(库内纯函数 calc_crc32),编出 rudp_test,避免设备上因 socket 导致的 Signal 11;
  • 设备上执行 ./rel/rudp_test,输出 4 条 [PASS] 表示全部通过。

二、环境与框架简介

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

2.1 编译环境搭建

  • 宿主机:建议 Mac(Darwin)或 Linux;需安装 makewget(或 curl)等。
  • OHOS SDK:需包含 native/llvm(提供 *-linux-ohos-clangllvm-ar);环境变量指向 SDK 根目录,例如:
    export OHOS_SDK=/path/to/OpenHarmony/Sdk/20
    
  • lycium:每个三方库由目录下的 HPKBUILD 定义“下载 → 解压 → prepare → 编译 → 安装”;产物落在 lycium/usr/<pkgname>/<ARCH>/;设备侧测试由 HPKCHECK 中的 openharmonycheck() 定义。

2.2 rudp 上游特点

  • 源码:使用 master 分支,通过 https://codeload.github.com/evercomer/rudp/zip/refs/heads/master 下载,解压后目录名为 rudp-master;主要文件为 rudp.crudp.hcrc32.ccrc32.hplatform_adpt.c 等。
  • 构建:上游仅提供 Makefile,使用 CC=$(CROSS)gccAR=$(CROSS)ar,无 make install;本适配不引入 CMake,在 build() 中通过命令行传入 CCAR 覆盖,使 OHOS 的 *-linux-ohos-clangllvm-ar 生效,执行 make rel=1 all 生成 rel/librudp.a
  • API:RUDPListen、RUDPAccept、RUDPSend、RUDPRecv 等,需头文件 basetype.h、platform_adpt.h、rudp.h。
  • 依赖:仅系统库 pthread、rt。
  • 测试:上游有 socket 相关测试;本适配为避免设备上网络/socket 导致 Signal 11,在 prepare() 中通过 heredoc 生成 rudp_test.c,仅对库内纯函数 calc_crc32(crc32.h)做 4 条用例校验(空串、"a""hello""123456789"),不调用 RUDPStart 或 socket。

2.3 HPKBUILD / HPKCHECK 在本库中的角色

  • HPKBUILD:定义 pkgname=rudp、pkgver=1.0、source、builddir=rudp-master、buildtools=make;prepare() 中复制 $builddir$builddir-$ARCH-build,按 ARCH 设置 cc/ar(OHOS 的 clang、llvm-ar),并用 heredoc 生成 rudp_test.c(4 条 CRC32 用例);build()make CC="${cc}" AR="${ar}" rel=1 all 编出 librudp.a,再编译 rudp_test.c 链接 librudp.a 得到 rel/rudp_testpackage() 中拷贝头文件、librudp.a、rudp_test 到 usr/rudp/$ARCH/。
  • HPKCHECK:设备上进入 ${builddir}-${ARCH}-build,执行 ./rel/rudp_test,将输出写入 logfile,以退出码作为测试结果。

三、接入步骤

3.1 创建三方库目录与文件

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

文件 作用
HPKBUILD 包名、版本、源码、prepare(设 cc/ar、生成 rudp_test.c)/build/package
HPKCHECK 设备上进入构建目录执行 ./rel/rudp_test,以退出码为结果
README.OpenSource 开源协议(Unlicense)、上游地址、版本(JSON 格式)
README_zh.md 中文说明:简介、产物、编译、测试、API 用法等
.gitignore 忽略 rudp-master.zip、rudp-master/、rudp-master--build/、.log 等

3.2 rudp 的 HPKBUILD 配置要点

rudp 取值 / 说明
pkgname rudp
pkgver 1.0
source https://codeload.github.com/evercomer/rudp/zip/refs/heads/master
builddir rudp-master
buildtools make
archs armeabi-v7a、arm64-v8a、x86_64
depends
  • prepare()cp -rf $builddir $builddir-$ARCH-build,进入构建目录后按 ARCH 设置 ccar(如 arm64-v8a 为 aarch64-linux-ohos-clangllvm-ar);用 heredoc 生成 rudp_test.c,内含 4 条 CRC32 用例结构体与 main 循环,调用 calc_crc32(init, data, len) 与预期值比较,不涉及 socket。
  • build():在 $builddir-$ARCH-build 中执行 $MAKE CC="${cc}" AR="${ar}" rel=1 all 生成 rel/librudp.a;再执行 "${cc}" -o rel/rudp_test rudp_test.c -D__LINUX__ -I. rel/librudp.a -lpthread -lrt 编出测试程序。
  • package():拷贝 basetype.h、platform_adpt.h、rudp.h 到 usr/rudp/$ARCH/include/,rel/librudp.a 到 usr/rudp/$ARCH/lib/,rel/rudp_test 到 usr/rudp/$ARCH/bin/

prepare() 核心片段(按 ARCH 设置工具链并生成 rudp_test.c):

prepare() {
    cp -rf $builddir $builddir-$ARCH-build
    cd $builddir-$ARCH-build
    if [ "$ARCH" = "armeabi-v7a" ]; then
        cc=${OHOS_SDK}/native/llvm/bin/arm-linux-ohos-clang
        ar=${OHOS_SDK}/native/llvm/bin/llvm-ar
    fi
    if [ "$ARCH" = "arm64-v8a" ]; then
        cc=${OHOS_SDK}/native/llvm/bin/aarch64-linux-ohos-clang
        ar=${OHOS_SDK}/native/llvm/bin/llvm-ar
    fi
    if [ "$ARCH" = "x86_64" ]; then
        cc=${OHOS_SDK}/native/llvm/bin/x86_64-linux-ohos-clang
        ar=${OHOS_SDK}/native/llvm/bin/llvm-ar
    fi
    # 用 heredoc 生成 rudp_test.c(4 条 CRC32 用例,略)
    cat > rudp_test.c << 'ENDTEST'
#include "crc32.h"
#include <stdio.h>
#include <string.h>
/* ... test_case_t 与 cases[]、main 循环 ... */
ENDTEST
    cd $OLDPWD
}

build() 核心片段

build() {
    cd $builddir-$ARCH-build
    $MAKE CC="${cc}" AR="${ar}" rel=1 all >> "$buildlog" 2>&1
    ret=$?
    if [ $ret -ne 0 ]; then
        cd $OLDPWD
        return $ret
    fi
    "${cc}" -o rel/rudp_test rudp_test.c -D__LINUX__ -I. rel/librudp.a -lpthread -lrt >> "$buildlog" 2>&1
    ret=$?
    cd $OLDPWD
    return $ret
}

package() 核心片段

package() {
    cd $builddir-$ARCH-build
    _usr="$LYCIUM_ROOT/usr/$pkgname/$ARCH"
    mkdir -p "$_usr/include" "$_usr/lib" "$_usr/bin"
    cp -f basetype.h platform_adpt.h rudp.h "$_usr/include/"
    cp -f rel/librudp.a "$_usr/lib/"
    [ -f rel/rudp_test ] && cp -f rel/rudp_test "$_usr/bin/"
    cd $OLDPWD
    unset cc ar
}

3.3 为何采用 CRC32 测试而非完整 socket 测试

  • 上游 rudp 的典型用法需 RUDPListen/RUDPAccept、RUDPSend/RUDPRecv,依赖网络与 socket。在部分 OpenHarmony 设备或环境下,直接跑完整服务端/客户端测试可能触发 Signal 11(SIGSEGV),不利于 CI 与自动化检查。
  • 本适配仿 emoji_segmenter 思路:只测库内纯函数(不依赖 socket)。rudp 中的 calc_crc32(crc32.h)满足这一点,且与 RUDP 协议校验逻辑相关,具有代表性。4 条用例(空串、单字符、短串、数字串)即可验证 CRC32 实现正确性,设备上无需网络即可稳定通过。

3.4 HPKCHECK 设备侧测试逻辑

设备上进入 ${builddir}-${ARCH}-build(即 rudp-master/armeabi-v7a-build 等):

  • 若存在 rel/rudp_test,则执行 ./rel/rudp_test,标准输出与错误写入 ${logfile},以可执行文件退出码作为测试结果(0 为通过);
  • 若不存在可执行文件,则记录 “No rel/rudp_test executable, skip test”,返回 1。

四、编译流程与命令

  1. 进入 lycium 目录

    cd /path/to/tpc_c_cplusplus/lycium
    
  2. 执行编译(仅编译 rudp):

    ./build.sh rudp
    
  3. 脚本将依次:检查 OHOS_SDK、下载/解压 rudp-master、对每个 ARCH 执行 prepare → build → package,并写入 lycium/usr/hpk_build.csv

    image-20260212103946422

  4. 产物位置

    • 静态库与头文件:lycium/usr/rudp/armeabi-v7a/lycium/usr/rudp/arm64-v8a/lycium/usr/rudp/x86_64/(lib/librudp.a、include/basetype.h、platform_adpt.h、rudp.h)。
    • 测试可执行文件:lycium/usr/rudp/<ARCH>/bin/rudp_test,或构建目录内 thirdparty/rudp/rudp-master/<ARCH>-build/rel/rudp_test

五、设备侧测试

将对应架构的构建目录(如 rudp-master/arm64-v8a-build)中的 rel/rudp_test 拷贝到设备,或直接使用安装后的 usr/rudp/<ARCH>/bin/rudp_test。在设备上进入包含 rel/rudp_test 的目录(若在构建目录内则为 rudp-master/<ARCH>-build)后执行:

./rel/rudp_test

通过时输出示例:

rudp tests (CRC32), 4 cases
  [PASS] crc32 empty
  [PASS] crc32 "a"
  [PASS] crc32 "hello"
  [PASS] crc32 "123456789"
All 4 tests passed.

退出码 0 表示全部通过。HPKCHECK 在设备上执行同一命令,结果写入 thirdparty/rudp/rudp_<ARCH>_<SDK_VER>_test.log,便于排查。

image-20260212104349413


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

问题一:HPKBUILD 使用 CRLF 导致 source 报错或语法错误

现象:执行 ./build.sh rudp 时出现 syntax error near unexpected tokencommand not found(在 prepare/build 附近)。

原因:HPKBUILD 使用 Windows 换行符(CRLF),行尾 \r 导致 bash 解析异常。

解决:将 HPKBUILD、HPKCHECK 统一为 Unix 换行(LF),例如:

tr -d '\r' < HPKBUILD > HPKBUILD.tmp && mv HPKBUILD.tmp HPKBUILD

或在仓库内通过 .gitattributes 指定 HPKBUILD text eol=lfHPKCHECK text eol=lf,避免再次引入 CRLF。


问题二:GitHub 源码下载失败(archive 链接超时或 404)

现象:使用 https://github.com/evercomer/rudp/archive/refs/heads/master.zip 等归档链接时下载失败。

原因:部分网络环境下 GitHub archive 不稳定或需代理。

解决:将 source 改为 codeload 形式:https://codeload.github.com/evercomer/rudp/zip/refs/heads/master,并设置 packagename=$builddir.zip(解压后目录仍为 rudp-master),提高下载成功率。若仍失败,可尝试镜像(如 mirror.ghproxy.com)或本地放置 zip 后关闭 downloadpackage。


问题三:设备上跑完整 socket 测试出现 Signal 11

现象:若在 rudp_test 中调用 RUDPListen、RUDPSend 等做完整收发测试,在部分设备上运行时报 Signal 11(SIGSEGV)。

原因:与设备侧网络栈、权限或运行时环境有关,非编译错误。

解决:本适配采用仅测 CRC32 的策略,不调用 RUDP 与 socket,仅验证库内 calc_crc32 的正确性,保证 HPKCHECK 与设备侧自动化测试稳定通过。完整 RUDP 功能可在应用集成后在实际网络环境中自行验证。


七、总结

  • rudp 在 OpenHarmony 上的交叉编译依赖 lycium 的 HPKBUILD/HPKCHECK 机制。上游仅 Makefile、无 CMake,本适配通过 make 命令行传入 CC/AR 覆盖工具链(参考 make 交叉编译文档),在宿主机完成构建,得到 librudp.a、头文件与 rudp_test
  • 测试策略:为避免设备上 socket 导致的 Signal 11,在 prepare() 中生成 rudp_test.c,仅对 calc_crc32 做 4 条用例校验,无网络依赖,设备上执行 ./rel/rudp_test 即可稳定通过;HPKCHECK 以该可执行文件退出码作为结果。
  • 典型问题:HPKBUILD 的 CRLF 需统一为 LF;源码下载可改用 codeload 或镜像;完整 socket 测试建议在应用集成后于实际环境中验证。
  • 最终产物:lycium/usr/rudp/<ARCH>/ 下的静态库与头文件可供应用集成(链接 -lrudp -lpthread -lrt);rel/rudp_test 用于设备端 CRC32 功能验证。

若你在使用 lycium 接入仅提供 Makefile 的 C 库时,可参考本文的“CC/AR 覆盖 + prepare 内生成无 socket 测试”的方式。更多鸿蒙三方库共建内容,欢迎在 开源鸿蒙跨平台社区 交流。


参考与相关链接

Logo

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

更多推荐