| subject | heterogeneous |
|---|---|
| status | active |
Executes 2026-09-08-island-boundary-names.md across three repositories. One pull request per repository, ordered by what each one's CI needs to be green.
mcpp:plugins0.5.0. The floor stays mcpp 2026.9.8.1 -- nothing here uses an engine API newer than 0.4.0 already required, soMCPP_VERSIONin the plugins CI does not move and neither does any index floor.- The generated header stays flat,
extern "C", free of namespaces, and is what a device compiler reads. Only the.cppmgains namespaces. - No compatibility flag. The four call sites are updated in the same batch.
- Prose is declarative and free of decoration; no emoji in documentation, in code comments, or in commit messages.
- Every generated name passes through one sanitiser, shared by both lanes.
T1..T5 mcpp-plugins PR ──> merge ──> tag v0.5.0 ──> GitHub release
│
├─> gtc: CN asset
│
T6 mcpp-index PR (0.5.0 + latest)
│
T7..T10 mcpp PR (docs + examples)
│
T11 sandbox verification
examples/09-heterogeneous/boundary is built by mcpp's own CI
(.github/tools/build_examples.sh) and resolves mcpp:plugins through the
index, so the mcpp pull request cannot be green until 0.5.0 is published and
indexed. The plugins fixtures use path = "../.." and are therefore independent.
Files: src/plugins.cppm (add mcpp::plugins::names),
rules/spirv.cppm (call it instead of defining it).
identifier, split_module_name, common_base_dir and namespace_of become
mcpp::plugins::names::*. surface and the island generator both call them, so
a directory named 2d or default gets one answer rather than two that agree
today by inspection.
Exported inline functions in this package must not range-for over a
std::string: GCC 16 then instantiates std::string::iterator in the BMI and
every consumer's build program fails to compile in <bits/stl_iterator.h>.
Index instead. tools/island.cppm records the measurement.
Criterion: rules/spirv.cppm contains no definition of common_base_dir or
namespace_of, and tests/spirv-module-consumer still emits
namespace default_ {.
Files: tools/island.cppm.
struct options {
std::string module_name; // the module root
std::string out_dir;
std::string produced_by;
bool emit_module = true;
std::string marker = "MCPP_EXPORT_C";
std::vector<std::string> roots; // directories, or single files
std::string layout_root; // default: roots.front()
std::vector<std::string> extensions; // default: device table + C/C++
std::string strip_prefix; // empty: no short name
};
struct entry {
std::string decl; // verbatim, as scanned
std::string name; // the identifier before `(`
std::vector<std::string> name_space; // segments below the layout root
std::string origin; // the file it was first seen in
};
std::optional<std::vector<entry>> scan(const options&);
std::optional<emitted> emit(std::span<const entry>, const options&);
entry declared(std::string decl, std::vector<std::string> ns = {}); // rung L2scan walks each root in declaration order, sorted by path, reading files whose
extension is in the set. For each marked declaration it records the entry, its
name and the namespace segments of its directory relative to its own root. An
entry's namespace is the one it has in the layout root; an entry the layout root
does not declare keeps the namespace of the first root that does.
emit writes one flat header and one module. The module groups entries by
namespace path and opens each block once.
Criteria: the four fixtures below.
Files: tools/island.cppm.
- A name declared twice within one root is refused, naming both files and saying that two implementations of one entry point belong in two roots.
- A name declared in several roots whose declarations differ is refused, naming both files and both declarations. This is the check 0.4.0 performs; what changes is that it no longer doubles as the collision check.
scanthat finds no marked entry point in any root is an error naming the roots. An empty module is a misspelled path or a marker that never arrived.
Files: tools/island.cppm.
strip_prefix non-empty emits inline constexpr auto <short> = <name>; beside
using ::<name>;. The short name passes through names::identifier. Two entries
stripping to one short name are refused naming both. An entry not carrying the
prefix gets no short name.
Measured 2026-09-08: app::kernels::image::blur == &app::kernels::image::opkit_blur
under clang++ (DPC++ 7.1.0) -std=c++23, and the same declarations compile under
GCC 13.
Files: tests/island-interface/**, .github/workflows/ci.yml,
README.md, mcpp.toml (0.5.0), src/plugins.cppm (the version constant).
The fixture gains a subdirectory in the layout root and a flat fallback file, so the namespace, the flat-fallback allowance and the layout root's authority are all exercised by the shape of the tree rather than by an assertion about it:
src/kernels/saxpy.c island_saxpy_device -> ::kernels
src/kernels/image/scale.c island_scale_device -> ::kernels::image
src/cpu/ops.c both, flat
CI steps, each with a denominator:
- the module carries
export namespace island_interface::kernels {andexport namespace island_interface::kernels::image {; - the header carries neither
namespacenor any of the short names; - the flat fallback is accepted and
imagesurvives -- movingsrc/cpu/ops.ctosrc/cpu/deep/ops.cleaves the generated.cppmbyte-identical; - two files in ONE root declaring one name are refused naming both;
- two entries stripping to one short name are refused naming both;
- roots that hold no marker are refused naming the roots;
- the short name and the long name are one entity, and the artifact holds one symbol for the pair;
- the 0.4.0 disagreement check still fires, unchanged;
- the CPU leg (
--no-accel) reaches the same qualified names.
Files: pkgs/m/mcpp.plugins.lua.
A 0.5.0 entry in each of the three platform tables with the release tarball's
sha256, and ["latest"] = { ref = "0.5.0" } in each. The header comment gains
the paragraph describing what 0.5.0 changes. Existing consumers pin exact
versions, so moving latest breaks none of them.
Criterion: the descriptor parses under mcpp xpkg parse, holds exactly one
["latest"] per platform table, and the new version resolves in a sandbox
through an exact pin.
The obvious criterion -- resolve it through latest -- cannot be written.
Measured in a sandbox: version = "latest" in a manifest is taken as a literal
wire address and fails with install path missing after fetch; omitting
version is refused by the manifest parser; and mcpp add mcpp:plugins answers
package version required (M2 supports exact-version only). So no mcpp
consumer path reads the latest alias today -- it is consumed by xlings'
own resolution. Moving it is correct and costs nothing, and the criterion has
to be the descriptor's content plus an exact-pin resolution.
Files: examples/09-heterogeneous/boundary/**,
examples/09-heterogeneous/cuda/app/**, examples/09-heterogeneous/sycl/app/**.
Each pins plugins = { version = "0.5.2", ... }, passes roots and a
layout_root, and reaches the boundary through the qualified name. boundary
additionally shows strip_prefix, because it is the example whose whole subject
is the generated interface.
Files: docs/42-heterogeneous-builds.md, docs/zh/42-...,
docs/31-authoring-a-rule-package.md, docs/zh/31-..., docs/README.md,
docs/zh/README.md, examples/09-heterogeneous/boundary/README.md,
examples/09-heterogeneous/README.md.
The island generator's section moves from 31 to 42, because 31's reader is a rule author and no shipped rule calls the generator. 31 keeps one sentence and a link. The name table in 42 gains the island rows. Both languages, with the section numbering and the cross-references checked.
.github/tools/ already holds the documentation parity check that CI runs. The
new sections are added to both languages in the same commit, and the check is
run locally before the pull request.
Tag the release, publish it from the tag, gtc upload of the same bytes to
GitCode, then T6. This ran three times: 0.5.0 for the design, 0.5.1 for the
refusal of overlapping roots that the design states and 0.5.0 omitted, and
0.5.2 for the separator defect the first cross-platform run of the fixture
found.
In an xlings sandbox, with the CN mirror configured for both mcpp and xlings:
resolve mcpp:plugins@0.5.0 from the index, build and run the boundary
example against the published package rather than a path override, and confirm
the qualified names in the generated module.
Criterion: the sandbox is the only thing that verifies the published artifact; a path override in a working tree verifies the working tree.