【鸿蒙PC命令行适配】基于OHOS SDK移植libnghttp2库(1.68.0)到鸿蒙PC命令行工具中,交叉编译与部署方案详解
libnghttp2是nghttp2项目的核心组件,是一个用C语言编写的高性能、可重用的HTTP/2协议库。它主要实现了HTTP/2协议的帧层(framing layer),为构建支持HTTP/2的客户端和服务器应用程序提供了基础功能。核心功能:libnghttp2库提供了HTTP/2协议的完整实现,包括连接管理、流控制、帧的编码与解码等核心机制,并支持HPACK头部压缩算法。主要用途:该库本身不
libnghttp2 是一个用 C 语言编写的高性能 HTTP/2 协议库。它实现了 HTTP/2 的核心功能,包括二进制分帧层、多路复用、头部压缩(HPACK)以及服务器推送等特性。该库不仅支持 HTTP/2 客户端和服务器的实现,还提供了用于负载测试和基准评测的工具。
一、什么是libnghttp2?
libnghttp2是nghttp2项目的核心组件,是一个用C语言编写的高性能、可重用的HTTP/2协议库。它主要实现了HTTP/2协议的帧层(framing layer),为构建支持HTTP/2的客户端和服务器应用程序提供了基础功能。
-
核心功能:libnghttp2库提供了HTTP/2协议的完整实现,包括连接管理、流控制、帧的编码与解码等核心机制,并支持HPACK头部压缩算法。
-
主要用途:该库本身不直接提供命令行工具,而是作为开发库供其他软件集成,用于在应用程序中添加HTTP/2支持。
-
相关工具:nghttp2项目还包含基于libnghttp2构建的实用工具,例如
nghttp(HTTP/2客户端)和nghttpx(HTTP/2代理),但这些是独立于libnghttp2的可执行程序。 -
依赖与集成:许多网络工具和服务器软件(如curl、Apache、Node.js、Wireshark等)都依赖于libnghttp2库来实现HTTP/2功能。
-
开发版本:在Linux系统中,
libnghttp2-dev软件包提供了编译基于libnghttp2的应用程序所需的头文件和开发资源。
二、libnghttp2 的主要功能和用途:
libnghttp2 的设计注重灵活性,不直接处理 I/O 操作,允许开发者将其轻松集成到现有的事件循环系统中。它被广泛应用于需要高效处理 HTTP/2 请求与响应的场景,例如 Web 服务器、代理和客户端工具。
此外,libnghttp2 还提供了对 HTTP/2 协议栈的完整支持,包括对 RFC 7540、RFC 7541 和最新的 RFC 9113 的实现。其源码结构清晰,主要包含 src/、lib/ 和 tests/ 等目录,其中 lib/nghttp2 目录下是核心协议实现。
除了作为底层库使用外,libnghttp2 还支持多种高级功能,如命令行客户端工具 nghttp、高性能代理 nghttpx 以及负载测试工具 h2load 等。这些工具使得开发者可以方便地测试和调试 HTTP/2 服务。
在实际部署中,libnghttp2 也常用于嵌入式平台或物联网设备上,例如 ESP32 系列 SOC 平台。它支持多种操作系统和编译环境,并且提供了详细的开发文档和示例。
三、如何在鸿蒙PC命令行工具中移植libnghttp2?
3.1 编译环境准备:
在鸿蒙PC命令行工具中移植使用的是交叉编译的方式,交叉编译是指在A架构(如x86_64 Linux)编译出能在B架构(如鸿蒙PC)运行的程序,这样可以达到命令跨平台运行的目的。
本人使用的是vagrant ubuntu 22.04的镜像包进行的测试,在x86_64的Linux主机(Ubuntu 24.04)上编译出能在aarch64架构HarmonyOS系统的鸿蒙PC上运行的程序。

