| 1 | # Windows Subsystem for Linux (WSL) |
| 2 | |
| 3 | **ALWAYS reference these instructions first and fallback to search or bash commands only when you encounter unexpected information that does not match the info here.** |
| 4 | |
| 5 | WSL is the Windows Subsystem for Linux - a compatibility layer for running Linux binary executables natively on Windows. This repository contains the core Windows components that enable WSL functionality. |
| 6 | |
| 7 | ## Coding Conventions |
| 8 | |
| 9 | ### Naming |
| 10 | |
| 11 | - **Classes/Structs**: `PascalCase` (e.g., `ConsoleProgressBar`, `DeviceHostProxy`) |
| 12 | - **Functions/Methods**: `PascalCase()` (e.g., `GetFamilyName()`, `MultiByteToWide()`) |
| 13 | - **Member variables**: `m_camelCase` (e.g., `m_isOutputConsole`, `m_outputHandle`) |
| 14 | - **Local variables**: `camelCase` (e.g., `distroGuidString`, `asyncResponse`) |
| 15 | - **Constants**: `c_camelCase` with `constexpr` (e.g., `constexpr size_t c_progressBarWidth = 58;`) |
| 16 | - **Namespaces**: lowercase with `::` nesting (e.g., `wsl::windows::common::registry`) |
| 17 | - **Enums**: `PascalCaseValue` (e.g., `LxssDistributionStateInstalled`) |
| 18 | - **Windows types**: Keep as-is (`LPCWSTR`, `HRESULT`, `DWORD`, `ULONG`, `GUID`) |
| 19 | |
| 20 | ### Error Handling |
| 21 | |
| 22 | Use WIL (Windows Implementation Libraries) macros — **never** bare `if (FAILED(hr))`: |
| 23 | - `THROW_IF_FAILED(hr)` — throw on HRESULT failure |
| 24 | - `THROW_HR_IF(hr, condition)` — conditional throw |
| 25 | - `THROW_HR_IF_MSG(hr, condition, fmt, ...)` — conditional throw with message |
| 26 | - `THROW_IF_NULL_ALLOC(ptr)` — throw on null allocation |
| 27 | - `THROW_LAST_ERROR_IF(condition)` — throw last Win32 error |
| 28 | - `RETURN_IF_FAILED(hr)` — return HRESULT on failure (no throw) |
| 29 | - `RETURN_LAST_ERROR_IF_EXPECTED(condition)` — expected failure path |
| 30 | - `LOG_IF_FAILED(hr)` — log but don't throw |
| 31 | - `CATCH_LOG()` — catch and log exceptions |
| 32 | |
| 33 | For user-facing errors, set a localized message before throwing: |
| 34 | ```cpp |
| 35 | THROW_HR_WITH_USER_ERROR(E_INVALIDARG, Localization::MessageConfigInvalidBoolean(name, value)); |
| 36 | ``` |
| 37 | |
| 38 | At API boundaries (COM interfaces), return `HRESULT` with out params. Internal code throws exceptions. |
| 39 | |
| 40 | ### Memory Management and RAII |
| 41 | |
| 42 | Use WIL smart pointers — **never** raw `CloseHandle()` or manual cleanup: |
| 43 | - `wil::unique_handle` — kernel handles |
| 44 | - `wil::com_ptr<T>` — COM objects |
| 45 | - `wil::unique_hfile` — file handles |
| 46 | - `wil::unique_hkey` — registry keys |
| 47 | - `wil::unique_event` — events |
| 48 | - `wil::unique_hlocal_string` — HLOCAL strings |
| 49 | - `wil::unique_cotaskmem_string` — CoTaskMem strings |
| 50 | |
| 51 | For non-standard resource types, use `wil::unique_any<Type, Deleter, Fn>`. |
| 52 | |
| 53 | For cleanup scopes, use `wil::scope_exit`: |
| 54 | ```cpp |
| 55 | auto cleanup = wil::scope_exit([&] { registry::DeleteKey(LxssKey, guid.c_str()); }); |
| 56 | // ... work ... |
| 57 | cleanup.release(); // dismiss on success |
| 58 | ``` |
| 59 | |
| 60 | ### Synchronization |
| 61 | |
| 62 | Use `wil::srwlock` (Slim Reader/Writer locks) with SAL annotations: |
| 63 | ```cpp |
| 64 | mutable wil::srwlock m_lock; |
| 65 | _Guarded_by_(m_lock) std::vector<Entry> m_entries; |
| 66 | ``` |
| 67 | |
| 68 | ### Strings |
| 69 | |
| 70 | - `std::wstring` / `std::wstring_view` are dominant throughout the codebase |
| 71 | - Use `MultiByteToWide()` / `WideToMultiByte()` from `stringshared.h` for conversions |
| 72 | - Use `std::format()` for formatting (the repo defines `std::formatter<std::wstring, char>` for wide-to-narrow support) |
| 73 | - The `STRING_TO_WIDE_STRING()` macro handles compile-time conversion |
| 74 | |
| 75 | ### Copy/Move Semantics |
| 76 | |
| 77 | Use macros from `defs.h` to declare copy/move behavior: |
| 78 | ```cpp |
| 79 | NON_COPYABLE(MyClass); |
| 80 | NON_MOVABLE(MyClass); |
| 81 | DEFAULT_MOVABLE(MyClass); |
| 82 | ``` |
| 83 | |
| 84 | ### Headers |
| 85 | |
| 86 | - Use `#pragma once` (no traditional `#ifndef` include guards) |
| 87 | - In Windows C++ components, every `.cpp` file must start with `#include "precomp.h"` |
| 88 | - Linux-side code (`src/linux/`) does not use precompiled headers |
| 89 | - Use `.h` for C-compatible headers, `.hpp` for C++-only headers |
| 90 | - Include order is enforced by `.clang-format` (precomp first, then system, then project) |
| 91 | |
| 92 | ### Copyright Headers |
| 93 | |
| 94 | Use this single-line format for new files: |
| 95 | ```cpp |
| 96 | // Copyright (C) Microsoft Corporation. All rights reserved. |
| 97 | ``` |
| 98 | |
| 99 | Some older files use the block format (`/*++ Copyright (c) Microsoft. All rights reserved. ... --*/`). Match the surrounding files in the same directory when editing. |
| 100 | |
| 101 | ### Localization |
| 102 | |
| 103 | - Use `wsl::shared::Localization::MessageXxx()` static methods for user-facing strings |
| 104 | - Use `EMIT_USER_WARNING(Localization::MessageXxx(...))` for non-fatal config warnings |
| 105 | - All new user-facing strings must have entries in `localization/strings/en-US/Resources.resw` |
| 106 | - In Resources.resw comments, use `{Locked="..."}` to prevent translation of `.wslconfig` property key names |
| 107 | - Localized files are generated by a separate localization team and regenerated downstream, so translation edits in a GitHub PR cannot be merged (they would be overwritten). This covers the per-locale `localization/strings/<locale>/Resources.resw` UI strings and the per-locale `intune/<locale>/WSL.adml` policy templates (anything other than the `en-US` sources and the neutral `intune/WSL.admx`). Filing a GitHub issue is the correct path for contributors; see `CONTRIBUTING.md`. Ignore this guidance for automated localization-service PRs that are generated by that pipeline. |
| 108 | - Community localization reports come in as **both GitHub issues and pull requests** - when triaging, look for both and file a tracking Bug for each. These are tracked via Bugs in the GCS Azure DevOps project, not merged directly. See `.github/copilot/localization-bugs.md` for the project coordinates, required fields, and `az boards` workflow. |
| 109 | |
| 110 | ### Telemetry and Logging |
| 111 | |
| 112 | - `WSL_LOG(Name, ...)` — standard trace event |
| 113 | - `WSL_LOG_DEBUG(Name, ...)` — debug-only (compiled out in release via `if constexpr`) |
| 114 | - `WSL_LOG_TELEMETRY(Name, Tag, ...)` — metrics with privacy tag and version info |
| 115 | - Provider: `g_hTraceLoggingProvider`, initialized via `WslTraceLoggingInitialize()` |
| 116 | |
| 117 | ### Platform Conditionals |
| 118 | |
| 119 | Prefer `constexpr` checks over `#ifdef` where possible: |
| 120 | ```cpp |
| 121 | if constexpr (wsl::shared::Debug) { /* debug-only code */ } |
| 122 | if constexpr (wsl::shared::Arm64) { /* ARM64-specific code */ } |
| 123 | ``` |
| 124 | |
| 125 | For compiler-specific code, use `#ifdef _MSC_VER` (Windows) / `#ifdef __GNUC__` (Linux). |
| 126 | |
| 127 | ### Formatting |
| 128 | |
| 129 | Enforced by `.clang-format`: |
| 130 | - 130 character column limit |
| 131 | - 4-space indentation, no tabs |
| 132 | - Allman-style braces (opening brace on new line for classes, functions, structs, control statements) |
| 133 | - Left-aligned pointers (`int* ptr`, not `int *ptr`) |
| 134 | - `InsertBraces: true` — all control statements must have braces |
| 135 | |
| 136 | ### IDL / COM Conventions |
| 137 | |
| 138 | When modifying service interfaces (`src/windows/service/inc/`): |
| 139 | - Interface attributes on separate lines: `[uuid(...), pointer_default(unique), object]` |
| 140 | - String params: `[in, unique] LPCWSTR` with `[string]` for marshaled strings |
| 141 | - Handle params: `[in, system_handle(sh_file)] HANDLE` |
| 142 | - User-facing errors: pass `[in, out] LXSS_ERROR_INFO* Error` |
| 143 | - **ABI stability applies only to SDK-facing and public surfaces.** `WSLCCompat.idl` (the WSLC SDK-facing layer) and the public plugin API (`WslPluginApi.h`) must stay backward compatible: do not add, remove, or reorder methods on their existing interfaces, and do not change struct layouts. Introduce a new versioned interface with a new IID instead. Every other interface (`IWSLCSession` in `wslc.idl`, the interfaces in `wslservice.idl`, etc.) is internal and non-stable: rebuilt and shipped in lockstep with its only clients, so appending new methods to those is fine. |
| 144 | - Custom error codes: `WSL_E_xxx` via `MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, WSL_E_BASE + N)` |
| 145 | |
| 146 | ### Config File (.wslconfig) Conventions |
| 147 | |
| 148 | When adding settings to `src/shared/configfile/`: |
| 149 | - Format is `.gitconfig`-style INI: `[section]`, `key = value`, `#` comments, `\` line continuation |
| 150 | - Use the `ConfigKey` template class for type-safe parsing |
| 151 | - Supported types: `bool`, `int` (hex/octal), `std::string`, `std::wstring`, `MemoryString`, `MacAddress`, enum maps |
| 152 | - Report invalid values with `EMIT_USER_WARNING(Localization::MessageConfigXxx(...))` |
| 153 | - New settings require a corresponding localization string in Resources.resw |
| 154 | |
| 155 | ## Repository Navigation |
| 156 | |
| 157 | ### Key Directories |
| 158 | - `src/windows/` — Main Windows WSL service components |
| 159 | - `src/linux/` — Linux-side WSL components |
| 160 | - `src/shared/` — Shared code between Windows and Linux |
| 161 | - `test/windows/` — Windows-based tests (TAEF framework) |
| 162 | - `test/linux/unit_tests/` — Linux unit test suite |
| 163 | - `doc/` — Documentation source (MkDocs) |
| 164 | - `tools/` — Build and deployment scripts |
| 165 | - `distributions/` — Distribution validation and metadata |
| 166 | - `localization/` — Localized string resources |
| 167 | |
| 168 | ### Namespace → Directory Map |
| 169 | |
| 170 | | Namespace | Location | |
| 171 | |---|---| |
| 172 | | `wsl::shared::` | `src/shared/` | |
| 173 | | `wsl::windows::common::` | `src/windows/common/` | |
| 174 | | `wsl::windows::service::` | `src/windows/service/exe/` | |
| 175 | | `wsl::core::` | `src/windows/service/exe/` | |
| 176 | | `wsl::core::networking::` | `src/windows/common/` + `src/windows/service/exe/` | |
| 177 | | `wsl::linux::` | `src/linux/init/` | |
| 178 | |
| 179 | ### Key Files |
| 180 | - `src/shared/inc/defs.h` — Shared platform definitions (NON_COPYABLE, Debug, Arm64, etc.) |
| 181 | - `src/shared/inc/stringshared.h` — String conversion utilities |
| 182 | - `src/windows/common/WslTelemetry.h` — Telemetry macros |
| 183 | - `src/windows/common/ExecutionContext.h` — Error context and user-facing error macros |
| 184 | - `src/windows/service/inc/wslservice.idl` — Main service COM interface definitions |
| 185 | - `src/windows/service/inc/wslc.idl` — Container COM interface definitions |
| 186 | - `src/windows/inc/WslPluginApi.h` — Plugin API header |
| 187 | - `src/shared/configfile/configfile.h` — Config file parser |
| 188 | - `.clang-format` — Code formatting rules (130 col, 4-space indent, Allman braces) |
| 189 | |
| 190 | ## Building and Deploying |
| 191 | |
| 192 | ### Critical Platform Requirements |
| 193 | - **Full builds ONLY work on Windows** with Visual Studio and Windows SDK 26100 |
| 194 | - **DO NOT attempt to build the main WSL components on Linux** — they require Windows-specific APIs, MSBuild, and Visual Studio toolchain |
| 195 | - Many validation and development tasks CAN be performed on Linux (documentation, formatting, Python validation scripts) |
| 196 | |
| 197 | ### Windows Build Requirements |
| 198 | - CMake >= 3.25 (`winget install Kitware.CMake`) |
| 199 | - Visual Studio with these components: |
| 200 | - Windows SDK 26100 |
| 201 | - MSBuild |
| 202 | - Universal Windows platform support for v143 build tools (X64 and ARM64) |
| 203 | - MSVC v143 - VS 2022 C++ ARM64 build tools (Latest + Spectre) (X64 and ARM64) |
| 204 | - C++ core features |
| 205 | - C++ ATL for latest v143 tools (X64 and ARM64) |
| 206 | - C++ Clang compiler for Windows |
| 207 | - .NET desktop development |
| 208 | - .NET WinUI app development tools |
| 209 | - Enable Developer Mode in Windows Settings OR run with Administrator privileges (required for symbolic link support) |
| 210 | |
| 211 | ### Building WSL (Windows Only) |
| 212 | 1. Clone the repository |
| 213 | 2. Generate Visual Studio solution: `cmake .` |
| 214 | 3. Build: `cmake --build . -- -m` OR open `wsl.sln` in Visual Studio |
| 215 | |
| 216 | Build parameters: |
| 217 | - `cmake . -A arm64` — Build for ARM64 |
| 218 | - `cmake . -DCMAKE_BUILD_TYPE=Release` — Release build |
| 219 | - `cmake . -DBUILD_BUNDLE=TRUE` — Build bundle MSIX package (requires ARM64 built first) |
| 220 | |
| 221 | ### Deploying WSL (Windows Only) |
| 222 | - Install MSI: `bin\<platform>\<target>\wsl.msi` |
| 223 | - OR use script: `powershell tools\deploy\deploy-to-host.ps1` |
| 224 | - For Hyper-V VM: `powershell tools\deploy\deploy-to-vm.ps1 -VmName <vm> -Username <user> -Password <pass>` |
| 225 | |
| 226 | ## Testing |
| 227 | |
| 228 | ### Writing Tests (TAEF Framework) |
| 229 | |
| 230 | Tests use TAEF. See `.github/copilot/test.md` for detailed patterns and macros. |
| 231 | |
| 232 | Key points: |
| 233 | - Use `WSL_TEST_CLASS(Name)` — not raw `BEGIN_TEST_CLASS` |
| 234 | - Use `VERIFY_*` macros for assertions (`VERIFY_ARE_EQUAL`, `VERIFY_IS_TRUE`, etc.) |
| 235 | - Skip macros: `WSL1_TEST_ONLY()`, `WSL2_TEST_ONLY()`, `SKIP_TEST_ARM64()` |
| 236 | - Test infrastructure is in `test/windows/Common.h` |
| 237 | |
| 238 | ### Running Tests (Windows Only) |
| 239 | |
| 240 | **CRITICAL: ALWAYS build the ENTIRE project before running tests:** |
| 241 | ```powershell |
| 242 | cmake --build . -- -m |
| 243 | bin\<platform>\<target>\test.bat |
| 244 | ``` |
| 245 | |
| 246 | **Why full build is required:** |
| 247 | - Tests depend on multiple components (libwsl.dll, wsltests.dll, wslservice.exe, etc.) |
| 248 | - Partial builds will cause test failures |
| 249 | - **DO NOT skip the full build step even if only one file changed** |
| 250 | |
| 251 | Test execution: |
| 252 | - Run all tests: `bin\<platform>\<target>\test.bat` |
| 253 | - Run subset: `bin\<platform>\<target>\test.bat /name:*UnitTest*` |
| 254 | - Run specific test: `bin\<platform>\<target>\test.bat /name:<class>::<test>` |
| 255 | - WSL1 tests: Add `-Version 1` flag |
| 256 | - Fast mode (after first run): Add `-f` flag (requires `wsl --set-default test_distro`) |
| 257 | - **Requires Administrator privileges** |
| 258 | |
| 259 | Test debugging: |
| 260 | - Attach WinDbgX automatically: `/attachdebugger` |
| 261 | - Wait for debugger (manual attach): `/waitfordebugger` |
| 262 | - Break on failure: `/breakonfailure` |
| 263 | - Run in-process: `/inproc` |
| 264 | |
| 265 | ### Linux Unit Tests (Linux Only) |
| 266 | - Location: `test/linux/unit_tests/` |
| 267 | - Build script: `test/linux/unit_tests/build_tests.sh` |
| 268 | - **Note**: Requires specific Linux build environment setup not covered in main build process |
| 269 | |
| 270 | ## Cross-Platform Validation Tasks |
| 271 | |
| 272 | ### Documentation (Works on Linux/Windows) |
| 273 | - Install tools: `pip install mkdocs-mermaid2-plugin mkdocs --break-system-packages` |
| 274 | - Build docs: `mkdocs build -f doc/mkdocs.yml` |
| 275 | - Output location: `doc/site/` |
| 276 | - **Note**: May show warnings about mermaid CDN access on restricted networks |
| 277 | |
| 278 | ### Code Formatting and Validation |
| 279 | - Format all source (Windows, requires `cmake .` first): `.\FormatSource.ps1` |
| 280 | - Format check (Linux/cross-platform): `clang-format --dry-run --style=file <files>` |
| 281 | - Validate copyright headers: `python3 tools/devops/validate-copyright-headers.py` |
| 282 | - **Note**: Will report missing headers in generated/dependency files (`_deps/`), which is expected |
| 283 | - Validate localization: `python3 tools/devops/validate-localization.py` |
| 284 | - **Note**: Only works after Windows build (requires `localization/strings/en-US/Resources.resw`) |
| 285 | |
| 286 | ### Distribution Validation (Limited on Linux) |
| 287 | - Validate distribution info: `python3 distributions/validate.py distributions/DistributionInfo.json` |
| 288 | - **Note**: May fail on Linux due to network restrictions accessing distribution URLs |
| 289 | |
| 290 | ### Pre-commit Checklist |
| 291 | Always run before committing: |
| 292 | 1. `.\FormatSource.ps1` to verify formatting on changed C++ files |
| 293 | 2. `python3 tools/devops/validate-copyright-headers.py` (ignore `_deps/` warnings) |
| 294 | 3. `mkdocs build -f doc/mkdocs.yml` if documentation changed |
| 295 | 4. Full Windows build if core components changed |
| 296 | |
| 297 | **Note**: The `.gitignore` properly excludes build artifacts (`*.sln`, `*.dll`, `*.pdb`, `obj/`, `bin/`, etc.) — do not commit these files. |
| 298 | |
| 299 | ## Frequently Used Commands |
| 300 | |
| 301 | ### Windows Development |
| 302 | ```powershell |
| 303 | # Initial setup |
| 304 | cmake . |
| 305 | cmake --build . -- -m |
| 306 | |
| 307 | # Deploy and test |
| 308 | powershell tools\deploy\deploy-to-host.ps1 |
| 309 | wsl --version |
| 310 | |
| 311 | # Run tests |
| 312 | bin\x64\debug\test.bat |
| 313 | ``` |
| 314 | |
| 315 | ### Cross-Platform Validation |
| 316 | ```powershell |
| 317 | # Documentation |
| 318 | mkdocs build -f doc/mkdocs.yml |
| 319 | |
| 320 | # Code formatting (Windows) |
| 321 | .\FormatSource.ps1 |
| 322 | |
| 323 | # Copyright header validation (reports expected issues in _deps/) |
| 324 | python3 tools/devops/validate-copyright-headers.py |
| 325 | |
| 326 | # Distribution validation (may fail on networks without external access) |
| 327 | python3 distributions/validate.py distributions/DistributionInfo.json |
| 328 | ``` |
| 329 | |
| 330 | ## Debugging and Logging |
| 331 | |
| 332 | ### ETL Tracing (Windows Only) |
| 333 | ```powershell |
| 334 | # Collect traces |
| 335 | wpr -start diagnostics\wsl.wprp -filemode |
| 336 | # [reproduce issue] |
| 337 | wpr -stop logs.ETL |
| 338 | |
| 339 | # Available profiles: |
| 340 | # - WSL (default) - General WSL tracing |
| 341 | # - WSL-Storage - Enhanced storage tracing |
| 342 | # - WSL-Networking - Comprehensive networking tracing |
| 343 | # - WSL-HvSocket - HvSocket-specific tracing |
| 344 | # Example: wpr -start diagnostics\wsl.wprp!WSL -filemode |
| 345 | ``` |
| 346 | |
| 347 | ### Log Analysis Tools |
| 348 | - Use WPA (Windows Performance Analyzer) for ETL traces |
| 349 | - Key providers: `Microsoft.Windows.Lxss.Manager`, `Microsoft.Windows.Subsystem.Lxss` |
| 350 | - For graphical/audio (WSLg) issues, see `.github/copilot/wslg-logs.md`. `collect-wsl-logs.ps1` gathers WSLg logs (`/mnt/wslg`: weston.log, pulseaudio.log, wlog.log, stderr.log, versions.txt) into a `wslg/` folder using `wsl.exe --system --user root`; crash dumps (`%TEMP%\wsl-crashes`, legacy `/mnt/wslg/dumps`) are only collected with `-Dump`. WSLg code lives in https://github.com/microsoft/wslg, not this repo. |
| 351 | |
| 352 | ### Debug Console (Linux) |
| 353 | Add to `%USERPROFILE%\.wslconfig`: |
| 354 | ```ini |
| 355 | [wsl2] |
| 356 | debugConsole=true |
| 357 | ``` |
| 358 | |
| 359 | ### Common Debugging Commands |
| 360 | - Debug shell: `wsl --debug-shell` |
| 361 | - Collect WSL logs: `powershell diagnostics\collect-wsl-logs.ps1` |
| 362 | - Network logs: `powershell diagnostics\collect-wsl-logs.ps1 -LogProfile networking` |
| 363 | |
| 364 | ## Timing and Timeout Guidelines |
| 365 | |
| 366 | **NEVER CANCEL these operations — always wait for completion:** |
| 367 | |
| 368 | | Operation | Typical Duration | Minimum Timeout | |
| 369 | |---|---|---| |
| 370 | | Full Windows build | 20-45 minutes | 60+ minutes | |
| 371 | | Full test suite | 30-60 minutes | 90+ minutes | |
| 372 | | Unit test subset | 5-15 minutes | 30+ minutes | |
| 373 | | Documentation build | ~0.5 seconds | 5+ minutes | |
| 374 | | Distribution validation | 2-5 minutes | 15+ minutes | |
| 375 | |
| 376 | ## CI/CD Integration |
| 377 | |
| 378 | ### GitHub Actions |
| 379 | - **distributions.yml** — Validates distribution metadata (Linux) |
| 380 | - **documentation.yml** — Builds and deploys docs (Linux) |
| 381 | - **modern-distributions.yml** — Tests modern distribution support |
| 382 | |
| 383 | ## Development Environment Setup |
| 384 | |
| 385 | ### Windows (Full Development) |
| 386 | 1. Install Visual Studio with required components (listed above) |
| 387 | 2. Install CMake 3.25+ |
| 388 | 3. Enable Developer Mode |
| 389 | 4. Clone repository |
| 390 | 5. Run `cmake .` to generate solution |
| 391 | |
| 392 | ### Linux (Documentation/Validation Only) |
| 393 | 1. Install Python 3.8+ |
| 394 | 2. Install docs tools: `pip install mkdocs-mermaid2-plugin mkdocs` |
| 395 | 3. Clone repository |
| 396 | 4. Run validation commands as needed |
| 397 | |
| 398 | Remember: **This is a Windows-focused project**. While some tasks can be performed on Linux, full WSL development requires Windows with Visual Studio. |