diff --git a/.agents/docs/2026-10-16-add-mcr-plan.md b/.agents/docs/2026-10-16-add-mcr-plan.md new file mode 100644 index 00000000..14d1be37 --- /dev/null +++ b/.agents/docs/2026-10-16-add-mcr-plan.md @@ -0,0 +1,94 @@ +# 新增 mcr 收录(Form A,模块库) + +## 1. 来源与形态 + +- 收录 [yizhinailong/mcr](https://github.com/yizhinailong/mcr) 0.1.5,即上游最新 tag + `v0.1.5`(在此之前为 `v0.1.3`、`v0.1.4`)。 +- 形态为 **A**:上游仓自带 `mcpp.toml`(`[lib] path = "src/mcr.cppm"`)与 + `build.mcpp`,是完整的 mcpp 工程,而不是需要本仓以 `compat` 形态适配的第三方库。 + 因此描述符只登记身份与下载地址,构建交给上游 `mcpp.toml` + (`mcpp = "*/mcpp.toml"`,`gzj-creator.galay` / `marzer.tomlplusplus` 同形); + `mcpp xpkg parse` 也自报 `form A — no mcpp segment`。 +- **GLOBAL 必须是 tag 归档而不是 release 资产**:GitHub API 列出 3 个 release + (`v0.1.3/4/5`),`assets` 全为空 —— 上游的 `version-tag.yml` 只打 tag 并触发 CI, + 不做 `mcpp pack`、不发布 tarball。归档 + `https://github.com/yizhinailong/mcr/archive/refs/tags/v0.1.5.tar.gz` + SHA-256 `bd55e9dc19b620d7dfb89d20fd4a6b1ab9cf947fe872dc536dee53b4e869f8f5` + (248 803 字节),两次下载一致;顶层包装层为 `mcr-0.1.5/`,由前导 `*/` 吞掉。 +- License MIT(`LICENSE` 首行 `MIT License` / `Copyright (c) 2026 yizhinailong`)。 +- 上游依赖 `compat.curl` 8.21.0 与 `nlohmann.json` 3.12.0(见其 `mcpp.lock`),两者 + 本仓都已在索引中;`compat.openssl` 3.5.1 亦已存在(仅 linux/macosx 需要)。 + +## 2. 描述符设计 + +- 身份 `yizhinailong:mcr`,文件 `pkgs/y/yizhinailong.mcr.lua` —— 目录取**完整包名** + `yizhinailong.mcr` 的首字母(`compat.rapidcsv` → `pkgs/c/`、`nlohmann.json` → + `pkgs/n/` 同理,`docs/repository-and-schema.md` §Repository layout 的规则)。 +- **命名空间由来**:mcr 自己的 `mcpp.toml` 只写 `name = "mcr"`,不带命名空间;索引侧 + 身份由描述符给,取仓主 `yizhinailong`。这与既有先例一致 —— + `tensorvia-cpu` 的上游同样无命名空间,描述符补 `namespace = "aimol"`; + `galay` 补 `gzj-creator`。消费侧因此写作 + `[dependencies.yizhinailong] mcr = "0.1.5"`。 +- 三平台共用同一份源码归档(纯源码,无平台差异),`xpm` 的 linux/macosx/windows + 三个块 url 与 sha256 全等。 +- **平台差异不内联进描述符**:mcr 自己的 manifest 已按平台分支 + (`[target.linux|macosx.dependencies.compat] openssl` + + `defines = ["MCR_SSL_CTX_OPENSSL"]`,Windows 走 Schannel)。Form A 的要点正是 + 这一决定仍归上游所有,描述符不重复表达,也就不会与上游漂移。 +- **CN 镜像**:本次没有 `mcpp-res` 写权限,按 `docs/cn-mirror.md` 的回退路径写 + **纯字符串 url**(`gzj-creator.galay` 同形)。`tests/check_mirror_urls.lua` 明确 + 「plain url: fine」,只对表形 url 校验 GLOBAL/CN 成对。日后补镜像只需把 `url` + 改写成 `{ GLOBAL = …, CN = … }`,sha256 不变。 + +## 3. Feature 评估 + +无。feature 机制只对 **Form B**(本仓内联构建)有意义 —— 它门控的是描述符 `mcpp` +段里的 `sources`。Form A 的可选组件由上游 manifest 自己的 `features` 表达,消费者 +直接写 `features = [...]` 即可,本仓无需(也无法)再门控一层。 + +## 4. 测试与验证 + +`tests/examples/mcr` 是公开 Form A 消费测试。成员级 `[indices]` 只声明 +`yizhinailong`(成员级表**替换**而非合并仓根的 `compat`,这是硬约束:两个项目级 +index repo 会让每次查找歧义,mcpp#238),因此 mcr 自带的 `compat.*` 依赖故意从 +**已发布的远端索引**解析,新命名空间才解析到本 checkout。 + +测试刻意**离线**:活体 HTTP 往返需要本地服务与 curl 运行时,不适合放进索引成员。 +断言覆盖离线可观测的全部面: + +- `mcr::VERSION` / `VERSION_MAJOR|MINOR|PATCH` —— 该模块由 mcr **自己的 + `build.mcpp`** 从 `mcpp.toml` 生成,断言它等于 `0.1.5` 即证明构建钩子确实跑过、 + 且生成模块进了 lib 目标(这是本次最值得盯的一环,见下); +- `mcr::status` 的五个 `constexpr` 分类器(`static_assert`)+ 具名状态码常量; +- `mcr::Url` 与 `mcr::Header` 的大小写无关查找(`CaseInsensitiveCompare`); +- `mcr::JsonBody` 构造期取紧凑序列化、与原值往返相等; +- `mcr::Response::TryJson()` 在成功时给出值、在非法 JSON 时给出 `JsonError`,而 + `Json()` 对同一输入抛 `mcr::Json::exception`。 + +## 5. 注意事项与风险 + +- **`build.mcpp` 是本次唯一非平凡风险点**。上游的构建钩子 `import mcpp;`、调用 + `mcpp::manifest_dir()` / `mcpp::out_dir()` / `mcpp::generated()`,并生成 + `mcr_version.cppm`(其 global module fragment 里 `#include `), + 因此构建程序需要 host 侧 `mcpp` 模块可达。既有 Form A 案例 + (`galay` / `tinyhttps` / `tensorvia-cpu`)都没有 `build.mcpp`,本条无先例可依; + 测试里对 `mcr::VERSION` 的断言就是为它设的探针。 +- **上游只对 Windows 有 CI**。mcr 的 README 与 `.github/workflows/windows-ci.yml` + 只覆盖 Windows(LLVM 22.1.8 + MSVC);linux/macosx 的 OpenSSL 路径由上游 manifest + 声明但未被上游验证。描述符按上游 manifest 的意图声明三平台,若 linux/macos 腿在 + CI 暴露问题,退路是像 `gzj-creator.galay` 那样先只声明已验证的平台。 +- 上游 Windows 配置使用 Schannel,`compat.openssl` 无 Windows 构建 —— 这一点上游 + manifest 已经处理好,本仓无需介入。 + +### 验证结论 + +- `mcpp xpkg parse pkgs/y/yizhinailong.mcr.lua` → `parse OK`(三平台 0.1.5, + mcpp 自报 `form A`)。 +- 冷验证 `mcpp test -p mcr`(清掉 `tests/examples/mcr/{target,.mcpp}`)结果见 commit/PR + 描述;关键中间证据:本地索引能解析并下载 —— 日志出现 + `Workspace building member 'mcr-tests'` 与 `Downloading yizhinailong.mcr v0.1.5`。 +- 本机缺 `lua5.4` 与 `bash`,`tests/check_*.lua` 与 `tests/run_members.sh` 无法本地 + 复现,交由 CI 的 `lint` 与 `workspace` 覆盖;本地已按 `check_mirror_urls.lua` / + `check_cross_package_refs.lua` 的规则逐条核对(纯字符串 url 合法、无 `pkginfo.*` + 跨包引用)。本机 mcpp 为 2026.10.11.1,新于 CI pin 的 2026.10.1.2,故本地跑绿 + 不等于 CI 跑绿。 diff --git a/.agents/docs/2026-10-16-update-compat-imgui-plan.md b/.agents/docs/2026-10-16-update-compat-imgui-plan.md new file mode 100644 index 00000000..623c3a69 --- /dev/null +++ b/.agents/docs/2026-10-16-update-compat-imgui-plan.md @@ -0,0 +1,40 @@ +# Update compat:imgui to 1.93.0 + +## Scope and source + +- Upstream: , released 2026-10-14. +- Add `1.93.0` and `1.93.0-docking` to Linux, macOS and Windows; retain both 1.92.8 entries. +- Keep the existing Form B recipe: four core C++ sources, public headers and backend include directory. +- Update the `imgui` and `imgui-window` example dependencies to `1.93.0`. +- The separate `ocornut:imgui` module package is outside this update. + +## Archives and mirrors + +The GitHub tag archives were downloaded and each SHA-256 was calculated twice: + +| Version | SHA-256 | +| --- | --- | +| 1.93.0 | `f7bf6bc76e5d79d40d751096663e6c5d18daf08129dd52e7f7b09e4251c8eeee` | +| 1.93.0-docking | `746c265540bd3aa109570f29492ef4d8f5b421dd9fd0049c35ca35f21496f1a5` | + +No GitCode configuration or token is available in this environment. The new entries use plain upstream URLs, +as allowed by `docs/zh/cn-mirror.md`; the existing 1.92.8 mirror entries are retained. + +## Recipe and compatibility + +There are no new sources to gate behind a feature. Docking remains an upstream archive variant. +The existing rendering test exercises context creation, font atlas generation and valid draw data without a display. +1.93.0 changes custom draw-list rendering; see upstream's release notes for stroke and pixel-alignment changes. + +## Validation + +- Lua syntax, mirror URL rules, package identity, reserved namespaces, platform version parity and duplicate-version checks passed. +- `mcpp xpkg parse pkgs/c/compat.imgui.lua` passed with both the CI-pinned mcpp 2026.10.1.2 and local mcpp 2026.10.11.1, + listing both new versions on all three platforms. +- `mcpp test -p imgui --cache local` passed on Windows with the CI-pinned mcpp 2026.10.1.2 and LLVM 23.1.3 / system MSVC: + the 1.93.0 core sources were recompiled, and the rendering test passed (one test, zero failures). +- The verified `1.93.0-docking` archive's four core sources were compiled directly with `clang++ -std=c++23`, together + with the existing `tests/examples/imgui/tests/render.cpp`. The resulting executable passed (exit code 0). + A separate mcpp docking test was stopped after spending over three minutes waiting on another archive download; + the docking check therefore covers the downloaded source build and rendering, not a completed mcpp install. +- `imgui-window` is Linux-only; Windows does not exercise its backend build or window rendering. diff --git a/README.md b/README.md index 45888654..b7a8b48a 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,8 @@ Additional example: [`compat.etl`](pkgs/c/compat.etl.lua) — Header-only; [`con Additional example: [`compat.richdem`](pkgs/c/compat.richdem.lua) — C++ sources, serial terrain analysis; [`consumer test`](tests/examples/richdem/mcpp.toml). Additional example: [`compat.fmt`](pkgs/c/compat.fmt.lua) — {fmt} in header form (`#include `; the non-module sibling of `fmtlib.fmt`), its C API behind a `c-api` feature; [`consumer test`](tests/examples/fmt/mcpp.toml), [`feature test`](tests/examples/fmt-c/mcpp.toml). Additional example: [`compat.soci`](pkgs/c/compat.soci.lua) — C++ database API, with the SQLite3 backend compiled in and the engine taken from `compat.sqlite3`; [`consumer test`](tests/examples/soci/mcpp.toml). +Additional example: [`compat.imgui`](pkgs/c/compat.imgui.lua) — Dear ImGui 1.93.0 core sources, including the docking variant; [`headless test`](tests/examples/imgui/mcpp.toml), [`GLFW/OpenGL3 backend test`](tests/examples/imgui-window/mcpp.toml). +Additional example: [`yizhinailong.mcr`](pkgs/y/yizhinailong.mcr.lua) — Form A module library: libcurl-based C++23 HTTP client with sync, async, coroutine and batch requests, built from the upstream's own `mcpp.toml`; [`consumer test`](tests/examples/mcr/mcpp.toml). ## Documentation diff --git a/README.zh-CN.md b/README.zh-CN.md index cc334fa8..7e25b24b 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -65,6 +65,8 @@ agent(如 Claude Code)即可: 新增示例: [`compat.richdem`](pkgs/c/compat.richdem.lua) — C++ sources, serial terrain analysis; [`消费测试`](tests/examples/richdem/mcpp.toml)。 新增示例: [`compat.fmt`](pkgs/c/compat.fmt.lua) — {fmt} 头文件形态(`#include `,即 `fmtlib.fmt` 的非模块兄弟),C API 由 `c-api` feature 门控; [`消费测试`](tests/examples/fmt/mcpp.toml)、[`feature 测试`](tests/examples/fmt-c/mcpp.toml)。 新增示例: [`compat.soci`](pkgs/c/compat.soci.lua) — C++ 数据库访问层,SQLite3 后端编入同一库,引擎来自 `compat.sqlite3`; [`消费测试`](tests/examples/soci/mcpp.toml)。 +示例: [`compat.imgui`](pkgs/c/compat.imgui.lua) — Dear ImGui 1.93.0 核心源码,含 docking 版本; [`无窗口测试`](tests/examples/imgui/mcpp.toml)、[`GLFW/OpenGL3 后端测试`](tests/examples/imgui-window/mcpp.toml)。 +新增示例: [`yizhinailong.mcr`](pkgs/y/yizhinailong.mcr.lua) — Form A 模块库:基于 libcurl 的 C++23 HTTP 客户端,支持同步、异步、协程与批量请求,构建由上游自带 `mcpp.toml` 负责; [`消费测试`](tests/examples/mcr/mcpp.toml)。 ## 文档 diff --git a/mcpp.toml b/mcpp.toml index d1d380a5..461c1064 100644 --- a/mcpp.toml +++ b/mcpp.toml @@ -199,6 +199,7 @@ members = [ "tests/examples/wamr-runtime-features", "tests/examples/quickjs-ng", "tests/examples/rapidcsv", + "tests/examples/mcr", ] # ── The index redirect, hoisted to the workspace root ─────────────────── diff --git a/pkgs/c/compat.imgui.lua b/pkgs/c/compat.imgui.lua index 0c4a37e5..3495f565 100644 --- a/pkgs/c/compat.imgui.lua +++ b/pkgs/c/compat.imgui.lua @@ -9,6 +9,15 @@ package = { xpm = { linux = { + -- No CN mirror credentials: use upstream URLs for the new releases. + ["1.93.0"] = { + url = "https://github.com/ocornut/imgui/archive/refs/tags/v1.93.0.tar.gz", + sha256 = "f7bf6bc76e5d79d40d751096663e6c5d18daf08129dd52e7f7b09e4251c8eeee", + }, + ["1.93.0-docking"] = { + url = "https://github.com/ocornut/imgui/archive/refs/tags/v1.93.0-docking.tar.gz", + sha256 = "746c265540bd3aa109570f29492ef4d8f5b421dd9fd0049c35ca35f21496f1a5", + }, ["1.92.8"] = { url = { GLOBAL = "https://github.com/ocornut/imgui/archive/refs/tags/v1.92.8.tar.gz", @@ -25,6 +34,14 @@ package = { }, }, macosx = { + ["1.93.0"] = { + url = "https://github.com/ocornut/imgui/archive/refs/tags/v1.93.0.tar.gz", + sha256 = "f7bf6bc76e5d79d40d751096663e6c5d18daf08129dd52e7f7b09e4251c8eeee", + }, + ["1.93.0-docking"] = { + url = "https://github.com/ocornut/imgui/archive/refs/tags/v1.93.0-docking.tar.gz", + sha256 = "746c265540bd3aa109570f29492ef4d8f5b421dd9fd0049c35ca35f21496f1a5", + }, ["1.92.8"] = { url = { GLOBAL = "https://github.com/ocornut/imgui/archive/refs/tags/v1.92.8.tar.gz", @@ -41,6 +58,14 @@ package = { }, }, windows = { + ["1.93.0"] = { + url = "https://github.com/ocornut/imgui/archive/refs/tags/v1.93.0.tar.gz", + sha256 = "f7bf6bc76e5d79d40d751096663e6c5d18daf08129dd52e7f7b09e4251c8eeee", + }, + ["1.93.0-docking"] = { + url = "https://github.com/ocornut/imgui/archive/refs/tags/v1.93.0-docking.tar.gz", + sha256 = "746c265540bd3aa109570f29492ef4d8f5b421dd9fd0049c35ca35f21496f1a5", + }, ["1.92.8"] = { url = { GLOBAL = "https://github.com/ocornut/imgui/archive/refs/tags/v1.92.8.tar.gz", diff --git a/pkgs/y/yizhinailong.mcr.lua b/pkgs/y/yizhinailong.mcr.lua new file mode 100644 index 00000000..aa64787a --- /dev/null +++ b/pkgs/y/yizhinailong.mcr.lua @@ -0,0 +1,51 @@ +-- Form A descriptor: mcr is an mcpp-native library — its own mcpp.toml and +-- build.mcpp sit at the archive root — so the descriptor carries identity and +-- the download address only, and the build comes from upstream through +-- `mcpp = "*/mcpp.toml"` (the galay / marzer.tomlplusplus shape). +-- +-- GLOBAL is the TAG ARCHIVE, not a release tarball: upstream publishes git +-- tags v0.1.3 .. v0.1.5, but all three GitHub releases are empty (no assets), +-- so there is nothing else to point at. The archive wraps as `mcr-0.1.5/`, +-- which is what the leading `*/` absorbs. +-- +-- All three platforms share the one source archive. TLS is not inlined here +-- because mcr's OWN manifest already branches it — Schannel on Windows, +-- `compat.openssl` on linux/macosx — and Form A means upstream keeps owning +-- that decision. Its dependencies (compat.curl 8.21.0, nlohmann.json 3.12.0) +-- are both already in this index. +-- +-- No mcpp-res mirror is configured locally, so the plain-string GLOBAL url is +-- the documented fallback for CN consumers (docs/cn-mirror.md) until a +-- maintainer creates the mirror; lint accepts this form. +package = { + spec = "1", + namespace = "yizhinailong", + name = "mcr", + description = "Modular C++23 HTTP client on libcurl — sync, async, coroutine and batch requests with JSON support", + licenses = {"MIT"}, + repo = "https://github.com/yizhinailong/mcr", + type = "package", + + xpm = { + linux = { + ["0.1.5"] = { + url = "https://github.com/yizhinailong/mcr/archive/refs/tags/v0.1.5.tar.gz", + sha256 = "bd55e9dc19b620d7dfb89d20fd4a6b1ab9cf947fe872dc536dee53b4e869f8f5", + }, + }, + macosx = { + ["0.1.5"] = { + url = "https://github.com/yizhinailong/mcr/archive/refs/tags/v0.1.5.tar.gz", + sha256 = "bd55e9dc19b620d7dfb89d20fd4a6b1ab9cf947fe872dc536dee53b4e869f8f5", + }, + }, + windows = { + ["0.1.5"] = { + url = "https://github.com/yizhinailong/mcr/archive/refs/tags/v0.1.5.tar.gz", + sha256 = "bd55e9dc19b620d7dfb89d20fd4a6b1ab9cf947fe872dc536dee53b4e869f8f5", + }, + }, + }, + + mcpp = "*/mcpp.toml", +} diff --git a/tests/examples/imgui-window/mcpp.toml b/tests/examples/imgui-window/mcpp.toml index 0a804ce9..fce20a4f 100644 --- a/tests/examples/imgui-window/mcpp.toml +++ b/tests/examples/imgui-window/mcpp.toml @@ -6,7 +6,7 @@ name = "imgui-window-tests" version = "0.1.0" [target.'cfg(linux)'.dependencies.compat] -imgui = "1.92.8" +imgui = "1.93.0" glfw = "3.4.0.1" [target.'cfg(linux)'.build] ldflags = ["-ldl"] diff --git a/tests/examples/imgui/mcpp.toml b/tests/examples/imgui/mcpp.toml index 84a254b7..940bd5a1 100644 --- a/tests/examples/imgui/mcpp.toml +++ b/tests/examples/imgui/mcpp.toml @@ -4,4 +4,4 @@ name = "imgui-tests" version = "0.1.0" [dependencies.compat] -imgui = "1.92.8" +imgui = "1.93.0" diff --git a/tests/examples/mcr/mcpp.toml b/tests/examples/mcr/mcpp.toml new file mode 100644 index 00000000..391e4ed0 --- /dev/null +++ b/tests/examples/mcr/mcpp.toml @@ -0,0 +1,18 @@ +# Public Form-A consumer for `yizhinailong.mcr`. The package owns its build +# (upstream mcpp.toml + build.mcpp), so this member only proves the descriptor +# resolves and the exported module compiles and links. +# +# The member-level [indices] REPLACES the workspace root's `compat` table +# rather than merging with it, which is the documented hard constraint: two +# project index repos make every lookup ambiguous (mcpp#238). So `compat.*` — +# mcr's own compat.curl / nlohmann.json dependencies — deliberately resolves +# from the published remote index while the new namespace resolves here. +[indices] +yizhinailong = { path = "../../.." } + +[package] +name = "mcr-tests" +version = "0.1.0" + +[dependencies.yizhinailong] +mcr = "0.1.5" diff --git a/tests/examples/mcr/tests/api.cpp b/tests/examples/mcr/tests/api.cpp new file mode 100644 index 00000000..5ac5af85 --- /dev/null +++ b/tests/examples/mcr/tests/api.cpp @@ -0,0 +1,65 @@ +// yizhinailong.mcr — prove the public module surface compiles, links and +// behaves. A live HTTP round trip is deliberately out of scope: it would need +// a local server plus the curl runtime, neither of which belongs in an index +// member. What is exercised here is everything that is observable offline — +// the generated version module, the status classifiers, the owned option +// types, and the Response JSON parsing path. + +import std; +import mcr; + +int main() { + // mcr.version is generated by the package's own build.mcpp, read out of + // its mcpp.toml. Asserting on it proves the build hook ran and the + // generated module unit reached the library target. + if (mcr::VERSION != "0.1.5") return 1; + if (mcr::VERSION_MAJOR != 0 || mcr::VERSION_MINOR != 1 || mcr::VERSION_PATCH != 5) return 2; + + // Status classification is constexpr and independent of libcurl. + static_assert(mcr::status::is_informational(100)); + static_assert(mcr::status::is_success(200)); + static_assert(mcr::status::is_redirect(301)); + static_assert(mcr::status::is_client_error(404)); + static_assert(mcr::status::is_server_error(503)); + if (!mcr::status::is_success(mcr::status::HTTP_OK)) return 3; + if (mcr::status::is_success(mcr::status::HTTP_NOT_FOUND)) return 4; + + // Url and Header are the owned, cpr-shaped option types. Header lookups + // fold case, which is the property std::map alone would not give. + mcr::Url const url{ "http://127.0.0.1:8080/echo" }; + if (url.Str() != "http://127.0.0.1:8080/echo") return 5; + + mcr::Header header; + header["Content-Type"] = "application/json"; + if (header.find("content-type") == header.end()) return 6; + if (header.at("CONTENT-TYPE") != "application/json") return 7; + + // JsonBody owns the compact serialization of a value, taken at construction. + mcr::Json const value{ { "name", "Alice" }, { "enabled", true } }; + mcr::JsonBody const body{ value }; + if (mcr::Json::parse(body.Str()) != value) return 8; + + // Response::TryJson reports a parse failure as a diagnostic rather than + // throwing, while Json() throws and does not check the status code. + mcr::Response response; + response.status_code = mcr::status::HTTP_OK; + response.text = R"({"answer":42})"; + auto parsed = response.TryJson(); + if (!parsed) return 9; + if (parsed->at("answer").get() != 42) return 10; + + response.text = "{ not json"; + auto failed = response.TryJson(); + if (failed) return 11; + if (failed.error().message.empty()) return 12; + + bool threw{ false }; + try { + (void)response.Json(); + } catch (mcr::Json::exception const&) { + threw = true; + } + if (!threw) return 13; + + return 0; +}