欢迎加入【开源鸿蒙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-skills https://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/LDFLAGS Makefile 变量传递方式与 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 关键变量说明

变量 说明
pkgname wrk 必须与目录名 thirdparty/wrk 一致
pkgver v4.2.0 对应 GitHub Release 标签
archs arm64-v8a 仅 64 位 ARM(OpenSSL 依赖限制)
license Apache-2.0 上游许可证
depends LuaJIT, openssl 两个外部依赖,由 lycium 自动先构建
buildtools make 非 CMake 项目,需手动管理编译和链接
patchflag true 启用补丁管理
cc aarch64-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 问题修复清单

# 问题 修复方式
1 Makefile 的 WITH_LUAJIT 变量未生效 改为 export 环境变量
2 OpenSSL/LuaJIT 头文件找不到 在 CFLAGS 中显式添加 -I 路径
3 luajit ARM64 无法在 x86 主机运行 创建 stub obj/bytecode.c
4 LuaJIT 库未链接 在 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 路径给 Makefile Makefile 的 ifneq 检查需要
echo '...' > obj/bytecode.c 创建空字节码 避免 HOST 架构 luajit 不可用导致的构建中断
-I${luajit_dir}/include/luajit-2.1 LuaJIT 头文件路径 LuaJIT 头文件在 include/luajit-2.1/ 子目录
-lluajit-5.1 链接 LuaJIT 运行时 wrk 的 script.cscript.h 依赖 Lua API
-lssl -lcrypto 链接 OpenSSL wrk 的 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开发者,共建全场景原生生态,共享一次开发多端部署创新价值。

更多推荐