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
46 changes: 41 additions & 5 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ name: validate

on:
pull_request:
paths: ["pkgs/**/*.lua", "tests/**", "README.md", ".github/workflows/validate.yml"]
# mcpp.toml and index.toml carry the workspace member list, the inherited
# [indices] redirect and the client version floor — a change to any of them
# can break every member, so they gate the run like the descriptors do.
paths: ["pkgs/**/*.lua", "tests/**", "README.md", "mcpp.toml", "index.toml", ".github/workflows/validate.yml"]
push:
branches: [main]
schedule:
Expand All @@ -11,6 +14,21 @@ on:
workflow_dispatch:

env:
# 0.0.109: a bare dependency's wire address takes BOTH halves from the
# descriptor the identity gate accepted (mcpp#286). This is the client-side
# other half of the SPEC-001 migration below: mcpp used to take the NAME from
# the descriptor and the NAMESPACE from the request, so a bare `gtest =
# "1.15.2"` addressed `mcpplibs:gtest` — a key no index has. It only ever
# worked because the pre-migration literal `package.name` read
# "compat.gtest", which the hardcoded `compat.<short>` retry then caught.
# Short names removed that coincidence and left every bare request against
# this index broken on 0.0.108, which is why min_mcpp moves to 0.0.109.
# Note this index cannot cover that spelling itself: the `[indices]` redirect
# is keyed by the REQUEST's namespace, so a bare dependency resolves from the
# published remote index rather than the checkout under test. Bare-name
# resolution against a short-name index is upstream's e2e 165; what moving
# the floor buys here is that consumers of THIS index get a client that can
# address it.
# 0.0.106: SPEC-001 package identity (mcpp#280). `package.name` is a SINGLE
# ATOMIC SEGMENT — all hierarchy lives in `package.namespace` — and mcpp
# addresses a package by the LITERAL name it read, so descriptors no longer
Expand Down Expand Up @@ -57,7 +75,7 @@ env:
# 0.0.94 fixed feature-gated `sources` under `mcpp test` (mcpp#218); 0.0.91
# added standard = "c++fly" to the resolver grammar, so c++fly descriptors
# get the lint WARN below, not a hard grammar-parse rejection.
MCPP_VERSION: "0.0.108"
MCPP_VERSION: "0.0.109"

jobs:
lint:
Expand Down Expand Up @@ -222,21 +240,21 @@ jobs:
ext: tar.gz
mcpp: bin/mcpp
xlings: registry/bin/xlings
mcpp_version: "0.0.108" # keep in sync with env.MCPP_VERSION
mcpp_version: "0.0.109" # keep in sync with env.MCPP_VERSION
- platform: macos
os: macos-15
suffix: macosx-arm64
ext: tar.gz
mcpp: bin/mcpp
xlings: registry/bin/xlings
mcpp_version: "0.0.108" # keep in sync with env.MCPP_VERSION
mcpp_version: "0.0.109" # keep in sync with env.MCPP_VERSION
- platform: windows
os: windows-latest
suffix: windows-x86_64
ext: zip
mcpp: bin/mcpp.exe
xlings: registry/bin/xlings.exe
mcpp_version: "0.0.108" # keep in sync with env.MCPP_VERSION
mcpp_version: "0.0.109" # keep in sync with env.MCPP_VERSION
env:
MCPP_EFFECTIVE: ${{ matrix.mcpp_version }}
steps:
Expand Down Expand Up @@ -375,3 +393,21 @@ jobs:
exit $rc
fi

# install()-driven packages (openssl, openblas) build through their own
# Make/Configure system, whose output xim's interface mode swallows; a
# failed hook surfaces only as `E_INTERNAL: [<pkg>] failed:`. Each writes
# a log into its install prefix, so on failure surface those — otherwise
# diagnosing a platform-specific build break costs a full CI round-trip
# per guess.
- name: Dump install() build logs on failure
if: failure()
shell: bash
run: |
found=0
while IFS= read -r log; do
found=1
echo "::group::$log"
tail -80 "$log"
echo "::endgroup::"
done < <(find tests/examples "$HOME/.mcpp/registry" -name 'mcpp_*_build.log' 2>/dev/null)
[ "$found" = 1 ] || echo "no install() build logs found"
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ mcpp self config --mirror CN # 切换至国内镜像,默认使用 GLOBAL 上
| 原生模块库(Form A) | [`mcpplibs.xpkg`](pkgs/x/xpkg.lua) · [`mcpplibs.tinyhttps`](pkgs/t/tinyhttps.lua) · [`tensorvia-cpu`](pkgs/t/tensorvia-cpu.lua) · [`ffmpeg`](pkgs/f/ffmpeg.lua)(模块层,源码经 `compat.ffmpeg` 直编) · [`opencv`](pkgs/o/opencv.lua)(单仓库:模块层与 OpenCV 5 全源码构建同在包内,索引侧只留本描述符) |
| C 源码 compat(含 `features`) | [`compat.cjson`](pkgs/c/compat.cjson.lua) · [`compat.zlib`](pkgs/c/compat.zlib.lua) |
| header-only(含 `features`) | [`compat.eigen`](pkgs/c/compat.eigen.lua) |
| 外部构建系统(`install()` 从源码构建) | [`compat.openblas`](pkgs/c/compat.openblas.lua)(Make) |
| 外部构建系统(`install()` 从源码构建) | [`compat.openblas`](pkgs/c/compat.openblas.lua)(Make) · [`compat.openssl`](pkgs/c/compat.openssl.lua)(Perl Configure + Make,静态 libssl/libcrypto) |
| 全源码直编(config 快照 + 源列表,零外部构建系统) | [`compat.ffmpeg`](pkgs/c/compat.ffmpeg.lua)(2281 TU 含 NASM 汇编,28 个目录 glob 声明) |
| C++23 module wrapper | [`nlohmann.json`](pkgs/n/nlohmann.json.lua) · [`marzer.tomlplusplus`](pkgs/m/marzer.tomlplusplus.lua) |

Expand All @@ -59,8 +59,9 @@ mcpp self config --mirror CN # 切换至国内镜像,默认使用 GLOBAL 上
- 字段规范见 [mcpp 扩展字段文档](https://github.com/mcpp-community/mcpp/blob/main/docs/04-schema-xpkg-extension.md)。

> 提交 PR 后,`validate` 自动执行 lint 并按改动库选跑对应 workspace 成员(整个测试面是一个 mcpp
> workspace,公开模块包 `imgui`/`ffmpeg`/`opencv`/`tinyhttps` 也是普通成员——各成员经 `[indices]`
> 把所消费命名空间重定向到 checkout,零 shell 驱动);合并后,`deploy-site` 将其发布至在线浏览站。
> workspace,公开模块包 `imgui`/`ffmpeg`/`opencv`/`tinyhttps` 也是普通成员——`compat` 的重定向声明在
> workspace 根并由成员继承,消费其他命名空间的成员各自覆盖,零 shell 驱动);合并后,`deploy-site`
> 将其发布至在线浏览站。

## 相关链接

Expand Down
13 changes: 9 additions & 4 deletions docs/package-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ A、B、C 三类共用的骨架(`package` 头与 `xpm`)如下:
```lua
package = {
spec = "1",
namespace = "compat", -- compat / nlohmann / mcpplibs 等,决定 import 前缀与依赖 key
name = "compat.<lib>", -- 完整包名,决定 pkgs/<首字母>/ 的落点
namespace = "compat", -- 点分层级路径;compat / nlohmann / mcpplibs 等,决定 import 前缀与依赖 key
name = "<lib>", -- 单一原子段,不重复 namespace(SPEC-001 §3.2)
description = "…",
licenses = {"MIT"}, -- SPDX
repo = "https://…",
Expand All @@ -36,6 +36,10 @@ package = {
}
```

