☰
nghttp2 在 Debian 上交叉编译 Android 二进制:NDK 工具链、依赖库与 android-config 完整实战指南
2026/10/13 2:36:23 网站建设 项目流程
  • 网络
  • 通信
  • 后端

【免费下载链接】nghttp2

nghttp2 - HTTP/2 C Library and tools

项目地址:https://gitcode.com/gh_mirrors/ng/nghttp2
点击查看免费下载

导读:本文基于 nghttp2 仓库官方文档 building-android-binary.rst,系统讲解如何在 Debian Linux 上使用 Android NDK 交叉编译 nghttp2,产出nghttpx、nghttpd、nghttp等可直接部署到 Android 设备的可执行文件。读者将掌握两条完整路径:一条是使用仓库自带的 Dockerfile.android 一键构建,另一条是手动配置 NDK 环境变量、交叉编译 OpenSSL/libev/c-ares/zlib 四大依赖库、运行 android-config 并最终用llvm-strip瘦身产物的全流程,同时深入理解 android-env 脚本背后各工具链变量(TARGET/API/CC/AR 等)的真实含义。

一、总体构建思路:两种可行路径

nghttp2 的 Android 交叉编译本质上是"用一个目标架构的工具链,把 nghttp2 及其依赖库全部编译成静态库/静态二进制"。官方文档给出了两种方式:

  1. Docker 一键构建:使用仓库根目录下的 Dockerfile.android(推荐,最省事)。该镜像内部已经固化了 NDK 版本、依赖库版本、目标架构与全部编译步骤,构建完成后直接从容器中拷贝产物即可。
  2. 手动构建:自己下载 NDK、设置环境变量,逐一编译 OpenSSL、libev、c-ares、zlib,最后编译 nghttp2 本身。下文 2~6 节详述该路径。

无论走哪条路径,最终结果都是src/目录下生成的nghttpx、nghttpd、nghttp等二进制(见 src/Makefile.am 中bin_PROGRAMS += nghttp nghttpd nghttpx的定义)。

二、准备工作:解压 NDK 并设置环境变量

手动构建的第一步是获取并解压 Android NDK。以$NDK_VERSION表示 NDK 版本号(仓库 Dockerfile.android 当前使用r27c):

$ unzip android-ndk-$NDK_VERSION-linux.zip $ cd android-ndk-$NDK_VERSION $ export NDK=$PWD

这里NDK环境变量必须指向NDK 解压后的根目录,后续所有脚本(android-env、android-config)都会依赖它。在运行任何构建脚本之前,务必确认:

$ echo $NDK # 必须输出非空且正确的 NDK 路径

2.1 第二个必需变量:NGHTTP2

除了NDK,还需要设置NGHTTP2环境变量,指向nghttp2 源码目录的绝对路径(注意与NDK不同,它指的是仓库本身的位置):

$ export NGHTTP2=$PWD # 在 nghttp2 源码根目录下执行

2.2 准备 Debian 宿主环境

手动构建需要以下宿主工具,文档与 Dockerfile.android 中apt-get install的清单可以互相印证:

$ sudo apt-get install unzip make binutils autoconf automake autotools-dev \ libtool pkg-config git curl dpkg-dev libc6-i386 lib32stdc++6

其中dpkg-dev提供dpkg-architecture命令,用于自动探测宿主机的构建架构(下文所有--build参数都会用到)。

三、android-env:统一导出交叉编译工具链变量

仓库根目录的 android-env 脚本是整个手动流程的"公共头文件",被依赖库配置脚本和 android-config 共同引用。它完成三件事:校验 NDK、定义目标三元组、导出全套 LLVM 工具链变量。核心内容如下:

if [ -z "$NDK" ]; then echo 'No $NDK specified.' exit 1 fi export TOOLCHAIN=$NDK/toolchains/llvm/prebuilt/linux-x86_64 export TARGET=aarch64-linux-android export API=33 export AR=$TOOLCHAIN/bin/llvm-ar export CC=$TOOLCHAIN/bin/$TARGET$API-clang export CXX=$TOOLCHAIN/bin/$TARGET$API-clang++ export LD=$TOOLCHAIN/bin/ld export RANDLIB=$TOOLCHAIN/bin/llvm-ranlib export STRIP=$TOOLCHAIN/bin/llvm-strip export PREFIX=$NDK/usr/local

这些变量的含义与作用如下:

