Skip to content

Commit fe6cb32

Browse files
committed
fix(prepare): a version conflict on a package with no C++ module says so
Two versions of one package are reconciled by mangling the secondary copy's module names. The two branches that refuse name both versions and who asked for them; the third reported only that the package declares no named C++ module to rewrite, which is a true statement about a package the reader never asked to be staged and says nothing about the conflict that brought it there. A C package reaches it: compat.vulkan-runtime compiles one C file, so a manifest that pins one version of it while a dependency asks for another got a message about modules. It now names both versions, both requesters, and what to do. examples/10 moves its pin to compat.vulkan-runtime 2026.09.06, the version compat.vulkan asks for since mcpp-index#350. The example is the consumer that found this.
1 parent 3306ac6 commit fe6cb32

3 files changed

Lines changed: 34 additions & 5 deletions

File tree

.agents/docs/2026-09-05-heterogeneous-verify.sh

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,11 @@ got=$("$STORE" --version 2>&1 | head -1)
3131
# value was written, so both tools are asked what they hold afterwards.
3232
"$STORE" self config --mirror "${MCPP_VERIFY_MIRROR:-CN}" >/dev/null 2>&1 || true
3333
"$XL" config --mirror "${MCPP_VERIFY_MIRROR:-CN}" >/dev/null 2>&1 || true
34-
# Both tools print their configuration banner on stderr, so a `2>/dev/null`
35-
# here reads an empty string and reports a mirror that is in fact set.
36-
xm=$("$XL" config 2>&1 | sed 's/\x1b\[[0-9;]*m//g' | grep -i 'mirror' | head -1 | awk '{print $NF}')
34+
# THE SETTING, NOT THE TOOL'S OUTPUT. `xlings config` renders a banner through
35+
# its ui layer, which prints nothing when its stdout is a pipe -- so a command
36+
# substitution reads an empty string and reports a mirror that is in fact set.
37+
# The file the tool writes answers the same question and cannot be suppressed.
38+
xm=$(python3 -c "import json,os;print(json.load(open(os.path.expanduser('~/.xlings/.xlings.json'))).get('mirror',''))" 2>/dev/null)
3739
[ "$xm" = "${MCPP_VERIFY_MIRROR:-CN}" ] && ok "xlings mirror is $xm" || fail "xlings mirror is '$xm', not ${MCPP_VERIFY_MIRROR:-CN}"
3840
mm=$("$STORE" self config 2>&1 | sed 's/\x1b\[[0-9;]*m//g' | grep -i 'mirror' | head -1 | awk '{print $NF}')
3941
[ -n "$mm" ] && ok "mcpp mirror is $mm" || printf 'note: mcpp self config does not print its mirror (%s)\n' "$("$STORE" self config 2>&1 | head -1)"
@@ -142,6 +144,13 @@ if [ -n "$SRC" ] && [ -d "$SRC/examples/10-vulkan-compute/app" ]; then
142144
|| fail "example 10 --no-accel: $(printf '%s' "$out" | tail -3 | tr '\n' ' ')"
143145
hs=$(ls "$HOME"/.mcpp/registry/data/xpkgs/compat-x-vulkan-runtime/*/mcpp_generated/vulkan_runtime/HOST-SURFACE.txt \
144146
"$ex10"/.mcpp/.xlings/data/xpkgs/compat-x-vulkan-runtime/*/mcpp_generated/vulkan_runtime/HOST-SURFACE.txt 2>/dev/null | head -1)
147+
# WHICH ADAPTER WROTE IT. The substitution criteria below are properties of
148+
# 2026.09.06, the version that declares its payload set; an older report
149+
# carries neither the declarations nor the class they produce, so both
150+
# would pass on an empty finding. The version is a path segment.
151+
adapter=$(printf '%s' "$hs" | sed -n 's#.*/compat-x-vulkan-runtime/\([^/]*\)/.*#\1#p')
152+
[ "$adapter" = "${MCPP_VERIFY_ADAPTER:-2026.09.06}" ] && ok "the farm was written by compat.vulkan-runtime $adapter" \
153+
|| fail "the farm was written by compat.vulkan-runtime '$adapter', not ${MCPP_VERIFY_ADAPTER:-2026.09.06}"
145154
if [ -n "$hs" ]; then
146155
printf -- '--- %s\n' "$hs"; sed -n '/^## farmed/,$p' "$hs" | head -60
147156
# WHAT A SANDBOX CAN AND CANNOT ASSERT. A subos shares the host's

examples/10-vulkan-compute/app/mcpp.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ plugins = { version = "0.1.0", features = ["rules-spirv"], host-module = true }
2222
# below is a payload and the hardware ones are the host's.
2323
[dependencies.compat]
2424
vulkan = "1.4.357.0"
25-
vulkan-runtime = "2026.09.05"
25+
vulkan-runtime = "2026.09.06"
2626

2727
# The two payloads this build names rather than discovers: the shader compiler,
2828
# and a Vulkan driver that is always present because it is the CPU. With

src/build/prepare.cppm

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5554,7 +5554,27 @@ prepare_build(bool print_fingerprint,
55545554
// same map in both the secondary and its consumer.
55555555
auto moduleNames = declared_modules_for(
55565556
secondaryRoot, secondaryManifest);
5557-
if (!moduleNames) return std::unexpected(moduleNames.error());
5557+
// The two branches above name both versions and who asked
5558+
// for them; this one used to report only that the package
5559+
// declares no named C++ module, which is a true statement
5560+
// about a package the reader never asked to be staged. A
5561+
// C package -- compat.vulkan-runtime is one -- reaches
5562+
// here whenever a manifest pins one version of it and
5563+
// another dependency asks for a second, and the message
5564+
// has to say that before it says anything about modules.
5565+
if (!moduleNames) return std::unexpected(std::format(
5566+
"dependency '{}{}{}' has irreconcilable versions:\n"
5567+
" '{}' requested by '{}'\n"
5568+
" '{}' requested by '{}'\n"
5569+
"Multi-version mangling cannot separate them: {}.\n"
5570+
"A package with no named C++ module has nothing to "
5571+
"rewrite, so the two requests must agree. Align the "
5572+
"pin in your mcpp.toml with the version the other "
5573+
"dependency asks for.",
5574+
key.ns, key.ns.empty() ? "" : ".", key.shortName,
5575+
it->second.version, it->second.requestedBy,
5576+
spec.version, item.requestedBy,
5577+
moduleNames.error()));
55585578
std::map<std::string, std::string> rename;
55595579
for (auto const& module : *moduleNames) {
55605580
rename.emplace(module,

0 commit comments

Comments
 (0)