From 239531fbb8156f21800a739e6f3fa655b0ea5713 Mon Sep 17 00:00:00 2001 From: wellwei <96378453+wellwei@users.noreply.github.com> Date: Tue, 21 Jul 2026 15:02:59 +0800 Subject: [PATCH] refactor(asio): make module package canonical --- mcpp.toml | 1 - pkgs/a/asio.lua | 272 ++++++++++++ pkgs/c/chriskohlhoff.asio.lua | 419 ------------------ pkgs/c/compat.asio.lua | 95 ---- tests/examples/asio-module/mcpp.toml | 10 +- .../asio-module/tests/experimental.cpp | 1 - tests/examples/asio-module/tests/network.cpp | 2 +- tests/examples/asio/mcpp.toml | 10 - tests/examples/asio/tests/core.cpp | 72 --- tests/examples/asio/tests/coroutine.cpp | 34 -- tests/examples/asio/tests/experimental.cpp | 42 -- tests/examples/asio/tests/network.cpp | 103 ----- tests/examples/asio/tests/platform.cpp | 42 -- tests/examples/asio/tests/surface.cpp | 84 ---- 14 files changed, 277 insertions(+), 910 deletions(-) create mode 100644 pkgs/a/asio.lua delete mode 100644 pkgs/c/chriskohlhoff.asio.lua delete mode 100644 pkgs/c/compat.asio.lua delete mode 100644 tests/examples/asio/mcpp.toml delete mode 100644 tests/examples/asio/tests/core.cpp delete mode 100644 tests/examples/asio/tests/coroutine.cpp delete mode 100644 tests/examples/asio/tests/experimental.cpp delete mode 100644 tests/examples/asio/tests/network.cpp delete mode 100644 tests/examples/asio/tests/platform.cpp delete mode 100644 tests/examples/asio/tests/surface.cpp diff --git a/mcpp.toml b/mcpp.toml index 0ed6250..6ca8a67 100644 --- a/mcpp.toml +++ b/mcpp.toml @@ -9,7 +9,6 @@ [workspace] members = [ "tests/examples/archive", - "tests/examples/asio", "tests/examples/asio-module", "tests/examples/build-mcpp", "tests/examples/cjson", diff --git a/pkgs/a/asio.lua b/pkgs/a/asio.lua new file mode 100644 index 0000000..b4671de --- /dev/null +++ b/pkgs/a/asio.lua @@ -0,0 +1,272 @@ +-- asio -- 将独立版 Asio 1.38.1 暴露为 C++23 模块 `asio` +-- (Form B inline descriptor, separate-compilation mode)。 +-- +-- 注意事项 +-- * 使用 `mcpp add asio@1.38.1` 引入;消费者需显式写 +-- `import std; import asio;`,因为本包设置 import_std = false。 +-- * 本包只支持模块方式消费。同一 translation unit 不要混用 +-- `#include ` 和 `import asio;`,避免 inline 定义与模块 BMI +-- 的 separate-compilation 定义产生 ODR 差异。 +-- * 默认 feature 显式传播 ASIO_STANDALONE、ASIO_SEPARATE_COMPILATION、 +-- ASIO_DISABLE_BOOST_CONTEXT_FIBER 和 ASIO_HAS_THREADS。Asio 头文件内部 +-- 自动检测的其他 ASIO_HAS_* 宏不会由 `import asio;` 导出。 +-- +-- 与 header-only Asio 的区别/限制 +-- * 上游 1.38.x 没有模块接口单元。本描述生成 `asio.cppm`,并只编译一次 +-- `*/src/asio.cpp` 中的非模板实现;首次构建需生成 BMI,增量构建可避免 +-- 每个消费者 translation unit 重复解析整组 Asio 头文件。 +-- * 模块只暴露 wrapper 中明确 export 的声明,不等同于 +-- `#include ` 的完整 API 表面。 +-- * asio::error_code 是 std::error_code 的别名;wrapper 导出 +-- asio::use_future 变量,但未导出 asio::use_future_t 类模板。 +-- * 依赖未导出 ASIO_HAS_* 宏、平台专用头文件或 Boost 扩展的代码,需要 +-- 改用标准/操作系统能力检测或另行扩展模块 wrapper。 +-- +-- 未导出的组件 +-- * SSL/TLS (`asio/ssl/*.hpp`):需要 OpenSSL/wolfSSL 等外部依赖。 +-- * Unix 域套接字、POSIX 描述符和 Windows 句柄: +-- `asio/local/*.hpp`、`asio/posix/*.hpp`、`asio/windows/*.hpp`。 +-- * 串口、pipe 和文件 I/O:`asio/serial_port.hpp`、 +-- `asio/*able_pipe.hpp`、`asio/stream_file.hpp`、 +-- `asio/random_access_file.hpp`。 +-- * spawn()/yield_context 有栈协程:需要 Boost.Context;本包禁用其自动 +-- 检测,应改用 co_spawn + awaitable + use_awaitable。 +-- * deadline_timer、generic protocol、execution、traits、遗留宏式协程和 +-- streambuf:对应 `asio/deadline_timer.hpp`、`asio/generic/*.hpp`、 +-- `asio/execution/*.hpp`、`asio/traits/*.hpp`、`asio/yield.hpp`、 +-- `asio/coroutine.hpp`、`asio/streambuf.hpp`。 +package = { + spec = "1", + namespace = "", + name = "asio", + description = "Standalone asio exposed as the C++23 module `asio` (separate compilation)", + licenses = {"BSL-1.0"}, + repo = "https://github.com/chriskohlhoff/asio", + type = "package", + + xpm = { + linux = { + ["1.38.1"] = { + url = { + GLOBAL = "https://github.com/chriskohlhoff/asio/archive/refs/tags/asio-1-38-1.tar.gz", + CN = "https://gitcode.com/mcpp-res/asio/releases/download/1.38.1/asio-1.38.1.tar.gz", + }, + sha256 = "2827b229972be80cdb14e5497962fa393d1adf036b5869e2b9c99f644daadacc", + }, + }, + macosx = { + ["1.38.1"] = { + url = { + GLOBAL = "https://github.com/chriskohlhoff/asio/archive/refs/tags/asio-1-38-1.tar.gz", + CN = "https://gitcode.com/mcpp-res/asio/releases/download/1.38.1/asio-1.38.1.tar.gz", + }, + sha256 = "2827b229972be80cdb14e5497962fa393d1adf036b5869e2b9c99f644daadacc", + }, + }, + windows = { + -- Upstream tag archives carry two POSIX symlinks + -- (asio/include -> ../include, asio/src -> ../src) that tar.exe + -- cannot materialize on the Windows runner. This uses the existing + -- symlink-free repack documented by xlings-res/asio. + ["1.38.1"] = { + url = { + GLOBAL = "https://github.com/xlings-res/asio/releases/download/1.38.1/asio-1.38.1-nosymlinks.tar.gz", + CN = "https://gitcode.com/mcpp-res/asio/releases/download/1.38.1/asio-1.38.1-nosymlinks.tar.gz", + }, + sha256 = "77f74094bb12cd867a6edbf5736bbed816c6ce0906e880de8573097a81714d89", + }, + }, + }, + + mcpp = { + schema = "0.1", + language = "c++23", + import_std = false, + modules = { "asio" }, + -- GitHub wraps the tag as asio-asio-1-38-1/; expose its include root + -- so the wrapper's `#include ` resolve. + include_dirs = { "*/include" }, + generated_files = { + ["mcpp_generated/asio.cppm"] = [==[ +module; +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +export module asio; + +export namespace asio::detail { +using ::std::chrono::operator==; +using ::std::chrono::operator<; +using ::std::chrono::operator>=; +using ::std::chrono::operator+; +using ::std::chrono::operator-; +using ::std::coroutine_traits; +} + +export namespace asio::error { +using ::asio::error::make_error_code; +using ::asio::error::operation_aborted; +} + +export namespace asio { +using ::asio::io_context; +using ::asio::post; +using ::asio::make_work_guard; +using ::asio::dispatch; +using ::asio::defer; +using ::asio::steady_timer; +using ::asio::thread_pool; +using ::asio::make_strand; +using ::asio::mutable_buffer; +using ::asio::const_buffer; +using ::asio::buffer; +using ::asio::awaitable; +using ::asio::use_awaitable; +using ::asio::co_spawn; +using ::asio::cancellation_signal; +using ::asio::cancellation_type; +using ::asio::bind_cancellation_slot; +using ::asio::execution_context; +using ::asio::any_io_executor; +using ::asio::system_executor; +using ::asio::system_context; +using ::asio::associated_executor; +using ::asio::associated_allocator; +using ::asio::associated_cancellation_slot; +using ::asio::error_code; +using ::asio::detached; +using ::asio::detached_t; +using ::asio::use_future; +using ::asio::deferred; +using ::asio::deferred_t; +using ::asio::redirect_error; +using ::asio::bind_executor; +using ::asio::signal_set; +using ::asio::system_timer; +using ::asio::bind_allocator; +using ::asio::append; +using ::asio::prepend; +using ::asio::consign; +using ::asio::as_tuple; +using ::asio::socket_base; +using ::asio::connect; +using ::asio::async_read; +using ::asio::async_write; +using ::asio::read; +using ::asio::write; +using ::asio::read_until; +} + +export namespace asio::experimental { +using ::asio::experimental::channel; +using ::asio::experimental::concurrent_channel; +using ::asio::experimental::use_promise; +} + +export namespace asio::experimental::error { +using ::asio::experimental::error::make_error_code; +} + +export namespace asio::ip { +using ::asio::ip::tcp; +using ::asio::ip::udp; +using ::asio::ip::address; +using ::asio::ip::address_v4; +using ::asio::ip::address_v6; +} + +export namespace asio::this_coro { +using ::asio::this_coro::executor; +using ::asio::this_coro::cancellation_state; +using ::asio::this_coro::throw_if_cancelled; +using ::asio::this_coro::reset_cancellation_state; +} + +]==], + }, + sources = { + "mcpp_generated/asio.cppm", + "*/src/asio.cpp", + }, + targets = { ["asio"] = { kind = "lib" } }, + -- `separate-compilation` is a default feature so its defines propagate + -- to every consumer TU (the module BMI and the consumer must agree on + -- ASIO_SEPARATE_COMPILATION or the inline/extern split miscompiles). + -- + -- ASIO_HAS_THREADS: asio's detection keys off CRT macros + -- (_MT/_REENTRANT/_POSIX_THREADS) that the workspace's llvm-on-Windows + -- toolchain does not define, otherwise silently selecting null_thread. + -- Pin the known multithreaded package contract; POSIX pthread selection + -- still runs beneath this define where applicable. + features = { + ["default"] = { implies = { "separate-compilation" } }, + ["separate-compilation"] = { + defines = { + "ASIO_STANDALONE", + "ASIO_SEPARATE_COMPILATION", + "ASIO_DISABLE_BOOST_CONTEXT_FIBER", + "ASIO_HAS_THREADS", + }, + }, + }, + deps = {}, + -- POSIX threading is detected by asio from unistd.h feature macros; + -- retain the portable driver-level thread link contract on Linux. + linux = { + ldflags = { "-pthread" }, + }, + -- On the supported desktop MSVC-ABI route, asio autolinks ws2_32.lib + -- and mswsock.lib. Do not inject GNU -l flags into native link.exe. + }, +} diff --git a/pkgs/c/chriskohlhoff.asio.lua b/pkgs/c/chriskohlhoff.asio.lua deleted file mode 100644 index ad183a8..0000000 --- a/pkgs/c/chriskohlhoff.asio.lua +++ /dev/null @@ -1,419 +0,0 @@ --- chriskohlhoff.asio -- Asio 1.38.1 暴露为 C++23 模块 `asio` (Form B inline) --- --- 消费者引入: --- mcpp add chriskohlhoff.asio@1.38.1 --- --- 注意: 不要使用简写 mcpp add asio@1.38.1。 --- 简写 "asio" 已在默认注册表中匹配多个包 (compat.asio, mcpplibs.asio 等), --- 会导致解析冲突或解析到错误的包。 --- --- 本包是 compat.asio (header-only: #include ) 的模块伴侣包。 --- 采用 ASIO_SEPARATE_COMPILATION 模式 (编译 */src/asio.cpp), --- 上层叠加生成的模块接口单元 (.cppm wrapper), 使用者只需: --- import std; import asio; --- --- 为何用 generated_files: upstream 1.38.x 未提供模块接口单元, --- wrapper 在 mcpp-index 内手工编写, 先以 docs/asio.lua 本地验证。 --- --- ========== 基本用法 ========== --- import std; -- 必须, 模块版不会自动拉入标准库 --- import asio; --- --- using namespace std::chrono_literals; --- asio::io_context io; --- auto strand = asio::make_strand(io); --- asio::steady_timer timer(io, 100ms); --- asio::co_spawn(io, my_coro(), asio::detached); --- --- ========== 必须写 import std; ========== --- 与 header-only 的 compat.asio 不同, 本模块不会隐式拉入任何标准库头文件。 --- 要使用 std::vector, std::error_code, std::thread, std::mutex, --- std::chrono 等, 必须写 `import std;`。省略则标准库不可见。 --- --- ========== 与 compat.asio(header-only) 的主要差异 ========== --- --- 1. 构建模型 (HEADER_ONLY -> SEPARATE_COMPILATION) --- compat.asio: ASIO_HEADER_ONLY -- asio 模板在每个消费者 TU 中实例化, --- 编译系统只需一个锚定 .c 文件。 --- chriskohlhoff.asio: ASIO_SEPARATE_COMPILATION -- 每次构建只编译一次 --- */src/asio.cpp; BMI (模块) 缓存模板实例化。 --- 首次构建较慢 (编译 asio 实现), 增量构建更快 --- (消费者 TU 变更时无需重解析 asio 头文件)。 --- --- 2. 宏 (宏定义) 不可见 --- `import asio;` 后, 模块边界隔离了预处理状态。使用者不能写: --- #ifdef ASIO_HAS_THREADS -- 不可见 --- #ifndef ASIO_HEADER_ONLY -- 不可见 --- #ifdef ASIO_HAS_PTHREADS -- 不可见 --- #ifdef ASIO_HAS_PIPE -- 不可见 --- #ifdef ASIO_HAS_FILE -- 不可见 --- #ifdef ASIO_HAS_SERIAL_PORT -- 不可见 --- #ifdef ASIO_HAS_BOOST_* -- 不可见 --- 只有 ASIO_STANDALONE 和 ASIO_SEPARATE_COMPILATION 通过 feature defines --- 暴露 (见下方 "features" 块)。需要平台检测时, 请使用 C++ 标准宏或 --- 操作系统级宏 (#ifdef __linux__ 等)。 --- --- 3. error_code 类型一致性 --- asio::error_code = std::error_code。模块导出了类型别名, 两者可互换。 --- 定时器回调签名 (const std::error_code&) 和 asio::error::* 枚举值 --- 均正常工作。 --- --- 4. 完成令牌 (Completion Token) 的模板类型 --- 模块使用者可以写 asio::detached / asio::detached_t / asio::deferred / --- asio::deferred_t 作为类型。但 asio::use_future_t 是类模板, --- 未导出。请直接使用 asio::use_future 变量, 无需命名其类型。 --- --- 5. 禁止混合 #include 和 import --- 不要在同一个 TU 中混用 #include 和 import asio; -- --- 头文件的 inline 实例化与模块 BMI 之间可能存在 ODR 差异。选一种。 --- 需要 #include 方式时, 请依赖 compat.asio。同理, 不要在同一 TU 中 --- 混合 #include 和 import std;。 --- --- 6. import_std = false --- mcpp schema "0.1" 要求自身提供模块接口的包必须设置 import_std = false --- (由使用者显式写 `import std; import asio;`)。chriskohlhoff.asio 不会 --- 在包级别自动引入 import std;。 --- --- ========== 本模块不可用的 API 组件 ========== --- --- 以下组件在 compat.asio (header-only) 中可用, 但本模块未导出: --- --- 组件 头文件 / 路径 原因 / 替代方案 --- ------------------------+----------------------------+---------------------- --- SSL/TLS asio/ssl/*.hpp 需 OpenSSL/wolfSSL --- (ssl::context, (外部依赖), 本包不包含 --- ssl::stream, --- ssl::host_name_verify) --- Unix 域套接字 asio/local/*.hpp 未导出。改用 TCP loopback, --- (local::stream_protocol, 或在你的代码中 #include --- local::datagram_proto) --- POSIX 流描述符 asio/posix/*.hpp 未导出。 --- (posix::stream_descriptor, --- posix::descriptor_base) --- Windows 句柄 asio/windows/*.hpp Windows 专用, 未导出。 --- (stream_handle, object_handle, --- overlapped_ptr) --- 串口 asio/serial_port.hpp 平台相关 --- (ASIO_HAS_SERIAL_PORT)。 --- 未导出。 --- Pipe (管道) asio/*able_pipe.hpp 需 ASIO_HAS_PIPE。 --- (readable_pipe, writable_pipe) 未导出。 --- 文件 I/O asio/stream_file.hpp 需 ASIO_HAS_FILE。 --- asio/random_access_file 未导出。 --- spawn() 有栈协程 asio/spawn.hpp 需 Boost.Context --- (spawn, yield_context) (ASIO_HAS_BOOST_CONTEXT --- _FIBER)。我们定义了 --- ASIO_DISABLE_BOOST_ --- CONTEXT_FIBER, 因此 --- spawn() 给出编译期 --- #error。 --- -> 改用 co_spawn + --- awaitable (C++20 --- 无栈协程) --- Boost.Date_Time 定时器 asio/deadline_timer.hpp 已废弃。改用 --- steady_timer / --- system_timer --- (使用 std::chrono) --- 通用套接字协议 asio/generic/*.hpp 较少使用, 未导出。 --- 执行器属性框架 asio/execution/*.hpp 高级执行器框架, 暂未导出。 --- 自定义点检测特质 asio/traits/*.hpp 检测特质, 最终用户 --- 价值较低, 未导出。 --- 遗留宏式协程 已过时。改用 awaitable。 --- --- asio::streambuf asio/streambuf.hpp 改用 mutable_buffer + --- asio::buffer()。 --- --- ========== Boost 淘汰说明 ========== --- --- 独立版 asio (定义了 ASIO_STANDALONE) 已从所有核心和网络 API 中移除 --- Boost 依赖: --- --- * Boost.DateTime -- 已完全移除。ASIO_STANDALONE 在 config.hpp 中设置 --- ASIO_DISABLE_BOOST_DATE_TIME, 导致 deadline_timer (依赖 --- boost::posix_time) 完全不可编译。所有现代 asio 定时器 --- (steady_timer, system_timer, high_resolution_timer) 直接使用 --- std::chrono。 --- --- * Boost.Context -- 已从核心库移除, 但 spawn() 仍需要。 --- spawn() / basic_yield_context API 使用 boost::context::fiber 实现 --- 有栈协程。由于我们定义了 ASIO_DISABLE_BOOST_CONTEXT_FIBER, --- 任何使用 spawn() 的代码都会产生编译期 #error。 --- -> 改用 C++20 无栈协程, 功能完全等价: --- // 之前 (Boost.Context 有栈): --- asio::spawn(io, [](asio::yield_context yield) { --- timer.async_wait(yield); --- }); --- // 之后 (C++20 无栈, 零 Boost): --- asio::co_spawn(io, coro(), asio::detached); --- asio::awaitable coro() { --- co_await timer.async_wait(asio::use_awaitable); --- } --- --- * Boost.Regex -- ASIO_STANDALONE 禁用了 ASIO_HAS_BOOST_REGEX。 --- * Boost.Config, Boost.Array, Boost.Bind, Boost.Limits, Boost.Chrono, --- Boost.ThrowException 等 -- 全部已禁用。 --- --- * 陷阱提示: ASIO_HAS_BOOST_CONTEXT_FIBER 会针对任意 C++11 兼容编译器 --- (clang/GCC/MSVC) 自动检测并设置自身, 即使你从未要求过 Boost。 --- 如果 Boost 头文件碰巧在 include path 中, spawn() 看起来能编译, --- 但会在链接时报错 (除非链接了 libboost_context)。 --- ASIO_DISABLE_BOOST_CONTEXT_FIBER 防护了这一点: 我们主动抑制自动检测, --- 使结果是明确的编译期错误, 而非运行时崩溃。 --- --- ========== 迁移指南 (header-only -> 模块) ========== --- --- 将项目从 compat.asio (#include ) 切换到 --- chriskohlhoff.asio (import asio;) 时, 请检查以下断点: --- --- [ ] 在每一个使用 asio 的 TU 顶部添加 import std; --- (标准库类型不再隐式可用) --- [ ] 删除所有 #include -- 替换为 import asio; --- [ ] 删除 #include (如果有) --- [ ] 检查 #ifdef ASIO_HAS_THREADS / ASIO_HAS_PIPE / 等 --- -> 替换为操作系统级宏或 if-constexpr 检测 --- [ ] 检查 asio::spawn() / yield_context 用法 --- -> 重写为 co_spawn + awaitable + use_awaitable --- [ ] 检查 deadline_timer -> 替换为 steady_timer --- [ ] 检查 asio::ssl::* -> 需要单独的 OpenSSL 集成包 --- [ ] 检查 asio::local::* / posix::* -> 如确实需要, 添加 #include --- (但同一 TU 中混用 #include 和 import 有风险; 要么对这类文件 --- 继续使用 compat.asio, 要么在 .cppm 文件的模块前导区 --- 仅添加全局性 #include) --- [ ] 构建时间: 首次构建较慢 (编译 asio.cpp), 增量构建更快 --- (BMI 缓存)。总体上更大的目标文件被跨 TU 更少的模板实例化抵消。 -package = { - spec = "1", - namespace = "chriskohlhoff", - name = "chriskohlhoff.asio", - description = "Standalone asio exposed as the C++23 module `asio` (separate compilation)", - licenses = {"BSL-1.0"}, - repo = "https://github.com/chriskohlhoff/asio", - type = "package", - - xpm = { - linux = { - ["1.38.1"] = { - url = { - GLOBAL = "https://github.com/chriskohlhoff/asio/archive/refs/tags/asio-1-38-1.tar.gz", - CN = "https://gitcode.com/mcpp-res/asio/releases/download/1.38.1/asio-1.38.1.tar.gz", - }, - sha256 = "2827b229972be80cdb14e5497962fa393d1adf036b5869e2b9c99f644daadacc", - }, - }, - macosx = { - ["1.38.1"] = { - url = { - GLOBAL = "https://github.com/chriskohlhoff/asio/archive/refs/tags/asio-1-38-1.tar.gz", - CN = "https://gitcode.com/mcpp-res/asio/releases/download/1.38.1/asio-1.38.1.tar.gz", - }, - sha256 = "2827b229972be80cdb14e5497962fa393d1adf036b5869e2b9c99f644daadacc", - }, - }, - windows = { - -- Same symlink-free repack as compat.asio: upstream's tag archives - -- carry two POSIX symlinks (asio/include -> ../include, - -- asio/src -> ../src) that tar.exe cannot materialize on the - -- Windows runner. Provenance: xlings-res/asio README. - ["1.38.1"] = { - url = { - GLOBAL = "https://github.com/xlings-res/asio/releases/download/1.38.1/asio-1.38.1-nosymlinks.tar.gz", - CN = "https://gitcode.com/mcpp-res/asio/releases/download/1.38.1/asio-1.38.1-nosymlinks.tar.gz", - }, - sha256 = "77f74094bb12cd867a6edbf5736bbed816c6ce0906e880de8573097a81714d89", - }, - }, - }, - - mcpp = { - schema = "0.1", - language = "c++23", - import_std = false, - modules = { "asio" }, - -- GitHub wraps the tag as asio-asio-1-38-1/; expose its include root - -- so the wrapper's `#include ` resolve. - include_dirs = { "*/include" }, - generated_files = { - ["mcpp_generated/asio.cppm"] = [==[ -module; -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -export module asio; - -export namespace asio::detail { -using ::std::chrono::operator==; -using ::std::chrono::operator<; -using ::std::chrono::operator>=; -using ::std::chrono::operator+; -using ::std::chrono::operator-; -using ::std::coroutine_traits; -} - -export namespace asio::error { -using ::asio::error::make_error_code; -using ::asio::error::operation_aborted; -} - -export namespace asio { -using ::asio::io_context; -using ::asio::post; -using ::asio::make_work_guard; -using ::asio::dispatch; -using ::asio::defer; -using ::asio::steady_timer; -using ::asio::thread_pool; -using ::asio::make_strand; -using ::asio::mutable_buffer; -using ::asio::const_buffer; -using ::asio::buffer; -using ::asio::awaitable; -using ::asio::use_awaitable; -using ::asio::co_spawn; -using ::asio::cancellation_signal; -using ::asio::cancellation_type; -using ::asio::bind_cancellation_slot; -using ::asio::execution_context; -using ::asio::any_io_executor; -using ::asio::system_executor; -using ::asio::system_context; -using ::asio::associated_executor; -using ::asio::associated_allocator; -using ::asio::associated_cancellation_slot; -using ::asio::error_code; -using ::asio::detached; -using ::asio::detached_t; -using ::asio::use_future; -using ::asio::deferred; -using ::asio::deferred_t; -using ::asio::redirect_error; -using ::asio::bind_executor; -using ::asio::signal_set; -using ::asio::system_timer; -using ::asio::bind_allocator; -using ::asio::append; -using ::asio::prepend; -using ::asio::consign; -using ::asio::as_tuple; -using ::asio::socket_base; -using ::asio::connect; -using ::asio::async_read; -using ::asio::async_write; -using ::asio::read; -using ::asio::write; -using ::asio::read_until; -} - -export namespace asio::experimental { -using ::asio::experimental::channel; -using ::asio::experimental::concurrent_channel; -using ::asio::experimental::use_promise; -} - -export namespace asio::experimental::error { -using ::asio::experimental::error::make_error_code; -} - -export namespace asio::ip { -using ::asio::ip::tcp; -using ::asio::ip::udp; -using ::asio::ip::address; -using ::asio::ip::address_v4; -using ::asio::ip::address_v6; -} - -export namespace asio::this_coro { -using ::asio::this_coro::executor; -using ::asio::this_coro::cancellation_state; -using ::asio::this_coro::throw_if_cancelled; -using ::asio::this_coro::reset_cancellation_state; -} - -]==], - }, - sources = { - "mcpp_generated/asio.cppm", - "*/src/asio.cpp", - }, - targets = { ["asio"] = { kind = "lib" } }, - -- `separate-compilation` is a default feature so its defines propagate - -- to every consumer TU (the module BMI and the consumer must agree on - -- ASIO_SEPARATE_COMPILATION or the inline/extern split miscompiles). - -- - -- ASIO_HAS_THREADS: same rationale as compat.asio -- asio's thread - -- detection keys off CRT macros (_MT/_REENTRANT/_POSIX_THREADS) the - -- workspace's llvm-on-Windows toolchain does not define, silently - -- selecting null_thread; pin the detection result. asio only ever - -- tests defined(ASIO_HAS_THREADS), and on POSIX the pthread selection - -- beneath it still runs, so this is a no-op where detection works. - features = { - ["default"] = { implies = { "separate-compilation" } }, - ["separate-compilation"] = { - defines = { - "ASIO_STANDALONE", - "ASIO_SEPARATE_COMPILATION", - "ASIO_DISABLE_BOOST_CONTEXT_FIBER", - "ASIO_HAS_THREADS", - }, - }, - }, - deps = {}, - -- POSIX threading is detected by asio from unistd.h feature macros; - -- retain the portable driver-level thread link contract on Linux. - linux = { - ldflags = { "-pthread" }, - }, - -- On the supported desktop MSVC-ABI route, asio autolinks ws2_32.lib - -- and mswsock.lib. Do not inject GNU -l flags into native link.exe. - }, -} diff --git a/pkgs/c/compat.asio.lua b/pkgs/c/compat.asio.lua deleted file mode 100644 index 1f0bc63..0000000 --- a/pkgs/c/compat.asio.lua +++ /dev/null @@ -1,95 +0,0 @@ --- compat.asio — standalone Asio 1.38.1, exposed in upstream's default --- header-only mode. The package intentionally does not provide optional --- OpenSSL/wolfSSL, Boost.Context/Regex/Date_Time, or liburing dependencies. -package = { - spec = "1", - namespace = "compat", - name = "compat.asio", - description = "Standalone asynchronous I/O and networking library (header-only)", - licenses = {"BSL-1.0"}, - repo = "https://github.com/chriskohlhoff/asio", - type = "package", - - xpm = { - linux = { - ["1.38.1"] = { - url = { - GLOBAL = "https://github.com/chriskohlhoff/asio/archive/refs/tags/asio-1-38-1.tar.gz", - CN = "https://gitcode.com/mcpp-res/asio/releases/download/1.38.1/asio-1.38.1.tar.gz", - }, - sha256 = "2827b229972be80cdb14e5497962fa393d1adf036b5869e2b9c99f644daadacc", - }, - }, - macosx = { - ["1.38.1"] = { - url = { - GLOBAL = "https://github.com/chriskohlhoff/asio/archive/refs/tags/asio-1-38-1.tar.gz", - CN = "https://gitcode.com/mcpp-res/asio/releases/download/1.38.1/asio-1.38.1.tar.gz", - }, - sha256 = "2827b229972be80cdb14e5497962fa393d1adf036b5869e2b9c99f644daadacc", - }, - }, - windows = { - ["1.38.1"] = { - -- Upstream's tag archives (tar.gz AND zip) both carry two POSIX - -- symlinks (asio/include -> ../include, asio/src -> ../src) that - -- tar.exe cannot materialize on the Windows runner, and upstream - -- publishes no symlink-free asset for 1.38.x. This asset is the - -- upstream tag tarball with only those two symlink entries - -- removed (tar --delete); all 1544 regular files are - -- byte-identical to upstream. Provenance: xlings-res/asio README. - url = { - GLOBAL = "https://github.com/xlings-res/asio/releases/download/1.38.1/asio-1.38.1-nosymlinks.tar.gz", - CN = "https://gitcode.com/mcpp-res/asio/releases/download/1.38.1/asio-1.38.1-nosymlinks.tar.gz", - }, - sha256 = "77f74094bb12cd867a6edbf5736bbed816c6ce0906e880de8573097a81714d89", - }, - }, - }, - - mcpp = { - language = "c++23", - import_std = false, - c_standard = "c11", - -- GitHub wraps the tag as asio-asio-1-38-1/; expose its public include root. - include_dirs = { "*/include" }, - -- Header-only packages still need a buildable target in mcpp. - generated_files = { - ["mcpp_generated/asio_anchor.c"] = [==[ -int mcpp_compat_asio_headers_anchor(void) { return 0; } -]==], - }, - sources = { "mcpp_generated/asio_anchor.c" }, - targets = { ["asio"] = { kind = "lib" } }, - -- Explicitly pin the package's public configuration. `standalone` is a - -- default feature so its defines propagate to every consumer TU. - -- - -- ASIO_HAS_THREADS: asio's own thread detection keys off CRT macros - -- (_MT/_REENTRANT/_POSIX_THREADS) that the workspace's llvm-on-Windows - -- toolchain does not define, so asio silently selects null_thread and - -- every internal-thread operation (e.g. the waitable-timer wait thread) - -- throws operation_not_supported (10045) at runtime. All supported - -- targets are multithreaded; pin the detection result. asio only ever - -- tests defined(ASIO_HAS_THREADS), and on POSIX the pthread selection - -- below it still runs, so this is a no-op where detection already works. - features = { - ["default"] = { implies = { "standalone" } }, - ["standalone"] = { - defines = { - "ASIO_STANDALONE", - "ASIO_HEADER_ONLY", - "ASIO_DISABLE_BOOST_CONTEXT_FIBER", - "ASIO_HAS_THREADS", - }, - }, - }, - deps = {}, - -- POSIX threading is detected by Asio from unistd.h feature macros; - -- retain the portable driver-level thread link contract on Linux. - linux = { - ldflags = { "-pthread" }, - }, - -- On the supported desktop MSVC-ABI route, Asio autolinks ws2_32.lib - -- and mswsock.lib. Do not inject GNU -l flags into native link.exe. - }, -} diff --git a/tests/examples/asio-module/mcpp.toml b/tests/examples/asio-module/mcpp.toml index 75e359f..cc13ac3 100644 --- a/tests/examples/asio-module/mcpp.toml +++ b/tests/examples/asio-module/mcpp.toml @@ -1,13 +1,11 @@ -# Asio C++23-module consumer test project: `import asio;` (chriskohlhoff.asio, -# Form B inline descriptor, separate-compilation mode). Complements -# tests/examples/asio, which exercises the same upstream in header-only -# `#include ` form. +# Asio C++23-module consumer test project: `import std; import asio;`. +# The public package is the default-root module-only `asio@1.38.1` package. [package] name = "asio-module-tests" version = "0.1.0" [indices] -chriskohlhoff = { path = "../../.." } +default = { path = "../../.." } -[dependencies.chriskohlhoff] +[dependencies] asio = "1.38.1" diff --git a/tests/examples/asio-module/tests/experimental.cpp b/tests/examples/asio-module/tests/experimental.cpp index c7d66fd..aa1480b 100644 --- a/tests/examples/asio-module/tests/experimental.cpp +++ b/tests/examples/asio-module/tests/experimental.cpp @@ -1,5 +1,4 @@ // Experimental channel/concurrent_channel/use_promise over the module surface. -// Mirrors tests/examples/asio/tests/experimental.cpp. import std; import asio; diff --git a/tests/examples/asio-module/tests/network.cpp b/tests/examples/asio-module/tests/network.cpp index 381fd3a..c8d72f2 100644 --- a/tests/examples/asio-module/tests/network.cpp +++ b/tests/examples/asio-module/tests/network.cpp @@ -1,5 +1,5 @@ // TCP (acceptor/socket, async_read/async_write) and UDP (datagram send/receive) -// over the module surface. Mirrors tests/examples/asio/tests/network.cpp. +// over the imported module surface. import std; import asio; diff --git a/tests/examples/asio/mcpp.toml b/tests/examples/asio/mcpp.toml deleted file mode 100644 index ba10afc..0000000 --- a/tests/examples/asio/mcpp.toml +++ /dev/null @@ -1,10 +0,0 @@ -# Asio consumer test project: standalone, header-only, cross-platform behavior. -[package] -name = "asio-tests" -version = "0.1.0" - -[indices] -compat = { path = "../../.." } - -[dependencies.compat] -asio = "1.38.1" diff --git a/tests/examples/asio/tests/core.cpp b/tests/examples/asio/tests/core.cpp deleted file mode 100644 index 21f11fd..0000000 --- a/tests/examples/asio/tests/core.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#include - -#include -#include -#include -#include - -#if !defined(_WIN32) -#ifndef ASIO_HAS_THREADS -#error "Asio must detect POSIX thread support" -#endif -#ifndef ASIO_HAS_PTHREADS -#error "Asio must select its pthread implementation on POSIX" -#endif -#endif - -int main() { - using namespace std::chrono_literals; - - asio::io_context io; - auto guard = asio::make_work_guard(io); - auto serial = asio::make_strand(io); - asio::steady_timer timer(io, 2ms); - - std::atomic posted{0}; - std::mutex order_mutex; - std::vector order; - bool timer_called = false; - - asio::post(serial, [&] { - std::lock_guard lock(order_mutex); - order.push_back(1); - ++posted; - }); - asio::post(serial, [&] { - std::lock_guard lock(order_mutex); - order.push_back(2); - ++posted; - }); - timer.async_wait([&](const asio::error_code& ec) { - timer_called = !ec; - guard.reset(); - }); - - asio::thread worker([&] { io.run(); }); - worker.join(); - - if (posted != 2 || !timer_called || order != std::vector{1, 2}) return 1; - - asio::thread_pool pool(2); - std::atomic pooled{0}; - asio::post(pool, [&] { ++pooled; }); - asio::post(pool, [&] { ++pooled; }); - pool.join(); - if (pooled != 2) return 2; - - asio::io_context cancel_io; - asio::steady_timer cancelled(cancel_io, 1h); - asio::cancellation_signal cancellation; - asio::error_code cancelled_ec; - bool cancelled_called = false; - cancelled.async_wait(asio::bind_cancellation_slot( - cancellation.slot(), - [&](const asio::error_code& ec) { - cancelled_ec = ec; - cancelled_called = true; - })); - cancellation.emit(asio::cancellation_type::all); - cancel_io.run(); - - return cancelled_called && cancelled_ec == asio::error::operation_aborted ? 0 : 3; -} diff --git a/tests/examples/asio/tests/coroutine.cpp b/tests/examples/asio/tests/coroutine.cpp deleted file mode 100644 index eb39ad4..0000000 --- a/tests/examples/asio/tests/coroutine.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include - -#include - -#ifndef ASIO_HAS_CO_AWAIT -#error "C++23 compat.asio consumers must have co_await support" -#endif -#ifndef ASIO_HAS_STD_COROUTINE -#error "C++23 compat.asio consumers must use the standard coroutine library" -#endif - -asio::awaitable timer_value() { - asio::steady_timer timer(co_await asio::this_coro::executor); - timer.expires_after(std::chrono::milliseconds(1)); - co_await timer.async_wait(asio::use_awaitable); - co_return 42; -} - -int main() { - asio::io_context io; - int result = 0; - bool completed = false; - - asio::co_spawn(io, timer_value(), - [&](std::exception_ptr error, int value) { - if (!error) { - result = value; - completed = true; - } - }); - - io.run(); - return completed && result == 42 ? 0 : 1; -} diff --git a/tests/examples/asio/tests/experimental.cpp b/tests/examples/asio/tests/experimental.cpp deleted file mode 100644 index 816f857..0000000 --- a/tests/examples/asio/tests/experimental.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -int main() { - asio::io_context io; - - asio::experimental::channel channel(io, 1); - if (!channel.try_send(asio::error_code{}, "channel")) return 1; - std::string channel_value; - asio::error_code channel_error; - channel.async_receive([&](asio::error_code ec, std::string value) { - channel_error = ec; - channel_value = std::move(value); - }); - - asio::experimental::concurrent_channel concurrent(io, 1); - if (!concurrent.try_send(asio::error_code{}, 42)) return 2; - int concurrent_value = 0; - asio::error_code concurrent_error; - concurrent.async_receive([&](asio::error_code ec, int value) { - concurrent_error = ec; - concurrent_value = value; - }); - - auto promised = asio::post(io, asio::experimental::use_promise); - bool promise_completed = false; - promised([&] { promise_completed = true; }); - - io.run(); - - return !channel_error && channel_value == "channel" - && !concurrent_error && concurrent_value == 42 - && promise_completed ? 0 : 3; -} diff --git a/tests/examples/asio/tests/network.cpp b/tests/examples/asio/tests/network.cpp deleted file mode 100644 index 2494945..0000000 --- a/tests/examples/asio/tests/network.cpp +++ /dev/null @@ -1,103 +0,0 @@ -#include - -#include -#include -#include - -int main() { - using asio::ip::tcp; - using asio::ip::udp; - using namespace std::chrono_literals; - - asio::io_context io; - tcp::acceptor acceptor(io, {asio::ip::address_v4::loopback(), 0}); - tcp::socket server(io); - tcp::socket client(io); - asio::steady_timer deadline(io, 5s); - - const std::string ping = "ping"; - const std::string pong = "pong"; - std::array server_data{}; - std::array client_data{}; - bool accepted = false; - bool connected = false; - bool tcp_done = false; - bool timed_out = false; - int failure = 0; - - auto fail = [&](int code) { - if (failure == 0) failure = code; - asio::error_code ignored; - acceptor.close(ignored); - server.close(ignored); - client.close(ignored); - deadline.cancel(); - }; - - deadline.async_wait([&](const asio::error_code& ec) { - if (!ec) { - timed_out = true; - fail(90); - } - }); - - acceptor.async_accept(server, [&](const asio::error_code& ec) { - if (ec) return fail(1); - accepted = true; - asio::async_read(server, asio::buffer(server_data), - [&](const asio::error_code& read_ec, std::size_t n) { - if (read_ec || n != ping.size() - || std::string(server_data.data(), n) != ping) return fail(2); - asio::async_write(server, asio::buffer(pong), - [&](const asio::error_code& write_ec, std::size_t written) { - if (write_ec || written != pong.size()) fail(3); - }); - }); - }); - - client.async_connect( - {asio::ip::address_v4::loopback(), acceptor.local_endpoint().port()}, - [&](const asio::error_code& ec) { - if (ec) return fail(4); - connected = true; - asio::async_write(client, asio::buffer(ping), - [&](const asio::error_code& write_ec, std::size_t written) { - if (write_ec || written != ping.size()) return fail(5); - asio::async_read(client, asio::buffer(client_data), - [&](const asio::error_code& read_ec, std::size_t n) { - if (read_ec || n != pong.size() - || std::string(client_data.data(), n) != pong) return fail(6); - tcp_done = true; - deadline.cancel(); - }); - }); - }); - - io.run(); - if (failure || timed_out || !accepted || !connected || !tcp_done) return failure ? failure : 7; - - asio::io_context udp_io; - udp::socket receiver(udp_io, {asio::ip::address_v4::loopback(), 0}); - udp::socket sender(udp_io, {asio::ip::address_v4::loopback(), 0}); - const std::string datagram = "asio-udp"; - std::array received{}; - udp::endpoint remote; - bool receive_done = false; - bool send_done = false; - asio::error_code udp_failure; - - receiver.async_receive_from(asio::buffer(received), remote, - [&](const asio::error_code& ec, std::size_t n) { - udp_failure = ec; - receive_done = !ec && n == datagram.size() - && std::string(received.data(), n) == datagram; - }); - sender.async_send_to(asio::buffer(datagram), receiver.local_endpoint(), - [&](const asio::error_code& ec, std::size_t n) { - if (ec) udp_failure = ec; - send_done = !ec && n == datagram.size(); - }); - - udp_io.run(); - return !udp_failure && receive_done && send_done ? 0 : 8; -} diff --git a/tests/examples/asio/tests/platform.cpp b/tests/examples/asio/tests/platform.cpp deleted file mode 100644 index eadbcd9..0000000 --- a/tests/examples/asio/tests/platform.cpp +++ /dev/null @@ -1,42 +0,0 @@ -#include - -#include -#include - -int main() { -#if defined(ASIO_HAS_PIPE) - asio::io_context io; - asio::readable_pipe reader(io); - asio::writable_pipe writer(io); - asio::error_code ec; - asio::connect_pipe(reader, writer, ec); - if (ec) return 1; - - const std::string sent = "pipe"; - std::array received{}; - if (asio::write(writer, asio::buffer(sent), ec) != sent.size() || ec) return 2; - if (asio::read(reader, asio::buffer(received), ec) != sent.size() || ec) return 3; - if (std::string(received.data(), received.size()) != sent) return 4; -#endif - -#if defined(ASIO_HAS_LOCAL_SOCKETS) - static_assert(sizeof(asio::local::stream_protocol::endpoint) > 0); -#endif -#if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) - static_assert(sizeof(asio::posix::stream_descriptor::native_handle_type) > 0); -#endif -#if defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) - static_assert(sizeof(asio::windows::stream_handle::native_handle_type) > 0); -#endif -#if defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE) - static_assert(sizeof(asio::windows::object_handle::native_handle_type) > 0); -#endif -#if defined(ASIO_HAS_FILE) - static_assert(sizeof(asio::random_access_file::native_handle_type) > 0); -#endif -#if defined(ASIO_HAS_SERIAL_PORT) - static_assert(sizeof(asio::serial_port::native_handle_type) > 0); -#endif - - return 0; -} diff --git a/tests/examples/asio/tests/surface.cpp b/tests/examples/asio/tests/surface.cpp deleted file mode 100644 index ca8e927..0000000 --- a/tests/examples/asio/tests/surface.cpp +++ /dev/null @@ -1,84 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef ASIO_STANDALONE -#error "compat.asio must expose standalone Asio to consumers" -#endif -#ifndef ASIO_HEADER_ONLY -#error "compat.asio must expose Asio's header-only configuration" -#endif -#ifndef ASIO_DISABLE_BOOST_CONTEXT_FIBER -#error "compat.asio must make the excluded Boost.Context spawn path explicit" -#endif -#ifdef ASIO_ENABLE_BOOST -#error "compat.asio must not enable Boost.Asio mode" -#endif -#ifdef ASIO_HAS_BOOST_CONFIG -#error "standalone Asio must not depend on Boost.Config" -#endif -#ifdef ASIO_HAS_BOOST_REGEX -#error "standalone Asio must not expose Boost.Regex overloads" -#endif -#ifdef ASIO_HAS_BOOST_DATE_TIME -#error "standalone Asio must not expose legacy Boost.Date_Time timers" -#endif -#ifdef ASIO_HAS_IO_URING -#error "compat.asio base package must not require liburing" -#endif - -#include - -int main() { - static_assert(std::is_class_v); - static_assert(std::is_class_v); - static_assert(std::is_class_v); - static_assert(std::is_class_v); - static_assert(std::is_class_v); - static_assert(std::is_class_v); - static_assert(std::is_class_v>); - static_assert(std::is_class_v>); - -#if defined(ASIO_HAS_POSIX_STREAM_DESCRIPTOR) - static_assert(std::is_class_v); -#endif -#if defined(ASIO_HAS_LOCAL_SOCKETS) - static_assert(std::is_class_v); -#endif -#if defined(ASIO_HAS_PIPE) - static_assert(std::is_class_v); - static_assert(std::is_class_v); -#endif -#if defined(ASIO_HAS_SERIAL_PORT) - static_assert(std::is_class_v); -#endif -#if defined(ASIO_HAS_WINDOWS_STREAM_HANDLE) - static_assert(std::is_class_v); -#endif -#if defined(ASIO_HAS_WINDOWS_OBJECT_HANDLE) - static_assert(std::is_class_v); -#endif -#if defined(ASIO_HAS_FILE) - static_assert(std::is_class_v); -#endif - - return 0; -}