变量值(示例)作用
TOOLCHAIN$NDK/toolchains/llvm/prebuilt/linux-x86_64NDK 自带 LLVM 工具链的宿主路径(Linux x86_64 前缀)
TARGETaarch64-linux-android目标平台三元组,Android arm64-v8a 架构
API33Android API 级别(对应 Android 13),参与编译器名称拼装
CC$TOOLCHAIN/bin/aarch64-linux-android33-clangC 交叉编译器
CXX$TOOLCHAIN/bin/aarch64-linux-android33-clang++C++ 交叉编译器
AR$TOOLCHAIN/bin/llvm-ar静态库归档工具
RANDLIB$TOOLCHAIN/bin/llvm-ranlib静态库索引工具
LD$TOOLCHAIN/bin/ld链接器
STRIP$TOOLCHAIN/bin/llvm-strip符号剥离工具
PREFIX$NDK/usr/local所有依赖库的统一安装前缀(即"安装到 NDK 目录里")

关键设计点:PREFIX=$NDK/usr/local意味着所有依赖库都会被安装到 NDK 目录内部。这样后续 nghttp2 配置时,通过CPPFLAGS=-I$PREFIX/include、LDFLAGS=-L$PREFIX/lib、PKG_CONFIG_LIBDIR=$PREFIX/lib/pkgconfig就能统一找到头文件和静态库,无需额外维护多个安装路径。从源码结构看,这是刻意让"NDK 目录 + usr/local"充当一个自包含的 Android 交叉编译 sysroot 的做法。

四、依赖库交叉编译:OpenSSL、libev、c-ares、zlib

nghttp2 的 Android 构建需要若干第三方依赖,且全部必须用同一套 NDK 工具链交叉编译,并安装到$NDK/usr/local(即$PREFIX)下。官方明确建议将这些库构建为静态库(--disable-shared/--enable-static),理由是静态链接的部署更简单——最终只需分发单个可执行文件,不依赖 Android 设备上的动态库。

4.1 为什么 zlib 必须自己编译?

文档特别指出:虽然 zlib 随 Android NDK 一起分发,但它不属于 NDK 的公共 API,不能直接链接使用,因此必须为 Android 目标自行编译。额外的好处是,自己编译会顺带生成 zlib 的.pc(pkg-config)文件,方便后续通过PKG_CONFIG_LIBDIR机制被 nghttp2 的配置脚本自动发现。

4.2 关于 libxml2:当前明确禁用

nghttp2 的--with-libxml2选项默认是check(自动探测,见 configure.ac)。但在 Android 构建中,官方明确表示libxml2 支持目前处于禁用状态,后续的 android-config 脚本也直接传入了--without-libxml2。这与 Dockerfile 中的做法一致,读者无需为 Android 目标编译 libxml2。

4.3 编译 OpenSSL

OpenSSL 使用其自带的Configure脚本,并在源码目录内直接构建。先执行配置脚本:

#!/bin/sh . $NGHTTP2/android-env export ANDROID_NDK_HOME=$NDK export PATH=$TOOLCHAIN/bin:$PATH ./Configure no-shared --prefix=$PREFIX android-arm64

其中:

  • . $NGHTTP2/android-env:以 source 方式载入全部工具链变量;
  • export ANDROID_NDK_HOME=$NDK:OpenSSL 的 Android 配置流程依赖此变量定位 NDK;
  • export PATH=$TOOLCHAIN/bin:$PATH:确保clang、llvm-ar等工具可直接在 PATH 中找到;
  • no-shared:只生成静态库;
  • android-arm64:OpenSSL 内置的 Android arm64 配置目标。

配置完成后,执行构建与安装脚本(install_sw表示只安装软件部分、跳过文档,缩短构建时间):

#!/bin/sh . $NGHTTP2/android-env export PATH=$TOOLCHAIN/bin:$PATH make install_sw

注意:在 Dockerfile.android 中,OpenSSL 步骤与此等价,但使用了完整make && make install_sw,并显式传入--prefix=$PREFIX(Docker 场景下PREFIX=/root/usr/local)。

4.4 编译 libev

libev 是标准 autotools 项目,用configure脚本交叉编译。配置脚本:

#!/bin/sh . $NGHTTP2/android-env ./configure \ --host=$TARGET \ --build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \ --prefix=$PREFIX \ --disable-shared \ --enable-static \ CPPFLAGS=-I$PREFIX/include \ LDFLAGS=-L$PREFIX/lib

