feat(asio): 导出文件 I/O、四组 error 枚举、async_connect 与 make_address - #213
Merged
Conversation
`import asio;` 的导出面此前少了三类消费者绕不过去的东西: 1. **error 条件只有 operation_aborted。** 消费者能认出取消,但认不出别的 —— 区分「连接被拒」和「DNS 解析失败」在模块边界这侧没有名字可比。改为导出 `basic_errors` / `netdb_errors` / `addrinfo_errors` / `misc_errors` 四个枚举 类型,并用 `using enum` 带出枚举量,避免变成一张会随上游漂移的 ~40 项手工清单。 2. **文件 I/O 完全没有。** `asio::stream_file` / `random_access_file` / `file_base`(及 basic_ 模板)在 `ASIO_HAS_FILE` 成立时导出。用 Asio 自己的 能力宏而不是在描述符里维护平台清单:Windows 下由 IOCP 提供,Linux 下需要 io_uring,macOS 无后端。本包未开启 io_uring,所以就本包而言判据 ⇔ Windows。 注意消费端**不能**用 `#if defined(ASIO_HAS_FILE)` 判断 —— 宏不跨模块边界, 模块消费者不 include Asio 头文件,那个宏在它的 TU 里永远为假。描述符注释和 tests/file.cpp 都写明了按 `_WIN32` 分支。 3. **`asio::async_connect` 与 `asio::ip::make_address` 缺失。** 前者是接受候选 端点序列的自由函数(成员版 `socket.async_connect` 只接受单个端点,替代不了 把 resolver 结果交给它的写法);后者是从字符串解析地址的标准入口,而 address / address_v4 / address_v6 三个类型本来就已导出。 测试(tests/examples/asio-module): - 新增 `errors.cpp`:四个枚举类型 + 九个枚举量经 make_error_code 往返,断言 `ec == asio::error::eof` 这类真实写法成立,并断言不同条件不互相塌缩; make_address / make_address_v4 / make_address_v6 的解析成功与失败路径。 - 新增 `file.cpp`:stream_file 写入 + 读回(三个 file_base 标志组合)、 random_access_file 按偏移读;非 Windows 腿只记录「本配置无文件后端」。 - `network.cpp` 补自由函数 async_connect 的语义断言:候选序列里第一个不可达 (loopback:1),必须跳过它连上第二个。不依赖 DNS,保持自足。 本地 linux/gcc16:`mcpp test -p asio-module` 7 passed。
Sunrisepeak
added a commit
to Sunrisepeak/SpinningMomo
that referenced
this pull request
Aug 17, 2026
上一轮 full-build 走到了业务代码编译阶段(依赖、CRT、链接全部就位),只在 一处失败,而且是已知的那处: root_availability.cpp(238): fatal error C1116: unrecoverable error importing module 'utils.network.network'. Specialization of 'asio::detail::service_registry::use_service' with arguments 'asio::config_service' 根因是 asio 被 N 个模块各自的 GMF 分别 #include:附着于全局模块的特化在每个 导入方被重新实例化,MSVC 调和不了。`import asio;` 让它们只在 asio 模块内实例化 一次 —— 这就是「asio 必须用 module 方式」的技术含义。 ## 转换范围由约束推出,不是挑的 模块单元的 purview 里不能 #include,而头文件根本不能 import。所以一旦 asio 变成 模块,直接 include 它的**头文件**必须跟着变模块,并沿 include 图向上传播,直到 遇到 .cpp —— .cpp 可以 import 而不必自己变成模块,传播到此为止。 `mcpp-modularize.py --closure vendor/asio.hpp` 把这条规则固化成脚本:18 个头文件 (其中 pch 单独处理),45 个 .cpp/.cppm 改 include 为 import,共 63 / 497 个文件。 ## 三件配套 1. **删除 src/pch.hpp 与 xmake 的 set_pcxxheader。** PCH 是文本快照,跟具名模块 对同一份 SDK 头会给出不同的实体归属;mcpp 本来就没有 PCH。留着它,一个 TU 会 同时文本包含 asio 和 import asio。 2. **17 个旧模块补 sm. 前缀。** 它们建成时没加,因为 mcpp 禁的是 `util` 而不是 `utils`,侥幸合法。但一棵树里一半带前缀一半不带,规则就变成了「看上一批怎么 做的」。`--rename-prefix utils` 一次改齐。 3. **两个新的转换 pass。** `--normalize` 把落进 GMF 的 import 移进 purview (rewrite-consumers 原地替换 include,而在已转换的模块里那行 include 正好在 GMF —— 替换是对的,留在原地不对),并删掉因此空掉的 `module;`。 ## asio 描述符 导出面缺 11 个本项目实际调用的名字。修订已合入上游 mcpplibs/mcpp-index#213(Windows/macOS/Linux/llvm 四条腿全绿)。已发布的索引 快照还没跟上,所以 mcpp/pkgs/a/sm.asio.lua 是一份**临时覆盖**,内容逐字复制自 合入后的官方描述符。`scripts/check-asio-override.sh` 在 Linux 上几秒钟回答 「可以删了吗」,不用花一轮 Windows CI。 新增 probes/p6-asio-module:按 SpinningMomo 实际调用面断言 module 形态的 asio (make_address / 六个 error 条件 / 自由函数 async_connect / stream_file + random_access_file)。文件 I/O 段按 _WIN32 门控 —— 宏不跨模块边界,消费者 TU 里 ASIO_HAS_FILE 恒假;这样这个探针在本地 Linux 上也能跑,已通过。 ## 架构守卫跟上现实 check-cpp-architecture.py 还在按 Headers/PCH 时代检查(要求每个文件都 `#include "vendor/std.hpp"`,且完全不看 .cppm)。改为: - 扫描 .cppm; - 标准库一个单元一扇门:模块单元 `import std;`,普通 TU `vendor/std.hpp`; - utils::hash 的来源两种拼法都认; - 新增「模块接口只放声明」检查 —— 模板 / inline / constexpr / 类内成员不算。
Sunrisepeak
added a commit
to Sunrisepeak/SpinningMomo
that referenced
this pull request
Aug 17, 2026
## 1. 生态闭环(P7) `mcpp.toml` 不再有 `[indices]`,`mcpp/` 目录整个删除。依赖来源: chriskohlhoff.asio mcpplibs/mcpp-index#213(导出面**修订**,不是另起一个包) compat.xxhash #214 compat.libwebp #214 compat.reflectcpp #214 compat.sqlitecpp #215 → compat.sqlite3 compat.usockets #215 → compat.libuv compat.uwebsockets #215 → compat.usockets compat.wil #216(Windows-only,[target.'cfg(windows)'] 门控) 本地已验证整套依赖能从**已发布**的索引解析并构建(linux/gcc16,10.3s)。 **sm.asio 覆盖描述符可以删**,因为它的两个理由都没了:导出面由 #213 补齐;而 `_WIN32_WINNT` 那个 pin —— p8 第三轮把它拿掉、直接依赖官方包,**绿**。做功的一直是 「include 在 import 之前」那条规则。 **WebView2 不在里面,这是判断不是遗漏。** 它是 NuGet **二进制**分发(头文件 + 预编译 loader `.lib`),索引的 A–H 形态分类里没有这一档,引入新形态是比这组 PR 大得多的讨论。 它继续走 `scripts/mcpp-prebuild.sh` 的解包,经 include_dirs/ldflags 到达构建。闭环的 判据是「工程 mcpp.toml 不再声明 `[indices]`」,不是「所有第三方物料都进索引」—— 这条写在 mcpp.toml 的注释里,免得下一个人以为是漏了。 连带清理:`mcpp-link-index.sh`(path 索引在 Windows 上要 junction 的绕行)、 `check-asio-override.sh`(问题已有答案)、CI 两处索引注册步骤与为索引物化设的 build 重试、parity 检查的候选顺序。 **p5-index → p5-official-index**:同一个探针反过来问 —— 从「项目自有索引端到端」变成 「SpinningMomo 的整套依赖,从已发布索引解析」,而且是在一个从没见过本仓库描述符的 runner 上。八个包各按真实用法跑(asio 走 module、其余走头文件),六分钟给出生态闭环的 答案而不是四十分钟。 ## 2. 补齐七处 vendor 头,并加一条守卫 features/screenshot/state.cppm:43: error: use of undeclared identifier 'winrt' 模块化拿走了一个一直在悄悄工作的通道:转换前这个文件通过 `#include "utils/graphics/capture.hpp"` 顺带拿到了 WinRT 投影头;`capture` 现在是模块, 而模块的 GMF **不是名字的传递通道** —— 里面的实体附着于全局模块,但那个 TU 里没有 `winrt` 这个名字的声明。项目本来就要求「每个 TU 自包含」,只是以前有传递包含兜底。 winrt:: screenshot/state.cppm, recording/recording.cpp, overlay/capture.cpp, preview/capture.cpp Microsoft::WRL:: core/webview/{static,host}.cpp wil:: ui/notification_window/painter.cpp 七处同一个错误,每处单独暴露要一轮 40 分钟的构建,所以加规则而不是逐个修:守卫按 **目录**匹配,`vendor/windows/winrt/` 下新增门面当天就被覆盖。已反向验证。
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
动机
chriskohlhoff.asio的模块导出面在三处挡住了真实消费者。这些缺口是把一个 66k 行的 Windows 桌面工程(SpinningMomo)从#include <asio.hpp>迁到import asio;的过程中逐条撞出来的,不是猜的。1. error 条件只导出了
operation_aborted消费者能认出「取消」,认不出别的。区分「连接被拒」「超时」「DNS 查不到」在模块边界这一侧根本没有名字可比 —— 而这是任何网络重试逻辑要做的第一件事。
改为导出四个枚举类型
basic_errors/netdb_errors/addrinfo_errors/misc_errors,并用using enum带出枚举量。用using enum而不是逐个using是有意的:后者会变成一张 ~40 项的手工清单,上游加一个错误码它就悄悄过期。2. 文件 I/O 完全没有
asio::stream_file/asio::random_access_file/asio::file_base(及其basic_模板)现在在ASIO_HAS_FILE成立时导出。守卫用 Asio 自己的能力宏,不是描述符里维护的平台清单 —— Windows 下后端是 IOCP,Linux 下需要 io_uring,macOS 下没有后端(
asio/detail/config.hpp的// Files.一节)。这样它随上游演进,不需要这里跟着改。#if defined(ASIO_HAS_FILE)判断。宏不跨模块边界,而模块消费者不 include Asio 头文件,那个宏在它的 TU 里永远为假。就本包的配置而言判据是确定的 —— 未开启 io_uring,所以ASIO_HAS_FILE⇔ Windows,跨平台消费者按_WIN32分支即可。3.
asio::async_connect与asio::ip::make_address缺失async_connect是接受候选端点序列的自由函数。成员版socket.async_connect只接受单个端点,替代不了「把 resolver 的results_type交给它、逐个试」这个标准写法。make_address是从字符串解析地址的入口,而address/address_v4/address_v6三个类型本来就已经导出了 —— 有类型没有构造入口。一并补上make_address_v4/make_address_v6以保持对称。测试
tests/examples/asio-module新增两个成员测试、扩充一个:errors.cpp(新):四个枚举类型 + 九个枚举量经make_error_code往返,断言ec == asio::error::eof这类真实写法成立(这只有在枚举量的名字跨过模块边界时才编得过);断言不同条件不互相塌缩;make_address/_v4/_v6的解析成功与失败两条路径。file.cpp(新):stream_file写入 + 读回(write_only|create|truncate三标志组合)、random_access_file按偏移读、basic_模板别名与基类关系的static_assert。非 Windows 腿只打印「本配置无文件后端」并返回 0。network.cpp:补自由函数async_connect的语义断言 —— 候选序列第一个是loopback:1(不可达),必须跳过它连上第二个真实 acceptor。完全自足,不依赖 DNS。验证
lint 本地全过(
loadfile/check_mirror_urls/check_package_name/check_platform_version_parity/mcpp xpkg parse)。描述符头部的「未导出的组件」清单已同步:文件 I/O 从该清单移到新的「平台条件导出」一节,串口与 pipe 留在原处。