学习教程可以看看Ubuntu如何搭建OpenHarmony_6.1.0.28的lycium_plusplus及鸿蒙 PC 环境设计的 C/C++ 编译框架 这个文章,讲的还是比较详细的。
3.2 下载并配置ohos-sdk(版本:OpenHarmony_6.1.0.28):
直接使用wget将这个包下载下来,我们可以看到这个包的大小有2.33G:
wget https://cidownload.openharmony.cn/version/Daily_Version/OpenHarmony_6.1.0.28/20260120_120146/version-Daily_Version-OpenHarmony_6.1.0.28-20260120_120146-ohos-sdk-full.tar.gz

使用tar来解压这个gz压缩包:
tar xf version-Daily_Version-OpenHarmony_6.1.0.28-20260120_120146-ohos-sdk-full.tar.gz

接下来,我们进入linux目录中,我们解压native模块:
unzip -q native-linux-x64-6.1.0.28-Beta1.zip

同时,再次解压toolchains模块:
unzip -q toolchains-linux-x64-6.0.0.46-Beta1.zip

3.3 配置环境变量:
SDK解压完成之后,这里我们设置一下全局的环境变量,配置交叉编译必备的环境变量(可以根据自己的):
export OHOS_SDK=~/harmonypc/linux
echo $OHOS_SDK
# 下面的都是根据上面的环境变量来动态配置的,不需要改动
export PATH=${OHOS_SDK}/native/llvm/bin:${OHOS_SDK}/native/build-tools/cmake/bin:$PATH
export AS=${OHOS_SDK}/native/llvm/bin/llvm-as
export CC="${OHOS_SDK}/native/llvm/bin/clang --target=aarch64-linux-ohos"
export CXX="${OHOS_SDK}/native/llvm/bin/clang++ --target=aarch64-linux-ohos"
export LD=${OHOS_SDK}/native/llvm/bin/ld.lld
export STRIP=${OHOS_SDK}/native/llvm/bin/llvm-strip
export RANLIB=${OHOS_SDK}/native/llvm/bin/llvm-ranlib
export OBJDUMP=${OHOS_SDK}/native/llvm/bin/llvm-objdump
export OBJCOPY=${OHOS_SDK}/native/llvm/bin/llvm-objcopy
export NM=${OHOS_SDK}/native/llvm/bin/llvm-nm
export AR=${OHOS_SDK}/native/llvm/bin/llvm-ar
export CFLAGS="-fPIC -D__MUSL__=1"
export CXXFLAGS="-fPIC -D__MUSL__=1"

上面在设置完全局环境变量后,我们再执行$CC -v命令可以查询到clang的版本号,就说明设置成功了,到此为止,编译环境就全部准备就绪,接下来就可以进行编译移植了。
3.4 编译libnghttp2命令集:
源码的原始仓库维护在github上,我们直接使用git clone下载下来:
wget https://github.com/nghttp2/nghttp2/releases/download/v1.68.0/nghttp2-1.68.0.tar.gz
tar xf nghttp2-1.68.0.tar.gz

配置编译规则,通过configure脚本指定目标架构、安装路径、依赖等,核心参数说明,完整配置命令:
CC="$CC $CFLAGS" ./configure --host=aarch64-unknown-linux-musl --prefix=`pwd`/nghttp2_target
- aarch64-unknown-linux-musl:目标架构(对应鸿蒙PC的aarch64-linux-ohos)
- –prefix:指定安装路径(建议设为源码目录下的target,方便后续引用)

使用make命令进行编译(多线程编译,可根据CPU核心数调整-j后的数字,加快编译速度):
make


使用make install命令安装到指定路径(–prefix指定的target目录,这里是当前源码目录下的nghttp2_target目录):
make install


- 1.configure是GNU Autotools生成的配置脚本,核心作用是检测环境、适配平台、生成Makefile,新手只需掌握“配置→编译→安装”核心三步;
- 2.鸿蒙PC交叉编译的核心是通过–host=aarch64-linux-ohos指定目标架构,并提前配置鸿蒙PC SDK的交叉编译器环境变量;
- 3.鸿蒙PC编译需确保编译器、依赖库均为适配鸿蒙PC的aarch64版本,避免混用x86架构的工具或依赖。
3.5 确认编译产物:
安装完成后,进入target目录,会看到以下核心产物(适配aarch64-linux-ohos架构):
lib/:库文件目录,包含libnghttp2.so,核心文件。
bin/:工具目录,包含鸿蒙PC版可执行文件(用于验证库可用性),但是这时空的,是因为这个库不是可执行程序。

