|
2 | 2 |
|
3 | 3 | Date: 2026-05-17 |
4 | 4 |
|
5 | | -## 1. 目标 |
| 5 | +## 目标 |
6 | 6 |
|
7 | | -在 Windows x86_64 上用 xlings LLVM(clang++ / clang-cl)支持 mcpp 构建 C++23 模块项目,达到与 Linux/macOS 同等的核心可用水平: |
8 | | -- `mcpp build` / `mcpp run` / `mcpp test` |
9 | | -- `import std` 支持 |
10 | | -- 多模块项目 + 增量编译 |
11 | | -- 自举(mcpp 编译自己) |
| 7 | +mcpp 在 Windows x86_64 上通过 xmake bootstrap 达到可用水平,产出 mcpp.exe 作为后续自举依赖。 |
12 | 8 |
|
13 | | -## 2. 现状分析 |
| 9 | +## 平台特征 |
14 | 10 |
|
15 | | -### 2.1 xlings LLVM Windows 包 |
| 11 | +### Windows LLVM 包(xlings-res 20.1.7) |
16 | 12 |
|
17 | | -**已有**(xlings-res/llvm 20.1.7): |
18 | 13 | ``` |
19 | | -bin/clang++.exe, clang.exe, clang-cl.exe ← 编译器 |
20 | | -bin/lld-link.exe ← MSVC 兼容链接器 |
21 | | -bin/llvm-ar.exe, llvm-lib.exe ← 归档工具 |
22 | | -bin/llvm-rc.exe, llvm-mt.exe ← 资源编译器 |
23 | | -lib/clang/20/lib/windows/ ← compiler-rt |
| 14 | +bin/clang.exe, clang++.exe, clang-cl.exe, lld-link.exe |
| 15 | +bin/llvm-ar.exe, llvm-lib.exe, llvm-rc.exe |
| 16 | +lib/clang/20/lib/windows/clang_rt.*.lib |
| 17 | +没有 libc++(没有 include/c++/v1,没有 std.cppm) |
| 18 | +没有 clang-scan-deps.exe |
24 | 19 | ``` |
25 | 20 |
|
26 | | -**没有**: |
27 | | -- ❌ libc++ 头文件和库(`include/c++/v1/` 不存在) |
28 | | -- ❌ `std.cppm` / `std.compat.cppm` 模块源码 |
29 | | -- ❌ `clang-scan-deps.exe`(P1689 模块扫描器) |
| 21 | +Windows LLVM 包不含 libc++。Windows 上 clang 搭配 MSVC STL。 |
30 | 22 |
|
31 | | -### 2.2 含义 |
| 23 | +### Bootstrap 策略 |
32 | 24 |
|
33 | | -Windows LLVM 包设计为 **MSVC 兼容模式**: |
34 | | -- 使用 MSVC 的 STL(`<iostream>` 等来自 Visual Studio) |
35 | | -- 使用 MSVC 的 C runtime(ucrt) |
36 | | -- 通过 `clang-cl.exe` 驱动(接受 `/std:c++latest`、`/EHsc` 等 MSVC 风格参数) |
37 | | -- 链接用 `lld-link.exe`(MSVC `link.exe` 兼容) |
| 25 | +用 xmake + MSVC(和 xlings 自身做法一致): |
| 26 | +- GitHub Actions windows-latest 预装 Visual Studio |
| 27 | +- xmake 对 MSVC C++23 modules 支持成熟 |
| 28 | +- 不需要额外安装 LLVM(MSVC 即可) |
38 | 29 |
|
39 | | -这是 **Windows 上的行业标准做法**——即使用 Clang,也通常走 MSVC ABI。 |
| 30 | +## 代码适配清单 |
40 | 31 |
|
41 | | -### 2.3 C++23 Modules 在 Windows MSVC STL 上的状态 |
| 32 | +### 必须修改 |
42 | 33 |
|
43 | | -MSVC STL 从 VS 2022 17.5 起支持 `import std;`: |
44 | | -- 需要 `/std:c++latest` 或 `/std:c++23` |
45 | | -- 模块文件格式:`.ifc`(不是 `.pcm` 或 `.gcm`) |
46 | | -- 但 **clang-cl 目前不支持 MSVC 的 `.ifc` 格式** |
47 | | - |
48 | | -**clang++ (GNU 驱动) on Windows**: |
49 | | -- 可以用 `-stdlib=libc++` 但需要自带 libc++ |
50 | | -- 当前 xlings Windows LLVM 包没有 libc++ |
51 | | -- 如果补充 libc++,可以用与 Linux/macOS 相同的 `.pcm` 模块模型 |
52 | | - |
53 | | -### 2.4 mcpp 代码现状 |
54 | | - |
55 | | -| 组件 | Windows 状态 | 需要改动 | |
56 | | -|------|-------------|---------| |
57 | | -| 平台检测(`_WIN32`) | ✅ 已有 | 无 | |
58 | | -| CompilerId::MSVC | ✅ enum 定义 | 需要实现 | |
59 | | -| `probe.cppm` | ❌ 用 Unix shell | 需要 Windows 移植 | |
60 | | -| `flags.cppm` | ❌ 全是 Unix flags | 需要 MSVC flags | |
61 | | -| `ninja_backend.cppm` | ❌ shell 命令 | 需要 cmd/PowerShell 适配 | |
62 | | -| `config.cppm` | ❌ `/proc/self/exe` | 需要 `GetModuleFileName` | |
63 | | -| `install.sh` | ⚠️ bash only | Windows 需要 PowerShell | |
64 | | - |
65 | | -## 3. 技术方案 |
66 | | - |
67 | | -### 3.1 两条路径对比 |
68 | | - |
69 | | -| 方案 | 路径 | 优点 | 缺点 | |
70 | | -|------|------|------|------| |
71 | | -| **A: clang++ + libc++** | GNU 驱动 + 自带 libc++ | 与 Linux/macOS 统一,`.pcm` 格式 | 需要补充 libc++ 到 LLVM 包 | |
72 | | -| **B: clang-cl + MSVC STL** | MSVC 兼容驱动 | Windows 原生,ABI 兼容 | 全新编译模型(`/std:c++latest`),`.ifc` 格式不兼容 | |
73 | | - |
74 | | -**推荐方案 A**:用 `clang++.exe`(GNU 驱动)+ 补充 libc++。理由: |
75 | | -1. 与 Linux/macOS 共享同一套模块编译逻辑(`.pcm`、`-fmodule-file=`) |
76 | | -2. 不依赖 Visual Studio 安装 |
77 | | -3. mcpp 核心代码改动最小(只需要处理路径分隔符和 shell 命令差异) |
78 | | - |
79 | | -### 3.2 前提条件 |
80 | | - |
81 | | -1. **xlings LLVM Windows 包需要补充 libc++**: |
82 | | - - `include/c++/v1/` — libc++ 头文件 |
83 | | - - `share/libc++/v1/std.cppm` + `std.compat.cppm` — 模块源 |
84 | | - - `lib/libc++.lib` (或 `.a`) — 静态库 |
85 | | - - `bin/clang-scan-deps.exe` — P1689 扫描器 |
86 | | - |
87 | | -2. **或者**:在 LLVM Windows 包中生成 `clang++.cfg` 配置 libc++ 路径 |
88 | | - |
89 | | -### 3.3 mcpp 代码改动清单 |
90 | | - |
91 | | -#### Phase 1: 核心编译(让 `mcpp build` 在 Windows 上工作) |
92 | | - |
93 | | -| 文件 | 改动 | 优先级 | |
94 | | -|------|------|--------| |
95 | | -| `probe.cppm` | `probe_compiler_binary`: Windows 用 `where.exe` 替代 `command -v` | P0 | |
96 | | -| `probe.cppm` | `run_capture`: Windows 用 `_popen`/`_pclose` | P0 | |
97 | | -| `probe.cppm` | `discover_*_dirs`: 添加 `#if defined(_WIN32)` 分支 | P0 | |
98 | | -| `flags.cppm` | Windows 链接 flags:无 `-rpath`(Windows 不支持) | P0 | |
99 | | -| `ninja_backend.cppm` | Shell 命令替换:`mkdir -p` → `cmd /c mkdir`, `cp` → `copy` | P0 | |
100 | | -| `ninja_backend.cppm` | `mcpp_exe_path`: 用 `GetModuleFileNameW` | P0 | |
101 | | -| `config.cppm` | 同上,exe 路径获取 | P0 | |
102 | | -| `clang.cppm` | Windows libc++ 路径发现 | P1 | |
103 | | -| `cli.cppm` | 默认工具链 `llvm@20.1.7` for Windows | P1 | |
104 | | - |
105 | | -#### Phase 2: 可执行文件扩展名 |
106 | | - |
107 | | -| 位置 | 改动 | |
108 | | -|------|------| |
109 | | -| `ninja_backend.cppm` | 输出 `bin/mcpp.exe` 而非 `bin/mcpp` | |
110 | | -| `manifest.cppm` | `kind = "bin"` 产出 `.exe` | |
111 | | -| `cli.cppm` | `mcpp run` 查找 `.exe` | |
112 | | - |
113 | | -#### Phase 3: CI + Release |
114 | | - |
115 | | -| 改动 | 说明 | |
116 | | -|------|------| |
117 | | -| `.github/workflows/ci-windows.yml` | Windows CI(`windows-latest` runner) | |
118 | | -| `.github/workflows/bootstrap-windows.yml` | xmake 首次编译 | |
119 | | -| `release.yml` | 添加 Windows job | |
120 | | - |
121 | | -### 3.4 Ninja shell 命令移植 |
122 | | - |
123 | | -这是最复杂的部分。当前 build.ninja 中的 shell 命令: |
124 | | - |
125 | | -| 当前 (Unix) | Windows 等价 | 说明 | |
126 | | -|-------------|-------------|------| |
127 | | -| `mkdir -p $(dirname $out) && cp -f $in $out` | `cmd /c if not exist "$$(dir $out)" mkdir "$$(dir $out)" && copy /y $in $out` | 复制 BMI | |
128 | | -| `if [ -n "$bmi_out" ] && ...` | `cmd /c ...` 或 PowerShell | BMI restat 逻辑 | |
129 | | -| `cd ... && $cxx ...` | `cmd /c cd /d ... && $cxx ...` | 编译命令 | |
130 | | -| `env LD_LIBRARY_PATH=...` | 不需要(Windows 用 PATH) | 运行时路径 | |
131 | | - |
132 | | -**建议**:在 `ninja_backend.cppm` 中按平台生成不同的 rule 命令,用 `#if defined(_WIN32)` 条件编译。 |
133 | | - |
134 | | -### 3.5 Windows 链接策略 |
135 | | - |
136 | | -```cpp |
137 | | -#if defined(_WIN32) |
138 | | - // Windows: clang++ GNU driver links against libc++ automatically |
139 | | - // No -rpath (not a thing on Windows) |
140 | | - // No sysroot (not needed for MSVC ucrt) |
141 | | - // Static libc++: -static-libc++ (or statically link libc++.a) |
142 | | - f.ld = std::format("{}{}", full_static, b_flag); |
143 | | -#endif |
144 | | -``` |
145 | | - |
146 | | -Windows 产出的 `.exe` 运行时依赖: |
147 | | -- `ucrt` (Universal C Runtime) — Windows 10+ 自带 |
148 | | -- `libc++.dll` 或静态链接 `libc++.a` |
149 | | -- `vcruntime140.dll` — 如果用 MSVC 兼容模式 |
150 | | - |
151 | | -## 4. 实施计划 |
152 | | - |
153 | | -### Step 1: 验证 xlings LLVM Windows 能否编译 C++23 模块 |
154 | | - |
155 | | -创建 `ci-windows.yml` 在 GitHub Actions `windows-latest` runner 上: |
156 | | -1. 安装 xlings |
157 | | -2. 安装 LLVM |
158 | | -3. 手动用 clang++ 编译 `import std`(如果 libc++ 可用) |
159 | | -4. 如果 libc++ 不可用,验证 clang-cl + MSVC STL |
160 | | - |
161 | | -### Step 2: xmake bootstrap |
162 | | - |
163 | | -用 xmake 在 Windows 上编译 mcpp(参考 mcpp-dev 的 xmake.lua)。 |
164 | | - |
165 | | -### Step 3: mcpp 代码适配 |
166 | | - |
167 | | -基于 CI 验证结果,逐步适配 probe/flags/ninja_backend。 |
168 | | - |
169 | | -### Step 4: Self-host + Release |
170 | | - |
171 | | -mcpp 自举 → 打包 → release。 |
172 | | - |
173 | | -## 5. 风险 |
174 | | - |
175 | | -| 风险 | 影响 | 缓解 | |
| 34 | +| 文件 | 问题 | 方案 | |
176 | 35 | |------|------|------| |
177 | | -| xlings Windows LLVM 包无 libc++ | 无法用 `import std` | 需要上游补充或用 MSVC STL | |
178 | | -| ninja shell 命令移植复杂 | build.ninja 在 Windows 上不工作 | 可用 ninja 的 `msvc_deps_prefix` 特性 | |
179 | | -| `clang-scan-deps.exe` 缺失 | P1689 扫描不可用 | GCC 模式的 `-fdeps-format` 也可用 | |
180 | | -| Windows path separator (`\` vs `/`) | 路径拼接问题 | `std::filesystem` 已处理大部分 | |
181 | | - |
182 | | -## 6. 依赖关系 |
183 | | - |
184 | | -``` |
185 | | -xlings LLVM Windows 包 (libc++ 补充) |
186 | | - ↓ |
187 | | -CI 验证 (clang++ + import std) |
188 | | - ↓ |
189 | | -xmake bootstrap (产出 mcpp.exe) |
190 | | - ↓ |
191 | | -mcpp 代码适配 (probe/flags/ninja) |
192 | | - ↓ |
193 | | -self-host (mcpp.exe 编译 mcpp.exe) |
194 | | - ↓ |
195 | | -release |
196 | | -``` |
| 36 | +| ninja_backend.cppm | POSIX shell 命令 | #if _WIN32 cmd.exe 语法 | |
| 37 | +| ninja_backend.cppm | mcpp_exe_path() 缺 Windows | GetModuleFileNameA() | |
| 38 | +| config.cppm | MCPP_HOME 路径发现缺 Windows | 同上 | |
| 39 | +| probe.cppm | command -v Unix only | where.exe | |
| 40 | +| probe.cppm | LD_LIBRARY_PATH | Windows 用 PATH | |
| 41 | +| flags.cppm | 链接 flags 缺 Windows 分支 | 无 sysroot/rpath | |
| 42 | +| xlings.cppm | popen | _popen | |
| 43 | + |
| 44 | +## 执行顺序 |
| 45 | + |
| 46 | +1. 创建 ci-windows.yml 用 xmake 构建,看编译错误 |
| 47 | +2. 根据 CI 错误逐步修代码 |
| 48 | +3. 产出 mcpp.exe bootstrap binary |
| 49 | +4. 上传到 xlings-res |
0 commit comments