Skip to content

toolchain post-install fixup: glibc@2.44 binding cannot resolve after 2.44.3 was published (every clean machine fails) #660

Description

@Sunrisepeak

Summary

After xim:glibc@2.44.3 was published, every mcpp verb that resolves a toolchain fails on a clean
machine:

error: toolchain post-install fixup: selected RuntimeBinding glibc@2.44 requires payload
'/home/runner/.mcpp/registry/data/xpkgs/xim-x-glibc/2.44', but no installed payload is its
resolution; mcpp will not fall back to another directory entry

The binding resolves to glibc@2.44 and demands the directory xim-x-glibc/2.44 exactly. A clean
machine installs the newest of the 2.44 line — 2.44.3 — into xim-x-glibc/2.44.3, and nothing
matches.

Timeline

Last green CI run 2026-09-16 16:01 UTC
xim-pkgindex a6c2fe67 — fix(glibc): 2.44.3 (#852) between those two
First failing CI run 2026-09-16 19:07 UTC

Every run since fails the same way.

What makes it clear this is the binding, not a project change

Three jobs in one run failed with the identical error while downloading three unrelated things:

Downloading mcpplibs.openkal-linux v0.12.0   → error
Downloading xim:glibc@2.44.3                 → error
Downloading xim:python@3.13.12               → error

Anything that triggers toolchain resolution hits it. No change in the consuming project can produce
that pattern.

Why it does not reproduce on a developer machine

A machine that installed glibc before 2.44.3 was published already has xim-x-glibc/2.44 on disk,
so the binding finds its directory and the build succeeds. Only a clean store — CI, a new
contributor, a fresh container — installs 2.44.3 and fails. Locally green, CI red, from the same
commit.

Environment

  • mcpp 2026.9.15.1 (.github/versions.env)
  • xlings v2026.8.17.2
  • Consumer: Sunrisepeak/lsp-mcpp-private, CI runs 35138626160 / 35141001192 / 35142035831
  • Reproduces on ubuntu-24.04 runners and on both cross-build targets

What would resolve it

Either the binding should accept a directory entry that satisfies 2.44 (2.44.3 does), or the
resolution should name the exact version it wants so the store installs that one. The error already
says "mcpp will not fall back to another directory entry", so the refusal looks deliberate — the
question is whether 2.44.3 should have been considered a resolution of 2.44 in the first place.

Activity

  1. Sunrisepeak commented on Sep 16, 2026

    @Sunrisepeak
    MemberAuthor

    Root cause located, and it rules out the two workarounds a consuming project might try.

    The binding is recorded by xlings, as a line name, not a version.

    // <registry>/subos/default/.xlings.json
    "subos_info": {
      "created_by": "xlings 2026.9.16.1",
      "runtime": "glibc@2.44",
      "host_glibc": "2.39"
    }

    mcpp then treats glibc@2.44 as an exact directory name and refuses anything else:

    error: toolchain post-install fixup: selected RuntimeBinding glibc@2.44 requires payload
    '.../xim-x-glibc/2.44', but no installed payload is its resolution; mcpp will not fall back
    to another directory entry
    

    A clean store installs the newest of the 2.44 line — 2.44.3 since xim-pkgindex#852 — into
    xim-x-glibc/2.44.3, and nothing matches.

    Upgrading xlings does not help. I created a fresh subos with the current xlings
    (2026.9.16.1, a month newer than the v2026.8.17.2 our CI pins) into an isolated
    XLINGS_HOME. It still records glibc@2.44. So this is not an old-xlings artefact; it is what
    xlings writes today.

    Pinning glibc does not help either, and makes it worse. Declaring xim:glibc@2.44 in
    [xlings.workspace] installs the directory the binding wants, and then:

    Linux:  payload '.../xim-x-glibc/2.44' is stale/incomplete: no dynamic loader was found
            under lib64/ or lib/
    macOS:  xlings install xim:glibc@2.44   (a C library that platform has no use for)
    

    2.44 is the version whose missing default directory 2.44.3 exists to fix, so the pin installs a
    payload the fixup then rejects for a second reason. Five platforms failed instead of three.

    Why it is invisible to developers. A machine that installed glibc before 2.44.3 was published
    still has xim-x-glibc/2.44 on disk and keeps working. Moving that one directory aside reproduces
    CI's failure locally in seconds — which is how the above was measured.

    So the disagreement is between what xlings records (glibc@2.44, a line) and what mcpp requires (a
    directory named exactly 2.44). Either xlings should record the resolved version, or mcpp should
    accept a directory that satisfies the line it asked for. A consuming project cannot bridge it.

  2. Sunrisepeak commented on Sep 16, 2026

    @Sunrisepeak
    MemberAuthor

    Measured directly, by printing the store before anything installs:

    What glibc the restored store has
      2.44.2: /home/runner/.mcpp/registry/data/xpkgs/xim-x-glibc/2.44.2/lib/ld-linux-x86-64.so.2
    

    One directory, 2.44.2. The binding wants xim-x-glibc/2.44, and no version of the package
    creates that directory except 2.44 itself
    — each installs under its own name. So this is not a
    question of choosing the right member of the line:

    installed directory binding wants 2.44
    2.44 xim-x-glibc/2.44 matches, but the artifact has its loader under lib/ while the recipe declares lib64/ (openxlings/xim-pkgindex#853)
    2.44.2 xim-x-glibc/2.44.2 no match
    2.44.3 xim-x-glibc/2.44.3 no match

    Pinning cannot fix it. I tried both: 2.44 fails the loader check, 2.44.2 installs a directory
    the binding will not look at.

    Why it used to work. Runs green before 2026-09-16 16:01 restored a cache that still contained
    xim-x-glibc/2.44 from an earlier install, so the binding found its directory; the 2.44.2 download
    alongside it was incidental. Once that cache rotated out, nothing recreates the directory, and the
    project has no way to ask for it — the only version that would create it is the one #853 makes
    unusable.

    So a consuming project is stuck between the two issues: #660 requires a directory named 2.44, and
    #853 makes the only package that creates it fail the post-install check.

  3. Sunrisepeak commented on Sep 16, 2026

    @Sunrisepeak
    MemberAuthor

    Correcting my own two comments above, and adding the finding that actually unblocked it.

    A consuming project can bridge it — I was wrong about that. The bridge is ugly, but it works,
    and the reason it took so long to find is itself a gap worth reporting.

    First, a retraction. The second comment's table says the 2.44 artifact "has its loader under
    lib/ while the recipe declares lib64/". That is wrong, and so is the upstream report it cites
    (openxlings/xim-pkgindex#853, since retracted and closed). Installing xim:glibc@2.44 into an empty
    store gives:

    lrwxrwxrwx  lib64 -> lib
    .../2.44/lib/ld-linux-x86-64.so.2
    

    lib64 is a symlink, so the declared lib64/ld-linux-x86-64.so.2 resolves. I had read a
    tar -tzf | grep ld-linux listing, which cannot show a symlink whose own name lacks the pattern.
    Pinning xim:glibc@2.44 is therefore sound: it installs the directory the binding names, and the
    post-install check passes.

    What was left, and it is a mcpp gap of its own. With the pin in
    [target.'cfg(os = "linux")'.xlings.workspace], one CI job passed and two failed — same commit,
    same runner OS (all three on ubuntu-24.04). The difference is what they build:

    job command provisioning list result
    unit tests mcpp build (xim:node, xim:python, xim:rust, xim:glibc@2.44) pass
    cross-build mcpp build --target aarch64-macos (xim:node, xim:python, xim:rust) fail

    The glibc payload is a property of the build host — a Linux host resolves a RuntimeBinding
    whatever it builds for. But every key cfg() accepts is evaluated against the target:

    $ mcpp build --strict
    error: [target.'cfg(host_os = "linux")'] names 'host_os' in its cfg() predicate, which mcpp does
    not know, so the section never applies (ignored).
    Supported keys: arch, env, family, os, c++-abi, c-abi, compiler, compiler-runtime, kernel-abi
    

    host, host_os and target_os are all rejected. So a manifest cannot express a host-side
    requirement at all
    — which is a problem beyond this issue, since a host glibc, a host toolchain
    payload and a host build tool are all things a cross-compiling project may legitimately need.

    The bridge, for anyone else stuck here: features are not target-derived. Verified with a
    probe package that does not exist, so the only possible output is proof that provisioning ran:

    $ mcpp build --target aarch64-macos --features hostprobe
    Provisioning [xlings.workspace] entries (xim:definitely-no-such-pkg-xyz)
    

    So the pin goes in [feature-xlings.host-glibc] and the cross-building job asks for it explicitly:

    mcpp build --features host-glibc --profile release --target aarch64-macos
      -> Provisioning [xlings.workspace] entries (xim:node, xim:python, xim:rust, xim:glibc@2.44)
      -> Downloading xim:glibc@2.44  40.4 MB   (resolves to 2.44, not 2.44.3)
    

    Both cross-build jobs now pass.

    That leaves two separate asks:

    1. This issue stands. xlings records the binding as a line name (glibc@2.44) and mcpp requires
      a directory of that exact name. It survives only because 2.44 is still a concrete version; the
      day that entry is retired, every pin like mine breaks at once and there is no replacement, since
      2.44.2 and 2.44.3 install under their own names. Either xlings should record the resolved
      version, or mcpp should accept a directory that satisfies the line it asked for.

    2. A host predicate. Without one, "the host needs X" can only be said by feature flags passed at
      every cross-compiling call site — which is a workaround wearing a feature's clothes, and is
      invisible to anyone reading the manifest alone.

    Happy to open (2) as its own issue if you would rather keep this one to the binding.

  4. Sunrisepeak commented on Sep 17, 2026

    @Sunrisepeak
    MemberAuthor

    Fixed in mcpp 2026.9.17.2 (#663), released and indexed.

    The cause was not the version-line binding. mcpp never installed the glibc payload its default SubOS declares. The two loops meant to do it passed xim:glibc without a version; Fetcher::resolve_xpkg_path rejects such a target, and the rejection was logged at debug level and discarded. The payload therefore existed only when xlings installed it as a dependency of a toolchain. A toolchain restored from a CI cache that keeps only registry/data/xpkgs is not reinstalled, so a cache holding another glibc revision left the declared payload absent. The directory scan that accepted a unique 2.44.x for 2.44 concealed this until #852 put two revisions side by side. Upgrading xlings alone does not fix it: xlings 2026.9.14.1 with a cache-shaped store fails the same way.

    Change. mcpp installs xim:glibc@<declared version> before the first toolchain fixup that consumes it (gcc and llvm payloads on Linux only; no process starts when the payload is present). The payload lookup is exact. Offline, the error names the coordinate to provide. The xlings shipped beside the mcpp executable is now acquired ahead of the PATH xlings.

    Verified.

    For consumers: the [feature-xlings.host-glibc] pin and --features host-glibc are no longer needed once CI installs 2026.9.17.2. The host-predicate question (cfg(host_os)) is independent and would be better tracked in its own issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions