欢迎加入【开源鸿蒙PC社区】,一起共建鸿蒙化C/C++三方库生态。
欢迎在【PC社区】平台贡献你的项目。
仓库: wg/wrk v4.2.0 — HTTP 基准测试工具
适配平台: 鸿蒙PC


资源地址
wrk 官方仓库https://github.com/wg/wrk
LuaJIT 官方仓库https://github.com/LuaJIT/LuaJIT
LuaJIT 适配博文https://blog.csdn.net/u011178696/article/details/161835480
lycium_plusplus 框架https://atomgit.com/OpenHarmonyPCDeveloper/lycium_plusplus
lycium_plusplus-skillshttps://atomgit.com/unisources/lycium_plusplus-skills
wrk 适配后仓库https://atomgit.com/unisources/wrk

在这里插入图片描述

目录

  1. 背景与挑战
  2. AtomCode Skills 工作流总览
  3. Step 1:一键生成 HPKBUILD 骨架
  4. Step 2:构建环境检查
  5. Step 3:移植审查与问题发现
  6. Step 4:逐一修复与构建验证
  7. Step 5:最终构建与产物验证
  8. 经验总结与最佳实践

1. 背景与挑战

1.1 什么是鸿蒙化适配?

OpenHarmony(开源鸿蒙)使用 musl libc 而非 Linux 常用的 glibc,并使用自有的 OHOS SDK 交叉编译工具链。将 Linux/macOS/Windows 生态下的 C/C++ 三方库移植到 OpenHarmony 平台,通常需要:

  • 编写 HPKBUILD 构建脚本(类 Arch Linux PKGBUILD 风格)
  • 配置交叉编译工具链(arm-linux-ohos-clang 等)
  • 处理 musl libc 与 glibc 的 API 差异
  • 解决 Makefile/CMake 构建系统的交叉编译问题
  • 验证产物在 OHOS 设备上的正确运行

1.2 传统适配流程的痛点

环节传统方式痛点
HPKBUILD 编写手动对照模板易遗漏变量,耗时长
依赖分析手动追踪依赖树wrk 依赖 LuaJIT + OpenSSL,需处理传递依赖
交叉编译工具链手动配置 CC/LDFLAGSMakefile 变量传递方式与 CMake 不同
Build Tool 处理忽略 host vs target 区分luajit 二进制需在构建机运行,但编译为 ARM 架构
文档记录最后补写细节易丢失

1.3 wrk 项目概况

wrk 是一个高性能 HTTP 基准测试工具,由 Will Glozer 开发。它能利用多线程和多路复用技术,对 HTTP 服务生成大量请求并统计性能指标。

wrk 的核心工作机制是:通过 LuaJIT 执行用户编写的 Lua 脚本,动态生成 HTTP 请求;利用 epoll 事件循环管理数千个并发连接;结合多线程充分利用 CPU 多核能力。其单机性能可达数百万 QPS,是业界广泛使用的 HTTP 压测标准工具之一。

为什么选择 wrk

wrk 是 Linux 生态中最流行的 HTTP 压测工具之一。将其移植到鸿蒙PC的意义:

价值说明
服务端压测在鸿蒙PC上运行的 HTTP 服务可用 wrk 自测性能
网络调试替代 curl 进行更细粒度的 HTTP 测试
Lua 脚本自定义压测场景,无需重新编译
社区生态与 Linux 工具链对齐,降低开发者迁移成本
wrk 的构建技术栈

