Skip to content

Commit 70c49da

Browse files
authored
feat: add compat.c-ares 1.34.5 (#149)
The last index-side piece before grpc-m: with abseil, protobuf(+upb), re2 and now c-ares, the gRPC package has to vendor only gRPC's own source. WHY IT IS HERE AT ALL. An earlier plan was to ship the first gRPC without c-ares, since upstream has a sanctioned knob (grpc_no_ares=true → GRPC_ARES=0). That was the wrong call: gRPC enables c-ares by default and so does everyone else, and an index package should not quietly ship less than upstream. The shape is default-on, switchable off — grpc-m will carry Cargo-style `[features] default = ["ares"]` and consumers turn it off with `default-features = false`. It cannot be built the other way round. mcpp features are ADDITIVE, so putting -DGRPC_ARES=0 in the base flags and having the feature flip it to 1 would put both on the command line. The off-switch therefore lives in grpc-m's build.mcpp (emit GRPC_ARES=0 only when the feature is absent, and drop the 7 ares TUs), while the dependency stays declarative in [feature-deps.ares] — build.mcpp is explicitly not allowed to add a registry dependency. SHAPE. c-ares normally learns about its host from configure/CMake writing ares_config.h. That step is replaced by a frozen per-OS snapshot under generated_files — the same shape compat.ffmpeg / compat.curl / compat.sdl2 already use. The upstream RELEASE tarball (a `make dist` product, not the tag archive) already ships include/ares_build.h and src/lib/config-win32.h, so neither is synthesized here. The snapshots are gRPC 1.83.0's own third_party/cares/config_{linux,darwin, windows}/ares_config.h. Not borrowed at random: gRPC pins c-ares at exactly this release (submodule d3a507e == tag v1.34.5) and maintains those files precisely so the library can be built without c-ares' own build system. KNOWN TRADE-OFF, recorded rather than hidden: those snapshots are more conservative than 1.34.5's ares_config.h.cmake template — 96 of the template's 143 HAVE_* symbols, missing HAVE_EPOLL, HAVE_GETIFADDRS, HAVE_GETRANDOM, HAVE_IF_NAMETOINDEX among others. Missing means 0, so c-ares takes portable fallbacks (poll rather than epoll). All 91 TUs compile with zero warnings, so this is a performance/feature degradation, not a functional gap; regenerating richer snapshots from c-ares' own CMake is a follow-up. Flags are upstream's (gRPC third_party/cares/cares.BUILD). Two are load-bearing rather than hygiene: HAVE_CONFIG_H is what makes src/lib/ares_setup.h include ares_config.h at all, and _GNU_SOURCE is required on glibc — without it <unistd.h>/<string.h> hide gethostname, clock_gettime, strcasecmp and getservbyport_r, and four TUs fail with implicit-declaration errors. src/lib/**/*.c is safe to glob: upstream keeps tests and tools in test/ and src/tools/, and no TU under src/lib defines main(). Verified cold with the pinned mcpp 2026.8.3.3, gcc@16.1.0, MCPP_INDEX_MIRROR=GLOBAL, MCPP_BUILD_CACHE=local, target/ and .mcpp/ removed first: `test result ok`, 92 objects linked (91 sources + the test). The test is entirely OFFLINE — it never sends a DNS query, so it does not depend on the runner's name resolution. It covers library init/cleanup, a channel with options, a set/get round trip of the server list as CSV (real string + record parsing), ares_inet_pton/ntop both ways, and ares_strerror, and it asserts that malformed input is REJECTED (a bad server CSV, "999.1.1.1") — otherwise "parsing succeeded" would prove nothing. It also asserts the version is 1.34.5, so a silently different vendored version cannot pass. CN mirror published and closed-loop checked: mcpp-res/c-ares@1.34.5 returns http=200 and is byte-identical to GLOBAL. Cross-package basename check: c-ares collides with none of abseil / protobuf / upb / re2. Alongside this, gRPC 1.83.0 was compiled in full with mcpp's gcc@16.1.0 — 1001 TUs (999 gRPC sources + 2 third_party/address_sorting), including the resolver path that goes through this package's real headers and config snapshot. The only extra include dirs needed are third_party/address_sorting/ include and third_party/xxhash, both of which have real content in gRPC's own tree, and the only file that must be excluded is src/core/ext/upb-gen/google/protobuf/descriptor.upb_minitable.c — byte-for-byte identical to the bootstrap copy compat.protobuf's upb feature already brings.
1 parent 320d024 commit 70c49da

7 files changed

Lines changed: 1603 additions & 2 deletions

File tree

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# 新增 compat.c-ares 1.34.5(2026-08-04)
2+
3+
[gRPC 收录可行性分析](2026-08-04-grpc-feasibility-analysis.md) P1 索引侧的最后一块,承接
4+
[abseil+protobuf](2026-08-04-add-abseil-and-protobuf-plan.md)
5+
[re2+upb](2026-08-04-add-re2-and-protobuf-upb-plan.md)。至此 `grpc-m` 的全部索引依赖备齐。
6+
7+
产出:`compat.c-ares@1.34.5`,91 TU,workspace 成员 `tests/examples/c-ares`
8+
9+
## 1. 为什么默认要有它
10+
11+
一度打算第一版跳过 c-ares(上游确有官方裁剪开关 `grpc_no_ares=true``GRPC_ARES=0`)。**这个决定被推翻了**:
12+
gRPC 上游默认就是启用 c-ares,行业惯例也如此,索引里的包不应该悄悄比上游少一块。正确形态是
13+
**默认开启 + 可关闭** —— `grpc-m` 用 Cargo 式 `[features] default = ["ares"]`,消费者以
14+
`default-features = false` 关掉。
15+
16+
方向不能反过来:mcpp 的 feature 是**只增不减**的,若把 `-DGRPC_ARES=0` 写进基础 flag 再让 feature
17+
翻成 1,两个 `-DGRPC_ARES` 会同时出现在命令行。关闭那一侧因此由 `grpc-m``build.mcpp` 承担
18+
(`mcpp::has_feature("ares")` 为假时才发 `GRPC_ARES=0` 并剔除对应 TU),依赖仍走
19+
`[feature-deps.ares]`(build.mcpp 明确不允许添加注册表依赖)。
20+
21+
## 2. 形态:只缺一个 ares_config.h
22+
23+
c-ares 平时靠 configure/CMake 生成 `ares_config.h`。本包用**冻结的按 OS 快照**替代该步骤,即
24+
`compat.ffmpeg` / `compat.curl` / `compat.sdl2` 已经在用的形态。
25+
26+
上游 release tarball(`make dist` 产物,不是 tag 归档)已经提供了另外两样,因此**不需要**合成:
27+
28+
- `include/ares_build.h` —— 已是生成好的成品;
29+
- `src/lib/config-win32.h` —— Windows 的备用配置。
30+
31+
快照直接取自 gRPC 1.83.0 的 `third_party/cares/config_{linux,darwin,windows}/ares_config.h`
32+
这不是随手挪用:gRPC 把 c-ares 精确 pin 在同一个 release(submodule `d3a507e` == tag `v1.34.5`),
33+
这三个文件正是它为"不跑 c-ares 自己的构建系统"而维护的,并在其自身 CI 的三平台上长期使用。
34+
35+
**已知取舍(如实记录)**:这三份快照比 1.34.5 的 `ares_config.h.cmake` 模板保守 —— 模板有 143 个
36+
`HAVE_*`,快照只给出 96 个,缺的包括 `HAVE_EPOLL``HAVE_GETIFADDRS``HAVE_GETRANDOM`
37+
`HAVE_IF_NAMETOINDEX` 等。缺失项一律按 0 处理,c-ares 因此走可移植的退化路径(如 poll 而非 epoll)。
38+
实测**91/91 TU 编译通过、零警告**,所以这是**性能/特性层面的退化,不是功能不可用**。日后可用
39+
c-ares 自己的 CMake 重新生成更完整的快照。
40+
41+
## 3. 编译开关照抄上游
42+
43+
`cflags` 取自 gRPC 的 `third_party/cares/cares.BUILD`:
44+
45+
- `CARES_STATICLIB` —— 选择静态链接的 declspec;
46+
- `HAVE_CONFIG_H` —— **没有它 `src/lib/ares_setup.h` 根本不会去 include `ares_config.h`**;
47+
- `_GNU_SOURCE` —— 在 glibc 上是**功能性必需**:缺了它 `<unistd.h>`/`<string.h>` 不声明
48+
`gethostname``clock_gettime``strcasecmp``getservbyport_r`,实测有 4 个 TU 直接报
49+
implicit-declaration 错误;
50+
- `_HAS_EXCEPTIONS=0`
51+
52+
Windows 另加 `NOMINMAX` / `_CRT_SECURE_NO_DEPRECATE` / `_CRT_NONSTDC_NO_DEPRECATE` /
53+
`_WIN32_WINNT=0x0600`,并链 `ws2_32` + `iphlpapi`;macOS 因快照定义了 `HAVE_LIBRESOLV` 而链 `-lresolv`;
54+
linux 链 `-lpthread`
55+
56+
`src/lib/**/*.c` 可以放心通配:上游把测试与工具放在 `test/``src/tools/`,该目录下**没有任何
57+
TU 定义 `main()`**(已核对)。
58+
59+
## 4. 验证结论
60+
61+
与 CI 一致的配置(mcpp **2026.8.3.3**、gcc@16.1.0、`MCPP_INDEX_MIRROR=GLOBAL`
62+
`MCPP_BUILD_CACHE=local`),先删 `target/``.mcpp/` 冷构建:
63+
64+
```
65+
c-ares test result ok. 1 passed; 0 failed
66+
objects: 92 (= 91 源 + 1 测试)
67+
```
68+
69+
- **测试全程离线**,不发任何 DNS 查询,因此不依赖 runner 的网络状况。覆盖面按"每一项落在库的不同部分"
70+
挑选:`ares_library_init/cleanup``ares_init_options`+`ares_destroy`
71+
CSV 服务器列表的**设置与回读往返**(真正走字符串与记录解析)、`ares_inet_pton/ntop` 双向、
72+
`ares_strerror`。并且断言**畸形输入必须被拒**(非法服务器 CSV、`999.1.1.1`),否则前面的"解析成功"
73+
什么也证明不了。版本号也断言到 1.34.5,避免悄悄换版本还能通过。
74+
- **CN 镜像已闭环**:`mcpp-res/c-ares@1.34.5` 返回 `http=200` 且与 GLOBAL **字节一致**
75+
- **跨包 basename 撞名检查**:c-ares 与索引中已有的 abseil / protobuf / upb / re2 **零撞名**
76+
(顺带记录:其余包之间存在若干撞名,如 abseil×protobuf 的 `parser.cc`、abseil×gRPC 的
77+
`status.cc`/`time.cc`,mcpp 会做嵌套消歧,且 CI 已用 `MCPP_BUILD_CACHE=local` 绕开 mcpp#344
78+
的缓存键问题 —— 见 [re2+upb 文档](2026-08-04-add-re2-and-protobuf-upb-plan.md) §6.2。)
79+
80+
## 5. gRPC 整库编译验证(索引侧到此为止的意义)
81+
82+
在本包落地的同时,已用 mcpp 的 gcc@16.1.0 对 gRPC 1.83.0 做了**全量编译验证**:
83+
84+
```
85+
1001 个 TU 全部通过(999 个 gRPC 源 + 2 个 third_party/address_sorting)
86+
```
87+
88+
其中包含走**真实 c-ares 头文件与本包配置快照**的解析器路径。所需的额外 include 只有
89+
`third_party/address_sorting/include``third_party/xxhash`(纯头),两者都在 gRPC 自带的
90+
third_party 里有实体内容。gRPC 的 1000 个源文件**没有一个来自 third_party**,因此 `grpc-m`
91+
只需 vendor `src/` + `include/`,abseil/protobuf/re2/c-ares/openssl 全部由索引提供。
92+
93+
唯一必须排除的是 `src/core/ext/upb-gen/google/protobuf/descriptor.upb_minitable.c` ——
94+
它与 `compat.protobuf``upb` feature 带入的 bootstrap 版本**逐字节完全相同**,同时编入会重复符号。

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ Two kinds of packages live here:
4242
| 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) · [`compat.re2`](pkgs/c/compat.re2.lua) (22 TUs, upstream's own `RE2_SOURCES`) |
4343
| header-only (with `features`) | [`compat.eigen`](pkgs/c/compat.eigen.lua) |
4444
| Runtime loader compat (pure sources, sidestepping upstream codegen/asm) | [`compat.vulkan`](pkgs/c/compat.vulkan.lua) (the Khronos loader: `loader/generated/` is checked in, and the assembly path degrades to plain C through `UNKNOWN_FUNCTIONS_SUPPORTED`, so no CMake/Python/assembler is needed; windows deferred) · [`compat.vulkan-headers`](pkgs/c/compat.vulkan-headers.lua) |
45-
| Whole-source direct build + generated config (only where a platform lacks one) | [`compat.curl`](pkgs/c/compat.curl.lua) (win32 uses upstream's checked-in config, unix generates one) · [`compat.sdl2`](pkgs/c/compat.sdl2.lua) (win/mac use upstream's checked-in config; linux generates one and enables X11 by hand) |
45+
| Whole-source direct build + generated config (only where a platform lacks one) | [`compat.curl`](pkgs/c/compat.curl.lua) (win32 uses upstream's checked-in config, unix generates one) · [`compat.sdl2`](pkgs/c/compat.sdl2.lua) (win/mac use upstream's checked-in config; linux generates one and enables X11 by hand) · [`compat.c-ares`](pkgs/c/compat.c-ares.lua) (91 TUs; the release tarball already ships `ares_build.h` and a Windows config, so only `ares_config.h` is snapshotted per OS) |
4646
| Upstream codegen frozen into the mirror archive | [`compat.godot-cpp`](pkgs/c/compat.godot-cpp.lua) (two versions: `4.5.0` = the `godot-4.5-stable` bindings, `10.0.0-rc1` = godot-cpp's own 10.x line, whose bindings target Godot 4.6. The ~1000 GDExtension classes under `gen/` exist in no upstream tag archive — upstream's `binding_generator.py` emits them at build time. Running it once offline and publishing upstream's tree byte-for-byte **plus** `gen/` keeps Python off the consumer side entirely; `tools/godot-cpp/repack.sh` reproduces the archive deterministically and refuses to publish if any upstream file differs) |
4747
| Header package filling a gap in the index | [`compat.glx-headers`](pkgs/c/compat.glx-headers.lua) (libglvnd's `GL/glx.h`, absent from the Khronos registry and required by SDL's X11 backend) |
4848
| C++ application framework compat (dependencies reuse packages already in the index) | [`compat.eui-neo`](pkgs/e/compat.eui-neo.lua) (upstream's `3rd/` ships 8 vendored dependencies; none of them is compiled here — all are redirected to the same-version `compat.*` packages in this index) |

README.zh-CN.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ mcpp self config --mirror CN # 切换至国内镜像,默认使用 GLOBAL 上
3939
| 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 运行时) · [`compat.re2`](pkgs/c/compat.re2.lua)(22 TU,取自上游自身的 `RE2_SOURCES`) |
4040
| header-only(含 `features`) | [`compat.eigen`](pkgs/c/compat.eigen.lua) |
4141
| 运行时 loader compat(纯源码,绕开上游 codegen/asm) | [`compat.vulkan`](pkgs/c/compat.vulkan.lua)(Khronos loader:`loader/generated/` 已签入,汇编路径经 `UNKNOWN_FUNCTIONS_SUPPORTED` 降级为纯 C,故无需 CMake/Python/汇编器;windows 延后)· [`compat.vulkan-headers`](pkgs/c/compat.vulkan-headers.lua) |
42-
| 全源码直编 + 生成 config(仅缺口平台) | [`compat.curl`](pkgs/c/compat.curl.lua)(win32 用上游签入 config,unix 生成) · [`compat.sdl2`](pkgs/c/compat.sdl2.lua)(win/mac 用上游签入 config,linux 生成 + 手工开 X11) |
42+
| 全源码直编 + 生成 config(仅缺口平台) | [`compat.curl`](pkgs/c/compat.curl.lua)(win32 用上游签入 config,unix 生成) · [`compat.sdl2`](pkgs/c/compat.sdl2.lua)(win/mac 用上游签入 config,linux 生成 + 手工开 X11) · [`compat.c-ares`](pkgs/c/compat.c-ares.lua)(91 TU;release tarball 已自带 `ares_build.h` 与 Windows 配置,故只需按 OS 冻结 `ares_config.h`) |
4343
| 上游 codegen 前置冻结进镜像归档 | [`compat.godot-cpp`](pkgs/c/compat.godot-cpp.lua)(两个版本:`4.5.0``godot-4.5-stable` 的绑定,`10.0.0-rc1` 是 godot-cpp 自己的 10.x 线、对应 Godot 4.6。`gen/` 下约 1000 个 GDExtension 类不在任何上游 tag 归档里,由上游 `binding_generator.py` 在构建时生成。改为离线跑一次,把上游源码树逐字节原样 **加上** `gen/` 一起发布,消费侧就完全不需要 Python;`tools/godot-cpp/repack.sh` 可确定性复现该归档,且上游文件一旦有出入即拒绝打包) |
4444
| 补索引空缺的头文件包 | [`compat.glx-headers`](pkgs/c/compat.glx-headers.lua)(libglvnd 的 `GL/glx.h`,Khronos registry 不含,SDL 的 X11 后端必需) |
4545
| C++ 应用框架 compat(依赖复用索引内既有包) | [`compat.eui-neo`](pkgs/e/compat.eui-neo.lua)(上游 `3rd/` 自带 8 个 vendored 依赖,此处一个不编,全部改指索引内同版本 `compat.*`) |

mcpp.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ members = [
1313
"tests/examples/asio-ssl",
1414
"tests/examples/boost-ext.ut",
1515
"tests/examples/build-mcpp",
16+
"tests/examples/c-ares",
1617
"tests/examples/catch2",
1718
"tests/examples/catch2-main",
1819
"tests/examples/catch2-v2",

0 commit comments

Comments
 (0)