Skip to content

Commit 698b95e

Browse files
authored
feat(pkg): add compat.hiredis@1.2.0 + compat.redis-plus-plus (1.3.3 & 1.3.13) (#188)
* feat(pkg): add compat.hiredis@1.2.0 and compat.redis-plus-plus@1.3.13 * feat(pkg): redis-plus-plus@1.3.3 — pre-watershed structure via source-list union One descriptor now serves both sides of the 1.3.6 source-structure watershed: 1.3.13 (17 sync TUs) and 1.3.3 (15 TUs, no redis_uri.cpp/redlock.cpp, no hiredis_features.h). The union works because 1.3.3's TUs are a strict subset of 1.3.13's, so exactly two source globs match nothing there (a warning, not an error — same premise as compat.catch2's disjoint union). New member tests/examples/redis-plus-plus-v133 pins 1.3.3; both members pass the same offline RESP round-trip test under mcpp 2026.8.8.2. * fix(pkg): force-include <cstdint> for redis-plus-plus@1.3.3 — 'uint16_t' under vendored gcc/libstdc++ 1.3.3's utils.h declares uint16_t crc16(...) without including <cstdint> (upstream added it in 1.3.6+). clang's libc++ pulls it in transitively, but the linux-default (gcc, vendored libstdc++) CI leg does not: 'uint16_t' does not name a type. Package cxxflags -include cstdint fixes the package build on every leg (harmless for 1.3.13, which includes it itself), and the v133 member's [build] cxxflags covers its test TU (which includes <sw/redis++/redis++.h> first). Caught by CI: workspace linux default 0/1. * fix(pkg): move compat.redis-plus-plus to pkgs/c/ — <x> is the full-name initial, not the short name The repository rule is pkgs/<x>/<name>.lua with <x> = initial of the FULL package name (compat.* → c, docs/repository-and-schema.md). compat.redis-plus-plus was wrongly placed in pkgs/r/ (short-name initial); the compat namespace belongs in pkgs/c/ next to compat.hiredis. Resolution is path-independent, so this is purely the directory convention — README links, the member comment and the design doc updated in lock-step.
1 parent 6e452b9 commit 698b95e

10 files changed

Lines changed: 737 additions & 4 deletions

File tree

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# 新增 redis-plus-plus + hiredis 收录(compat 源码形态,双包)
2+
3+
**日期**: 2026-08-09
4+
**本仓**: `mcpplibs/mcpp-index`
5+
**目标**:
6+
1. 收录 [`sewenew/redis-plus-plus`](https://github.com/sewenew/redis-plus-plus) **1.3.13** —— C++ Redis 客户端(同步 API),
7+
文件 `pkgs/c/compat.redis-plus-plus.lua`
8+
2. 收录其依赖 [`redis/hiredis`](https://github.com/redis/hiredis) **1.2.0** —— C 客户端,文件 `pkgs/c/compat.hiredis.lua`
9+
3. 形态:两者均为 **Form A 源码 compat**;redis-plus-plus 额外带一个 Shape-E 特征
10+
(`hiredis_features.h``generated_files` 快照)。
11+
4. `tests/examples/redis-plus-plus/` 最小工程:离线迷你 RESP server 断言 PING/SET 全链路。
12+
13+
版本选型原则:**不追最新,选经典、泛用、下游依赖面最广的稳定版**。后续再按 xpm 追加多版本。
14+
15+
---
16+
17+
## 1. 版本选型(经典优先)
18+
19+
|| 选定 | 依据 |
20+
|---|---|---|
21+
| hiredis | **1.2.0**(2023-06) | Debian 12 / Ubuntu 24.04 稳定版即 1.2.0;vcpkg 长期默认;conan 收录;含 `redisEnableKeepAliveWithInterval` |
22+
| redis-plus-plus | **1.3.13**(2024-10) | 2025 快速迭代前的长期稳定版,vcpkg/conan 长期默认;API 与最新 1.3.15 一致;源码结构与 1.3.15 **逐字节一致**(`.cpp` 集合 diff 为空) |
23+
24+
SHA-256(均两次独立下载一致,无归档漂移):
25+
- hiredis 1.2.0:`82ad632d31ee05da13b537c124f819eb88e18851d9cb0c30ae0552084811588c`
26+
- redis-plus-plus 1.3.13:`678a61898ed72f0c692102c7ce103a1bcae1e6ff85a4ad03e6002c1ba8fe1e08`
27+
28+
## 2. 形态判定
29+
30+
- **hiredis → Form A(C 源码 compat)**:7 个 `.c`(上游 CMake `hiredis_sources` 原样)、头平铺、C99、无生成文件。
31+
唯一特殊点:上游安装布局是 `<inc>/hiredis/hiredis.h`,tarball 却是平铺 → 用 `generated_files` 写两个
32+
**薄包装头**(`mcpp_generated/include/hiredis/hiredis.h` = `#include <hiredis.h>`),先例:compat.opengl 的
33+
`GL/gl.h`、compat.glx-headers 的 `X11/Xpoll.h`。必须是**尖括号**形式(跳过包装头自身目录,落到真实头);
34+
`"..."` 形式会在包装目录里自包含。
35+
- **redis-plus-plus → Form A(C++ 源码 compat)+ Shape-E 特征**:17 个同步 TU(上游 CMake 核心清单 +
36+
`patterns/redlock.cpp`);`async_*.cpp`/`event_loop.cpp`/`tls/…` 不编。CMake 唯一会生成的头
37+
`hiredis_features.h`(从 `.h.in` configure_file 产出,`connection.h` 会包含)用 `generated_files` 快照:
38+
```lua
39+
["mcpp_generated/sw/redis++/hiredis_features.h"] = "#define REDIS_PLUS_PLUS_HAS_redisEnableKeepAliveWithInterval\n"
40+
```
41+
既非 header-only(需编译),也无 `.cppm`(非 Form C),上游无 mcpp 描述符(非 Form D)。
42+
43+
include 布局(镜像上游 target_include_directories):
44+
- hiredis:`{ "*", "mcpp_generated/include" }`
45+
- redis-plus-plus:`{ "*/src", "*/src/sw/redis++/cxx17", "*/src/sw/redis++/no_tls", "mcpp_generated" }`
46+
47+
## 3. 多版本友好性(已跨分水岭落地)
48+
49+
- hiredis 全部 1.x(1.2.0/1.3.0/1.4.1 已核实)源列表与布局一致 → 加版本 = xpm 加一行,`mcpp` 块不动。
50+
- redis-plus-plus **1.3.6+** 源列表与结构一致(1.3.13 vs 1.3.15 diff 为空)→ 加 1.3.14/1.3.15 = xpm 加一行。
51+
- **1.3.6 之前是分水岭,现已用「并集源列表」支持**:1.3.3 的同步核心是 15 个 TU(有 `shards.cpp`,缺
52+
`redis_uri.cpp``patterns/redlock.cpp`),且无 `hiredis_features.h`(生成的快照头只是不被包含)、
53+
`no_tls/tls.h` 是平铺的(`#include "tls.h"`,经 `*/src/sw/redis++/no_tls` include dir 命中)。因为 1.3.3 的
54+
TU 是 1.3.13 17-TU 列表的**严格子集**,同一份 `sources` 对两个版本都成立:1.3.3 上恰好两个 glob 零命中
55+
(警告而非错误)—— 与 compat.catch2 的「不相交并集」同款前提,这里更简单。复核新版本时须重查该子集关系
56+
(长期解:per-version build blocks,mcpp-community/mcpp#290)。
57+
58+
## 4. feature 评估
59+
60+
- **tls**:需 hiredis_ssl(`ssl.c`)+ OpenSSL;`compat.openssl` 仅 linux/macos,且 openssl 是 install()-驱动。
61+
v1 不做,留后续(可做成 hiredis `ssl` feature + redis-plus-plus `tls` feature)。
62+
- **async**:需 libuv,索引中无此包,需先加 `compat.libuv`。v1 不做。
63+
- **coro**:依赖 async。v1 不做。
64+
- 负向口径:不启用时 async/tls 符号应缺失(链接期 undefined reference)。
65+
66+
## 5. CN 镜像
67+
68+
本机无 `gtc`、无 `mcpp-res` 写权限 → 按 docs/cn-mirror.md 回退,**url 用纯字符串上游 GitHub release**
69+
(先例:compat.spdlog、tensorvia-cpu)。后续由维护者补 `{ GLOBAL, CN }` 表(sha 不变)。
70+
71+
## 6. 验证结论(已实测)
72+
73+
- 本地 `mcpp test -p redis-plus-plus`(1.3.13)与 `mcpp test -p redis-plus-plus-v133`(1.3.3)
74+
(2026.8.8.4 与 CI 钉版 2026.8.8.2 各跑一遍,后者冷沙箱):
75+
均为 `test result ok. 1 passed; 0 failed`,测试输出 `OK: PING -> PONG, SET -> OK` —— 同一描述符、同一测试,
76+
两个分水岭两侧的版本都构建、链接、运行通过。
77+
- 独立 clang++ 冒烟(-std=c++17 与 c++23):17/17 TU 编译通过;静态链接 hiredis 后,
78+
离线 ping 连接被拒场景抛 `sw::redis::IoError`(完整覆盖 URI 解析 → hiredis 连接 → 错误映射)。
79+
- lint 全绿:`mcpp xpkg parse`(本地与钉版)、`check_mirror_urls.lua``check_package_name.lua`
80+
`check_cross_package_refs.lua``check_platform_version_parity.lua`
81+
82+
## 7. 注意事项 / 风险
83+
84+
- Windows 腿本机无法实证:`-DNOMINMAX`(redis-plus-plus,上游 CMake 同款)、
85+
`-D_CRT_SECURE_NO_WARNINGS -DWIN32_LEAN_AND_MEAN -lws2_32 -lcrypt32`(hiredis,上游 CMake 同款)按先例写入,
86+
待 CI 三平台验证;测试用与 websocket 成员相同的跨平台 socket 抽象。
87+
- 测试自建迷你 RESP server(PING→+PONG、SET→+OK),无需 redis-server 进程、无网络依赖;
88+
带 5s 接收超时防 CI 挂起。
89+
- 纯字符串 url 的 GLOBAL 拉取在 CI 冷缓存下需要 GitHub 可达(与 spdlog 等成员相同条件)。
90+
- 加 1.3.3 后,消费者侧有两个成员:`redis-plus-plus`(钉 1.3.13)与 `redis-plus-plus-v133`(钉 1.3.3),
91+
各自覆盖分水岭一侧;1.3.3 构建会产生两个零命中 glob 警告(预期,catch2 v2 同款)。
92+
- **CI 修复(PR #188 实测)**:linux-default(gcc/vendored libstdc++)腿报
93+
`'uint16_t' does not name a type` —— 1.3.3 的 `utils.h``uint16_t` 却未包含 `<cstdint>`
94+
(1.3.6+ 才补)。包级 `cxxflags = { "-include", "cstdint" }` 修复包自身,v133 成员
95+
`[build] cxxflags` 修复测试 TU(先包含 redis++.h);对 1.3.13 无害。

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ Two kinds of packages live here:
3838
| Shape | Examples |
3939
|------|------|
4040
| Native module library (Form A) | [`mcpplibs.xpkg`](pkgs/x/xpkg.lua) · [`mcpplibs.tinyhttps`](pkgs/t/tinyhttps.lua) · [`tensorvia-cpu`](pkgs/t/tensorvia-cpu.lua) · [`ffmpeg`](pkgs/f/ffmpeg.lua) (module layer; sources compiled directly through `compat.ffmpeg`) · [`opencv`](pkgs/o/opencv.lua) (single repository: the module layer and the full OpenCV 5 source build both live in the package, and only this descriptor stays on the index side) · [`mcpplibs.grpc`](pkgs/g/grpc.lua) (gRPC 1.83.0 — the one library here that CANNOT be a compat descriptor: upstream publishes no self-contained source artifact, its tag archive carrying abseil/protobuf/re2/boringssl/zlib as empty submodule placeholders, so [grpc-m](https://github.com/mcpplibs/grpc-m)'s release tarball IS that artifact. It vendors only gRPC's own source and takes the five dependencies from this index, so a consumer that also uses protobuf links one copy rather than two) |
41-
| C-source compat (with `features`) | [`compat.cjson`](pkgs/c/compat.cjson.lua) · [`compat.zlib`](pkgs/c/compat.zlib.lua) |
42-
| C++-source compat, one depending on the other | [`compat.abseil`](pkgs/c/compat.abseil.lua) (151 TUs; a wildcard over `absl/**` trimmed by upstream's test/benchmark naming conventions) · [`compat.protobuf`](pkgs/c/compat.protobuf.lua) (the libprotobuf runtime, 79 TUs transcribed from upstream's own `src/file_lists.cmake`; declares `compat.abseil` as a dependency because protobuf's public headers include `absl/…`, and its `gzip` feature defines `HAVE_ZLIB` and pulls `compat.zlib`, while `upb` adds protobuf's 64-TU C runtime out of the same tarball. It also exposes **`protoc`** as a `kind = "bin"` target, so a consumer writing `tools = ["protoc"]` gets the compiler built for its own machine out of the same package it links — making a generator/runtime version mismatch inexpressible) · [`compat.re2`](pkgs/c/compat.re2.lua) (22 TUs, upstream's own `RE2_SOURCES`) |
41+
| C-source compat (with `features`) | [`compat.cjson`](pkgs/c/compat.cjson.lua) · [`compat.zlib`](pkgs/c/compat.zlib.lua) · [`compat.hiredis`](pkgs/c/compat.hiredis.lua) (the classic 1.2.0 — a 7-TU C build whose flat tarball headers get `hiredis/`-prefixed wrapper headers via `generated_files`, so consumers write `#include <hiredis/hiredis.h>` exactly like upstream's install layout) |
42+
| C++-source compat, one depending on the other | [`compat.abseil`](pkgs/c/compat.abseil.lua) (151 TUs; a wildcard over `absl/**` trimmed by upstream's test/benchmark naming conventions) · [`compat.protobuf`](pkgs/c/compat.protobuf.lua) (the libprotobuf runtime, 79 TUs transcribed from upstream's own `src/file_lists.cmake`; declares `compat.abseil` as a dependency because protobuf's public headers include `absl/…`, and its `gzip` feature defines `HAVE_ZLIB` and pulls `compat.zlib`, while `upb` adds protobuf's 64-TU C runtime out of the same tarball. It also exposes **`protoc`** as a `kind = "bin"` target, so a consumer writing `tools = ["protoc"]` gets the compiler built for its own machine out of the same package it links — making a generator/runtime version mismatch inexpressible) · [`compat.re2`](pkgs/c/compat.re2.lua) (22 TUs, upstream's own `RE2_SOURCES`) · [`compat.redis-plus-plus`](pkgs/c/compat.redis-plus-plus.lua) (redis++ 1.3.13 — the sync client, 17 TUs + `patterns/redlock.cpp`, depends on `compat.hiredis`; the one header CMake would generate, `hiredis_features.h`, is snapshotted via `generated_files`, and the async/TLS TUs are left out so the base build stays a two-package pair. Two versions, one on each side of the source-structure watershed, share this ONE source list: 1.3.13 (modern 17-TU layout) and 1.3.3 (pre-`redis_uri.cpp`/`redlock` 15-TU layout) — the union works because 1.3.3's TUs are a strict subset, so exactly two globs match nothing there (a warning, not an error; same trick as compat.catch2)) |
4343
| C++-source compat, zero-dep client + optional components | [`compat.websocket`](pkgs/c/compat.websocket.lua) (IXWebSocket 12.0.1 — a pure RFC 6455 client compiled from upstream's `IXWEBSOCKET_SOURCES` minus the four server TUs, so the **base build has zero external dependencies**: TLS off (the OpenSSL/MbedTLS/AppleSSL TUs aren't built) and `IXWEBSOCKET_USE_ZLIB` unset, so the gzip codec compiles to a no-op. Two optional features add on top: `server` (the four server TUs — `IXWebSocketServer`, `IXSocketServer`, `IXHttpServer`, `IXWebSocketProxyServer` — needing nothing external, and it **implies `zlib`** because upstream's server advertises permessage-deflate by default, which the transport negotiates regardless of the define) and `zlib` (deps `compat.zlib` and turns the codec into real per-message-deflate compression). The default-feature test brings its own minimal RFC 6455 echo server on loopback sockets (handshake, masking, fragmentation and close all exercised offline); a second member, `websocket-features`, runs a real `ix::WebSocketServer` and asserts the compression is observable on the wire — a 64 KiB repeated payload round-trips with `wireSize` = 80) |
4444
| header-only (with `features`) | [`compat.eigen`](pkgs/c/compat.eigen.lua) |
4545
| header-only, nothing to gate | [`compat.CLI11`](pkgs/c/compat.CLI11.lua) (a command line parser whose every definition is `CLI11_INLINE`, so the package is `*/include` plus an anchor TU. Upstream's two extras stay out: `src/Precompile.cpp` only means anything when `CLI11_COMPILE` also reaches the CONSUMER's translation units — an interface define, not a sources-only gate — and `src/modules/CLI11.cppm` is a module layer, which is a package shape of its own rather than a feature of the compat package) |

README.zh-CN.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ mcpp self config --mirror CN # 切换至国内镜像,默认使用 GLOBAL 上
3535
| 形态 | 示例 |
3636
|------|------|
3737
| 原生模块库(Form A) | [`mcpplibs.xpkg`](pkgs/x/xpkg.lua) · [`mcpplibs.tinyhttps`](pkgs/t/tinyhttps.lua) · [`tensorvia-cpu`](pkgs/t/tensorvia-cpu.lua) · [`ffmpeg`](pkgs/f/ffmpeg.lua)(模块层,源码经 `compat.ffmpeg` 直编) · [`opencv`](pkgs/o/opencv.lua)(单仓库:模块层与 OpenCV 5 全源码构建同在包内,索引侧只留本描述符) · [`mcpplibs.grpc`](pkgs/g/grpc.lua)(gRPC 1.83.0 —— 本索引里唯一**无法**做成 compat 描述符的库:上游不发布任何自包含源码产物,其 tag 归档里 abseil/protobuf/re2/boringssl/zlib 全是空 submodule 占位,因此 [grpc-m](https://github.com/mcpplibs/grpc-m) 的 release tarball 才是那个产物。它只 vendor gRPC 自己的源码,五个依赖全取自本索引,故同时直接使用 protobuf 的消费者链进去的是同一份而非两份)|
38-
| C 源码 compat(含 `features`) | [`compat.cjson`](pkgs/c/compat.cjson.lua) · [`compat.zlib`](pkgs/c/compat.zlib.lua) |
39-
| C++ 源码 compat(彼此依赖) | [`compat.abseil`](pkgs/c/compat.abseil.lua)(151 TU;对 `absl/**` 取通配后,按上游自身的 test/benchmark 命名约定裁剪) · [`compat.protobuf`](pkgs/c/compat.protobuf.lua)(libprotobuf 运行时,79 TU 逐条转录自上游 `src/file_lists.cmake`;因 protobuf 公开头文件 include 了 `absl/…`,故显式依赖 `compat.abseil`;`gzip` feature 定义 `HAVE_ZLIB` 并拉入 `compat.zlib`,`upb` feature 则从同一个 tarball 里再编出 protobuf 的 64 TU C 运行时;还以 `kind = "bin"` target 暴露 **`protoc`**,消费者写 `tools = ["protoc"]` 即可从「自己链接的那个包」拿到为本机构建的编译器,使生成器与运行时的版本错配无法表达) · [`compat.re2`](pkgs/c/compat.re2.lua)(22 TU,取自上游自身的 `RE2_SOURCES`) |
38+
| C 源码 compat(含 `features`) | [`compat.cjson`](pkgs/c/compat.cjson.lua) · [`compat.zlib`](pkgs/c/compat.zlib.lua) · [`compat.hiredis`](pkgs/c/compat.hiredis.lua)(经典 1.2.0 —— 7 个 C TU;tarball 平铺头经 `generated_files``hiredis/` 前缀薄包装头,消费者可写 `#include <hiredis/hiredis.h>`,与上游安装布局一致) |
39+
| C++ 源码 compat(彼此依赖) | [`compat.abseil`](pkgs/c/compat.abseil.lua)(151 TU;对 `absl/**` 取通配后,按上游自身的 test/benchmark 命名约定裁剪) · [`compat.protobuf`](pkgs/c/compat.protobuf.lua)(libprotobuf 运行时,79 TU 逐条转录自上游 `src/file_lists.cmake`;因 protobuf 公开头文件 include 了 `absl/…`,故显式依赖 `compat.abseil`;`gzip` feature 定义 `HAVE_ZLIB` 并拉入 `compat.zlib`,`upb` feature 则从同一个 tarball 里再编出 protobuf 的 64 TU C 运行时;还以 `kind = "bin"` target 暴露 **`protoc`**,消费者写 `tools = ["protoc"]` 即可从「自己链接的那个包」拿到为本机构建的编译器,使生成器与运行时的版本错配无法表达) · [`compat.re2`](pkgs/c/compat.re2.lua)(22 TU,取自上游自身的 `RE2_SOURCES`) · [`compat.redis-plus-plus`](pkgs/c/compat.redis-plus-plus.lua)(redis++ 1.3.13 —— 同步客户端,17 TU + `patterns/redlock.cpp`,依赖 `compat.hiredis`;CMake 唯一会生成的头 `hiredis_features.h` 用 `generated_files` 快照,async/TLS TU 不收,基座保持两包成对。两个版本分处源码结构分水岭两侧,共享同一份源列表:1.3.13(现代 17-TU 布局)与 1.3.3(缺 `redis_uri.cpp`/`redlock` 的 15-TU 旧布局)—— 并集之所以成立,是因为 1.3.3 的 TU 是 1.3.13 的严格子集,恰好两个 glob 在 1.3.3 上零命中(仅警告,非错误;与 compat.catch2 同款手法)) |
4040
| C++ 源码 compat(零依赖客户端 + 可选组件) | [`compat.websocket`](pkgs/c/compat.websocket.lua)(IXWebSocket 12.0.1 —— 从上游 `IXWEBSOCKET_SOURCES` 剔掉 4 个 server TU 后直编的纯 RFC 6455 客户端,**基座零外部依赖**:TLS 关闭(OpenSSL/MbedTLS/AppleSSL 三组 TU 均不编),`IXWEBSOCKET_USE_ZLIB` 不定义(gzip codec 编译为 no-op)。两个可选 feature 在基座上叠加:`server`(4 个 server TU —— `IXWebSocketServer`/`IXSocketServer`/`IXHttpServer`/`IXWebSocketProxyServer`,零新增外部依赖,且 **implies `zlib`** —— 因为上游 server 默认就宣称 permessage-deflate,而 transport 的协商不受宏门控)与 `zlib`(依赖 `compat.zlib`,把 codec 变成真正的 permessage-deflate 压缩)。默认构建的测试自带基于 loopback 原始 socket 的最小 RFC 6455 echo server(握手/掩码/分片/关闭全部离线实测);第二个成员 `websocket-features` 跑真实的 `ix::WebSocketServer`,并断言压缩在线路上可观测 —— 64 KiB 重复载荷往返,`wireSize` = 80) |
4141
| header-only(含 `features`) | [`compat.eigen`](pkgs/c/compat.eigen.lua) |
4242
| header-only(无可门控组件) | [`compat.CLI11`](pkgs/c/compat.CLI11.lua)(命令行解析器,全部定义都是 `CLI11_INLINE`,故整包就是 `*/include` 加一个 anchor TU。上游两个额外件都不收:`src/Precompile.cpp` 只有在 `CLI11_COMPILE` 同时到达**消费者** TU 时才有意义 —— 那是 interface define,不是 sources 门控;`src/modules/CLI11.cppm` 属于模块层,是另一种包形态,而非 compat 包的 feature) |

mcpp.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ members = [
5757
"tests/examples/opencv-module-dnn",
5858
"tests/examples/opencv-module-unifont",
5959
"tests/examples/re2",
60+
"tests/examples/redis-plus-plus",
61+
"tests/examples/redis-plus-plus-v133",
6062
"tests/examples/sdl2",
6163
"tests/examples/spdlog",
6264
"tests/examples/freetype",

0 commit comments

Comments
 (0)