23 May 2024

Updated based on discussion on Hacker News

Developing on Windows can be frustrating; while some development environments are Windows-native or fully cross-platform, a lot of tools out there assume a Linux-like or macOS environment. Surprisingly this even includes very popular ones like Git. How do we work around this? Well, there are many solutions, though sadly none are perfect.

dev system ABI paths Linux compat access to Win. files file access from Win. GUI GPU acceleration
native MSVC Windows none direct direct native native
MinGW-w64 MinGW-w64 Windows tiny direct direct native native
Cygwin Cygwin Windows or Linux (virtual) moderate via mounts direct native/X11 native/none?
WSL1 Linux Linux (virtual) good via mounts via share X11 none?
WSL2 Linux Linux full VM via mounts (slow) via share (slow) full Linux support OpenGL, OpenCL

Use native Windows

If you can develop with native tools, that will be the simplest. Lots of programming languages fully support Windows.

To get development tools, programming languages, etc. like Git, Go, Node.js, fzf, you can use Scoop, a Windows command-line package installer. Scoop provides official builds where available.

The case where you’ll have the most difference to Linux is with C and C++. The official, 100% Microsoft way of building C software is to use the Windows SDK, along with Visual Studio and associated tools. The official C and C++ compiler is known colloquially as MSVC (Microsoft Visual C/C++). You can install these components with the Visual Studio installer (omitting the actual IDE if you don’t want it).

Use a VM / WSL2

The cleanest way of getting a Linux-like environment is to just use Linux on Windows, via a full VM, or through WSL2, which is a lightweight, well-integrated VM.

Pros

  • Fully-compatible Linux experience with GUI support

Cons

  • Minimal hardware access e.g. GPU, USB: While VM hosts can have some support for these (e.g. WSL2 has OpenGL and OpenCL acceleration) you won’t get the full experience.
  • Slower file access between VM and host. (You ideally want to be working only on files in the VM, especially avoiding major I/O work over the host bridge like long builds, or using Git in large repositories, or having large node_modules, etc.)
  • File path issues: If a program uses Linux paths, it may be difficult to integrate with Windows tools, as they won’t be able to see each others’ paths. Such is the case when using Windows VSCode and WSL Git. You may need to wrap the tools and convert paths to allow them to integrate; see andy-5/wslgit

(By the way: WSL2 exposes files to Windows via network shares, but these are inaccessible to some Windows programs. You have to mount a network drive (e.g. via net use command) to give it a drive letter for direct path access.)

There is also WSL1, which isn’t actually a VM. It’s a virtual environment which parses Linux executables and translates Linux OS API calls to Windows. The main advantage to WSL1 over 2 is that is no virtual storage drive, making it faster to access Windows files directly. Personally, I use WSL2 as I haven’t found that I’ve needed this.

Use Windows with a choice of compatibility tools

Another option, particularly where a native version is not available, is to use Cygwin. Cygwin is based around a modified port of Linux-based C compiler GCC which can compile code written for Linux; it understands lots of Linux APIs and compiles them to Windows equivalents. It does this with the help of a runtime library cygwin1.dll that is linked into the executable or library, which provides it a Linux-like virtual environment including a virtual filesystem. Cygwin also ships with a shell and package manager for lots of Linux software built with Cygwin, giving you a Linux feel on native Windows. It’s not fully compatible though, as there are many mismatches between Windows and Linux OS APIs.

In particular, Cygwin GCC produces builds with its own ABI, which makes it incompatible with pre-built libraries built with other compilers. This is particularly important for programming languages. For example, the official Windows Python builds use the Windows MSVC ABI, so the extension ecosystem is built around that; if you use Python from Cygwin, you’ll be unable to install compiled library packages with pip and pip will have to build them from source. Some such pip packages might not build at all with Cygwin. (Of course, Pure Python ones will work.)

Also, the same point about path incompatibility can apply to Cygwin programs.

So on Windows, I prefer native builds from official sources or Scoop, falling back to Cygwin for any unsupported utilities.

C and C++

If you want to develop C or C++ in a Linux-like way, i.e. not using Visual Studio tools, you could use Cygwin’s GCC and develop as if you were on Linux. However, you’ll get a Cygwin build at the end, which

  • has the Cygwin ABI
  • has the Cygwin DLL as a dependency
  • may have other compatibility quirks versus native software

Instead, you can get the convenience of both with MinGW-w64. MinGW-w64, like Cygwin, is a port of Linux-based compiler C GCC to Windows, but it compiles native Windows code to native Windows executables. This means you can use Linux-style build scripts to build normal Windows C and C++ programs. (It’s a fork of an earlier project called MinGW.) The only disadvantage is it again has a different ABI to MSVC and Cygwin.

The sweet spot of compatibility for C, then, is:

  • use build utilities like Bash, Make, coreutils, etc. from Cygwin for build system compatibility
  • use MinGW-w64 for the actual compilation

This is precisely the goal of MSYS2, which nicely integrates them together into a unified Linux-like environment with many packages. With MSYS2 you can use Cygwin or MinGW-w64 compilers as you choose, along with shell tools and build scripts written for Linux. I use MSYS2 to build native Windows versions of Brogue with barely any build system changes.

Other notes

  • You can use Linux GUI software with Cygwin or WSL1, even though they aren’t VMs, by running a native X11 server on Windows. You won’t get any graphics acceleration, though.

  • Personally, I’ve primarily used WSL2 for my personal software dev; but now that I understand the native Windows landscape better I’m considering moving in that direction, mainly for better integration.