避坑指南:鸿蒙 PC 部署 AtomCode Skills 压测工具 wrk
欢迎加入【开源鸿蒙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 |

目录
- 背景与挑战
- AtomCode Skills 工作流总览
- Step 1:一键生成 HPKBUILD 骨架
- Step 2:构建环境检查
- Step 3:移植审查与问题发现
- Step 4:逐一修复与构建验证
- Step 5:最终构建与产物验证
- 经验总结与最佳实践
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,它本身不是为交叉编译设计的。其构建流程包含:
- 预编译 LuaJIT:通过
luajit -b将 Lua 脚本转为 C 字节码(bytecode.c) - 编译 C 源码:
wrk.c,net.c,ssl.c,script.c等 - 链接依赖: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 依赖声明 |
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,需要手动处理:
- 将
buildtools设为make - 声明
depends=("LuaJIT" "openssl") - 在
build()中通过环境变量传递WITH_LUAJIT和WITH_OPENSSL - 在
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 构建系统两个信息:
- 构建顺序:在构建 wrk 之前,先构建
LuaJIT和openssl - 依赖注入:
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() 之前执行,用于:
- 创建架构特定构建目录(
$builddir/$ARCH-build) - 应用补丁(
patchflag确保每轮构建只打一次补丁)
wrk 的 prepare() 相对简单,因为 wrk 的适配问题主要集中在 build() 函数中(依赖路径和 Build Tool 架构)。
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 -b 将 wrk.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.c 和 script.h 依赖 Lua API |
-lssl -lcrypto |
链接 OpenSSL | wrk 的 ssl.c 依赖 SSL/TLS 功能 |
6.3 修复流程对比
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 鸿蒙化适配最佳实践
-
Makefile vs CMake 差异:Makefile 项目不能依赖
CMAKE_FIND_ROOT_PATH,需手动在CFLAGS/LDFLAGS/LIBS中配置依赖路径。 -
Build Tool 架构匹配:交叉编译时,所有在构建机上运行的工具(如代码生成器、脚本编译器)都必须是 HOST 架构版本。交叉编译的 ARM64 二进制无法在 x86_64 构建机上执行。
-
Makefile 变量传递:Makefile 的
ifneq ($(VAR),)在解析时检查变量是否定义。需要export环境变量或在make命令行中传递,二者不可兼用时优先使用export。 -
Stub 策略:当无法编译 HOST 版本的 build tool 时,可以创建 stub 文件满足链接需求。wrk 的
obj/bytecode.c为空数组不会影响功能(Lua 脚本会在运行时加载)。 -
依赖声明顺序:
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 # 中文说明文档
更多推荐




所有评论(0)