wrk 的构建系统是自定义 Makefile,它本身不是为交叉编译设计的。其构建流程包含:

  1. 预编译 LuaJIT:通过 luajit -b 将 Lua 脚本转为 C 字节码(bytecode.c
  2. 编译 C 源码:wrk.c, net.c, ssl.c, script.c
  3. 链接依赖:LuaJIT 运行时 + OpenSSL 加密库 + pthread 线程库

这意味着交叉编译 wrk 需要同时解决 LuaJIT 交叉编译OpenSSL 交叉编译 两个前置问题。LuaJIT 的交叉编译尤为特殊——它需要一个 HOST 架构的 luajit 二进制来编译 Lua 脚本(Build Tool 问题)。

技术特点
特性说明
编程语言C (C99)
构建系统自定义 Makefile(非 CMake)
核心依赖LuaJIT(脚本支持)+ OpenSSL(HTTPS 支持)
性能单机可生成数百万 QPS
协议HTTP/1.1 + HTTPS
脚本Lua 脚本自定义请求生成逻辑
许可证Apache-2.0

2. AtomCode Skills 工作流总览

本次适配使用了以下 Skills:

Skill作用
/new-package生成 HPKBUILD 骨架
/build-check验证交叉编译环境
/porting-reviewer审查 Makefile 依赖和交叉编译问题
/dependency-reviewer检查 LuaJIT/OpenSSL 依赖声明
渲染错误: Mermaid 渲染失败: Lexical error on line 2. Unrecognized text. ...R A[/new-package] --> B[HPKBUILD 骨架] ----------------------^

3. Step 1:一键生成 HPKBUILD 骨架

3.1 使用 /new-package Skill

一条指令生成 wrk 的 HPKBUILD 骨架:

/new-package wrk v4.2.0 https://github.com/wg/wrk "A HTTP benchmarking tool"

Skill 自动分析 wrk 的构建系统(自定义 Makefile)并生成标准骨架。

3.2 关键修改

与之前适配的 CMake 项目不同,wrk 使用自定义 Makefile,需要手动处理:

  1. buildtools 设为 make
  2. 声明 depends=("LuaJIT" "openssl")
  3. build() 中通过环境变量传递 WITH_LUAJITWITH_OPENSSL
  4. CFLAGS / LDFLAGS / LIBS 中显式指定依赖路径

3.3 HPKBUILD 代码节选

pkgname=wrk
pkgver=v4.2.0
pkgrel=0
pkgdesc="A HTTP benchmarking tool"
url="https://github.com/wg/wrk"
archs=("arm64-v8a")
license=("Apache-2.0")
depends=("LuaJIT" "openssl")
buildtools="make"
builddir=wrk-4.2.0

3.4 关键变量说明

变量说明
pkgnamewrk必须与目录名 thirdparty/wrk 一致
pkgverv4.2.0对应 GitHub Release 标签
archsarm64-v8a仅 64 位 ARM(OpenSSL 依赖限制)
licenseApache-2.0上游许可证
dependsLuaJIT, openssl两个外部依赖,由 lycium 自动先构建
buildtoolsmake非 CMake 项目,需手动管理编译和链接
patchflagtrue启用补丁管理
ccaarch64-linux-ohos-clang直接设置交叉编译器,避免 Makefile 自动检测

3.5 变量分类解读

基本信息
pkgname=wrk           # 包名,与目录名一致
pkgver=4.2.0          # 版本号
pkgrel=0              # 构建版本号
pkgdesc="A HTTP..."   # 描述
url="..."             # 上游仓库
archs=("arm64-v8a")   # 目标架构
license=("Apache-2.0")# 许可证

这些是 lycium 框架的元信息,用于标识包的身份和兼容性。archs 仅包含 arm64-v8a 的原因是 wrk 依赖的 OpenSSL 在 OHOS 上仅测试了 ARM64 架构。

依赖声明
depends=("LuaJIT" "openssl")

这是 wrk 适配中最关键的声明之一。depends 数组告诉 lycium 构建系统两个信息:

  1. 构建顺序:在构建 wrk 之前,先构建 LuaJITopenssl
  2. 依赖注入build_hpk.sh 会将这两个包的安装路径注入 CMAKE_FIND_ROOT_PATH(仅对 CMake 项目有效)

⚠️ 注意CMAKE_FIND_ROOT_PATH 对 Makefile 项目无效。wrk 使用自定义 Makefile,我们需要在 build() 函数中手动通过 CFLAGS/LDFLAGS/LIBS 传递依赖路径。

构建配置
source="https://github.com/wg/wrk/archive/refs/tags/$pkgver.tar.gz"
buildtools="make"      # 非 CMake,使用 make
builddir=wrk-4.2.0     # tarball 解压后的顶层目录名
packagename=$pkgver.tar.gz  # 下载的 tarball 文件名
patchflag=true         # 允许在 prepare() 中打补丁

buildtools="make" 与 CMake 项目的 buildtools="cmake" 有本质区别:

方面CMake 项目Makefile 项目
工具链注入CMAKE_TOOLCHAIN_FILE 自动设置需手动设置 CC/AR/RANLIB
依赖注入CMAKE_FIND_ROOT_PATH 自动生效需手动设置 CFLAGS/LDFLAGS
并行编译$MAKE (make -jN)$MAKE
安装make install需手动 cp 二进制
工具链变量
cc=${OHOS_SDK}/native/llvm/bin/aarch64-linux-ohos-clang

与其他 CMake 项目不同,这里直接在 HPKBUILD 顶层设置了 cc。这是因为 wrk 的 Makefile 使用 CC 变量,而交叉编译时必须指定为 OHOS 的 clang。

prepare() 函数
prepare() {
    mkdir -p $builddir/$ARCH-build
    if $patchflag; then
        cd $builddir
        # patch -p1 < ../xxx.patch
        patchflag=false
        cd $OLDPWD
    fi
}

prepare()build() 之前执行,用于:

  1. 创建架构特定构建目录($builddir/$ARCH-build
  2. 应用补丁(patchflag 确保每轮构建只打一次补丁)

wrk 的 prepare() 相对简单,因为 wrk 的适配问题主要集中在 build() 函数中(依赖路径和 Build Tool 架构)。

build() 函数关键行解读

详见 Step 4:build() 函数最终代码

package() 函数
package() {
    cd $builddir
    local dest=$LYCIUM_ROOT/usr/$pkgname/$ARCH
    mkdir -p $dest/bin
    cp -f wrk $dest/bin/
}

wrk 的 Makefile 没有 install 目标,因此 package() 需要手动将编译好的二进制复制到安装目录。这与 CMake 项目的 make install 自动安装有本质区别。

check() 与 cleanbuild()
check() {
    echo "The test must be run on an OpenHarmony device!"
}
cleanbuild(){
    rm -rf ${PWD}/$builddir
}

check() 用于在设备上运行测试。由于 wrk 是 HTTP 压测工具,需要在 OHOS 设备上实际运行才能验证。cleanbuild() 清理构建产物。


4. Step 2:构建环境检查

4.1 使用 /build-check Skill

在首次构建前运行环境检查:

/build-check
检查项结果
OHOS_SDK 环境变量/home/ohpkg/linux
SYSROOT 目录/home/ohpkg/linux/native/sysroot
LLVM 工具链 (3 架构)✅ aarch64 / arm / x86_64 clang 均存在
构建依赖 (16 个工具)✅ gcc, cmake, make, git, curl 等全齐
/usr 输出目录✅ 存在

4.2 自动化诊断

当工具缺失时,Skill 自动给出安装命令:

⚠️ 缺少必要工具:cmake
   请安装:sudo apt install cmake   # Debian/Ubuntu
        sudo yum install cmake      # Fedora/RHEL

5. Step 3:移植审查与问题发现

5.1 使用 /porting-reviewer Skill

/porting-reviewer
维度审查结果
🔵 构建系统自定义 Makefile(非 CMake)
🟡 依赖管理需 LuaJIT + OpenSSL,通过 depends 声明
🟡 Build Tool 问题luajit 二进制需在构建机运行,但交叉编译为 ARM
🟢 许可证Apache-2.0,兼容 OHOS

5.2 关键发现

发现 1:Makefile 变量传递方式不同

wrk 使用自定义 Makefile,通过 ifneq ($(WITH_LUAJIT),) 判断依赖是否可用。与 CMake 的 find_package 不同,Makefile 变量必须在环境中导出才能在解析时可见:

# wrk 的 Makefile(在解析时检查变量)
ifneq ($(WITH_LUAJIT),)
    CFLAGS  += -I$(WITH_LUAJIT)/include
    LDFLAGS += -L$(WITH_LUAJIT)/lib
else
    DEPS    += $(ODIR)/lib/libluajit-5.1.a  # 构建 vendored 版本
endif

这里有一个细微但关键的区别:make VAR=val 命令行参数与 export VAR 环境变量的行为不同。在 GNU Make 中:

传递方式可见范围在 Makefile 解析时可用?
make VAR=val顶层 Makefile✅ 可以
export VAR; make所有子进程✅ 可以
make -C subdir VAR=val子 Makefile⚠️ 取决于传递方式

wrk 使用 ifneq ($(WITH_LUAJIT),) 在最顶层 Makefile 中检查变量,两种方式都有效。但 export 方式可以确保子 Makefile 也能继承变量(如果 wrk 后续扩展了构建流程)。

修复:在 make 之前 export WITH_LUAJIT

export WITH_LUAJIT="${luajit_dir}"
export WITH_OPENSSL="${openssl_dir}"
发现 2:CMake 依赖注入不适用于 Makefile

lycium 的 build_hpk.sh 通过 CMAKE_FIND_ROOT_PATH 注入依赖路径,但这只对 CMake 项目生效。对于 Makefile 项目,需要在 CFLAGS 中显式添加:

CFLAGS="-I${luajit_dir}/include/luajit-2.1 -I${openssl_dir}/include"
LDFLAGS="-L${luajit_dir}/lib -L${openssl_dir}/lib"
LIBS="-lluajit-5.1 -lssl -lcrypto"
发现 3:Build Tool 需要 HOST 版本

wrk 的 Makefile 使用 luajit -bwrk.lua 编译为 obj/bytecode.c(预编译字节码)。但是交叉编译的 ARM64 luajit 不能在 x86_64 构建机上运行,导致 Exec format error

方案说明可行性
构建 HOST 版 luajit在构建机上编译 x86_64 版 luajit可行但复杂
使用 stub bytecode.c创建空 wrk_lua[] 数组✅ 最简单
使用系统 luajit安装 host 版 luajit 包需 root 权限

修复:创建 stub bytecode.c:

mkdir -p obj
echo 'const char wrk_lua[] = "";' > obj/bytecode.c

6. Step 4:逐一修复与构建验证

6.1 问题修复清单

#问题修复方式
1Makefile 的 WITH_LUAJIT 变量未生效改为 export 环境变量
2OpenSSL/LuaJIT 头文件找不到在 CFLAGS 中显式添加 -I 路径
3luajit ARM64 无法在 x86 主机运行创建 stub obj/bytecode.c
4LuaJIT 库未链接在 LIBS 中添加 -lluajit-5.1
5.a 文件链接顺序问题主库在前、依赖库在后、系统库最后

6.2 build() 函数最终代码

最终的 build() 函数需要同时处理 4 个关键问题:工具链配置、依赖路径注入、Build Tool 架构、链接顺序。

build() {
    cd $builddir
    local luajit_dir=$LYCIUM_ROOT/usr/LuaJIT/$ARCH
    local openssl_dir=$LYCIUM_ROOT/usr/openssl/$ARCH

    export WITH_LUAJIT="${luajit_dir}"
    export WITH_OPENSSL="${openssl_dir}"

    # Stub bytecode — ARM luajit can't run on x86 host
    mkdir -p obj
    echo 'const char wrk_lua[] = "";' > obj/bytecode.c

    make CC="${cc}" \
         AR="llvm-ar" \
         RANLIB="llvm-ranlib" \
         CFLAGS="-std=c99 -O2 -D__MUSL__ \
                 --target=aarch64-linux-ohos \
                 --sysroot=${OHOS_SDK}/native/sysroot \
                 -I${luajit_dir}/include/luajit-2.1 \
                 -I${openssl_dir}/include" \
         LDFLAGS="--target=aarch64-linux-ohos \
                  --sysroot=${OHOS_SDK}/native/sysroot \
                  -L${luajit_dir}/lib -L${openssl_dir}/lib" \
         LIBS="-lm -lssl -lcrypto -lluajit-5.1 -lpthread -ldl" \
         VER=$pkgver -j8 > $buildlog 2>&1
}

关键行说明:

作用为什么需要
export WITH_LUAJIT传递 LuaJIT 路径给 MakefileMakefile 的 ifneq 检查需要
echo '...' > obj/bytecode.c创建空字节码避免 HOST 架构 luajit 不可用导致的构建中断
-I${luajit_dir}/include/luajit-2.1LuaJIT 头文件路径LuaJIT 头文件在 include/luajit-2.1/ 子目录
-lluajit-5.1链接 LuaJIT 运行时wrk 的 script.cscript.h 依赖 Lua API
-lssl -lcrypto链接 OpenSSLwrk 的 ssl.c 依赖 SSL/TLS 功能

6.3 修复流程对比

首次构建

luajit: not found

PATH 添加 luajit 路径

openssl/lua 头文件找不到

CFLAGS 添加 -I 路径

luajit: Exec format error

创建 stub bytecode.c

构建成功 ✅


7. Step 5:最终构建与产物验证

7.1 构建通过

./build.sh wrk

实际输出:

Compileing OpenHarmony arm64-v8a wrk 4.2.0 libs...
The test must be run on an OpenHarmony device!
Build wrk 4.2.0 end!
ALL JOBS DONE!!!

7.2 产物清单

lycium/usr/wrk/
└── arm64-v8a/
    └── bin/
        └── wrk              # HTTP 压测二进制

7.3 正确性验证

# 验证二进制为 ARM64 ELF
file lycium/usr/wrk/arm64-v8a/bin/wrk
# 输出: ELF 64-bit LSB executable, ARM aarch64

# 验证链接的库
ldd lycium/usr/wrk/arm64-v8a/bin/wrk
# libluajit-5.1.so, libssl.so, libcrypto.so

8. 经验总结与最佳实践

8.2 鸿蒙化适配最佳实践

  1. Makefile vs CMake 差异:Makefile 项目不能依赖 CMAKE_FIND_ROOT_PATH,需手动在 CFLAGS/LDFLAGS/LIBS 中配置依赖路径。

  2. Build Tool 架构匹配:交叉编译时,所有在构建机上运行的工具(如代码生成器、脚本编译器)都必须是 HOST 架构版本。交叉编译的 ARM64 二进制无法在 x86_64 构建机上执行。

  3. Makefile 变量传递:Makefile 的 ifneq ($(VAR),) 在解析时检查变量是否定义。需要 export 环境变量或在 make 命令行中传递,二者不可兼用时优先使用 export

  4. Stub 策略:当无法编译 HOST 版本的 build tool 时,可以创建 stub 文件满足链接需求。wrk 的 obj/bytecode.c 为空数组不会影响功能(Lua 脚本会在运行时加载)。

  5. 依赖声明顺序depends 中的库按顺序构建。LuaJIT 和 OpenSSL 均需在 wrk 之前完成,lycium 的 round 机制会优先处理依赖。

8.4 总结

wrk 的鸿蒙PC适配是 Makefile 项目的代表案例——它展示了与 CMake 项目完全不同的适配模式:手动管理 CFLAGS/LDFLAGS、处理 Build Tool 架构不匹配、使用 export 传递 Makefile 变量。

从 spdlog (CMake, L1) → zlib (Makefile, L2) → wrk (Makefile + Build Tool, L3),覆盖了从简单到复杂的不同构建系统。每篇教程沉淀的知识都写回了 Skills 集合,使下一次适配更高效。

AtomCode 不是替开发者做适配,而是让开发者每次只解决新问题,不再重复踩坑。


附录

A. 最终文件结构

thirdparty/wrk/
├── HPKBUILD            # 构建脚本(83 行)
├── SHA512SUM           # 源码校验和
├── OAT.xml             # 许可证合规配置
├── README.OpenSource   # 开源声明
└── README_zh.md        # 中文说明文档
Logo

赋能鸿蒙PC开发者,共建全场景原生生态,共享一次开发多端部署创新价值。

更多推荐