11name : ci-windows
22
33# Windows CI for mcpp — validates LLVM/Clang as the Windows toolchain.
4- # Same flow as Linux (ci.yml) and macOS (ci-macos.yml):
5- # xlings install mcpp → self-host build → unit tests → E2E → smoke
4+ # Uses xmake to bootstrap mcpp from source (until xlings mcpp ships
5+ # Windows-native fixes), then self-hosts, tests, and packages.
66
77on :
88 push :
9- branches : [ feat/windows-support, main ]
9+ branches : [ main ]
1010 pull_request :
1111 branches : [ main ]
1212 workflow_dispatch :
2020 name : build + test (windows x64, self-host)
2121 runs-on : windows-latest
2222 timeout-minutes : 45
23+ env :
24+ MCPP_HOME : C:\Users\runneradmin\.mcpp
2325 steps :
2426 - uses : actions/checkout@v4
2527
@@ -42,111 +44,128 @@ jobs:
4244 "https://github.com/d2learn/xlings/releases/download/v${XLINGS_VERSION}/${zipfile}"
4345 cd "${WORK}"
4446 unzip -q "${zipfile}"
45- XLINGS_DIR="${WORK}/xlings-${XLINGS_VERSION}-windows-x86_64"
46- "$XLINGS_DIR/subos/default/bin/xlings.exe" self install
47+ "$WORK/xlings-${XLINGS_VERSION}-windows-x86_64/subos/default/bin/xlings.exe" self install
4748 echo "$USERPROFILE/.xlings/subos/default/bin" >> "$GITHUB_PATH"
4849 echo "$USERPROFILE/.xlings/bin" >> "$GITHUB_PATH"
4950
50- - name : Bootstrap mcpp via xlings
51+ - name : Install LLVM + xmake via xlings
5152 shell : bash
5253 run : |
5354 xlings.exe --version
54- xlings.exe install mcpp -y
55- MCPP="$USERPROFILE/.xlings/subos/default/bin/mcpp.exe"
56- test -f "$MCPP" || MCPP="$USERPROFILE/.xlings/subos/default/bin/mcpp"
57- test -f "$MCPP"
58- "$MCPP" --version
59- echo "MCPP=$MCPP" >> "$GITHUB_ENV"
60- XLINGS_BIN=$(cygpath -w "$USERPROFILE/.xlings/subos/default/bin/xlings.exe")
61- echo "XLINGS_BIN=$XLINGS_BIN" >> "$GITHUB_ENV"
62-
63- - name : Build mcpp from source (self-host)
55+ xlings.exe install llvm -y || xlings.exe install llvm@20.1.7 -y
56+ xlings.exe install xmake -y
57+
58+ - name : Bootstrap mcpp with xmake (MSVC)
59+ shell : pwsh
60+ run : |
61+ @"
62+ add_rules("mode.release")
63+ set_languages("c++23")
64+ package("cmdline")
65+ set_homepage("https://github.com/mcpplibs/cmdline")
66+ add_urls("https://github.com/mcpplibs/cmdline/archive/refs/tags/`$(version).tar.gz")
67+ add_versions("0.0.1", "3fb2f5495c1a144485b3cbb2e43e27059151633460f702af0f3851cbff387ef0")
68+ on_install(function (package)
69+ import("package.tools.xmake").install(package)
70+ end)
71+ package_end()
72+ add_requires("cmdline 0.0.1")
73+ target("mcpp")
74+ set_kind("binary")
75+ add_files("src/main.cpp")
76+ add_files("src/**.cppm")
77+ add_packages("cmdline")
78+ add_includedirs("src/libs/json")
79+ set_policy("build.c++.modules", true)
80+ "@ | Out-File -Encoding utf8 xmake.lua
81+
82+ xmake f -p windows -m release -y
83+ xmake build -y mcpp
84+
85+ $mcpp = Get-ChildItem -Recurse build -Filter mcpp.exe -ErrorAction SilentlyContinue | Select-Object -First 1
86+ if ($mcpp) {
87+ Write-Host ":: mcpp.exe built at: $($mcpp.FullName)"
88+ & $mcpp.FullName --version
89+ "MCPP_BOOTSTRAP=$($mcpp.FullName)" | Out-File -Append $env:GITHUB_ENV
90+ } else {
91+ exit 1
92+ }
93+
94+ - name : Self-host — mcpp builds itself
6495 shell : bash
6596 run : |
66- export MCPP_VENDORED_XLINGS="$XLINGS_BIN"
67- export MCPP_HOME="$USERPROFILE/.mcpp"
97+ # Save bootstrap binary, clean xmake artifacts
98+ mkdir -p /tmp/mcpp-bootstrap
99+ cp "$MCPP_BOOTSTRAP" /tmp/mcpp-bootstrap/mcpp.exe
100+ MCPP_EXE="/tmp/mcpp-bootstrap/mcpp.exe"
101+ rm -rf build xmake.lua .xmake
68102
69- # Pre-seed mcpp sandbox with xlings LLVM (avoids redundant download)
70- MCPP_XPKGS="$MCPP_HOME/registry/data/xpkgs"
103+ XLINGS_WIN=$(cygpath -w "$USERPROFILE/.xlings/subos/default/bin/xlings.exe")
104+ export MCPP_VENDORED_XLINGS="$XLINGS_WIN"
105+
106+ # Pre-seed LLVM from global xlings
107+ MCPP_XPKGS="$USERPROFILE/.mcpp/registry/data/xpkgs"
71108 XLINGS_XPKGS="$USERPROFILE/.xlings/data/xpkgs"
72109 if [ -d "$XLINGS_XPKGS/xim-x-llvm" ]; then
73110 mkdir -p "$MCPP_XPKGS"
74111 rm -rf "$MCPP_XPKGS/xim-x-llvm"
75112 cp -r "$XLINGS_XPKGS/xim-x-llvm" "$MCPP_XPKGS/xim-x-llvm"
76- echo "Pre-seeded LLVM from global xlings"
77113 fi
78114
79- "$MCPP" build
115+ "$MCPP_EXE" build
116+
117+ SELF_MCPP=$(find target -name "mcpp.exe" -path "*/bin/*" | head -1)
118+ test -n "$SELF_MCPP" || { echo "FAIL: no mcpp.exe"; exit 1; }
119+ SELF_MCPP=$(cd "$(dirname "$SELF_MCPP")" && pwd)/$(basename "$SELF_MCPP")
120+ echo "Self-hosted binary: $SELF_MCPP"
121+ "$SELF_MCPP" --version
122+ echo "MCPP_SELF=$SELF_MCPP" >> "$GITHUB_ENV"
80123
81124 - name : Unit + integration tests via mcpp test
82125 shell : bash
83126 run : |
84- MCPP_FRESH=$(find target -name "mcpp.exe" -path "*/bin/*" | head -1)
85- MCPP_FRESH=$(cd "$(dirname "$MCPP_FRESH")" && pwd)/$(basename "$MCPP_FRESH")
86- echo "Self-hosted binary: $MCPP_FRESH"
87- "$MCPP_FRESH" --version
88- export MCPP_VENDORED_XLINGS="$XLINGS_BIN"
89- # Share the sandbox from self-host build (has LLVM toolchain)
90- export MCPP_HOME="$USERPROFILE/.mcpp"
91- "$MCPP_FRESH" test
127+ export MCPP_VENDORED_XLINGS=$(cygpath -w "$USERPROFILE/.xlings/subos/default/bin/xlings.exe")
128+ "$MCPP_SELF" test
92129
93130 - name : E2E suite
94131 shell : bash
95132 run : |
96- MCPP=$(find target -name "mcpp.exe" -path "*/bin/*" | head -1)
97- MCPP=$(cd "$(dirname "$MCPP")" && pwd)/$(basename "$MCPP")
98- test -f "$MCPP"
99- export MCPP
100- export MCPP_HOME="$USERPROFILE/.mcpp"
101- export MCPP_VENDORED_XLINGS="$XLINGS_BIN"
133+ export MCPP="$MCPP_SELF"
134+ export MCPP_VENDORED_XLINGS=$(cygpath -w "$USERPROFILE/.xlings/subos/default/bin/xlings.exe")
102135 export MCPP_E2E_TOOLCHAIN_MIRROR=GLOBAL
103- "$MCPP " self config --mirror "$MCPP_E2E_TOOLCHAIN_MIRROR" 2>/dev/null || true
104- "$MCPP " toolchain default llvm@20.1.7 2>/dev/null || true
136+ "$MCPP_SELF " self config --mirror GLOBAL 2>/dev/null || true
137+ "$MCPP_SELF " toolchain default llvm@20.1.7 2>/dev/null || true
105138 bash tests/e2e/run_all.sh
106139
107140 - name : Self-host smoke (freshly-built mcpp builds itself again)
108141 shell : bash
109142 run : |
110- MCPP=$(find target -name "mcpp.exe" -path "*/bin/*" | head -1)
111- MCPP=$(cd "$(dirname "$MCPP")" && pwd)/$(basename "$MCPP")
112- export MCPP_VENDORED_XLINGS="$XLINGS_BIN"
113- export MCPP_HOME="$USERPROFILE/.mcpp"
114- "$MCPP" build
115- "$MCPP" --version
143+ export MCPP_VENDORED_XLINGS=$(cygpath -w "$USERPROFILE/.xlings/subos/default/bin/xlings.exe")
144+ "$MCPP_SELF" build
145+ "$MCPP_SELF" --version
116146 echo ":: Self-host smoke PASS"
117147
118148 - name : Package Windows release zip
119149 id : package
120150 shell : bash
121151 run : |
122152 VERSION=$(awk -F '"' '/^version[[:space:]]*=/{print $2; exit}' mcpp.toml)
123- PLAT="windows-x86_64"
124- WRAPPER="mcpp-${VERSION}-${PLAT}"
153+ WRAPPER="mcpp-${VERSION}-windows-x86_64"
125154 ZIPNAME="${WRAPPER}.zip"
126155
127- MCPP_SELF=$(find target -name "mcpp.exe" -path "*/bin/*" | head -1)
128- MCPP_SELF=$(cd "$(dirname "$MCPP_SELF")" && pwd)/$(basename "$MCPP_SELF")
129-
130156 STAGING=$(mktemp -d)
131- mkdir -p "$STAGING/$WRAPPER/bin"
132- mkdir -p "$STAGING/$WRAPPER/registry/bin"
133-
157+ mkdir -p "$STAGING/$WRAPPER/bin" "$STAGING/$WRAPPER/registry/bin"
134158 cp "$MCPP_SELF" "$STAGING/$WRAPPER/bin/mcpp.exe"
135159 printf '@echo off\r\n"%%~dp0bin\\mcpp.exe" %%*\r\n' > "$STAGING/$WRAPPER/mcpp.bat"
136160 cp README.md "$STAGING/$WRAPPER/" 2>/dev/null || true
137161 cp LICENSE "$STAGING/$WRAPPER/" 2>/dev/null || true
138-
139162 XLINGS_EXE="$USERPROFILE/.xlings/subos/default/bin/xlings.exe"
140- if [ -f "$XLINGS_EXE" ]; then
141- cp "$XLINGS_EXE" "$STAGING/$WRAPPER/registry/bin/xlings.exe"
142- fi
163+ [ -f "$XLINGS_EXE" ] && cp "$XLINGS_EXE" "$STAGING/$WRAPPER/registry/bin/xlings.exe"
143164
144165 mkdir -p dist
145166 (cd "$STAGING" && 7z a -tzip "$ZIPNAME" "$WRAPPER")
146167 cp "$STAGING/$ZIPNAME" "dist/$ZIPNAME"
147168 (cd dist && sha256sum "$ZIPNAME" > "$ZIPNAME.sha256")
148-
149- echo "version=$VERSION" >> "$GITHUB_OUTPUT"
150169 echo "zipname=$ZIPNAME" >> "$GITHUB_OUTPUT"
151170 ls -la dist/
152171
0 commit comments