构建并安装:

make install

参数说明:

参数含义
--host=$TARGET目标运行平台为aarch64-linux-android
--build=$(dpkg-architecture -qDEB_BUILD_GNU_TYPE)自动探测 Debian 宿主机架构,与--host一起构成标准的交叉编译三元组
--disable-shared --enable-static只产出静态库
CPPFLAGS=-I$PREFIX/include让 libev 自身找得到先前装进$PREFIX的头文件
LDFLAGS=-L$PREFIX/lib链接时搜索$PREFIX/lib

4.5 编译 c-ares

c-ares 同样是 autotools 项目,配置方式与 libev 类似。配置脚本:

#!/bin/sh -e . $NGHTTP2/android-env ./configure \ --host=$TARGET \ --build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \ --prefix=$PREFIX \ --disable-shared

构建并安装:

make install

c-ares 提供异步 DNS 解析能力,是nghttpx进行域名解析时的重要依赖;同样只构建静态库(--disable-shared)。

4.6 编译 zlib

zlib 使用自己的configure脚本(非 autotools),交叉编译时需要把目标三元组通过HOST环境变量传入。配置脚本:

#!/bin/sh -e . $NGHTTP2/android-env export HOST=$TARGET ./configure \ --prefix=$PREFIX \ --libdir=$PREFIX/lib \ --includedir=$PREFIX/include \ --static

构建并安装:

make install

参数说明:

  • export HOST=$TARGET:zlib 的 configure 通过HOST环境变量感知目标平台;
  • --libdir=$PREFIX/lib与--includedir=$PREFIX/include:显式把库和头文件安装到$PREFIX对应子目录,配合--static生成静态库,同时产生.pc文件(这正是文档所说的"bonus")。

4.7 依赖库版本参考

Dockerfile.android 中固化的版本组合可以作为手动构建的参考:

依赖库Dockerfile 中使用版本
OpenSSL1.1.1w
libev4.33
zlib1.3.1
c-ares1.18.1

五、编译 nghttp2 本体:android-config + make

四个依赖库全部安装到$PREFIX后,即可编译 nghttp2 本身。仓库根目录的 android-config 脚本封装了 configure 步骤:

. ./android-env ./configure \ --disable-shared \ --host=$TARGET \ --build=`dpkg-architecture -qDEB_BUILD_GNU_TYPE` \ --without-libxml2 \ --disable-examples \ --disable-threads \ CPPFLAGS="-fPIE -I$PREFIX/include" \ PKG_CONFIG_LIBDIR="$PREFIX/lib/pkgconfig" \ LDFLAGS="-fPIE -pie -L$PREFIX/lib"

运行:

$ ./android-config $ make

各参数背后的实现逻辑(与 configure.ac 的定义互相印证):

参数configure.ac 中的定义作用
--disable-shared—只构建静态库/静态可执行文件,简化部署
--host=$TARGET—目标平台aarch64-linux-android
--build=$(dpkg-architecture -qDEB_BUILD_GNU_TYPE)—宿主构建平台自动探测
--without-libxml2--with-libxml2默认check(configure.ac)显式禁用 libxml2 支持
--disable-examples--enable-examples默认check(configure.ac)不构建 examples 目录下的示例程序
--disable-threads--disable-threads:Turn off threading in apps(configure.ac)关闭应用中的线程支持,Android 交叉环境下更简洁
CPPFLAGS="-fPIE -I$PREFIX/include"—-fPIE生成位置无关代码,Android 可执行文件必需;-I找到$PREFIX下依赖库头文件
PKG_CONFIG_LIBDIR="$PREFIX/lib/pkgconfig"—让 pkg-config 只从$PREFIX/lib/pkgconfig查找.pc(含 zlib 自带的那个)
LDFLAGS="-fPIE -pie -L$PREFIX/lib"—-pie链接为位置无关可执行文件,-L链接$PREFIX/lib下的静态库

补充说明:在 Docker 构建中(Dockerfile.android),还会额外传入--enable-app(明确要求构建 nghttp、nghttpd、nghttpx、h2load 等应用,见 configure.ac)以及LDFLAGS="-static-libstdc++ -static-libgcc ...",把 C++ 运行时也静态链入,进一步降低对 Android 系统库的依赖。手动场景如果希望强制构建全部应用,也可以自行加上--enable-app。

