Kong 中 PCRE2 的 Bazel 构建机制详解:从版本锁定到 nginx --with-pcre-jit 的完整依赖链
本篇以 build/openresty/pcre/README.md 为核心,系统讲解 Kong 源码构建体系中 PCRE2 正则引擎的 Bazel 集成方案。读完本文,你将理解 Kong 如何从上游 rules_foreign_cc 示例改造出可复用的第三方依赖构建规则,如何在 .requirements 中锁定 PCRE2 版本与 SHA256 校验值,以及编译出的静态库如何被 OpenResty(nginx)通过 --with-pcre-jit 消费——这是理解 Kong 高性能路由匹配(正则路由)底层依赖构建的关键。
一、文档背景:Kong 为何要自己管理 PCRE 构建
build/openresty/pcre/README.md 虽然篇幅很短,但它记录了 Kong 构建体系中一个关键的工程决策:Kong 没有直接复用 Bazel 官方 rules_foreign_cc 项目中现成的第三方 C/C++ 库示例,而是基于该项目的示例做了针对性改造,改造点有两条:
- 版本号不再硬编码在构建规则里,而是从版本清单文件读取(README 中写作
requirements.txt,在本仓库实际落地为 build/.requirements); build_file路径更新为//build/openresty目录下的新位置,即 build/openresty/pcre/BUILD.pcre.bazel。
这个决策背后的原因是:Kong 的构建体系需要对 Nginx、LuaJIT、PCRE、OpenSSL、Brotli 等十余个底层依赖做统一、可复现的版本锁定。Kong 运行在 nginx(OpenResty)之上,nginx 的正则能力(location ~、rewrite、路由匹配)完全依赖 PCRE 库。Kong 的 changelog 清晰地记录了这条依赖线的演进:
- 3.7.0 将 PCRE 从遗留的 libpcre 8.45 升级到 libpcre2 10.43(见 bump-pcre.yml);
- 3.8.0 继续升级到 PCRE2 10.44(见 bump-pcre.yml);
- 当前未发布版本已升级到 PCRE2 10.45(见 bump-pcre.yml)。
PCRE2 相比 PCRE 1 是重大重写(API、内部结构均不兼容),Kong 选择跟随 nginx 上游完成迁移,而迁移能否在 x86_64/aarch64、Linux/macOS、原生/交叉编译等全矩阵下稳定复现,正是这套 Bazel 规则要解决的问题。
二、版本锁定:.requirements 如何成为唯一事实来源
README 提到的第一条改造——"从 requirements 文件读取版本"——在仓库中的实现链路是:
1. 版本清单文件 build/.requirements 中显式锁定:
PCRE=10.45
PCRE_SHA256=0e138387df7835d7403b8351e2226c1377da804e0737db0e071b48f07c9d12ee
2. 绑定仓库读取该文件:build/kong_bindings.bzl 通过 repository_rule 在分析阶段读取 @kong//:.requirements(第 7 行 ctx.read(Label("@kong//:.requirements"))),解析每一行 KEY=VALUE 后生成 variables.bzl 文件,其中第 69 行写出 KONG_VAR = { ... } 字典。这样所有 Bazel 规则都能以 KONG_VAR["PCRE"]、KONG_VAR["PCRE_SHA256"] 的形式引用版本,而无需知道文件细节。
3. 消费方:build/openresty/pcre/pcre_repositories.bzl 第 8 行直接 version = KONG_VAR["PCRE"]。
这种"单点锁定"设计的收益:升级 PCRE2 只需改 .requirements 两行(版本 + SHA256),配合 changelog 提交即可完成一次受控升级,且 SHA256 校验保证了供应链完整性。
三、源码获取:pcre_repositories 仓库规则
pcre_repositories.bzl 是一个标准的 http_archive 包装,核心逻辑(第 7–19 行):
def pcre_repositories():
version = KONG_VAR["PCRE"]
maybe(
http_archive,
name = "pcre",
build_file = "//build/openresty/pcre:BUILD.pcre.bazel",
strip_prefix = "pcre2-" + version,
sha256 = KONG_VAR["PCRE_SHA256"],
urls = [
"https://github.com/PCRE2Project/pcre2/releases/download/pcre2-" + version + "/pcre2-" + version + ".tar.gz",
],
)
要点解析:
maybe包装:确保该仓库规则在重复调用时幂等(openresty_repositories()之外的其他入口也可能触发它);build_file参数:这正是 README 提到的第二条改造——把 BUILD.pcre.bazel 作为"外挂 BUILD 文件"注入下载并解压后的 PCRE2 源码树中,让一份没有 Bazel 支持的纯 C 项目立刻变成可构建的外部仓库(仓库标签为@pcre);strip_prefix = "pcre2-" + version:源码包顶层目录会随版本变化(pcre2-10.45/),用版本号动态拼接保证剥离前缀始终正确;urls:指向 PCRE2 官方项目的 release 渠道,与 SHA256 成对使用。
该仓库规则由 build/openresty/repositories.bzl 中的 openresty_repositories() 统一编排,pcre_repositories() 是整个 OpenResty 依赖列表的第一个调用(第 33 行),随后依次是 OpenSSL、simdjson_ffi、atc_router、wasmx、brotli、snappy、ada 等,形成完整的底层依赖清单。
四、编译规则:BUILD.pcre.bazel 中的 cmake 目标
注入源码树的 BUILD.pcre.bazel 是整套规则的核心,它用 rules_foreign_cc 的 cmake 规则构建 PCRE2:
# pcre cmake detects cross compile automatically
cmake(
name = "pcre",
build_args = [
"--", # <- Pass remaining options to the native tool.
"-j" + KONG_VAR["NPROC"],
],
cache_entries = {
"CMAKE_C_FLAGS": "${CMAKE_C_FLAGS:-} -fPIC",
"PCRE2_SUPPORT_JIT": "ON", # enable JIT support for pcre2_jit_compile
"PCRE2_BUILD_PCRE2GREP": "OFF", # we don't need the cli binary
"PCRE2_BUILD_TESTS": "OFF", # test doesn't compile on aarch64-linux-gnu (cross)
"CMAKE_INSTALL_LIBDIR": "lib", # force distros that uses lib64 (rhel family) to use lib
},
lib_source = ":all_srcs",
out_static_libs = ["libpcre2-8.a"],
visibility = ["//visibility:public"],
)
逐条说明各参数的工程含义:
| 参数 | 作用 |
|---|---|
PCRE2_SUPPORT_JIT: ON |
启用 JIT 编译支持,生成 pcre2_jit_compile 能力。nginx 正则热点路径(路由匹配)可受益,且必须与 OpenResty 侧 --with-pcre-jit 配置配套(见第五节) |
PCRE2_BUILD_PCRE2GREP: OFF |
不构建 pcre2grep 命令行工具,网关只需要库 |
PCRE2_BUILD_TESTS: OFF |
源码注释说明原因:PCRE2 自带测试在 aarch64-linux-gnu 交叉编译环境下无法编译,因此关闭以避免交叉构建失败 |
CMAKE_C_FLAGS: ... -fPIC |
追加 -fPIC 位置无关代码标志,保证静态库可被动态链接进最终产物 |
CMAKE_INSTALL_LIBDIR: lib |
强制安装到 lib 而非 lib64,解决 RHEL 系发行版默认 lib64 导致的目录不一致问题 |
build_args 中的 -- 与 -j NPROC |
-- 之后的参数透传给 cmake 底层构建工具(make/ninja),NPROC 同样来自 .requirements 绑定,实现并行编译 |
out_static_libs = ["libpcre2-8.a"] |
声明产物为 8 位字符集的 PCRE2 静态库,供下游按名称消费 |
文件顶部的注释 # pcre cmake detects cross compile automatically 点出另一个设计事实:PCRE2 的 CMake 脚本能自动识别交叉编译目标(host ≠ target),因此 Kong 无需为 aarch64/x86_64 交叉场景额外传 CMAKE_SYSTEM_NAME 等变量,交叉构建的适配成本被上游工具链吸收。同目录的 BUILD.bazel 则用于声明本包内 .bzl/.bazel 文件在 Kong 主仓库侧的可见性。
五、消费端:OpenResty 如何把 PCRE 编进 nginx
PCRE 静态库最终被 build/openresty/BUILD.openresty.bazel 中的 configure_make 目标 openresty 消费,体现在三处:
1. configure 选项启用 JIT(第 127 行):
CONFIGURE_OPTIONS = [
"--with-pcre-jit",
...
这与第四节 PCRE2_SUPPORT_JIT=ON 形成闭环:PCRE 库侧编译了 JIT 能力,nginx 侧再以 --with-pcre-jit 打开对应的运行时开关。
2. 头文件与库路径指向 @pcre 的产物(第 149、152 行):
"--with-cc-opt=\"-I$$EXT_BUILD_DEPS/pcre/include\"",
"--with-ld-opt=\"-L$$EXT_BUILD_DEPS/pcre/lib\"",
$$EXT_BUILD_DEPS 是 rules_foreign_cc 提供的变量,指向依赖目标安装目录;pcre 子目录即上一节 cmake 规则 install 后的 include/ + lib/(其中 lib/ 正是 CMAKE_INSTALL_LIBDIR=lib 保证的目录)。同一组 --with-cc-opt/--with-ld-opt 也用于 OpenSSL 和 LuaJIT,体现了 Kong 对所有底层 C 依赖统一采用"外部静态库 + 路径注入"的集成模式。
3. 声明式依赖(第 327–330 行):
deps = [
"@openresty//:luajit",
"@openssl",
"@pcre",
]
通过 deps 声明后,Bazel 会自动把 @pcre 加入执行顺序与远程缓存的 action key,保证 PCRE 先于 OpenResty 构建,且版本变化(.requirements 改动)会正确触发重编译。
六、构建与验证路径
从源码结构看,开发者可用的验证入口包括:
- 单独构建 PCRE 目标:由于
BUILD.pcre.bazel被注入到外部仓库,实际构建标签是@pcre//:pcre(cmake规则名),产物为libpcre2-8.a; - 全链路构建:
@openresty//:openresty(configure_make规则名,见 BUILD.openresty.bazel 第 273–349 行)会按依赖顺序先构建@luajit、@openssl、@pcre,再执行 OpenResty 的configure && make && make install; - 调试辅助目标:同文件第 351 行起定义了
dev-just-make生成规则,用于在已 configure 的构建目录中快速重跑make && make install,适合修改 Nginx C 代码后的迭代验证。
完整的 Bazel 构建体系说明(包括交叉编译工具链、KONG_VAR 绑定机制等)可在 DEVELOPER.md 中继续查阅,其中"OpenResty system, including Nginx, LuaJIT, PCRE, etc."一节专门描述了该子系统的定位。PCRE 的许可文本也已按合规要求收录于仓库根目录的 COPYRIGHT 文件中。
七、小结
build/openresty/pcre/README.md 记录的是一次典型的"上游示例 → 生产化改造":Kong 在 rules_foreign_cc 官方示例基础上,把版本信息外置到 build/.requirements(当前锁定 PCRE2 10.45 并附 SHA256),把构建文件迁到 build/openresty/pcre/ 统一管理。围绕这份 README,整条链路是:
- kong_bindings.bzl 读取
.requirements生成KONG_VAR; - pcre_repositories.bzl 按版本拉取 PCRE2 源码并注入 BUILD.pcre.bazel;
cmake规则以 JIT ON、关闭 pcre2grep 与测试、强制lib目录等参数产出libpcre2-8.a;- BUILD.openresty.bazel 通过
--with-pcre-jit、-I/-L $$EXT_BUILD_DEPS/pcre/...与deps = ["@pcre"]将其集成进 nginx 可执行文件。
这套机制让 Kong 在保持与 nginx/OpenResty 上游正则能力同步演进(PCRE 8 → PCRE2 10.x)的同时,获得了跨平台、可复现、带完整性校验的底层依赖构建能力。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00