11name : ci-windows
22
3- # Windows validation CI for mcpp.
4- # Step 1: Verify xlings LLVM toolchain capabilities on Windows.
5- # Step 2: xmake bootstrap to produce first mcpp.exe.
6- # Step 3: Self-host — use the bootstrapped mcpp.exe to build itself (LLVM + MSVC STL).
7- # Step 4: Package the self-hosted binary into a distributable zip.
3+ # Windows CI for mcpp.
4+ # Step 1: Bootstrap mcpp via xlings (same as Linux/macOS).
5+ # Step 2: Self-host — use mcpp to build itself (LLVM + MSVC STL import std).
6+ # Step 3: Package the self-hosted binary into a distributable zip.
87
98on :
109 push :
@@ -23,8 +22,8 @@ concurrency:
2322 cancel-in-progress : true
2423
2524jobs :
26- windows-llvm-validation :
27- name : Windows x64 — LLVM toolchain validation
25+ windows-build :
26+ name : Windows x64 — build + self-host
2827 runs-on : windows-latest
2928 timeout-minutes : 45
3029 steps :
@@ -50,231 +49,43 @@ jobs:
5049 cd "${WORK}"
5150 unzip -q "${zipfile}"
5251 XLINGS_DIR="${WORK}/xlings-${XLINGS_VERSION}-windows-x86_64"
53- echo "xlings dir: $XLINGS_DIR"
54- ls "$XLINGS_DIR/bin/"
5552 "$XLINGS_DIR/subos/default/bin/xlings.exe" self install
5653 echo "$USERPROFILE/.xlings/subos/default/bin" >> "$GITHUB_PATH"
5754 echo "$USERPROFILE/.xlings/bin" >> "$GITHUB_PATH"
5855
59- - name : Verify xlings
56+ - name : Bootstrap mcpp via xlings
6057 shell : bash
6158 run : |
62- xlings.exe --version || xlings --version || echo "xlings not found in PATH"
63-
64- - name : Install LLVM via xlings
65- shell : bash
66- run : |
67- xlings.exe install llvm -y || xlings.exe install llvm@20.1.7 -y || {
68- echo "::warning::xlings install llvm failed"
69- exit 1
70- }
71- # Find LLVM root
72- LLVM_ROOT=$(find "$USERPROFILE/.xlings" -path "*/xpkgs/xim-x-llvm/*/bin/clang.exe" 2>/dev/null | head -1)
73- if [ -n "$LLVM_ROOT" ]; then
74- LLVM_ROOT=$(dirname "$(dirname "$LLVM_ROOT")")
75- fi
76- echo "LLVM_ROOT=$LLVM_ROOT"
77- echo "LLVM_ROOT=$LLVM_ROOT" >> "$GITHUB_ENV"
78-
79- - name : Inspect LLVM package structure
80- shell : bash
81- run : |
82- echo "=== bin/ ==="
83- ls "$LLVM_ROOT/bin/" | grep -iE "clang|lld|llvm-ar|scan" | head -20
84- echo "=== lib/ ==="
85- ls "$LLVM_ROOT/lib/" 2>/dev/null | head -10
86- echo "=== include/c++/ ==="
87- ls "$LLVM_ROOT/include/c++/" 2>/dev/null || echo "(no libc++ headers)"
88- echo "=== share/libc++/ ==="
89- find "$LLVM_ROOT" -name "std.cppm" 2>/dev/null || echo "(no std.cppm)"
90- echo "=== clang++.cfg ==="
91- cat "$LLVM_ROOT/bin/clang++.cfg" 2>/dev/null || echo "(no cfg)"
92- echo "=== clang version ==="
93- "$LLVM_ROOT/bin/clang++.exe" --version 2>/dev/null || "$LLVM_ROOT/bin/clang++" --version 2>/dev/null
94- echo "=== Target triple ==="
95- "$LLVM_ROOT/bin/clang++.exe" -dumpmachine 2>/dev/null || "$LLVM_ROOT/bin/clang++" -dumpmachine 2>/dev/null
96-
97- - name : Test — non-module C++ compilation (clang++)
98- shell : bash
99- run : |
100- WORK=$(mktemp -d)
101- cd "$WORK"
102- CXX="$LLVM_ROOT/bin/clang++.exe"
103- test -x "$CXX" || CXX="$LLVM_ROOT/bin/clang++"
104-
105- cat > main.cpp << 'EOF'
106- #include <iostream>
107- int main() {
108- std::cout << "Hello from clang++ on Windows!" << std::endl;
109- return 0;
110- }
111- EOF
112-
113- echo "=== Compile ==="
114- "$CXX" -std=c++23 -o hello.exe main.cpp 2>&1 || {
115- echo "::warning::clang++ compilation failed, trying with MSVC headers"
116- # clang++ on Windows may need MSVC include paths
117- "$CXX" -std=c++23 --target=x86_64-pc-windows-msvc -o hello.exe main.cpp 2>&1 || true
118- }
119-
120- if [ -f hello.exe ]; then
121- echo "=== Run ==="
122- ./hello.exe
123- else
124- echo "::warning::Compilation did not produce hello.exe"
125- fi
126-
127- - name : Test — clang-cl compilation
128- shell : bash
129- run : |
130- WORK=$(mktemp -d)
131- cd "$WORK"
132- CLANGCL="$LLVM_ROOT/bin/clang-cl.exe"
133- test -x "$CLANGCL" || CLANGCL="$LLVM_ROOT/bin/clang-cl"
134-
135- cat > main.cpp << 'EOF'
136- #include <iostream>
137- int main() {
138- std::cout << "Hello from clang-cl on Windows!" << std::endl;
139- return 0;
140- }
141- EOF
142-
143- echo "=== Compile with clang-cl ==="
144- "$CLANGCL" /std:c++latest /EHsc main.cpp /Fe:hello.exe 2>&1 || {
145- echo "::warning::clang-cl compilation failed"
146- echo "clang-cl may need Visual Studio installation for MSVC headers/libs"
147- }
148-
149- if [ -f hello.exe ]; then
150- echo "=== Run ==="
151- ./hello.exe
152- fi
153-
154- - name : Check libc++ availability for import std
155- shell : bash
156- run : |
157- echo "=== Checking for libc++ in LLVM package ==="
158- find "$LLVM_ROOT" -name "*.cppm" 2>/dev/null | head -5 || echo "No .cppm files found"
159- find "$LLVM_ROOT" -path "*/c++/v1" -type d 2>/dev/null | head -3 || echo "No libc++ include dir"
160- find "$LLVM_ROOT" -name "libc++*" 2>/dev/null | head -5 || echo "No libc++ library files"
161-
162- echo
163- echo "=== Checking MSVC STL for import std ==="
164- # Visual Studio on GitHub runners includes MSVC STL with module support
165- VSDIR="/c/Program Files/Microsoft Visual Studio/2022/Enterprise"
166- if [ -d "$VSDIR" ]; then
167- echo "Visual Studio found at: $VSDIR"
168- find "$VSDIR" -name "std.ixx" 2>/dev/null | head -3 || echo "No std.ixx found"
169- find "$VSDIR" -path "*/modules" -name "*.ixx" 2>/dev/null | head -5 || echo "No .ixx module files"
170- else
171- echo "Visual Studio not found at expected path"
172- ls "/c/Program Files/Microsoft Visual Studio/" 2>/dev/null || true
173- fi
174-
175- - name : Summary
176- shell : bash
177- run : |
178- echo "=== Windows LLVM Validation Summary ==="
179- echo "LLVM Root: $LLVM_ROOT"
180- echo "Clang version: $("$LLVM_ROOT/bin/clang++.exe" --version 2>/dev/null | head -1 || echo 'N/A')"
181- echo "Target: $("$LLVM_ROOT/bin/clang++.exe" -dumpmachine 2>/dev/null || echo 'N/A')"
182- echo
183- echo "Has libc++: $([ -d "$LLVM_ROOT/include/c++/v1" ] && echo YES || echo NO)"
184- echo "Has std.cppm: $(find "$LLVM_ROOT" -name 'std.cppm' 2>/dev/null | head -1 | grep -q . && echo YES || echo NO)"
185- echo "Has clang-scan-deps: $([ -f "$LLVM_ROOT/bin/clang-scan-deps.exe" ] && echo YES || echo NO)"
186- echo "Has clang-cl: $([ -f "$LLVM_ROOT/bin/clang-cl.exe" ] && echo YES || echo NO)"
187- echo "Has lld-link: $([ -f "$LLVM_ROOT/bin/lld-link.exe" ] && echo YES || echo NO)"
188-
189- - name : Install xmake via xlings
190- shell : bash
191- run : |
192- xlings.exe install xmake -y || xlings install xmake -y
193- xmake.exe --version || xmake --version
194-
195- - name : Bootstrap mcpp with xmake (MSVC)
196- id : bootstrap
197- shell : pwsh
198- run : |
199- # Generate xmake.lua for bootstrap
200- @"
201- add_rules("mode.release")
202- set_languages("c++23")
203- package("cmdline")
204- set_homepage("https://github.com/mcpplibs/cmdline")
205- add_urls("https://github.com/mcpplibs/cmdline/archive/refs/tags/`$(version).tar.gz")
206- add_versions("0.0.1", "3fb2f5495c1a144485b3cbb2e43e27059151633460f702af0f3851cbff387ef0")
207- on_install(function (package)
208- import("package.tools.xmake").install(package)
209- end)
210- package_end()
211- add_requires("cmdline 0.0.1")
212- target("mcpp")
213- set_kind("binary")
214- add_files("src/main.cpp")
215- add_files("src/**.cppm")
216- add_packages("cmdline")
217- add_includedirs("src/libs/json")
218- set_policy("build.c++.modules", true)
219- "@ | Out-File -Encoding utf8 xmake.lua
220-
221- xmake f -p windows -m release -y
222- xmake build -y mcpp
223-
224- $mcpp = Get-ChildItem -Recurse build -Filter mcpp.exe -ErrorAction SilentlyContinue | Select-Object -First 1
225- if ($mcpp) {
226- Write-Host ":: mcpp.exe built at: $($mcpp.FullName)"
227- & $mcpp.FullName --version
228- # Export for subsequent steps
229- "MCPP_BOOTSTRAP=$($mcpp.FullName)" | Out-File -Append $env:GITHUB_ENV
230- } else {
231- Write-Host ":: Build produced files:"
232- Get-ChildItem -Recurse build -Filter *.exe | ForEach-Object { Write-Host " $($_.FullName)" }
233- exit 1
234- }
59+ xlings.exe --version
60+ xlings.exe install mcpp -y
61+ MCPP="$USERPROFILE/.xlings/subos/default/bin/mcpp.exe"
62+ test -f "$MCPP" || MCPP="$USERPROFILE/.xlings/subos/default/bin/mcpp"
63+ test -f "$MCPP"
64+ "$MCPP" --version
65+ echo "MCPP=$MCPP" >> "$GITHUB_ENV"
66+ echo "XLINGS_BIN=$USERPROFILE/.xlings/subos/default/bin/xlings.exe" >> "$GITHUB_ENV"
23567
23668 - name : Self-host — mcpp builds itself
23769 shell : bash
23870 run : |
239- echo "=== Self-host: using bootstrapped mcpp.exe to build mcpp ==="
240- # Save bootstrap binary before cleaning xmake artifacts
241- mkdir -p /tmp/mcpp-bootstrap
242- cp "$MCPP_BOOTSTRAP" /tmp/mcpp-bootstrap/mcpp.exe
243- MCPP_EXE="/tmp/mcpp-bootstrap/mcpp.exe"
244-
245- # Clean xmake artifacts so mcpp starts fresh
246- rm -rf build xmake.lua .xmake
71+ echo "=== Self-host: mcpp builds mcpp ==="
72+ "$MCPP" --version
24773
248- echo "Bootstrap binary: $MCPP_EXE"
249- "$MCPP_EXE" --version
250-
251- # mcpp build uses its own build system; mcpp.toml now has
252- # windows = "llvm@20.1.7" so it will use the xlings LLVM.
253- # Use Windows-native path for MCPP_VENDORED_XLINGS
254- XLINGS_WIN=$(cygpath -w "$USERPROFILE/.xlings/subos/default/bin/xlings.exe")
255- echo "MCPP_VENDORED_XLINGS=$XLINGS_WIN"
74+ # mcpp build uses LLVM on Windows (from mcpp.toml: windows = "llvm@20.1.7")
75+ XLINGS_WIN=$(cygpath -w "$XLINGS_BIN")
25676 export MCPP_VENDORED_XLINGS="$XLINGS_WIN"
25777
258- echo "xlings exists: $(test -f "$USERPROFILE/.xlings/subos/default/bin/xlings.exe" && echo YES || echo NO)"
259-
260- # Debug: test xlings directly
261- "$USERPROFILE/.xlings/subos/default/bin/xlings.exe" --version || echo "xlings direct call failed"
262-
263- # Pre-seed the mcpp sandbox with the already-installed LLVM from
264- # the global xlings. xlings won't re-download if the package dir
265- # exists, but it may create an empty stub. Copy instead of junction
266- # to avoid Windows symlink permission issues on CI runners.
78+ # Pre-seed mcpp sandbox with the already-installed LLVM from xlings
26779 MCPP_XPKGS="$USERPROFILE/.mcpp/registry/data/xpkgs"
26880 XLINGS_XPKGS="$USERPROFILE/.xlings/data/xpkgs"
26981 if [ -d "$XLINGS_XPKGS/xim-x-llvm" ]; then
27082 mkdir -p "$MCPP_XPKGS"
27183 rm -rf "$MCPP_XPKGS/xim-x-llvm"
27284 cp -r "$XLINGS_XPKGS/xim-x-llvm" "$MCPP_XPKGS/xim-x-llvm"
273- echo "Copied LLVM xpkg from global xlings"
274- ls "$MCPP_XPKGS/xim-x-llvm/20.1.7/bin/" | head -5
85+ echo "Pre-seeded LLVM from global xlings"
27586 fi
27687
277- "$MCPP_EXE " build
88+ "$MCPP " build
27889
27990 # Find the self-hosted binary
28091 SELF_MCPP=$(find target -name "mcpp.exe" -path "*/bin/*" | head -1)
@@ -304,11 +115,11 @@ jobs:
304115 mkdir -p "$STAGING/$WRAPPER/bin"
305116 mkdir -p "$STAGING/$WRAPPER/registry/bin"
306117
307- # Binary: use the self-hosted build
118+ # Binary: self-hosted build
308119 echo "Packaging binary: $MCPP_SELF"
309120 cp "$MCPP_SELF" "$STAGING/$WRAPPER/bin/mcpp.exe"
310121
311- # Launcher batch script (equivalent to the shell wrapper on Linux/macOS)
122+ # Launcher batch script
312123 printf '@echo off\r\n"%%~dp0bin\\mcpp.exe" %%*\r\n' > "$STAGING/$WRAPPER/mcpp.bat"
313124
314125 # Metadata
@@ -324,7 +135,7 @@ jobs:
324135 echo "::warning::xlings.exe not found at $XLINGS_EXE"
325136 fi
326137
327- # Create zip (use 7z to avoid backslash path issues from Compress-Archive)
138+ # Create zip
328139 mkdir -p dist
329140 (cd "$STAGING" && 7z a -tzip "$ZIPNAME" "$WRAPPER")
330141 cp "$STAGING/$ZIPNAME" "dist/$ZIPNAME"
0 commit comments