From 9d328bfa612e27eab58a06f3435a2c9cf94b4763 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sat, 9 May 2026 05:14:56 +0800 Subject: [PATCH 1/2] ci(release): replace fetch-tags with fetch-depth:0 in checkout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The push-tag trigger that fired for v0.0.2 failed with Cannot fetch both ef6dffd0a... and refs/tags/v0.0.2 to refs/tags/v0.0.2 — a known interaction in actions/checkout@v4 where `fetch-tags: true` combined with a tag ref tries to fetch the same ref twice. Switching to `fetch-depth: 0` gives the resolve-tag step the full history it needs without the duplicate-fetch conflict. (The release.yml flow itself is unchanged; this only fixes the runner side.) --- .github/workflows/release.yml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ceedc33..b8e1ab5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -27,11 +27,15 @@ jobs: # so we pin to a known path. MCPP_HOME: /home/runner/.mcpp steps: - # fetch-tags so the resolve-tag step can detect existing tags - # without an extra round-trip; full history isn't needed. + # fetch-depth: 0 instead of fetch-tags: true — actions/checkout@v4 + # fails on push-tag triggers when both the ref'd tag and + # `fetch-tags: true` are set: + # "Cannot fetch both and refs/tags/vX.Y.Z to refs/tags/vX.Y.Z" + # Full-history fetch covers the resolve-tag step's needs without + # that contention. - uses: actions/checkout@v4 with: - fetch-tags: true + fetch-depth: 0 - name: Resolve target tag + commit id: resolve From 55ae025a9531ef87717080c73b067f961fe4d237 Mon Sep 17 00:00:00 2001 From: sunrisepeak Date: Sat, 9 May 2026 05:30:21 +0800 Subject: [PATCH 2/2] fix(pm): de-inline resolver functions to satisfy musl-gcc 15.1 link MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The release.yml musl-static build of v0.0.2 failed at the link step: obj/cli.m.o: in function `std::_Vector_base::~_Vector_base()': undefined reference to `std::_Vector_base<...>::_Vector_impl::~_Vector_impl()' `pm/resolver.cppm` declared `resolve_semver` `inline`, so every importer (currently `cli.cppm`) wound up locally instantiating the destructor of `std::_Vector_base`. With musl-gcc 15.1's libstdc++ that specific instantiation is missing the corresponding `_Vector_impl` destructor symbol, and the linker rejects. Move the function bodies out of the `export` block in `pm/resolver.cppm` (declarations only there, definitions in a non-export `mcpp::pm` block later in the same module unit). Single definition point, single instantiation site — the cross-module duplicate goes away and musl-gcc links cleanly. Reproduced and verified locally with `mcpp build --target x86_64-linux-musl` on the same musl-gcc 15.1 toolchain CI uses. `mcpp build` (glibc) + `mcpp test` (9/9 unit) still pass. --- src/pm/resolver.cppm | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/pm/resolver.cppm b/src/pm/resolver.cppm index 3603f80..af3bea3 100644 --- a/src/pm/resolver.cppm +++ b/src/pm/resolver.cppm @@ -5,6 +5,13 @@ // `.agents/docs/2026-05-08-pm-subsystem-architecture.md`). Strictly // pulled out of `cli.cppm` with no behavior change; the same // signatures, the same error strings, the same platform key picking. +// +// Implementation note: `resolve_semver` is **not** declared inline on +// purpose. Inlining it across modules makes every importer +// (cli.cppm, ...) instantiate `std::_Vector_base`'s +// destructor locally. With musl-gcc 15.1's libstdc++ that triggers +// `undefined reference to std::_Vector_base<...>::_Vector_impl::~_Vector_impl()` +// at link time. Single-definition-point sidesteps the bug. export module mcpp.pm.resolver; @@ -34,7 +41,22 @@ inline constexpr std::string_view kXpkgPlatform = // "constraint" so callers re-resolve via the index — bare `1.2.3` is // treated as exact for back-compat with pre-SemVer pinning workflows; // users opt into resolution by writing `^1.2.3` etc. -inline bool is_version_constraint(std::string_view v) { +bool is_version_constraint(std::string_view v); + +// Resolve a SemVer constraint against the index entry's available +// versions. Returns the chosen exact version string, or an error +// message. The fetcher is used to read the lua descriptor for the +// requested package name. +std::expected +resolve_semver(std::string_view name, + std::string_view constraint, + mcpp::pm::Fetcher& fetcher); + +} // namespace mcpp::pm + +namespace mcpp::pm { + +bool is_version_constraint(std::string_view v) { if (v.empty()) return true; if (v == "*") return true; char c = v.front(); @@ -43,11 +65,7 @@ inline bool is_version_constraint(std::string_view v) { return false; } -// Resolve a SemVer constraint against the index entry's available -// versions. Returns the chosen exact version string, or an error -// message. The fetcher is used to read the lua descriptor for the -// requested package name. -inline std::expected +std::expected resolve_semver(std::string_view name, std::string_view constraint, mcpp::pm::Fetcher& fetcher)