From c162a8fc4413f8e42a16c1b1dd034032c8a75c87 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sun, 9 Aug 2026 00:37:37 +0800 Subject: [PATCH] =?UTF-8?q?fix(pkg):=20catch2=20=E7=9A=84=20v2/v3=20?= =?UTF-8?q?=E5=88=A4=E5=88=AB=E4=B8=8D=E8=83=BD=E9=97=AE=E7=B3=BB=E7=BB=9F?= =?UTF-8?q?=E7=9B=AE=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `catch2_main.cpp` 用 `__has_include()` 区分两个大版本。 这个探测同样会翻系统 include 目录,而 catch_all.hpp 正是每个发行版的 catch2 包都会装的头。于是在一台装了系统 Catch2 v3 的机器上,一个 v2 消费者被回答 "你是 v3",编出 Catch::Session 那条入口,再死在链接: ld.lld: error: undefined symbol: Catch::Session::Session() >>> referenced by /usr/include/catch2/catch_session.hpp:39 和 #183 修的 compat.ffmpeg 是同一类问题:宿主机装了同名开发包,vendored 的 东西就被挤掉。gcc 不中招是因为它通过 --sysroot 进 xlings subos,那里没有 /usr/include/catch2 —— 所以这条在 CI 和默认工具链下一直是绿的。 改成探测 `catch2/catch_user_config.hpp.in`:上游把它作为 CMake 模板放在 v3 的源码树里,装的是生成后的 .hpp,模板本身从不安装。三种情形在 clang 22.1.8 和 gcc 16.1.0 上都验过: vendored v3 在 -I 上 -> v3 (两种探测一致) vendored v2 在 -I 上 -> v2 (catch_all.hpp 答 v3,即本 bug) 只有系统 v3 -> v2 (catch_all.hpp 答 v3) 四个 catch2 成员 × 两个工具链,在一台装了系统 Catch2 v3 的机器上全过 —— catch2-v2-main 此前在 llvm 下是 FAIL。 #183 的描述里把这条列为"要等 per-version build blocks(mcpp#290)才能修", 那个判断下早了:要的不是"知道自己是哪个版本",只是一个系统装不出来的探针。 mcpp#290 仍然是更干净的答案,它让这个问题整个消失,而不是换一个探针。 --- pkgs/c/compat.catch2.lua | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-) diff --git a/pkgs/c/compat.catch2.lua b/pkgs/c/compat.catch2.lua index 7fe7d09..85f0900 100644 --- a/pkgs/c/compat.catch2.lua +++ b/pkgs/c/compat.catch2.lua @@ -29,9 +29,12 @@ -- -- Features (sources-only gate): -- `main` — compiles a GENERATED TU supplying a default entry point. It --- branches on __has_include(), which exists only in --- v3, to pick the v3 (Catch::Session) or v2 (CATCH_CONFIG_MAIN) spelling. --- Excluded by default; request `features = ["main"]`. +-- branches on __has_include() — upstream's +-- CMake template, present only in v3's SOURCE tree and never installed — to +-- pick the v3 (Catch::Session) or v2 (CATCH_CONFIG_MAIN) spelling. The probe +-- has to be source-only because __has_include searches the system dirs too; +-- see the note above the generated TU. Excluded by default; request +-- `features = ["main"]`. -- -- It deliberately does NOT point at upstream's -- src/catch2/internal/catch_main.cpp. That file is matched by the sources @@ -148,7 +151,7 @@ package = { -- and can never be used to detect v2. (On v3 it would be found -- and then fail in #include_next, since there is no upstream -- catch.hpp behind it — but __has_include never gets that far.) - -- The existing discriminator probes catch_all.hpp instead, which + -- The discriminator probes catch_user_config.hpp.in instead, which -- is unaffected. See the header comment for why per-version -- blocks (mcpp#290) are the real answer here. ["mcpp_generated/catch2/catch.hpp"] = [==[ @@ -187,8 +190,27 @@ int mcpp_compat_catch2_anchor(void) { return 0; } ]==], -- The `main` feature's TU. See the header comment for why this is -- generated rather than upstream's catch_main.cpp. + -- The discriminator probes a file upstream ships as a CMake + -- TEMPLATE and never installs: `catch_user_config.hpp.in`. It has + -- to be something a SYSTEM Catch2 cannot supply, because + -- __has_include searches the system dirs too — and the obvious + -- probe, catch_all.hpp, is installed by every distro's catch2 + -- package. On a box with system Catch2 v3 present, a v2 consumer + -- was answered "v3", compiled the Catch::Session entry point and + -- died at link time on undefined Catch::Session::Session(). + -- + -- Verified on clang 22.1.8 and gcc 16.1.0, all three cases: + -- vendored v3 on -I -> v3 (both probes agree) + -- vendored v2 on -I -> v2 (catch_all.hpp says v3: the bug) + -- only system v3 -> v2 (catch_all.hpp says v3) + -- + -- Re-check when bumping v3: if upstream ever materialises this + -- file in-tree instead of shipping the .in, or a distro starts + -- installing the template, the probe needs another source-only + -- marker. mcpp#290's per-version build blocks retire the whole + -- question by naming the major outright. ["mcpp_generated/catch2_main.cpp"] = [==[ -#if __has_include() +#if __has_include() // Catch2 v3: the library is compiled in; just drive a session. # include int main(int argc, char* argv[]) { return Catch::Session().run(argc, argv); }