六、产物与瘦身:llvm-strip 剥离调试信息

编译完成后,应用二进制(如nghttpx)会生成在src/目录下。Android 可执行文件往往带有大量调试符号,体积偏大,因此官方建议用 NDK 自带的llvm-strip剥离调试信息:

$ $NDK/toolchains/llvm/prebuilt/linux-x86_64/bin/llvm-strip src/nghttpx

这条命令正是 android-env 中STRIP变量对应的工具。在 Docker 构建中,这一步会自动执行并对三个主要应用同时生效:

$STRIP src/nghttpx src/nghttpd src/nghttp

剥离后即可得到适合部署的 Android 二进制。

七、Docker 一键构建:Dockerfile.android 的使用

如果手动流程受限(例如缺少 Debian 环境或想保持构建环境可复现),官方推荐直接使用仓库根目录的 Dockerfile.android。

构建镜像:

$ sudo docker build -t nghttp2-android - < Dockerfile.android

构建成功后,Android 二进制位于容器内的/root/build/nghttp2(源码位于/root/build/nghttp2,二进制在其src/子目录)。可通过docker run挂载宿主目录并拷贝产物:

$ sudo docker run -v /path/to/dest:/out nghttp2-android cp /root/build/nghttp2/src/nghttpx /out

该 Dockerfile 的内部流程与手动路径完全对应,可视为手动步骤的"可执行版本":

  1. 基于ubuntu:24.04,安装 unzip、make、binutils、autoconf、automake、libtool、pkg-config、git、curl、dpkg-dev 等构建工具;
  2. 下载并解压android-ndk-r27c-linux.zip(ARG NDK_VERSION=r27c);
  3. 依次下载、配置、编译并安装 OpenSSL 1.1.1w、libev 4.33、zlib 1.3.1、c-ares 1.18.1 到PREFIX=/root/usr/local;
  4. git clonenghttp2 源码(NGHTTP2_VERSION=master,--recursive --shallow-submodules拉取子模块),执行autoreconf -i生成 configure,再以与 android-config 一致的参数编译;
  5. 最后用$STRIP对nghttpx、nghttpd、nghttp统一瘦身。

八、常见问题与排查要点

  • "No $NDK specified.":运行 android-env 或依赖库脚本时若出现该提示,说明NDK未设置或未 export,需先执行export NDK=$PWD(在 NDK 根目录)。
  • --build探测失败:确认 Debian 宿主机已安装dpkg-dev,dpkg-architecture -qDEB_BUILD_GNU_TYPE才能正常输出宿主三元组。
  • 头文件/库找不到:检查所有依赖库是否确实安装到了$PREFIX(即$NDK/usr/local)下,且 nghttp2 的CPPFLAGS/LDFLAGS/PKG_CONFIG_LIBDIR三个参数指向一致。
  • 链接期-fPIE/-pie相关错误:Android 可执行文件要求 PIE,务必保证编译与链接阶段都传入-fPIE/-pie(android-config 已内置)。
  • 体积过大:发布前用$STRIP(llvm-strip)剥离调试符号,必要时参考 Docker 场景追加-static-libstdc++ -static-libgcc静态链接 C++ 运行时。

九、小结

通过本文,读者可以从零开始在 Debian 上完成 nghttp2 的 Android 交叉编译:先解压 NDK 并设置NDK/NGHTTP2环境变量,借助 android-env 导出统一的 LLVM 交叉工具链;再按 OpenSSL → libev → c-ares → zlib 的顺序把依赖库以静态方式安装进$NDK/usr/local;随后运行 android-config 并make,最后用llvm-strip瘦身src/下的nghttpx、nghttpd、nghttp产物。若想跳过繁琐的手动步骤,直接使用 Dockerfile.android 即可获得相同结果的隔离构建环境。官方完整说明可随时查阅仓库文档 building-android-binary.rst。

  • 网络
  • 通信
  • 后端

【免费下载链接】nghttp2

nghttp2 - HTTP/2 C Library and tools

项目地址:https://gitcode.com/gh_mirrors/ng/nghttp2
点击查看免费下载

相关推荐

上一篇:SketchUp STL插件技术深度解析:3D打印工作流的高效实现方案
下一篇:WeNet C API 详解:基于 vosk 风格接口的统一 ASR 推理编程接口

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询