Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,18 @@ jobs:
if ! lua5.4 tests/check_mirror_urls.lua "$f"; then
fail=1
fi
# 5. c++fly admission policy (mcpp design 2026-07-14 §11-Q2, v1):
# 5. `name` must be the fully-qualified `<namespace>.<short>`.
# The split form (namespace = "chriskohlhoff", name = "asio")
# parses and passes `mcpp xpkg parse`, but xlings keys the index
# on the literal `name` while mcpp asks for the reconstructed
# FQN — they never meet, so the package is uninstallable on
# every platform (mcpp-community/mcpp#278). This check is cheap
# and catches in seconds what otherwise fails an hour into the
# workspace job.
if ! lua5.4 tests/check_package_name.lua "$f"; then
fail=1
fi
# 6. c++fly admission policy (mcpp design 2026-07-14 §11-Q2, v1):
# c++fly means "toolchain's latest level + every experimental
# gate" — deliberately toolchain-dependent, so a published
# package built with it is not reproducible for consumers.
Expand Down
10 changes: 9 additions & 1 deletion pkgs/c/chriskohlhoff.asio.lua
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,15 @@
package = {
spec = "1",
namespace = "chriskohlhoff",
name = "asio",
-- `name` MUST be the fully-qualified `<namespace>.<short>`: xlings keys its
-- index on this literal (libxpkg build_index → entries[package.name]),
-- while mcpp asks for the FQN it reconstructs from the consumer's
-- `[dependencies.<ns>] <short>`. Writing the split form ("asio") is legal
-- per mcpp's own descriptor spec (manifest/xpkg.cppm canonical_xpkg_
-- identity normalizes both spellings) but registers the index entry under
-- `asio`, which no consumer request can ever hit → E_NOT_FOUND at install.
-- See mcpp-community/mcpp#278; the lint in validate.yml enforces this.
name = "chriskohlhoff.asio",
description = "Standalone asio exposed as the C++23 module `asio` (separate compilation)",
licenses = {"BSL-1.0"},
repo = "https://github.com/chriskohlhoff/asio",
Expand Down
9 changes: 8 additions & 1 deletion pkgs/t/tensorvia-cpu.lua
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
-- AUTO-GENERATED by `mcpp emit xpkg`. Do not edit by hand.
-- Source: mcpp.toml @ v0.1.1
--
-- Hand-edit on top of the generated file: `mcpp emit xpkg` writes the bare
-- project name and no `namespace`; the `namespace = "aimol"` line below was
-- added when the package was filed into this index, which made `name` the
-- split form and left the package uninstallable (xlings keyed the entry under
-- `tensorvia-cpu` while mcpp asks for `aimol.tensorvia-cpu`). `name` is now
-- the fully-qualified spelling. See mcpp-community/mcpp#278.
package = {
spec = "1",
name = "tensorvia-cpu",
name = "aimol.tensorvia-cpu",
description = "CPU backend of Tensorvia, ported to C++23 modules",
licenses = {"MIT"},
repo = "https://github.com/Aimol-l/Tensorvia-cpu",
Expand Down
77 changes: 77 additions & 0 deletions tests/check_package_name.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
-- Lint `package.name` against `package.namespace`.
--
-- Rule: a namespaced descriptor MUST spell `name` as the fully-qualified
-- `<namespace>.<short>`. The split form (namespace = "chriskohlhoff",
-- name = "asio") parses fine and passes `mcpp xpkg parse` — mcpp's own
-- identity layer normalizes both spellings to the same package — but it is
-- NOT installable from an index:
--
-- * xlings/libxpkg keys the index on the literal `package.name`
-- (libxpkg build_index → entries[package.name]), so the entry lands
-- under `asio`;
-- * mcpp asks xlings for the FQN it reconstructs from the consumer's
-- `[dependencies.<ns>] <short>`, i.e. `chriskohlhoff.asio`
-- (mcpp src/build/prepare.cppm — "xlings resolves packages by the full
-- qualified name (ns.shortName) as it appears in the index's name field").
--
-- The two never meet → E_NOT_FOUND at install time, on every platform, after
-- the workspace job has already burned an hour. No consumer-side spelling can
-- work around it; the descriptor is the only place it can be fixed.
--
-- Upstream: mcpp-community/mcpp#278 (mcpp should either use the declared name
-- or reject the split form in `mcpp xpkg parse`). Until that lands, this lint
-- is the index's guard.
--
-- Zero-namespace packages (the public default-namespace module packages —
-- imgui / ffmpeg / opencv) are unaffected: their bare `name` IS the FQN.
--
-- Usage: lua5.4 tests/check_package_name.lua <file.lua>

function import(...)
return setmetatable({}, {__index = function() return function() end end})
end

local path = assert(arg[1], "usage: check_package_name.lua <file>")
package = nil
local chunk = assert(loadfile(path, "t"))
chunk()

local p = package
if type(p) ~= "table" then os.exit(0) end

local fail = 0
local function err(msg)
io.stderr:write(string.format("::error file=%s::%s\n", path, msg))
fail = 1
end

local name = p.name
local ns = p.namespace or ""

if type(name) ~= "string" or name == "" then
err("package.name must be a non-empty string")
os.exit(fail)
end
if type(ns) ~= "string" then
err("package.namespace must be a string")
os.exit(fail)
end

if ns ~= "" then
local prefix = ns .. "."
if name:sub(1, #prefix) ~= prefix then
err(string.format(
"package.name must be the fully-qualified '<namespace>.<short>': " ..
"namespace = %q but name = %q — write name = %q. " ..
"The split form registers the index entry under %q, which no " ..
"consumer request can ever resolve (E_NOT_FOUND at install). " ..
"See mcpp-community/mcpp#278.",
ns, name, prefix .. name, name))
elseif #name == #prefix then
err(string.format(
"package.name = %q has an empty short name after the %q prefix",
name, prefix))
end
end

os.exit(fail)
Loading