身份是 `(namespace, name)` 二元组:层级一律放 `namespace`,`name` 只写一段。文件名不参与解析,推荐
`pkgs/<首字母>/<namespace>.<name>.lua`(命中 mcpp 的快路径)。详见
[仓库结构与 schema](repository-and-schema.md#包身份namespace-name)。

---

## A. C 源码 compat(`compat.cjson` / `compat.zlib`)
Expand Down Expand Up @@ -132,8 +136,9 @@ name = "<short>-example"
version = "0.1.0"
[toolchain]
default = "gcc@16.1.0"
[indices]
compat = { path = "../../.." } # 指回仓根,以使用本地描述符
# `compat` 由 workspace 根的 [indices] 继承,成员无需再写;
# 消费其他命名空间时才在此声明,例如 `[indices] fmtlib = { path = "../../.." }`
# —— 成员级声明会**替换**根级表而非与之合并(这正是保持单个项目索引 repo 的方式)。
[dependencies.compat]
<short> = "1.2.3" # 或:<short> = { version = "1.2.3", features = ["…"] }
[targets.<short>-example]
Expand Down
39 changes: 31 additions & 8 deletions docs/repository-and-schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@

```
pkgs/<x>/<name>.lua 描述符。<x> 取完整包名首字母(compat.* → c,nlohmann.json → n,imgui → i)
mcpp.toml workspace 清单(members 列表)
mcpp.toml workspace 清单(members 列表)+ 根级 [indices] compat = { path = "." },
由成员继承(相对路径按 workspace 根解析,mcpp ≥ 0.0.97)
tests/examples/<member>/ 每库测试工程(workspace 成员;<member> 为包名去前缀,模块包为
mcpp.toml <name>-module)。恰好一条 [indices] <ns> = { path = "../../.." }
把所消费命名空间重定向到本 checkout(模块包用 default,
mcpp ≥ 0.0.97;单条是硬约束——xlings 多项目级 repo 静默失败,
mcpp#238,修复后再做根级集中化)。依赖按平台自门控
mcpp.toml <name>-module)。消费 compat 的成员不写 [indices];消费其他
命名空间的成员写恰好一条(模块包用 default),该声明**替换**
根级表而非合并 —— 每个成员最多一个项目级索引 repo 是硬约束,
详见下文「索引重定向」。依赖按平台自门控
([target.'cfg(...)'])
tests/*.cpp 行为断言(独立 main,退出码非 0 即失败)
tests/check_mirror_urls.lua lint:GLOBAL+CN 表完整性,以及 CN 指向 mcpp-res
Expand Down Expand Up @@ -75,8 +76,27 @@ namespace = "mcpplibs", name = "capi.lua" -- ❌ 短名仍带点
| `sources` | glob 列表,编入 lib 的源码 |
| `cflags` / `cxxflags` / `ldflags` | 追加至对应规则 |
| `targets` | `{ ["name"]={ kind="lib"/"bin", main=…, soname=… } }` |
| `features` | `{ ["f"]={ sources={…} } }`,仅识别 sources |
| `deps` | `{ ["ns.name"]="ver" }`,扁平或点号式 |
| `features` | `{ ["f"]={ sources={…}, defines={…}, deps={…}, implies={…}, requires={…} } }`;`defines` 只作用于**包自身**的 TU,消费端若要按 feature 分支须自行声明(见 `tests/examples/openssl`、`openblas` 的 `[target.'cfg(…)'.build] cxxflags`) |
| `deps` | `{ ["ns.name"]="ver" }`,扁平或点号式;feature 内同形 |

## 索引重定向(`[indices]`)

测试面要验证的是 **checkout 里的描述符**,而不是已发布的远程索引,这靠 `[indices]` 把命名空间重定向到本仓完成。

**根级继承**:workspace 根的 `mcpp.toml` 声明 `[indices] compat = { path = "." }`,相对路径按 **workspace 根**解析(mcpp ≥ 0.0.97,[mcpp#224](https://github.com/mcpp-community/mcpp/issues/224)),成员直接继承,不必各写一份 `path = "../../.."`。

**为什么只有一条,而且是 `compat`**:

- 索引表**按命名空间取键**。声明在一个没有任何依赖会请求的名字下,该索引根本不会被注册,解析会静默回落到已发布的远程索引 —— 此时被测的根本不是这个 checkout。
- 同一路径声明成多个命名空间确实都会注册,但会变成 N 个各自独立的项目 repo,之后任何查找都以 N 路歧义失败(物理上是同一个描述符;[mcpp#238](https://github.com/mcpp-community/mcpp/issues/238) / [xlings#374](https://github.com/openxlings/xlings/issues/374),在 xlings 0.4.69 后由静默 exit 1 变为响亮报错)。

所以根级只能承载一个命名空间,`compat` 是收益最大的那个(13 个成员 vs 其余合计 10 个)。

**成员级覆盖**:消费其他命名空间的成员自己声明 `[indices]`,该表**替换**继承来的根级表而非与之合并 —— 这正是每个成员只保留一个项目索引 repo 的机制。

**跨命名空间的取舍**:一个成员无法同时从本 checkout 解析两个命名空间。`tests/examples/asio-ssl` 有意利用了这一点:它不写成员级声明、继承根级 `compat`,于是 asio 本身走已发布的远程索引,而它的 `ssl` feature 依赖 `compat.openssl` 从本 checkout 解析 —— 这样**未合并的 compat 描述符可以通过一个已发布的消费者去验证**。反过来,本地 asio 描述符由 `tests/examples/asio-module` 覆盖。

**裸名依赖不适用**:重定向按**请求侧**的命名空间取键,而裸写的 `eigen = "5.0.1"` 是以默认命名空间发出的请求,即使最终落到 `compat` 描述符上,也会从远程索引解析。因此各成员一律使用限定写法;裸名解析本身由 mcpp 上游的 e2e 165 覆盖。

## index 版本契约(index.toml)

Expand All @@ -101,7 +121,8 @@ mcpp 跑 `xpkg parse`(strict:未知键即失败),所以需要更新文法/键的
- `mirror-cn-reachable`(始终运行):逐个 `curl` CN url,均须返回 200。
- `workspace (linux|macos|windows)`:整个测试面就是一个 mcpp workspace,**唯一的构建/运行通道**——
没有任何 shell 驱动的例外(公开模块包 imgui/ffmpeg/opencv/tinyhttps 也是普通成员,经成员级
`[indices] default = { path = "../../.." }` 从 checkout 解析,mcpp ≥ 0.0.97)。
`[indices] default = { path = "../../.." }` 从 checkout 解析,mcpp ≥ 0.0.97;消费 `compat` 的
成员则继承根级声明,见上文「索引重定向」)。
- 选择性成员测试:PR 时由 `git diff` 将改动文件映射到受影响成员
(`pkgs/<x>/<lib>.lua` → mcpp.toml 引用 `<lib>` 的成员;`tests/examples/<m>/**` → 成员 `<m>`),
仅 `mcpp test -p <member>` 这些成员;workflow 本身、workspace 清单非成员部分、`tools/` 等
Expand Down Expand Up @@ -135,3 +156,5 @@ done
| C++23 module(generated wrapper) | `pkgs/n/nlohmann.json.lua` | `tests/examples/nlohmann.json/` | 同上 / #48 |
| header-only + source-gated feature | `pkgs/c/compat.eigen.lua` | `tests/examples/eigen/` | `.agents/docs/2026-06-28-add-eigen-plan.md` / #50 |
| header-only(纯头) | `pkgs/c/compat.opengl.lua`、`compat.khrplatform.lua` | — | `.agents/docs/2026-06-03-gl-runtime-packages-plan.md` |
| 外部构建系统(`install()` 驱动) | `pkgs/c/compat.openblas.lua`(Make)、`compat.openssl.lua`(Perl Configure + Make) | `tests/examples/openblas/`、`openssl/` | `docs/superpowers/specs/2026-07-26-openssl-asio-tls-design.md` / #124 |
| feature 拉起依赖(跨包) | `pkgs/c/chriskohlhoff.asio.lua` 的 `ssl` feature → `compat.openssl` | `tests/examples/asio-ssl/` | 同上 |
32 changes: 31 additions & 1 deletion docs/superpowers/specs/2026-07-26-openssl-asio-tls-design.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,38 @@
# Add OpenSSL package + Asio SSL support

> Created: 2026-07-26 · Status: design
> Created: 2026-07-26 · Status: design (superseded in part — see §0)
> Repo: `mcpplibs/mcpp-index` · Branch: `feat/add-openssl-asio-tls`

## 0. Corrections after landing

The design below is kept as written; three of its claims did not survive
contact with the implementation, and the descriptor now differs accordingly.

1. **`name = "compat.openssl"` → `name = "openssl"`.** SPEC-001 (mcpp 0.0.106)
makes `name` a single atomic segment with all hierarchy in `namespace`; the
fully-qualified spelling is only a compatible legacy form.

2. **`MCPP_FEATURE_SSL` is NOT propagated to consumer TUs.** A feature's
`defines` apply to the package's own translation units. The original
`tests/ssl.cpp` keyed its whole body off that macro and therefore compiled
to nothing — it passed while asserting nothing. A consumer that branches on
a feature declares its own macro (`tests/examples/asio-ssl` sets
`HAVE_ASIO_SSL` in its `[target.'cfg(…)'.build] cxxflags`), which is the
same shape the openblas member already used.

3. **`./config` needs an explicit `--libdir=lib`.** Unset, OpenSSL derives it
as `lib$target{multilib}`, and `linux-x86_64` declares `multilib => "64"` —
so the archives install to `$prefix/lib64` while `-Llib` and the post-build
check look at `$prefix/lib`. linux-aarch64 and both darwin64 targets declare
no multilib, which is why the build validated on an arm64 Mac and was still
broken for every x86_64 Linux consumer.

Also changed while landing: linux links `-l:libssl.a -l:libcrypto.a` (naming
the archive rather than letting the driver resolve a name that a shared object
would win) plus `-ldl -lpthread`; the build log moved into the install prefix
so it survives a failed build; `RANLIB` is pinned only on macOS, which is the
platform that needs it; and `install()` probes for `perl` up front.

## 1. Motivation

The mcpp ecosystem needs TLS support. `chriskohlhoff.asio@1.38.1` (C++23
Expand Down
4 changes: 2 additions & 2 deletions index.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@
# "floor first, new grammar after" rollout rule mechanically.
[index]
spec = "1"
min_mcpp = "0.0.108"
latest_mcpp = "0.0.108"
min_mcpp = "0.0.109"
latest_mcpp = "0.0.109"
Loading
Loading