add compat.catch2 — one package for 2.13.10 + 3.15.2 - #126
Merged
Conversation
Contributor
Author
|
参考 mcpp-community/mcpp#290 的需求,如果能够支持按版本区分构建规则,可以将 catch2 和 catch2-v2 合并,下游使用更加便捷 |
Catch2 is a modern C++ test framework. - compat.catch2 (v3): C-source compat static library built from individual source files under src/catch2/. Includes generated catch_user_config.hpp (normally CMake-generated). Default main suppressed via -DCATCH_AMALGAMATED_CUSTOM_MAIN; `main` feature gates a generated default main TU (same pattern as compat.gtest). - compat.catch2-v2 (v2): header-only, single-include via single_include/catch2/catch.hpp with anchor TU. `main` feature gates a generated TU with CATCH_CONFIG_MAIN. Both use GitHub tag archive tarballs. No CN mirror yet (no mcpp-res write access). Local `mcpp test -p catch2` and `mcpp test -p catch2-v2` pass on mcpp 0.0.108 (x86_64-windows-msvc).
…ature Collapse compat.catch2 + compat.catch2-v2 into a single `compat.catch2` carrying 2.13.10 and 3.15.2, and repair the v3 `main` feature, which did not work. ## One package The two majors' globs are DISJOINT — v2 has no `src/catch2/` (its only src/ file is `src/catch_with_main.cpp`) and v3 has no `single_include/` — so one `mcpp` block can carry the UNION and let each version light up exactly one half: v2 degenerates to header-only + anchor TU, v3 to a 106-TU static library. A glob that matches nothing is not an error, which is what makes this safe. Two packages was the wrong shape independent of that: `catch2-v2` encodes a major into the atomic `name` segment SPEC-001 identity reserves for the name (the same anti-pattern the compat.openssl → openssl rename removed), and it breaks semver across the major — a consumer cannot write `catch2 = "^3"`. It is also a one-way door: once `compat.catch2-v2` ships in a published artifact, withdrawing it is a breaking change. mcpp-community/mcpp#290 (per-version build blocks) is NOT a prerequisite — this works on 0.0.109 today — but it is the right destination: the disjointness is a property of two upstream trees, not something the descriptor can enforce. Recorded in the descriptor header as the premise to re-check when adding a version. ## The `main` feature was dead `features = ["main"]` on v3 produced `undefined reference to 'main'`. Measured on 0.0.109: glob + `!` negation, feature → negated path default ok | feature FAIL glob, no negation, feature → globbed path default FAIL| feature ok glob + negation + explicit re-add default ok | feature FAIL glob + `!` negation, feature → GENERATED TU default ok | feature ok Two mechanics: a `!` negation is an ABSOLUTE exclusion that a feature cannot add back, and feature gating matches LITERAL `sources` entries — a file pulled in by a glob is not gated at all. So compat.gtest's shape does not transfer (gtest_main.cc is a literal entry). The feature now compiles a generated TU that branches on `__has_include(<catch2/catch_all.hpp>)` to pick the v3 or v2 spelling. Cost: no LeakDetector registration and no wmain variant. Documented. ## Four members, because features are per-project One project cannot hold catch2 both with and without `main` (same constraint as asio-ssl vs asio-module), so 2 majors × {default, feature} = 4 members. The previous revision declared the feature on both packages and covered NEITHER — which is exactly why a non-functional feature passed CI. ## CN mirror Both versions mirrored to gitcode mcpp-res/catch2 and re-downloaded: byte-identical to upstream (same sha256, same size), so the single recorded sha256 covers either source. ## Verification (mcpp 0.0.109, gcc@16.1.0, linux-x86_64) - `mcpp xpkg parse` + `tests/check_mirror_urls.lua`: OK - all 4 members `mcpp test -p`: ok, 2 assertions each (not empty) - negative controls: dropping `features = ["main"]` from either -main member fails with `undefined reference to 'main'`, so the feature is demonstrably what supplies the entry point - both tarballs re-fetched from GLOBAL and CN and sha256-checked
Sunrisepeak
force-pushed
the
add-compat-catch2
branch
from
July 27, 2026 04:46
15857e4 to
0cc2fb2
Compare
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.
把 Catch2 加进 mcpp-index。已从初版的两个包改为单个
compat.catch2,同时携带 2.13.10 与 3.15.2。1. 为什么是一个包,不是两个
初版拆成
compat.catch2(v3)与compat.catch2-v2(v2),理由是"v2→v3 布局完全改变,无法共用一个mcpp块"。前提对,结论不对 —— 两套 glob 互不相交:*/single_include*/src/catch2/**/*.cppsrc/里只有src/catch_with_main.cpp,不在src/catch2/下)catch2/catch_all.hpp所以一个
mcpp块可以承载并集,每个版本恰好点亮一半:v2 退化为 header-only + anchor TU,v3 是 106 TU 的静态库。匹配不到的 glob 不是错误,这正是并集安全的原因。最后一行还顺带给出一个编译期 major 判别式:__has_include(<catch2/catch_all.hpp>)。抛开可行性,两个包本身就是错的形态:
catch2-v2把 major 塞进了 SPEC-001 身份留给原子 name 的那一段 —— 与compat.openssl→openssl改名要消除的是同一类问题;catch2 = "^3";compat.catch2-v2一旦随已发布 artifact 出去,再收回就是 breaking change。所以必须在合并前定。与 mcpp#290 的关系
mcpp-community/mcpp#290(按版本区分构建规则)不是本 PR 的前置 —— 在 0.0.109 上今天就能跑。
Catch2 也不是 #290 论证时用的那种形态:那个 issue 的例子(llama.cpp b10069 vs b10107)共享约 95% 构建规则、只差几个源文件;catch2 v2/v3 除了样板(
language/import_std/c_standard/targets/deps)什么都不共享,能合并纯粹是因为 glob 恰好不重叠。而"恰好"正是薄弱点,也正是 #290 要消除的:不相交是两棵上游树的性质,描述符管不住。#290 落地后这里会收敛成显式的
["2.x"]/["3.x"]块,隐式假设随之消失。在那之前,前提写在描述符头部,加版本时必须重核。2.
mainfeature 原来是死的初版 v3 的
features = ["main"]会得到undefined reference to 'main'。在 0.0.109 上逐一实测:features = ["main"]!取反,feature 指向被取反的路径undefined reference to 'main'multiple definition of 'main'undefined reference to 'main'!取反,feature 指向生成的 TU两条机制:
sources里的!取反是绝对排除,作用于最终源集合,feature 加不回来(即便之后再显式列一遍)。sources的字面条目匹配 —— 被 glob 匹到的文件根本不受选通,默认即编入。所以
compat.gtest的写法不能照搬:gtest_main.cc是字面条目才让选通生效。现在 feature 编译一个生成的 TU,用__has_include(<catch2/catch_all.hpp>)分别取 v3(Catch::Session)与 v2(CATCH_CONFIG_MAIN)的写法。代价:不复用上游
catch_main.cpp意味着没有LeakDetector注册、没有wmain分支(只在 Windows_UNICODE下可达)。已在描述符里记录。3. 四个成员 —— 因为 feature 是按项目解析的
一个项目不能同时持有带 feature 和不带 feature 的同一依赖(与 asio-ssl / asio-module 同一约束),所以 2 个 major × {默认,feature} = 4 个:
catch2main())multiple definition of 'main'catch2-mainfeatures = ["main"]undefined reference to 'main'catch2-v2CATCH_CONFIG_MAIN)single_include没解析上catch2-v2-mainfeatures = ["main"]__has_include的 ELSE 分支(v3 成员只走 THEN)初版在两个包上都声明了
mainfeature,覆盖 0 个 —— 这正是那个不工作的 feature 能绿着通过 CI 的原因。每个测试体都保留真断言,Catch2 退出时会打印断言数,所以"编译成空还通过"藏不住。4. CN 镜像
两个版本已镜像到 gitcode
mcpp-res/catch2,并重新下载校验:与上游逐字节一致(sha256 与大小均相同),所以单条sha256同时覆盖 GLOBAL 与 CN。5. 本地验证(mcpp 0.0.109,gcc@16.1.0,linux-x86_64)
mcpp xpkg parse+tests/check_mirror_urls.lua:通过mcpp test -p全绿,各 2 assertions in 2 test cases(非空)-main成员的features = ["main"]摘掉,均以undefined reference to 'main'失败 —— 证明入口确实由 feature 提供,而不是别的东西恰好补上了已知边界
src/catch2/"这一上游事实,已写进描述符注释,加版本时需重核;#290 落地后可迁移掉。catch_user_config.hpp只手写了两个必需的 value-define(其余全是#cmakedefine,缺省即编译器探测)。升 v3 版本时需对照上游.in,新增的必需 value-define 会在这里静默漏掉。