diff --git a/.agents/docs/2026-07-16-add-marzer-tomlplusplus-plan.md b/.agents/docs/2026-07-16-add-marzer-tomlplusplus-plan.md new file mode 100644 index 0000000..8e9f345 --- /dev/null +++ b/.agents/docs/2026-07-16-add-marzer-tomlplusplus-plan.md @@ -0,0 +1,109 @@ +# 收录 toml++(marzer.tomlplusplus)3.4.0 + +> PR: https://github.com/mcpplibs/mcpp-index/pull/64 +> 日期:2026-07-16 +> 背景:PR #64 原以 fork 形态提交,按 review 意见([comment](https://github.com/mcpplibs/mcpp-index/pull/64#issuecomment-4907425691)) +> 参照 `nlohmann.json` 重做。本文记录形态判定、镜像、验证结论与注意事项。 + +## 1. 来源与形态判定 + +- 来源:**(a) 第三方上游库**。上游 [marzer/tomlplusplus](https://github.com/marzer/tomlplusplus) 不提供 mcpp 支持。 +- 版本:`v3.4.0`(截至 2026-07-16 的最新 release tag)。 +- License:MIT。 +- 布局:tarball 顶层 wrap 目录为 `tomlplusplus-3.4.0/`,头文件位于 `include/toml++/`,**header-only**。 +- 形态:**C++23 module(generated wrapper)** —— 与 `nlohmann.json` 同类。 + +判定依据:release tarball **不含** 任何 `.cppm`: + +```console +$ tar tzf tomlplusplus-3.4.0.tar.gz | grep -iE 'cppm|modules' +tomlplusplus-3.4.0/.gitmodules # 仅 git submodule 配置,非模块单元 +``` + +而上游**确实**已编写官方模块单元 `src/modules/tomlplusplus.cppm`(`export module tomlplusplus;`), +但它只存在于 `master` 分支,未进入 v3.4.0。因此采用 `generated_files` 内嵌该 cppm, +基础头文件仍 pin 在可复现的 v3.4.0 release tag —— **信任链上不引入 fork**。 + +## 2. 关键注意事项:master 的 cppm 不能原样内嵌 + +⚠️ 这是本次收录最容易踩的坑,与 `nlohmann.json`(可 VERBATIM 内嵌)不同。 + +上游 master 的 cppm 面向 master 的头文件编写,其中一行: + +```cpp +using TOML_NAMESPACE::get_line; +``` + +`get_line` 是 v3.4.0 **之后**才加入 `include/toml++/impl/source_region.hpp` 的。对 pinned 的 v3.4.0 头文件做 +负向验证,确认其确实不存在: + +```console +$ grep -rn "get_line" tomlplusplus-3.4.0/ # 整个 tarball 无任何命中 + +$ cat probe.cpp +#include +namespace probe { using toml::get_line; } +int main(){} + +$ g++ -std=c++17 -fsyntax-only -Iinclude probe.cpp +probe.cpp:2:31: error: 'get_line' has not been declared in 'toml' + +$ # 对照组:同一探针换成 toml::parse,编译通过 —— 证明头文件本身无恙 +``` + +**结论**:内嵌版本删除该行,其余**逐字节一致**(已用 `diff` 对内嵌内容与上游 master 减去该行的结果做校验,结果 IDENTICAL)。 +差异已在描述符注释中写明。 + +**演进条件**:待上游发布 >3.4.0 且随 release 附带 `src/modules/tomlplusplus.cppm` 时,可切回 +`sources = { "*/src/modules/tomlplusplus.cppm" }` 并删除 `generated_files`,`get_line` 会随之回归。 + +## 3. 描述符 + +- 路径:`pkgs/m/marzer.tomlplusplus.lua`(目录取**完整包名首字母** `m`)。 +- 命名:`marzer.tomlplusplus`,遵循 `nlohmann.json` 的 `<命名空间>.<库>` 约定。 +- `include_dirs = { "*/include" }`:cppm 的 global-module fragment 内 `#include ` 由此解析; + 同时保留用户直接 `#include` 的能力。`*` 吸收 `tomlplusplus-3.4.0/` wrap 层。 +- `generated_files` 的 key 为 verdir 相对路径(无 glob),与 `nlohmann.json` 一致。 +- 多行字符串采用 `[==[ ]==]`(而非 `[[ ]]`):与 `nlohmann.json` 保持一致,且对 payload 中可能出现的 + `[[`/`]]` 更稳妥。已确认 payload 不含 `]==]`。 +- 版本号采用裸版本 `"3.4.0"`;URL 中保留上游 `…/v3.4.0.tar.gz` 拼写。 + +## 4. feature 评估 + +**不实现 feature**。toml++ 为 header-only,无“额外的可编译源码”可供门控;其可选行为(如 `TOML_EXCEPTIONS`、 +`TOML_ENABLE_FORMATTERS`)均为编译期 **define**,而 `features` 表当前仅能门控 `sources`,无法携带 define。 +与 Eigen 的 `EIGEN_MPL2_ONLY` 属同类限制,待 mcpp 支持 define/cflags 后再评估。 + +## 5. CN 镜像 + +- 新建 gitcode 仓库 `mcpp-res/tomlplusplus`(经 `gtc repo create` + init commit 建立 `main` 分支)。 +- release tag `3.4.0`,资产 `tomlplusplus-3.4.0.tar.gz`,上传的是**与 GLOBAL 完全相同**的 tarball。 +- 字节一致性验证: + +```console +CN sha: 8517f65938a4faae9ccf8ebb36631a38c1cadfb5efa85d9a72e15b9e97d25155 +GLB sha: 8517f65938a4faae9ccf8ebb36631a38c1cadfb5efa85d9a72e15b9e97d25155 +cmp : byte-identical +``` + +- sha 稳定性:GLOBAL 重复下载两次,sha 一致(无 GitLab 式重打包漂移)。 + +## 6. 验证结论 + +测试工程 `tests/examples/marzer.tomlplusplus/`,已登记进根 `mcpp.toml` 的 `[workspace].members` +(本仓测试面已由 `run_example.sh` 迁移至 `mcpp test --workspace`,故不再新增 `src/main.cpp` 式 bin 例子)。 +断言覆盖 parse、typed access、array/table 节点、`_toml` 字面量、serialize→reparse 往返。 + +| 检查 | 结果 | +|---|---| +| `mcpp test`(GLOBAL) | ✅ `parse ... ok` — 1 passed | +| `mcpp test`(`MCPP_INDEX_MIRROR=CN`,清 `target .mcpp mcpp.lock` 后真实重新下载) | ✅ `parse ... ok` — 1 passed | +| CN vs GLOBAL 字节比对 | ✅ byte-identical | +| 全量 lint(46 descriptor,含 `check_mirror_urls.lua`) | ✅ all valid | +| `mcpp xpkg parse`(CI pin 0.0.91 与本地 0.0.93) | ✅ OK | +| 内嵌 cppm vs 上游 master 减 get_line | ✅ `diff` IDENTICAL | + +## 7. 其它 + +- PR #64 原分支落后 `main` 10 个提交,已 rebase 到最新 `main` 后强推(`maintainerCanModify` 为 true)。 +- 原 `pkgs/c/compat.tomlplusplus.lua` 与 `tests/examples/tomlplusplus/` 已删除。 diff --git a/README.md b/README.md index 9a9ec29..53609c1 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ mcpp self config --mirror CN # 切换至国内镜像,默认使用 GLOBAL 上 | C 源码 compat(含 `features`) | [`compat.cjson`](pkgs/c/compat.cjson.lua) · [`compat.zlib`](pkgs/c/compat.zlib.lua) | | header-only(含 `features`) | [`compat.eigen`](pkgs/c/compat.eigen.lua) | | 外部构建系统(`install()` 从源码构建) | [`compat.openblas`](pkgs/c/compat.openblas.lua)(Make) · [`compat.opencv`](pkgs/c/compat.opencv.lua)(CMake) | -| C++23 module wrapper | [`nlohmann.json`](pkgs/n/nlohmann.json.lua) | +| C++23 module wrapper | [`nlohmann.json`](pkgs/n/nlohmann.json.lua) · [`marzer.tomlplusplus`](pkgs/m/marzer.tomlplusplus.lua) | ### 新增一个包 diff --git a/mcpp.toml b/mcpp.toml index e836eca..a7a8891 100644 --- a/mcpp.toml +++ b/mcpp.toml @@ -17,6 +17,7 @@ members = [ "tests/examples/gui-stack", "tests/examples/imgui", "tests/examples/imgui-window", + "tests/examples/marzer.tomlplusplus", "tests/examples/nlohmann.json", "tests/examples/openblas", "tests/examples/opencv", diff --git a/pkgs/m/marzer.tomlplusplus.lua b/pkgs/m/marzer.tomlplusplus.lua new file mode 100644 index 0000000..d61e6eb --- /dev/null +++ b/pkgs/m/marzer.tomlplusplus.lua @@ -0,0 +1,172 @@ +-- Form B inline descriptor for toml++ (marzer/tomlplusplus) — a TOML config +-- file parser and serializer for C++17 (and later), exposed as the C++23 +-- module `tomlplusplus` so users can write `import tomlplusplus;` out of the +-- box (no opt-in, no `#include` needed). +-- +-- Why generated: the released v3.4.0 source tarball is header-only and ships +-- NO module interface unit. Upstream HAS authored an official one at +-- `src/modules/tomlplusplus.cppm` (`export module tomlplusplus;`), but it +-- lives on the `master` branch only and is not in any release tag yet (v3.4.0 +-- 404s for that path). So we provide it ourselves via mcpp's `generated_files`, +-- embedding upstream's official tomlplusplus.cppm. The base headers stay +-- pinned to the reproducible v3.4.0 release tag, straight from upstream — +-- no fork in the trust path. +-- +-- ONE deviation from upstream master's cppm, deliberate and minimal: +-- `using TOML_NAMESPACE::get_line;` is dropped. `get_line` was added to +-- `impl/source_region.hpp` AFTER v3.4.0 and does not exist in the pinned +-- headers, so re-exporting it would not compile. Every other line is verbatim. +-- +-- Evolution: once a toml++ release (>3.4.0) ships src/modules/tomlplusplus.cppm, +-- switch `sources` to "*/src/modules/tomlplusplus.cppm", drop `generated_files`, +-- and the get_line re-export comes back with it. +-- +-- include_dirs exposes the tarball's include/ so the module unit's global-module +-- fragment `#include ` resolves (and `#include` remains +-- available to users who want it). The upstream path is a GLOB — the leading +-- `*` absorbs the archive's `tomlplusplus-3.4.0/` wrap layer — while the +-- generated cppm path is verdir-relative (no glob), like nlohmann.json. +package = { + spec = "1", + namespace = "marzer", + name = "marzer.tomlplusplus", + description = "TOML config file parser and serializer for C++, exposed as C++23 module tomlplusplus", + licenses = {"MIT"}, + repo = "https://github.com/marzer/tomlplusplus", + type = "package", + + xpm = { + linux = { + ["3.4.0"] = { + url = { + GLOBAL = "https://github.com/marzer/tomlplusplus/archive/refs/tags/v3.4.0.tar.gz", + CN = "https://gitcode.com/mcpp-res/tomlplusplus/releases/download/3.4.0/tomlplusplus-3.4.0.tar.gz", + }, + sha256 = "8517f65938a4faae9ccf8ebb36631a38c1cadfb5efa85d9a72e15b9e97d25155", + }, + }, + macosx = { + ["3.4.0"] = { + url = { + GLOBAL = "https://github.com/marzer/tomlplusplus/archive/refs/tags/v3.4.0.tar.gz", + CN = "https://gitcode.com/mcpp-res/tomlplusplus/releases/download/3.4.0/tomlplusplus-3.4.0.tar.gz", + }, + sha256 = "8517f65938a4faae9ccf8ebb36631a38c1cadfb5efa85d9a72e15b9e97d25155", + }, + }, + windows = { + ["3.4.0"] = { + url = { + GLOBAL = "https://github.com/marzer/tomlplusplus/archive/refs/tags/v3.4.0.tar.gz", + CN = "https://gitcode.com/mcpp-res/tomlplusplus/releases/download/3.4.0/tomlplusplus-3.4.0.tar.gz", + }, + sha256 = "8517f65938a4faae9ccf8ebb36631a38c1cadfb5efa85d9a72e15b9e97d25155", + }, + }, + }, + + mcpp = { + schema = "0.1", + language = "c++23", + import_std = false, + modules = { "tomlplusplus" }, + include_dirs = { "*/include" }, + -- Upstream's official module unit (master @ src/modules/tomlplusplus.cppm), + -- reproduced verbatim apart from the get_line drop documented above. + -- Verdir-relative path, no glob. + generated_files = { + ["mcpp_generated/tomlplusplus.cppm"] = [==[ +/** + * @file tomlpp.cppm + * @brief File containing the module declaration for toml++. + */ + +module; + +#define TOML_UNDEF_MACROS 0 +#include + +export module tomlplusplus; + +/** + * @namespace toml + * @brief The toml++ namespace toml:: + */ +export namespace toml { + /** + * @namespace literals + * @brief The toml++ namespace toml::literals:: + */ + inline namespace literals { + using TOML_NAMESPACE::literals::operator""_toml; + using TOML_NAMESPACE::literals::operator""_tpath; + } + + using TOML_NAMESPACE::array; + using TOML_NAMESPACE::date; + using TOML_NAMESPACE::date_time; + using TOML_NAMESPACE::inserter; + using TOML_NAMESPACE::json_formatter; + using TOML_NAMESPACE::key; + using TOML_NAMESPACE::node; + using TOML_NAMESPACE::node_view; + using TOML_NAMESPACE::parse_error; + using TOML_NAMESPACE::parse_result; + using TOML_NAMESPACE::path; + using TOML_NAMESPACE::path_component; + using TOML_NAMESPACE::source_position; + using TOML_NAMESPACE::source_region; + using TOML_NAMESPACE::table; + using TOML_NAMESPACE::time; + using TOML_NAMESPACE::time_offset; + using TOML_NAMESPACE::toml_formatter; + using TOML_NAMESPACE::value; + using TOML_NAMESPACE::yaml_formatter; + using TOML_NAMESPACE::format_flags; + using TOML_NAMESPACE::node_type; + using TOML_NAMESPACE::path_component_type; + using TOML_NAMESPACE::value_flags; + using TOML_NAMESPACE::array_iterator; + using TOML_NAMESPACE::const_array_iterator; + using TOML_NAMESPACE::const_table_iterator; + using TOML_NAMESPACE::default_formatter; + using TOML_NAMESPACE::inserted_type_of; + using TOML_NAMESPACE::optional; + using TOML_NAMESPACE::source_index; + using TOML_NAMESPACE::source_path_ptr; + using TOML_NAMESPACE::table_iterator; + + using TOML_NAMESPACE::at_path; + using TOML_NAMESPACE::operator""_toml; + using TOML_NAMESPACE::operator""_tpath; + using TOML_NAMESPACE::operator<<; + using TOML_NAMESPACE::parse; + using TOML_NAMESPACE::parse_file; + + using TOML_NAMESPACE::is_array; + using TOML_NAMESPACE::is_boolean; + using TOML_NAMESPACE::is_chronological; + using TOML_NAMESPACE::is_container; + using TOML_NAMESPACE::is_date; + using TOML_NAMESPACE::is_date_time; + using TOML_NAMESPACE::is_floating_point; + using TOML_NAMESPACE::is_integer; + using TOML_NAMESPACE::is_key; + using TOML_NAMESPACE::is_key_or_convertible; + using TOML_NAMESPACE::is_node; + using TOML_NAMESPACE::is_node_view; + using TOML_NAMESPACE::is_number; + using TOML_NAMESPACE::is_string; + using TOML_NAMESPACE::is_table; + using TOML_NAMESPACE::is_time; + using TOML_NAMESPACE::is_value; + + using TOML_NAMESPACE::preserve_source_value_flags; +} +]==], + }, + sources = { "mcpp_generated/tomlplusplus.cppm" }, + targets = { ["tomlplusplus"] = { kind = "lib" } }, + deps = { }, + }, +} diff --git a/tests/examples/marzer.tomlplusplus/mcpp.toml b/tests/examples/marzer.tomlplusplus/mcpp.toml new file mode 100644 index 0000000..6aadc4f --- /dev/null +++ b/tests/examples/marzer.tomlplusplus/mcpp.toml @@ -0,0 +1,11 @@ +# toml++ test project: consumes the C++23 module `tomlplusplus` and asserts +# parse + typed access + round-trip serialization under `mcpp test`. +[package] +name = "tomlplusplus-tests" +version = "0.1.0" + +[indices] +marzer = { path = "../../.." } + +[dependencies.marzer] +tomlplusplus = "3.4.0" diff --git a/tests/examples/marzer.tomlplusplus/tests/parse.cpp b/tests/examples/marzer.tomlplusplus/tests/parse.cpp new file mode 100644 index 0000000..27b90cb --- /dev/null +++ b/tests/examples/marzer.tomlplusplus/tests/parse.cpp @@ -0,0 +1,33 @@ +// Behavioral test: parse → typed access → array/table nodes → _toml literal → +// serialize-and-reparse round-trip, all through the C++23 module surface +// (`import tomlplusplus;`, no #include). +import std; +import tomlplusplus; + +int main() { + auto cfg = toml::parse(R"( + [server] + host = "localhost" + port = 8080 + tags = ["a", "b"] + )"); + + // typed access — value so this compares strings, not pointers + bool ok = cfg["server"]["port"].value() == 8080 + && cfg["server"]["host"].value() == "localhost" + && cfg["server"]["tags"].as_array()->size() == 2; + + // the _toml literal re-exported through toml::literals + using namespace toml::literals; + auto lit = "x = 1"_toml; + ok = ok && lit["x"].value() == 1; + + // round-trip: serialize via the exported operator<<, then re-parse + std::ostringstream os; + os << cfg; + auto again = toml::parse(os.str()); + ok = ok && again["server"]["port"].value() == 8080 + && again["server"]["tags"].as_array()->size() == 2; + + return ok ? 0 : 1; +}