因为这个库不是可执行程序,所以不能直接运行,所以,我们这里可以手写一个C的程序来验证一下库是否可用:
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <nghttp2/nghttp2.h>
int main(int argc, char **argv) {
nghttp2_session_callbacks *callbacks = NULL;
nghttp2_session *session = NULL;
nghttp2_session_callbacks_new(&callbacks);
nghttp2_session_client_new(&session, callbacks, NULL);
nghttp2_settings_entry iv[1];
iv[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
iv[0].value = 100;
nghttp2_submit_settings(session, NGHTTP2_FLAG_NONE, iv, 1);
const char *path = "/";
const char *host = "www.baidu.com";
const char *scheme = "https";
if (argc > 1) path = argv[1];
if (argc > 2) host = argv[2];
nghttp2_nv hdrs[] = {
{(uint8_t *)":method", (uint8_t *)"GET", 7, 3, NGHTTP2_NV_FLAG_NONE},
{(uint8_t *)":path", (uint8_t *)path, 5, (uint16_t)strlen(path), NGHTTP2_NV_FLAG_NONE},
{(uint8_t *)":scheme", (uint8_t *)scheme, 7, (uint16_t)strlen(scheme), NGHTTP2_NV_FLAG_NONE},
{(uint8_t *)":authority", (uint8_t *)host, 10, (uint16_t)strlen(host), NGHTTP2_NV_FLAG_NONE},
{(uint8_t *)"accept", (uint8_t *)"*/*", 6, 3, NGHTTP2_NV_FLAG_NONE},
};
int32_t stream_id = nghttp2_submit_request(session, NULL, hdrs, sizeof(hdrs)/sizeof(hdrs[0]), NULL, NULL);
const uint8_t *data;
ssize_t len = nghttp2_session_mem_send(session, &data);
if (len < 0) {
fprintf(stderr, "mem_send error: %zd\n", len);
nghttp2_session_del(session);
nghttp2_session_callbacks_del(callbacks);
return 1;
}
const nghttp2_info *info = nghttp2_version(0);
printf("nghttp2 version: %s\n", info->version_str);
printf("stream id: %d\n", (int)stream_id);
printf("encoded length: %zd\n", len);
for (ssize_t i = 0; i < len; ++i) {
printf("%02X", data[i]);
}
printf("\n");
nghttp2_session_del(session);
nghttp2_session_callbacks_del(callbacks);
return 0;
}
以上代码的作用是,创建一个简单的 HTTP/2 客户端会话,构造一个 GET 请求并序列化到内存中。这里不涉及网络通信,仅用于演示库的 API 使用和功能验证。
- 1.初始化一个 HTTP/2 客户端会话,设置一个简单的 SETTINGS 参数。
- 2.构造一个带伪首部字段的 GET 请求(:method/:path/:scheme/:authority)。
- 3.将当前待发送的 HTTP/2 帧序列化到内存中,并以十六进制打印出来。
- 4.不进行任何网络连接或收发,仅展示“会话打包出的字节”。
接下来我们使用鸿蒙PC的clang进行编译,将上面写的C程序编译成可执行文件:
/root/harmonypc/linux/native/llvm/bin/clang --target=aarch64-linux-ohos\
-I /root/test/nghttp2-1.68.0/nghttp2_target/include \
/root/test/main.c \
-L /root/test/nghttp2-1.68.0/nghttp2_target/lib \
-lnghttp2 \
-static -o /root/test/hello_nghttp2
这里最后打包的文件为hello_nghttp2,将hello_nghttp2拷贝到鸿蒙PC的/root目录下。
3.6 鸿蒙PC端验证:
所有文件拷贝到鸿蒙PC之后,启动终端,执行binary-sign-tool命令分别对hello_nghttp2进行自签名。
先需要进行签名部署,在鸿蒙 PC 上部署的程序和库文件完成后,需要进行 签名 操作,保证安全性与系统兼容性:
binary-sign-tool sign -inFile \xxxx\hello_nghttp2 -outFile \xxxx\hello_nghttp2 -selfSign "1"

如果出现 “Permission denied” 等错误,需要检查当前用户是否有足够的权限执行这些操作,或者尝试使用sudo来提升权限,我这里使用chmod 755 命令来修改文件权限。
接下来执行hello_nghttp2程序:

至此,鸿蒙PC版的libnghttp2编译移植完成。
四、错误处理:
4.1 错误1:Relocations in generic ELF (EM:183) error adding symbols:file in wrong format
在编译鸿蒙PC版的libnghttp2时,configure已经顺利通过,但是执行make命令编译时,最后链接阶段遇到如下报错:

从日志看,编译器使用的ohos sdk的clang,但是最终链接so时,链接器没有使用ohos sdk的lld,而是用了系统的ld,即使我们定义了LD环境变量也不起作用,就导致了最终的链接失败。在CFLAGS里指定了–target=aarch64-linux-ohos架构,但是libtool并没有去使用它,导致平台架构判断失败,使用了错误的链接器。要解决这个问题,需要在执行configure命令时,给CC环境变量强制追加一个–target=aarch64-linux-ohos,参考命令如下所示,我们将预先定义好的CFLAGS环境变量追加给CC环境变量即可:
CC="$CC $CFLAGS" ./configure --host=aarch64-unknown-linux-musl --prefix=`pwd`/nghttp2_target
重新执行./configure之后,重新运行make命令,就可以顺利编译通过了。
4.2 错误2:checking host system type… Invalid configuration aarch64-linux-ohos': OS ohos’ not recognized:
ds -c and -o together... yes
checking for stdio.h... yes
checking for stdlib.h... yes
checking for string.h... yes
checking for inttypes.h... yes
checking for stdint.h... yes
checking for strings.h... yes
checking for sys/stat.h... yes
checking for sys/types.h... yes
checking for unistd.h... yes
checking for wchar.h... yes
checking for minix/config.h... no
checking for vfork.h... no
checking whether it is safe to define __EXTENSIONS__... yes
checking whether _XOPEN_SOURCE should be defined... no
checking build system type... x86_64-pc-linux-gnu
checking host system type... Invalid configuration `aarch64-linux-ohos': OS `ohos' not recognized
configure: error: /bin/bash ././config.sub aarch64-linux-ohos failed
基于OHOS SDK环境,对某些C/C++应用进行交叉编译时需要指定–host=aarch64-linux-ohos参数,以便configure能正常识别目标平台架构和编译器等信息,在编译命令时遇到了一个报错:

在执行configure过程中,调用了/bin/bash ./build-aux/config.sub aarch64-linux-ohos,但是脚本不识别ohos这个配置,导致configure失败,更换host为aarch64-unknown-linux-musl,更换–host参数,重新执行configure命令:
CC="$CC $CFLAGS" ./configure --host=aarch64-unknown-linux-musl --prefix=`pwd`/nghttp2_target
五、总结:
鉴于鸿蒙操作系统(HarmonyOS)是一种与Windows、Linux及macOS等传统操作系统不同的新型平台,其软件架构和EABI(Embedded Application Binary Interface)等特性均采用了全新的设计,本次移植的核心是“配置正确的交叉编译环境+解决系统识别与依赖问题”,通过掌握configure的核心逻辑后,无论是本地编译还是鸿蒙PC交叉编译,核心都是让configure“认对”目标平台(鸿蒙PC)、“找对”编译器(鸿蒙PC SDK版)、“配对”依赖库(鸿蒙PC适配版),就能快速编译出可在鸿蒙PC上运行的程序。
更多推荐




所有评论(0)