Skip to content

fix(deps): staging a cross-major copy drops the headers beside its sources - #502

Merged
Sunrisepeak merged 1 commit into
mainfrom
fix/staging-drops-adjacent-headers
Aug 24, 2026
Merged

fix(deps): staging a cross-major copy drops the headers beside its sources#502
Sunrisepeak merged 1 commit into
mainfrom
fix/staging-drops-adjacent-headers

Conversation

@Sunrisepeak

Copy link
Copy Markdown
Member

#include "detail.h" resolves relative to the directory of the file holding it, so staging a package under target/.mangled/ moved the search away from a header the source expects beside it. No include_dirs entry is involved — a package with its header beside its source never declared a path it never needed.

target/.mangled/openkal-opensbi/__self__/src/time.cpp:44:10:
    fatal error: 'sbi.h' file not found

Hit for real in two ecosystem repositories today. Proved with two binaries: the unfixed one fails the extended fixture, the fixed one passes and the header is asserted on disk.

…urces

When two majors of one package are in a graph the resolver stages one
copy under `target/.mangled/` with its module declarations rewritten.
Staging moves the sources and, by design, leaves headers where they are:
those are reached through `[build].include_dirs`, which is absolutized so
the staged copy still finds them.

A header written BESIDE a source is a different case and was not
handled. `#include "detail.h"` resolves relative to the directory of the
file holding the directive, so moving the source moves the search — and
no `include_dirs` entry is involved, because a package with its header
beside its source never declared a path it never needed.

    target/.mangled/openkal-opensbi/__self__/src/time.cpp:44:10:
        fatal error: 'sbi.h' file not found

⚠️ Everything that diagnosis points at is wrong. The path is a staging
directory the author never wrote, the header sits exactly where the
source expects it, and the build that triggered it asked for nothing
unusual: two majors of one dependency is a supported arrangement and
this is its most ordinary consequence. It cost two repositories a red
CI run each, diagnosed first as a missing include path.

Every file in a directory that holds a staged source and is not itself
staged is now copied across verbatim — rewriting applies to module
declarations and a header has none. Directories with no staged source
are not visited.

Proved by two binaries rather than by one binary and an assumption:

    mcpp-unfixed  33_multi_version_mangling.sh → fatal error: libB_detail.h
    mcpp-fixed    33_multi_version_mangling.sh → ok, staged beside the source

The fixture gains a private header and a non-module translation unit
that includes it, and asserts the staged copy carries it on disk as well
as building — a build that found the header by some other path would
otherwise pass while leaving this broken.

Green beside it: 32, 119, 167, 188.
@Sunrisepeak
Sunrisepeak merged commit c545045 into main Aug 24, 2026
26 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants