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
1 change: 1 addition & 0 deletions .agents/skills/add-mcpp-index-package/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,5 +139,6 @@ rm -rf "tests/examples/<member>/target" "tests/examples/<member>/.mcpp" # 冷
| 声称实现了 feature 却未做负向验证 | 验证默认构建确实不含该组件 |
| 未对齐 CI 的 mcpp 版本,本地通过而 CI 失败 | 读取 `MCPP_VERSION` 并使用同一版本 |
| 直接推送 `main` | 切出分支并提交 PR |
| 构建插件把模块命名为 `mcpp.rules.*`、`mcpp.plugins.*` 等保留名,或把命名空间取作 `rules`、`tools` 等 | 模块命名为 `mcpp.<自身命名空间>.*`;保留第二段属于 mcpp 项目(docs/zh/package-types.md §I),成员构建出现引擎的保留名警告即失败 |

完成前应遵循 `verification-before-completion`:在声明“通过/完成”之前,须给出真实命令输出作为证据。
16 changes: 15 additions & 1 deletion .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,13 @@ env:
# that never match one target (linux, macos), so no descriptor's flags move.
#
# `index.toml` min_mcpp does not move: no descriptor grammar changed.
MCPP_VERSION: "2026.9.28.2"
#
# 2026.9.28.3 (mcpp-community/mcpp#734): build programs speak protocol 14,
# so every member's build program re-runs once; mcpp.plugins 0.17.0 states it
# as its floor, and tests/examples/mcpp-plugins builds against it. Engine
# warnings the members may newly print: W1 to W3 of SPEC-008 (the library
# interface), warnings only.
MCPP_VERSION: "2026.9.28.3"

jobs:
lint:
Expand Down Expand Up @@ -422,6 +428,14 @@ jobs:
if ! lua5.4 tests/check_package_name.lua "$f"; then
fail=1
fi
# 5b. The build-plugin naming rule (mcpp#734): a namespace may not be
# one of the reserved second segments of `mcpp.` (core, plugins,
# deps, rules, dist, tools), which name the mcpp project's own
# modules. The module names themselves are checked where members
# build (tests/run_members.sh), by the engine's own warning.
if ! lua5.4 tests/check_reserved_namespace.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
Expand Down
32 changes: 32 additions & 0 deletions docs/package-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,38 @@ Four things to get right:
The matching member is `tests/examples/protobuf-protoc`, and it is the complement of `tests/examples/protobuf`: that
one deliberately uses no generated code, this one is generated code end to end.

## I. Build-plugin package (`mcpp.plugins`)

A build plugin is a package whose modules a consumer's `build.mcpp` imports: its
units import `mcpp.core` (also spelled `mcpp`) and reach a consumer through a
`[build-dependencies]` edge with `host-module = true`. Three rules admit one to
this index (mcpp#734):

- **Module names.** A plugin names its build-program modules
`mcpp.<namespace>.*` after its own namespace (`mcpp.acme.protobuf`). The second
segments `core`, `plugins`, `deps`, `rules`, `dist` and `tools` belong to the
mcpp project. The engine warns when another package uses them (mcpp SPEC-007
§9); a member whose build prints that warning fails `tests/run_members.sh`,
and the lint refuses a namespace spelled like one of them
(`tests/check_reserved_namespace.lua`). Modules the package also offers to
programs follow the library rule, `<namespace>.<name>.*` (mcpp SPEC-008 I3).
- **The manifest.** The official general library is reached through the feature
`plugins-core`. A plugin built on it depends on `mcpp.plugins` with
`host-module = true` and `features = ["plugins-core"]`, and adds
`reexport = true` when its consumers' build programs import the library
themselves:

```toml
[build-dependencies.mcpp]
plugins = { version = "0.17.0", features = ["plugins-core"], host-module = true, reexport = true }
```
- **The engine floor.** The package states the first mcpp release it needs,
`[package] mcpp = ">=<release>"`; an older engine stops and names the upgrade.
A plugin that reads the build information (the resolved tools, `mcpp::report`)
needs 2026.9.28.3.

The matching member is `tests/examples/mcpp-plugins`.

---

## The minimal project (`tests/examples/<short>/`)
Expand Down
4 changes: 3 additions & 1 deletion docs/repository-and-schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ tests/examples/<member>/ one test project per library (a workspace member; <
tests/*.cpp behavioral assertions (standalone main; a non-zero exit code is a failure)
tests/check_mirror_urls.lua lint: GLOBAL+CN table completeness, and that CN points at mcpp-res
tests/check_package_name.lua lint: identity shape (name is a single atomic segment, hierarchy belongs to namespace)
tests/check_reserved_namespace.lua lint: a namespace is not a reserved second segment of `mcpp.` (core, plugins, deps, rules, dist, tools)
tests/list_cn_urls.lua extracts the CN urls for mirror-cn-reachable
tests/run_members.sh runs workspace members one at a time and times each. The entry point used both by CI
and locally; see "Running workspace members locally" below
Expand Down Expand Up @@ -164,7 +165,7 @@ locally with `mcpp xpkg parse pkgs/<x>/<name>.lua`.
- `env.MCPP_VERSION` is the mcpp version every job uses; local verification should match it.
- `lint` (always runs): lua syntax via `loadfile(f,'t')`; `spec=`/`name=`/`xpm=` must be present; leading-v versions
are rejected; runs `check_mirror_urls.lua`; runs `check_package_name.lua` (identity shape, see "Package identity"
above); then runs `mcpp xpkg parse` over every descriptor with the mcpp version CI pins (strict — an unknown key
above); runs `check_reserved_namespace.lua` (the build-plugin naming rule, docs/package-types.md §I); then runs `mcpp xpkg parse` over every descriptor with the mcpp version CI pins (strict — an unknown key
fails). `xpkg parse` in mcpp >= 0.0.106 enforces the identity shape itself, which makes the lua lint an earlier and
cheaper redundant gate.
- `mirror-cn-reachable` (always runs): `curl`s each CN url; all must return 200.
Expand Down Expand Up @@ -227,6 +228,7 @@ for f in pkgs/*/*.lua; do
grep -nqE '\["v[0-9]+|\["[^"]+"\][[:space:]]*=[[:space:]]*"v[0-9]+' "$f" && { echo "LEADING-V $f"; fail=1; }
lua5.4 tests/check_mirror_urls.lua "$f" >/dev/null 2>&1 || { echo "MIRROR $f"; fail=1; }
lua5.4 tests/check_package_name.lua "$f" || fail=1
lua5.4 tests/check_reserved_namespace.lua "$f" || fail=1
done
[ $fail -eq 0 ] && echo "ALL LINT PASS"
```
Expand Down
24 changes: 24 additions & 0 deletions docs/zh/package-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,30 @@ protobuf 最经典的坑——在这里**语法上无法表达**。`mcpp build -
对应的成员是 `tests/examples/protobuf-protoc`,它与 `tests/examples/protobuf` 互为补集:那个刻意**不用**
任何生成代码,这个从头到尾都是生成代码。

## I. 构建插件包(`mcpp.plugins`)

构建插件是其模块由消费方 `build.mcpp` 导入的包:它的单元导入 `mcpp.core`(也写作 `mcpp`),
经带 `host-module = true` 的 `[build-dependencies]` 边到达消费方。进入本索引需满足三条规则
(mcpp#734):

- **模块名。** 插件以自身命名空间为其构建程序模块命名:`mcpp.<namespace>.*`(例如
`mcpp.acme.protobuf`)。第二段 `core`、`plugins`、`deps`、`rules`、`dist`、`tools` 属于 mcpp
项目。其他包使用它们时引擎给出警告(mcpp SPEC-007 §9);构建输出含该警告的成员在
`tests/run_members.sh` 中失败,lint 拒绝与之同名的命名空间(`tests/check_reserved_namespace.lua`)。
包同时提供给程序的模块遵循库的规则 `<namespace>.<name>.*`(mcpp SPEC-008 I3)。
- **清单。** 官方通用库经 feature `plugins-core` 提供。基于它的插件以 `host-module = true` 与
`features = ["plugins-core"]` 依赖 `mcpp.plugins`;其消费方的构建程序也直接导入该库时,再加
`reexport = true`:

```toml
[build-dependencies.mcpp]
plugins = { version = "0.17.0", features = ["plugins-core"], host-module = true, reexport = true }
```
- **引擎下限。** 包以 `[package] mcpp = ">=<release>"` 写明所需的最早 mcpp 版本;更旧的引擎停止并
写出升级方式。读取构建信息(解析出的工具、`mcpp::report`)的插件需要 2026.9.28.3。

对应的成员是 `tests/examples/mcpp-plugins`。

---

## 最小工程(`tests/examples/<short>/`)
Expand Down
4 changes: 3 additions & 1 deletion docs/zh/repository-and-schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ tests/examples/<member>/ 每库测试工程(workspace 成员;<member> 为包
tests/*.cpp 行为断言(独立 main,退出码非 0 即失败)
tests/check_mirror_urls.lua lint:GLOBAL+CN 表完整性,以及 CN 指向 mcpp-res
tests/check_package_name.lua lint:身份形态(name 为单一原子段,层级归 namespace)
tests/check_reserved_namespace.lua lint:命名空间不得是 `mcpp.` 的保留第二段(core、plugins、deps、rules、dist、tools)
tests/list_cn_urls.lua 抽取 CN url,供 mirror-cn-reachable 使用
tests/run_members.sh 逐个运行 workspace 成员并计时。CI 与本地共用的入口,见下文「本地运行 workspace 成员」
tests/plan_shards.lua 依实测耗时将成员分配到各分片。由 `select` job 调用一次,`run_members.sh --shard`
Expand Down Expand Up @@ -125,7 +126,7 @@ mcpp 跑 `xpkg parse`(strict:未知键即失败),所以需要更新文法/键的
条件下比较,代价是显著更慢。
- `env.MCPP_VERSION` 为全部 job 使用的 mcpp 版本,本地验证应与之对齐。
- `lint`(始终运行):lua 语法 `loadfile(f,'t')`;须含 `spec=`/`name=`/`xpm=`;禁止前导 v 版本;执行
`check_mirror_urls.lua`;执行 `check_package_name.lua`(身份形态,见上文「包身份」);再用 CI pin 的
`check_mirror_urls.lua`;执行 `check_package_name.lua`(身份形态,见上文「包身份」);执行 `check_reserved_namespace.lua`(构建插件命名规则,见 package-types §I);再用 CI pin 的
mcpp 对每个描述符跑 `mcpp xpkg parse`(strict,未知键即失败)。mcpp ≥ 0.0.106 的 `xpkg parse` 自身
也强制身份形态,lua lint 因此是更早、更便宜的冗余闸门。
- `mirror-cn-reachable`(始终运行):逐个 `curl` CN url,均须返回 200。
Expand Down Expand Up @@ -179,6 +180,7 @@ for f in pkgs/*/*.lua; do
grep -nqE '\["v[0-9]+|\["[^"]+"\][[:space:]]*=[[:space:]]*"v[0-9]+' "$f" && { echo "LEADING-V $f"; fail=1; }
lua5.4 tests/check_mirror_urls.lua "$f" >/dev/null 2>&1 || { echo "MIRROR $f"; fail=1; }
lua5.4 tests/check_package_name.lua "$f" || fail=1
lua5.4 tests/check_reserved_namespace.lua "$f" || fail=1
done
[ $fail -eq 0 ] && echo "ALL LINT PASS"
```
Expand Down
8 changes: 7 additions & 1 deletion index.toml
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,13 @@
# Moved in the pull request that moves validate.yml's pin to 2026.9.28.2,
# which runs every member on every platform with it. The release changes no
# descriptor grammar.
# ── 2026-09-28: latest_mcpp -> 2026.9.28.3, min_mcpp unchanged ─────────────
#
# Moved in the pull request that moves validate.yml's pin to 2026.9.28.3 and
# registers mcpp.plugins 0.17.0, whose package floor it is. The release changes
# no descriptor grammar; its `[package] mcpp` key is manifest vocabulary, which
# an older engine reports as unsupported and ignores.
[index]
spec = "1"
min_mcpp = "2026.9.18.3"
latest_mcpp = "2026.9.28.2"
latest_mcpp = "2026.9.28.3"
1 change: 1 addition & 0 deletions mcpp.toml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ members = [
"tests/examples/imgui-window",
"tests/examples/jwt-cpp",
"tests/examples/marzer.tomlplusplus",
"tests/examples/mcpp-plugins",
"tests/examples/mio",
"tests/examples/libmysqlclient",
"tests/examples/mysql-connector-cpp",
Expand Down
40 changes: 36 additions & 4 deletions pkgs/m/mcpp.plugins.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,23 @@
-- each member selected by a feature.
--
-- [dependencies.mcpp]
-- plugins = { version = "0.16.0", features = ["rules-spirv"], host-module = true }
-- plugins = { version = "0.17.0", features = ["rules-spirv"], host-module = true }
--
-- // build.mcpp
-- import mcpp;
-- import mcpp.rules.spirv;
--
-- 0.17.0 (package floor 2026.9.28.3, `[package] mcpp`): the general library
-- for build programs behind `plugins-core` (renamed from `surface`, kept as an
-- alias until 2027-03-28) -- `mcpp.plugins.toolset`, `mcpp.plugins.fs` -- and
-- the test kit `mcpp.plugins.testing` behind `plugins-testing`. deps-vcpkg and
-- deps-cmake build with the toolset mcpp resolved: a Visual Studio instance is
-- selected with VCPKG_VISUAL_STUDIO_PATH (the ABI hash is unchanged), a managed
-- MSVC toolset and the clang rows are named in a derived triplet
-- `<base>-mcpp-<hash>`, and the Linux GCC row keeps vcpkg's detection; the C
-- runtime follows the program's contract. mcpp-community/mcpp#734,
-- mcpp-community/mcpp-plugins#37.
--
-- 0.16.0 (mcpp floor 2026.9.27.1 for `rules-qt`): the Linux C++ runtime a
-- Qt program needs is stated in the host rows `[target.x86_64-linux-gnu]` and
-- `[target.aarch64-linux-gnu]`, which a plain `mcpp build` now applies
Expand Down Expand Up @@ -608,6 +619,13 @@ package = {

xpm = {
linux = {
["0.17.0"] = {
url = {
GLOBAL = "https://github.com/mcpp-community/mcpp-plugins/archive/refs/tags/v0.17.0.tar.gz",
CN = "https://gitcode.com/mcpp-res/mcpp-plugins/releases/download/0.17.0/mcpp-plugins-0.17.0.tar.gz",
},
sha256 = "20e9fc467c83dce33fbb706f5373eeb14eb0880c1e08e9c2c30594147875c57e",
},
["0.16.0"] = {
url = {
GLOBAL = "https://github.com/mcpp-community/mcpp-plugins/archive/refs/tags/v0.16.0.tar.gz",
Expand Down Expand Up @@ -846,9 +864,16 @@ package = {
},
sha256 = "adf1f9d6691a5d05a8a4a94e83c733ea39caee1510ce2c9af4cb23bebabea9f5",
},
["latest"] = { ref = "0.16.0" },
["latest"] = { ref = "0.17.0" },
},
macosx = {
["0.17.0"] = {
url = {
GLOBAL = "https://github.com/mcpp-community/mcpp-plugins/archive/refs/tags/v0.17.0.tar.gz",
CN = "https://gitcode.com/mcpp-res/mcpp-plugins/releases/download/0.17.0/mcpp-plugins-0.17.0.tar.gz",
},
sha256 = "20e9fc467c83dce33fbb706f5373eeb14eb0880c1e08e9c2c30594147875c57e",
},
["0.16.0"] = {
url = {
GLOBAL = "https://github.com/mcpp-community/mcpp-plugins/archive/refs/tags/v0.16.0.tar.gz",
Expand Down Expand Up @@ -1087,9 +1112,16 @@ package = {
},
sha256 = "adf1f9d6691a5d05a8a4a94e83c733ea39caee1510ce2c9af4cb23bebabea9f5",
},
["latest"] = { ref = "0.16.0" },
["latest"] = { ref = "0.17.0" },
},
windows = {
["0.17.0"] = {
url = {
GLOBAL = "https://github.com/mcpp-community/mcpp-plugins/archive/refs/tags/v0.17.0.tar.gz",
CN = "https://gitcode.com/mcpp-res/mcpp-plugins/releases/download/0.17.0/mcpp-plugins-0.17.0.tar.gz",
},
sha256 = "20e9fc467c83dce33fbb706f5373eeb14eb0880c1e08e9c2c30594147875c57e",
},
["0.16.0"] = {
url = {
GLOBAL = "https://github.com/mcpp-community/mcpp-plugins/archive/refs/tags/v0.16.0.tar.gz",
Expand Down Expand Up @@ -1328,7 +1360,7 @@ package = {
},
sha256 = "adf1f9d6691a5d05a8a4a94e83c733ea39caee1510ce2c9af4cb23bebabea9f5",
},
["latest"] = { ref = "0.16.0" },
["latest"] = { ref = "0.17.0" },
},
},

Expand Down
38 changes: 38 additions & 0 deletions tests/check_reserved_namespace.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
-- Lint `package.namespace` against the build-plugin naming rule (mcpp#734;
-- mcpp SPEC-007 §9, "plugin names").
--
-- A build plugin names its modules `mcpp.<namespace>.*` after its own
-- package's namespace, and the second segments `core`, `plugins`, `deps`,
-- `rules`, `dist` and `tools` of `mcpp.` belong to the mcpp project: `mcpp.core`
-- is the engine's interface, the others are the families of mcpp-plugins. A
-- namespace spelled like one of them would make a third party's
-- `mcpp.<namespace>.*` indistinguishable from an official family, so the index
-- refuses such a namespace. The engine warns on the module names themselves;
-- the index can refuse, because it knows which namespaces are registered.
--
-- Usage: lua5.4 tests/check_reserved_namespace.lua <file.lua>

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

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

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

local reserved = { core = true, plugins = true, deps = true, rules = true, dist = true, tools = true }
local first = ns:match("^([^.]+)")
if first and reserved[first] then
io.stderr:write(string.format(
"::error file=%s::namespace '%s' is reserved: `mcpp.%s.*` names modules of the mcpp project " ..
"(mcpp SPEC-007 §9), so a plugin of this namespace could not be told from an official one\n",
path, ns, first))
os.exit(1)
end
os.exit(0)
14 changes: 14 additions & 0 deletions tests/examples/mcpp-plugins/build.mcpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import std;
import mcpp;
import mcpp.tools.embed;
import mcpp.plugins.fs;

int main() {
mcpp::tools::embed::options opt;
opt.name_space = "fixture";
opt.null_terminate = true;
// L2: a generated file keeps its time stamp while its content is unchanged.
const std::filesystem::path stamp = std::filesystem::path(mcpp::out_dir()) / "l2-probe.txt";
mcpp::plugins::fs::write_if_changed(stamp, "mcpp.plugins.fs\n");
return mcpp::tools::embed::file("data/message.txt", opt) ? 0 : 1;
}
1 change: 1 addition & 0 deletions tests/examples/mcpp-plugins/data/message.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
hello from mcpp.plugins
16 changes: 16 additions & 0 deletions tests/examples/mcpp-plugins/mcpp.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# mcpp.plugins consumer: the official plugin package, resolved from this
# checkout, reached from a build program. `tools-embed` needs no payload, so
# the member runs on every platform; its build program imports L3
# (`mcpp.tools.embed`) and L2 (`mcpp.plugins.fs`, through `plugins-core`, which
# every member implies). The member is also the positive leg of the naming rule
# tests/run_members.sh enforces: namespace `mcpp` provides `mcpp.tools.*` and
# `mcpp.plugins.*` without the engine's reserved-name warning.
[package]
name = "mcpp-plugins-tests"
version = "0.1.0"

[indices]
mcpp = { path = "../../.." }

[build-dependencies.mcpp]
plugins = { version = "0.17.0", features = ["tools-embed"], host-module = true }
12 changes: 12 additions & 0 deletions tests/examples/mcpp-plugins/tests/embed.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#include <cstddef>
#include <cstdio>
#include <cstring>
#include "message_txt.h"

int main() {
const char* text = reinterpret_cast<const char*>(fixture::message_txt);
if (fixture::message_txt_size != std::strlen("hello from mcpp.plugins")) return 1;
if (std::strcmp(text, "hello from mcpp.plugins") != 0) return 1;
std::puts("mcpp-plugins-tests: the embedded file reached the program");
return 0;
}
15 changes: 14 additions & 1 deletion tests/run_members.sh
Original file line number Diff line number Diff line change
Expand Up @@ -118,10 +118,23 @@ rows=$(mktemp)
trap 'rm -f "$rows"' EXIT
rc=0

# THE BUILD-PLUGIN NAMING RULE (mcpp#734). The engine warns when a package
# provides a build-program module under a reserved second segment of `mcpp.`
# (`mcpp.rules.*`, `mcpp.plugins.*`, ...) without being in namespace `mcpp`
# (mcpp SPEC-007 §9). The index admits no such package: a member whose build
# prints that warning fails. One rule, stated once, in the engine.
naming_rule='which belongs to the modules maintained by the mcpp project'
log=$(mktemp)
trap 'rm -f "$rows" "$log"' EXIT

for m in "${members[@]}"; do
echo "::group::mcpp test -p $m"
t0=$(date +%s)
if "$MCPP" test -p "$m"; then status=ok; else status=FAIL; rc=1; fi
if "$MCPP" test -p "$m" 2>&1 | tee "$log"; [ "${PIPESTATUS[0]}" -eq 0 ]; then status=ok; else status=FAIL; rc=1; fi
if grep -q "$naming_rule" "$log"; then
echo "::error::member $m builds a plugin whose module names a reserved segment of mcpp. (mcpp SPEC-007 §9)"
status=FAIL; rc=1
fi
t1=$(date +%s)
echo "::endgroup::"
printf '%s\t%s\t%s\n' "$((t1 - t0))" "$m" "$status" >> "$rows"
Expand Down
Loading