feat: Windows CI uses xlings to bootstrap mcpp (same as Linux/macOS) #34
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: ci-windows | |
| # Windows CI for mcpp. | |
| # Step 1: Bootstrap mcpp via xlings (same as Linux/macOS). | |
| # Step 2: Self-host — use mcpp to build itself (LLVM + MSVC STL import std). | |
| # Step 3: Package the self-hosted binary into a distributable zip. | |
| on: | |
| push: | |
| branches: [ feat/windows-support ] | |
| pull_request: | |
| branches: [ main ] | |
| paths: | |
| - 'src/toolchain/**' | |
| - 'src/build/**' | |
| - 'src/cli.cppm' | |
| - '.github/workflows/ci-windows.yml' | |
| workflow_dispatch: | |
| concurrency: | |
| group: ci-windows-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| windows-build: | |
| name: Windows x64 — build + self-host | |
| runs-on: windows-latest | |
| timeout-minutes: 45 | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: System info | |
| shell: bash | |
| run: | | |
| echo "OS: $(uname -s)" | |
| echo "Arch: $(uname -m)" | |
| echo "Runner: $RUNNER_OS" | |
| - name: Install xlings | |
| shell: bash | |
| env: | |
| XLINGS_NON_INTERACTIVE: '1' | |
| XLINGS_VERSION: '0.4.30' | |
| run: | | |
| WORK=$(mktemp -d) | |
| zipfile="xlings-${XLINGS_VERSION}-windows-x86_64.zip" | |
| curl -fsSL -o "${WORK}/${zipfile}" \ | |
| "https://github.com/d2learn/xlings/releases/download/v${XLINGS_VERSION}/${zipfile}" | |
| cd "${WORK}" | |
| unzip -q "${zipfile}" | |
| XLINGS_DIR="${WORK}/xlings-${XLINGS_VERSION}-windows-x86_64" | |
| "$XLINGS_DIR/subos/default/bin/xlings.exe" self install | |
| echo "$USERPROFILE/.xlings/subos/default/bin" >> "$GITHUB_PATH" | |
| echo "$USERPROFILE/.xlings/bin" >> "$GITHUB_PATH" | |
| - name: Bootstrap mcpp via xlings | |
| shell: bash | |
| run: | | |
| xlings.exe --version | |
| xlings.exe install mcpp -y | |
| MCPP="$USERPROFILE/.xlings/subos/default/bin/mcpp.exe" | |
| test -f "$MCPP" || MCPP="$USERPROFILE/.xlings/subos/default/bin/mcpp" | |
| test -f "$MCPP" | |
| "$MCPP" --version | |
| echo "MCPP=$MCPP" >> "$GITHUB_ENV" | |
| echo "XLINGS_BIN=$USERPROFILE/.xlings/subos/default/bin/xlings.exe" >> "$GITHUB_ENV" | |
| - name: Self-host — mcpp builds itself | |
| shell: bash | |
| run: | | |
| echo "=== Self-host: mcpp builds mcpp ===" | |
| "$MCPP" --version | |
| # mcpp build uses LLVM on Windows (from mcpp.toml: windows = "llvm@20.1.7") | |
| XLINGS_WIN=$(cygpath -w "$XLINGS_BIN") | |
| export MCPP_VENDORED_XLINGS="$XLINGS_WIN" | |
| # Pre-seed mcpp sandbox with the already-installed LLVM from xlings | |
| MCPP_XPKGS="$USERPROFILE/.mcpp/registry/data/xpkgs" | |
| XLINGS_XPKGS="$USERPROFILE/.xlings/data/xpkgs" | |
| if [ -d "$XLINGS_XPKGS/xim-x-llvm" ]; then | |
| mkdir -p "$MCPP_XPKGS" | |
| rm -rf "$MCPP_XPKGS/xim-x-llvm" | |
| cp -r "$XLINGS_XPKGS/xim-x-llvm" "$MCPP_XPKGS/xim-x-llvm" | |
| echo "Pre-seeded LLVM from global xlings" | |
| fi | |
| "$MCPP" build | |
| # Find the self-hosted binary | |
| SELF_MCPP=$(find target -name "mcpp.exe" -path "*/bin/*" | head -1) | |
| test -n "$SELF_MCPP" || { | |
| echo "FAIL: self-host build did not produce mcpp.exe" | |
| find target -name "*.exe" 2>/dev/null | |
| exit 1 | |
| } | |
| SELF_MCPP=$(cd "$(dirname "$SELF_MCPP")" && pwd)/$(basename "$SELF_MCPP") | |
| echo "Self-hosted binary: $SELF_MCPP" | |
| "$SELF_MCPP" --version | |
| echo "MCPP_SELF=$SELF_MCPP" >> "$GITHUB_ENV" | |
| - name: Package Windows release zip | |
| id: package | |
| shell: bash | |
| run: | | |
| VERSION=$(awk -F '"' '/^version[[:space:]]*=/{print $2; exit}' mcpp.toml) | |
| PLAT="windows-x86_64" | |
| WRAPPER="mcpp-${VERSION}-${PLAT}" | |
| ZIPNAME="${WRAPPER}.zip" | |
| echo "Packaging $ZIPNAME ..." | |
| STAGING=$(mktemp -d) | |
| mkdir -p "$STAGING/$WRAPPER/bin" | |
| mkdir -p "$STAGING/$WRAPPER/registry/bin" | |
| # Binary: self-hosted build | |
| echo "Packaging binary: $MCPP_SELF" | |
| cp "$MCPP_SELF" "$STAGING/$WRAPPER/bin/mcpp.exe" | |
| # Launcher batch script | |
| printf '@echo off\r\n"%%~dp0bin\\mcpp.exe" %%*\r\n' > "$STAGING/$WRAPPER/mcpp.bat" | |
| # Metadata | |
| cp README.md "$STAGING/$WRAPPER/" 2>/dev/null || true | |
| cp LICENSE "$STAGING/$WRAPPER/" 2>/dev/null || true | |
| # Bundle xlings | |
| XLINGS_EXE="$USERPROFILE/.xlings/subos/default/bin/xlings.exe" | |
| if [ -f "$XLINGS_EXE" ]; then | |
| cp "$XLINGS_EXE" "$STAGING/$WRAPPER/registry/bin/xlings.exe" | |
| echo "Bundled xlings.exe" | |
| else | |
| echo "::warning::xlings.exe not found at $XLINGS_EXE" | |
| fi | |
| # Create zip | |
| mkdir -p dist | |
| (cd "$STAGING" && 7z a -tzip "$ZIPNAME" "$WRAPPER") | |
| cp "$STAGING/$ZIPNAME" "dist/$ZIPNAME" | |
| # SHA256 | |
| (cd dist && sha256sum "$ZIPNAME" > "$ZIPNAME.sha256") | |
| echo "version=$VERSION" >> "$GITHUB_OUTPUT" | |
| echo "zipname=$ZIPNAME" >> "$GITHUB_OUTPUT" | |
| ls -la dist/ | |
| - name: Smoke-test the packaged zip | |
| shell: bash | |
| run: | | |
| VERSION="${{ steps.package.outputs.version }}" | |
| ZIPNAME="${{ steps.package.outputs.zipname }}" | |
| WRAPPER="${ZIPNAME%.zip}" | |
| SMOKE=$(mktemp -d) | |
| (cd "$SMOKE" && unzip -q "$GITHUB_WORKSPACE/dist/$ZIPNAME") | |
| echo "=== Layout ===" | |
| find "$SMOKE/$WRAPPER" -type f | |
| echo "=== Version check ===" | |
| "$SMOKE/$WRAPPER/bin/mcpp.exe" --version | |
| echo "=== xlings bundled ===" | |
| test -f "$SMOKE/$WRAPPER/registry/bin/xlings.exe" | |
| echo "=== Launcher ===" | |
| test -f "$SMOKE/$WRAPPER/mcpp.bat" | |
| echo "Smoke-test passed" | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: mcpp-windows-x86_64 | |
| path: | | |
| dist/*.zip | |
| dist/*.sha256 |