Skip to content

Commit 96c3617

Browse files
committed
docs+ci: 本地上手三步走 + 平台矩阵拆分(linux/macos/win10/win11/win 无 MSVC STL)
README(三语 + book 两语)重写「本地练习环境」段,改成明确的三步: 1. 装工具 —— `xlings install d2x mcpp -y`,两个工具名都链到各自仓库 2. 取课程并验证环境 —— 默认 `d2x install d2mcpp` → `cd d2mcpp` → `mcpp test`; clone 源码那条路收进 <details>,作为可选项而不是与默认路径并列的「二选一」 3. 开始练习 —— `d2x checker` / `d2x status` 第 2 步把 `mcpp test` 摆到台面上是有意的:练习就是测试,新环境跑一遍 「全部不通过」既是练习的起点,也已经证明工具链是通的。 CI 从单个 ubuntu job 拆成五档平台矩阵,每档都跑完整两层验证: linux / macos / windows-10 线(windows-2022)/ windows-11 线(windows-2025) / windows 且无 MSVC STL 最后一档把 runner 上的 Visual Studio 藏掉(改名 vswhere.exe 与 VC 目录 + 清空 VS* 环境变量,并就地检查后置条件),模拟学习者的干净 Windows —— 这 才是多数人的机器。mcpp 应当自动回落到自带的 winlibs MinGW,产物 target 目录名(x86_64-windows-gnu)就是断言依据。 两层验证: - `mcpp test`(已有 e2e.sh)—— pristine 全不过 + 覆盖答案后全过 - `d2x checker`(新增 checker-e2e.sh)—— 答案就位后 checker 必须自己走完 52 道题并退 0 加第二层是因为 checker 在 mcpp test 之上还叠了 Provider 的 NDJSON 协议、 进度持久化、文件监听三层;这三层断掉时 mcpp test 照样全绿,Windows 上就 出过这种静默回归(#87)。checker-e2e.sh 的看门狗自己用 shell 轮询实现, 不依赖 timeout(1)(macOS 默认没有)。 顺带: - .xlings.json pin 上抬 —— mcpp 2026.8.1.1 → 2026.8.2.1(裸 Windows 自动 回落 MinGW 是这个版本才有的能力,无 MSVC STL 那一档依赖它), d2x 2026.08.02.1 → 2026.08.02.2 - 修复文件名核对 job:它还在按迁移前的布局找 `intro/tests cpp*/tests`, 练习早已搬进 src/,于是一个文件都没扫到、永远绿。现在真的核对 52 对。 - 工作流触发路径补上 .xlings.json 本地已验:e2e.sh all(zh/en 各 52/52)、checker-e2e.sh zh 与 en 均全过。
1 parent 32a7a3e commit 96c3617

8 files changed

Lines changed: 426 additions & 48 deletions

File tree

.github/workflows/dslings-ref-ci.yml

Lines changed: 151 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,25 @@ name: Validate exercises and reference solutions
77
# 练习即测试:e2e 走 `mcpp test`,与 `d2x checker` 内部的 Provider 是同一条
88
# 链路,所以 CI 绿灯等价于学习者本地能跑通,而不是另一条平行的构建路径。
99
#
10+
# 两层都要验,因为它们的失效方式不同:
11+
# - `mcpp test` —— 编译/运行这一层(e2e.sh)
12+
# - `d2x checker` —— 在它之上还叠了 Provider 的 NDJSON 协议、进度持久化、
13+
# 文件监听三层(checker-e2e.sh)。这三层断掉时 mcpp test
14+
# 照样全绿,Windows 上就出过这样的静默回归(d2mcpp#87)。
15+
#
16+
# 平台矩阵拆成五档,因为它们各有各的踩法,合成一个 ubuntu job 等于没测:
17+
# linux / macos / windows-10 线 / windows-11 线 / windows 且无 MSVC STL
18+
# 最后一档见下方 mask_msvc 的注释。
19+
#
1020
# 依赖 mcpp >= 0.0.104(测试能力批次:逐测试隔离 / 过滤 / --list / --timeout /
1121
# --message-format json / tests 吃 [build].flags)。
1222
#
13-
# 但真正的下限已被上游抬高:mcpplibs 依赖索引现在要求 mcpp >= 0.0.109,更低的
14-
# 版本一律 E0006「index requires mcpp >= 0.0.109」而拒绝解析依赖 —— 原先钉的
15-
# 0.0.104 自此装不出来。pin 见 .xlings.json,当前为 2026.8.1.1。
23+
# 但真正的下限已被上游抬高两次:
24+
# - mcpplibs 依赖索引要求 mcpp >= 0.0.109,更低版本一律 E0006 拒绝解析依赖
25+
# - 「无 MSVC STL 的 Windows」这一档要求 mcpp >= 2026.8.2.1:自动回落到
26+
# winlibs MinGW(x86_64-windows-gnu)是那个版本才有的能力,再早的版本在
27+
# 裸 Windows 上直接硬失败
28+
# pin 见 .xlings.json,当前为 2026.8.2.1。
1629

1730
on:
1831
push:
@@ -23,6 +36,7 @@ on:
2336
- "d2x/**"
2437
- "mcpp.toml"
2538
- ".d2x.json"
39+
- ".xlings.json"
2640
- ".github/workflows/dslings-ref-ci.yml"
2741
pull_request:
2842
paths:
@@ -31,52 +45,172 @@ on:
3145
- "d2x/**"
3246
- "mcpp.toml"
3347
- ".d2x.json"
48+
- ".xlings.json"
3449
- ".github/workflows/dslings-ref-ci.yml"
3550
workflow_dispatch:
3651

52+
env:
53+
XLINGS_VERSION: "0.4.51"
54+
XLINGS_NON_INTERACTIVE: "1"
55+
3756
jobs:
3857
validate-exercises:
39-
runs-on: ubuntu-latest
58+
name: validate (${{ matrix.name }})
59+
runs-on: ${{ matrix.os }}
60+
timeout-minutes: 120
4061

41-
env:
42-
XLINGS_VERSION: "0.4.51"
43-
XLINGS_NON_INTERACTIVE: "1"
62+
# GitHub 不提供 Windows 客户端版的 x64 托管 runner,只有 Server 镜像;这里
63+
# 用与各自客户端版共享内核基线的 Server 镜像代表两条产品线:
64+
# windows-2022 = Server 2022,与 Windows 10 22H2 同基线(10.0.20348)
65+
# windows-2025 = Server 2025,与 Windows 11 24H2 同基线(10.0.26100)
66+
# 这是托管 runner 上能覆盖到的最接近真实 Win10/Win11 的组合。
67+
strategy:
68+
fail-fast: false
69+
matrix:
70+
include:
71+
- name: linux
72+
os: ubuntu-latest
73+
langs: all # zh + en 两套课程都验
74+
- name: macos
75+
os: macos-14
76+
langs: zh
77+
- name: windows-10 baseline
78+
os: windows-2022
79+
langs: zh
80+
- name: windows-11 baseline
81+
os: windows-2025
82+
langs: zh
83+
# 学习者的机器上装了 Visual Studio 才是少数情况。这一档把 VS 从
84+
# runner 上藏掉,验证「一台干净的 Windows」同样能跑完整门课 ——
85+
# mcpp 会自动回落到自带的 winlibs MinGW(x86_64-windows-gnu)。
86+
- name: windows-11, no MSVC STL
87+
os: windows-2025
88+
langs: zh
89+
mask_msvc: true
90+
91+
defaults:
92+
run:
93+
shell: bash
4494

4595
steps:
4696
- uses: actions/checkout@v4
4797

98+
# 必须排在装工具链之前:此后的任何一步都不该看见 Visual Studio。
99+
- name: Mask Visual Studio (simulate a bare Windows box)
100+
if: matrix.mask_msvc
101+
shell: pwsh
102+
run: |
103+
$ErrorActionPreference = 'Continue'
104+
105+
# mcpp 的三条 MSVC 发现路径(vswhere / 环境变量 / 已知路径扫描)最终
106+
# 都落到 <vsRoot>\VC\Tools\MSVC,所以藏的是 VC 目录而不是 VS 根目录:
107+
# 根目录在 runner 上被进程占着改不了名,低一层的 VC 可以。
108+
$vswhere = "C:\Program Files (x86)\Microsoft Visual Studio\Installer\vswhere.exe"
109+
if (Test-Path $vswhere) { Rename-Item $vswhere "vswhere.exe.masked" }
110+
111+
Resolve-Path "C:\Program Files*\Microsoft Visual Studio\*\*\VC" `
112+
-ErrorAction SilentlyContinue | ForEach-Object {
113+
$p = $_.Path
114+
Write-Host "masking $p"
115+
try { Rename-Item -LiteralPath $p -NewName "VC.masked" -ErrorAction Stop }
116+
catch { Write-Host " rename failed: $($_.Exception.Message)" }
117+
}
118+
119+
foreach ($v in @('VSINSTALLDIR','VCINSTALLDIR','VCToolsInstallDir',
120+
'VS170COMNTOOLS','VS160COMNTOOLS','VS150COMNTOOLS')) {
121+
"$v=" | Out-File -Append -FilePath $env:GITHUB_ENV -Encoding utf8
122+
}
123+
124+
# 就地检查遮蔽的后置条件。漏遮的后果是这一档静悄悄变成第二个
125+
# windows-11 baseline —— 绿灯,但什么都没验到。
126+
$left = Get-ChildItem "C:\Program Files*\Microsoft Visual Studio\*\*\VC\Tools\MSVC" `
127+
-Directory -ErrorAction SilentlyContinue
128+
if ($left) {
129+
Write-Host "FAIL: VC tools still present after masking:"
130+
$left | ForEach-Object { Write-Host " $($_.FullName)" }
131+
exit 1
132+
}
133+
Write-Host "Visual Studio masked: no VC\Tools\MSVC remains."
134+
48135
# 官方一键安装脚本自带镜像回退。手动 curl GitHub release 包会被
49136
# release CDN 的间歇性 504 打断。
50-
- name: Install xlings ${{ env.XLINGS_VERSION }}
137+
- name: Install xlings ${{ env.XLINGS_VERSION }} (Linux/macOS)
138+
if: runner.os != 'Windows'
51139
run: |
52140
set -eu
53141
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh \
54142
| bash -s "v${XLINGS_VERSION}"
55143
echo "$HOME/.xlings/subos/current/bin" >> "$GITHUB_PATH"
56144
57-
# 按 .xlings.json 安装 mcpp。mcpp 自带工具链沙箱,无需另装 gcc。
58-
- name: Install mcpp
145+
- name: Install xlings (Windows)
146+
if: runner.os == 'Windows'
147+
shell: pwsh
148+
run: |
149+
irm https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.ps1 | iex
150+
"$env:USERPROFILE\.xlings\subos\current\bin" | Out-File -Append -FilePath $env:GITHUB_PATH -Encoding utf8
151+
152+
# 按 .xlings.json 安装 mcpp + d2x。mcpp 自带工具链沙箱,无需另装 gcc。
153+
- name: Install pinned toolchain (.xlings.json)
59154
run: |
60155
set -eu
61156
xlings update
62157
xlings install -y
158+
mcpp --version
159+
d2x --version
160+
161+
- name: Report runner OS
162+
if: runner.os == 'Windows'
163+
shell: pwsh
164+
run: |
165+
$os = Get-CimInstance Win32_OperatingSystem
166+
Write-Host "runner=${{ matrix.os }} caption=$($os.Caption) build=$($os.Version)"
63167
64168
- name: Build d2x Provider
65169
run: mcpp build -p d2x/buildtools
66170

67-
- name: Validate exercises and solutions (zh + en)
68-
run: bash d2x/buildtools/tests/e2e.sh all
171+
# mcpp 把产物按 target triple 分目录,所以目录名就是「实际用了哪条
172+
# 工具链」最直接的证据。遮蔽生效时它必须是 gnu 而不是 msvc。
173+
- name: Assert MinGW fallback took effect (no MSVC STL)
174+
if: matrix.mask_msvc
175+
run: |
176+
set -eu
177+
ls d2x/buildtools/target/
178+
if [ ! -d d2x/buildtools/target/x86_64-windows-gnu ]; then
179+
echo "FAIL: 期望回落到 x86_64-windows-gnu,实际产物 target 目录如上"
180+
exit 1
181+
fi
182+
echo "OK: 无 MSVC STL 时回落到 winlibs MinGW (x86_64-windows-gnu)"
183+
184+
# 第一层:`mcpp test` —— pristine 全部不通过 + 覆盖答案后全部通过
185+
- name: mcpp test (pristine fails, solutions all pass)
186+
run: bash d2x/buildtools/tests/e2e.sh ${{ matrix.langs }}
187+
188+
# 第二层:`d2x checker` —— 答案就位后 checker 必须自己走完全程并退 0
189+
- name: d2x checker (solutions drive it to completion)
190+
run: bash d2x/buildtools/tests/checker-e2e.sh zh
191+
192+
- name: d2x checker — en course
193+
if: matrix.langs == 'all'
194+
run: bash d2x/buildtools/tests/checker-e2e.sh en
195+
196+
# 纯文件名核对,与工具链无关,跑一个平台就够。
197+
solutions-parity:
198+
name: exercises ↔ solutions filename parity
199+
runs-on: ubuntu-latest
200+
steps:
201+
- uses: actions/checkout@v4
69202

70203
- name: Verify exercises ↔ solutions filename parity
71204
run: |
72205
set -eu
73206
# en/ 镜像跳过 —— 参考答案与语言无关,两边共用同一份
74207
missing=0
75-
for f in $(find intro/tests cpp*/tests -name '*.cpp'); do
76-
std="${f%%/*}"
77-
rel="${f#*/tests/}"
78-
if [ ! -f "solutions/$std/$rel" ]; then
79-
echo "::warning::missing solutions/$std/$rel (paired with $f)"
208+
for f in $(find src/intro/tests src/cpp*/tests -name '*.cpp'); do
209+
rel="${f#src/}"
210+
std="${rel%%/*}"
211+
rest="${rel#*/tests/}"
212+
if [ ! -f "solutions/$std/$rest" ]; then
213+
echo "::warning::missing solutions/$std/$rest (paired with $f)"
80214
missing=$((missing+1))
81215
fi
82216
done

.xlings.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
{
22
"workspace": {
3-
"d2x": "2026.08.02.1",
3+
"d2x": "2026.08.02.2",
44
"mdbook": "0.4.43",
55
"code": "",
66
"mcpp": {
7-
"linux": "2026.8.1.1",
8-
"macosx": "2026.8.1.1",
9-
"windows": "2026.8.1.1"
7+
"linux": "2026.8.2.1",
8+
"macosx": "2026.8.2.1",
9+
"windows": "2026.8.2.1"
1010
}
1111
}
1212
}

README.md

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343

4444
### Interactive Code Practice (Local)
4545

46-
**Step 1 - Install the d2x tool**
46+
**Step 1 - Install the [d2x](https://github.com/d2learn/d2x) and [mcpp](https://github.com/mcpp-community/mcpp) tools**
4747

4848
<details>
4949
<summary>click to view xlings installation command</summary>
@@ -69,34 +69,48 @@ irm https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_i
6969
</details>
7070

7171
```bash
72-
xlings install d2x -y # exercise framework CLI
72+
xlings install d2x mcpp -y # d2x: exercise framework CLI | mcpp: C++ build & test tool
7373
```
7474

75-
**Step 2 - Get the course (choose one)**
75+
**Step 2 - Get the course, then configure and verify the environment**
7676

7777
```bash
78-
# Option A - one command: download the course, toolchain auto-configured
79-
d2x install d2mcpp
78+
d2x install d2mcpp # download the course, toolchain auto-configured
8079
cd d2mcpp
80+
mcpp test # verify the environment: every exercise compiles and runs
8181
```
8282

83+
> The exercises **are** the tests. On a fresh checkout `mcpp test` reports them all as
84+
> failing — that is the expected starting point, and it already proves your toolchain
85+
> works. Drop the reference answers from `solutions/` in and the very same command goes
86+
> all green.
87+
88+
<details>
89+
<summary>optional - start from the git source instead</summary>
90+
91+
---
92+
8393
```bash
84-
# Option B - git clone the source
8594
git clone https://github.com/mcpp-community/d2mcpp.git # or your fork
8695
cd d2mcpp
8796
xlings install -y # toolchain pinned by .xlings.json
97+
mcpp test # same environment check
8898
```
8999

90100
> Tip: fork this repo and clone your fork — `git commit / push` keeps your practice progress in your own repository.
91101
102+
---
103+
104+
</details>
105+
92106
**Step 3 - Start practicing**
93107

94108
```bash
95109
d2x checker # practice loop: edit -> save -> auto-check -> advance
96110
d2x status # progress overview
97111
```
98112

99-
> Exercises are real mcpp tests — `mcpp test -p src/cpp11` works too (no d2x involved).
113+
> Want to run a single chapter without d2x? `mcpp test -p src/cpp11` works too.
100114
101115
**👉 [more details...](https://mcpp-community.github.io/d2mcpp/base/chapter_1.html)**
102116

README.zh.hant.md

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343

4444
### 建立本地練習環境
4545

46-
**第一步 - 安裝 d2x 工具**
46+
**第一步 - 安裝 [d2x](https://github.com/d2learn/d2x)[mcpp](https://github.com/mcpp-community/mcpp) 工具**
4747

4848
<details>
4949
<summary>點選查看xlings安裝指令</summary>
@@ -69,34 +69,46 @@ irm https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_i
6969
</details>
7070

7171
```bash
72-
xlings install d2x -y # 練習框架 CLI
72+
xlings install d2x mcpp -y # d2x: 練習框架 CLI | mcpp: C++ 建置與測試工具
7373
```
7474

75-
**第二步 - 獲取課程(二選一)**
75+
**第二步 - 獲取課程, 並配置和驗證環境**
7676

7777
```bash
78-
# 方式 A - 一鍵安裝: 下載課程,環境自動配置
79-
d2x install d2mcpp
78+
d2x install d2mcpp # 下載課程,環境自動配置
8079
cd d2mcpp
80+
mcpp test # 驗證環境: 每道練習都能編譯並執行
8181
```
8282

83+
> 練習**就是**測試。剛拿到課程時 `mcpp test` 會報告全部未通過 —— 這正是練習的起點,
84+
> 同時也說明工具鏈已經跑通了。把 `solutions/` 裡的參考答案覆蓋進去,同一條指令就會全綠。
85+
86+
<details>
87+
<summary>可選 - 改用 clone 專案原始碼的方式</summary>
88+
89+
---
90+
8391
```bash
84-
# 方式 B - git clone 原始碼
8592
git clone https://github.com/mcpp-community/d2mcpp.git # 或你 fork 後的倉庫
8693
cd d2mcpp
8794
xlings install -y # 按 .xlings.json 安裝固定版本工具鏈
95+
mcpp test # 同樣的環境驗證
8896
```
8997

9098
> 建議: 先 fork 本倉庫再 clone 自己的 fork —— 通過 `git commit / push` 把練習進度保存到自己的倉庫裡。
9199
100+
---
101+
102+
</details>
103+
92104
**第三步 - 開始練習**
93105

94106
```bash
95107
d2x checker # 練習循環: 編輯 -> 保存 -> 自動偵測 -> 推進
96108
d2x status # 進度總覽
97109
```
98110

99-
> 練習就是真實的 mcpp 測試 —— 不經過 d2x,直接 `mcpp test -p src/cpp11` 同樣可用。
111+
> 想單獨跑某一章而不經過 d2x? 直接 `mcpp test -p src/cpp11` 同樣可用。
100112
101113
**👉 [更多細節...](https://mcpp-community.github.io/d2mcpp/base/chapter_1.html)**
102114

0 commit comments

Comments
 (0)