Skip to content

Building VcXsrv on WSL

millin edited this page Jul 11, 2026 · 4 revisions

Building VcXsrv on WSL

A step-by-step guide for building VcXsrv (X Server for Windows) using the Windows Subsystem for Linux
no modification on source code or build scripts, keeping your fork clean for pull requests.


1. Build Method Comparison: Docker vs. WSL

The WSL build method is recommended as it is more lightweight. The upstream source includes a buildall.sh script designed for WSL, but you must manually set up the build environment.

Comparison Item Docker Method WSL Method
Required on host Docker Desktop VS2022 + git + perl + nasm + python + nsis + GnuWin32
System changes Requires Hyper-V + Containers (reboot needed) None
C: drive usage ~50 GB (Docker Windows container images restricted to C:) ~10 GB
Source code (can be on D:) Source + build output ~5 GB Source + build output ~5 GB
Build environment Inside Docker container (Cygwin + pre-installed tools) WSL terminal (calls MSBuild directly)
Hard-coded paths in setenv.sh Handled by Dockerfile, no changes needed Must install to specific paths + junction symlinks
Restore after uninstall Uninstall Docker + disable Hyper-V/Containers Uninstall tools individually + revert env vars
Best for Plenty of disk space, want minimal setup Tight on disk, want a lightweight setup

2. WSL Configuration

2.1 Ensure WSL is Installed

buildall.sh is a bash script and must be executed within a WSL environment.

2.2 Configure /etc/wsl.conf

Enable inheritance of Windows environment variables:

[interop]
appendWindowsPath = true

After building, revert this to false and run wsl --shutdown if desired.


2.3 Install Visual Studio 2022 Community

During installation, select only the "Desktop development with C++" workload.

Note: Must be installed to the default location on the C: drive; the Windows SDK as well.

2.4 Set Windows Permanent Environment Variables (Critical Step)

The WSL WSLENV mechanism is unreliable when Windows programs are invoked through multiple layers (e.g., mhmake.exe -> link.exe), causing INCLUDE/LIB environment variables to be dropped and resulting in compile or link failures.

Setting these as permanent Windows environment variables ensures all programs can read them:

# Capture actual paths first (VS and Windows SDK versions may vary)
cmd /c '"C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" x64 && set > C:\vcenv.txt'

# Extract INCLUDE and LIB from the output, then set as permanent variables
# (adjust paths according to your actual installation):
[Environment]::SetEnvironmentVariable("INCLUDE", "...", "Machine")
[Environment]::SetEnvironmentVariable("LIB", "...", "Machine")

# Restart WSL for changes to take effect
wsl --shutdown

This bypasses the need for WSLENV dynamic propagation and solves all environment-variable-related build failures.

Example with default VS2022 Community paths:

# Run as Administrator

# Set permanent INCLUDE
[Environment]::SetEnvironmentVariable("INCLUDE", "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\include;C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\ATLMFC\include;C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\VS\include;C:\Program Files (x86)\Windows Kits\10\include\10.0.26100.0\ucrt;C:\Program Files (x86)\Windows Kits\10\include\10.0.26100.0\um;C:\Program Files (x86)\Windows Kits\10\include\10.0.26100.0\shared;C:\Program Files (x86)\Windows Kits\10\include\10.0.26100.0\winrt;C:\Program Files (x86)\Windows Kits\10\include\10.0.26100.0\cppwinrt", "Machine")

# Set permanent LIB
[Environment]::SetEnvironmentVariable("LIB", "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\ATLMFC\lib\x64;C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\lib\x64;C:\Program Files (x86)\Windows Kits\10\lib\10.0.26100.0\ucrt\x64;C:\Program Files (x86)\Windows Kits\10\lib\10.0.26100.0\um\x64", "Machine")

# Restart WSL
wsl --shutdown

2.5 Install Additional Dependencies via winget

# Run as Administrator in Windows PowerShell
winget install --id Git.Git --source winget --accept-source-agreements --accept-package-agreements
winget install --id StrawberryPerl.StrawberryPerl --source winget --accept-source-agreements --accept-package-agreements
winget install --id NASM.NASM --source winget --accept-source-agreements --accept-package-agreements
winget install --id Python.Python.3.9 --source winget --accept-source-agreements --accept-package-agreements
winget install --id NSIS.NSIS --source winget --accept-source-agreements --accept-package-agreements

Note: winget's default install path may differ from the hard-coded paths in setenv.sh. Create junction symlinks as needed:

mklink /J C:\Python39 "C:\Users\%USERNAME%\AppData\Local\Programs\Python\Python39"
mklink /J C:\perl C:\Strawberry
mklink /J C:\nasm "C:\Users\%USERNAME%\AppData\Local\bin\NASM"

2.6 Download jom

wget https://download.qt.io/official_releases/jom/jom.zip

Extract to C:\jom and add C:\jom to the Windows system PATH.

2.7 Download winflexbison

wget https://github.com/lexxmark/winflexbison/releases/download/v2.5.25/win_flex_bison-2.5.25.zip

Extract to C:\winflexbison and add C:\winflexbison to the Windows system PATH.

2.8 Install Python Packages

C:\Python39\python.exe -m pip install lxml mako pyyaml

2.9 Install WSL Toolchain

sudo apt install gawk        # usually pre-installed
sudo apt install gperf
sudo apt install meson

2.10 Install the GnuWin32 Utilities

setenv.sh expects /mnt/c/gnuwin32/bin to provide Windows versions of Unix utilities such as rm.exe and cp.exe.

Download from SourceForge and install to C:\gnuwin32:


3. Pre-Build Verification Checklist

Run the following checks in a WSL terminal before invoking buildall.sh:

# === WSL Terminal ===

# 1. WSL python
which python && python --version

# 2. Windows Python + lxml + mako
/mnt/c/Python39/python.exe -c "import lxml; import mako; print('lxml+mako OK')"

# 3. winflexbison location
ls /mnt/c/winflexbison/win_bison.exe /mnt/c/winflexbison/win_flex.exe

# 4. perl
/mnt/c/perl/perl/bin/perl.exe --version | head -2

# 5. nasm
/mnt/c/nasm/nasm.exe -v

# 6. jom (after setenv rebuilds PATH)
source ./setenv.sh 1
which jom.exe

# 7. WSL tools
which gawk
which gperf
which meson

# 8. Verify GnuWin32 tools
/mnt/c/gnuwin32/bin/rm.exe --version
# Should print version information

4. Clone the Source

# WSL Terminal
cd /mnt/d/vcxsrv
git clone https://github.com/marchaesen/vcxsrv.git

# Create a feature branch
git checkout -b feature/my-fix

5. Build

5.1 buildall.sh Parameters

buildall.sh is a bash script and must be run inside a WSL bash shell.

Parameter Meaning
1 64-bit build (0 = 32-bit)
9 9 parallel build jobs (recommended: CPU cores + 1)
R Release mode (D = Debug, A = All)
N (optional 4th arg) Build server only, skip dependencies

5.2 Compile

# WSL Terminal
cd /mnt/d/vcxsrv
export SHELLOPTS
# set -o igncr    # not supported in WSL, uncomment if bash reports \r syntax errors
./buildall.sh 1 9 R

set -o igncr tells bash to ignore \r characters from CRLF line endings. Skip this if the source has already been converted to LF.

If jom fails with Error 2 (intermittent), try reducing the job count, or build OpenSSL separately with nmake.exe and then rebuild with N:

# Build OpenSSL manually
cd openssl/release64
nmake.exe
cd ../..

# Rebuild server only, skipping dependencies
./buildall.sh 1 9 R N   # N = server only

5.3 Build Outputs

# Windows PowerShell

# Installer package
cd "D:\vcxsrv\xorg-server\installer"
# vcxsrv-64.21.1.16.1.installer.exe

# Standalone executable
cd "D:\vcxsrv\xorg-server\obj64\servrelease"
# vcxsrv.exe

5.4 Quick Verification

Copy the built vcxsrv.exe over the existing installation and test:

copy "D:\vcxsrv\xorg-server\obj64\servrelease\vcxsrv.exe" "C:\Program Files\VcXsrv\vcxsrv.exe"

"C:\Program Files\VcXsrv\vcxsrv.exe" :10 -multiwindow -clipboard

6. Cleanup and Restore

6.1 Uninstall the GnuWin32 Utilities

Remove via Windows "Apps & features" or delete C:\gnuwin32.

6.2 Remove WSL Tools

sudo apt remove gperf
sudo apt remove meson

6.3 Uninstall Python Packages

C:\Python39\python.exe -m pip uninstall lxml mako pyyaml

6.4 Remove winflexbison and jom

rmdir "C:\winflexbison"
rmdir "C:\jom"

Also remove C:\winflexbison and C:\jom from the Windows system PATH.

6.5 Uninstall winget Packages

# winget uninstall --id Git.Git  # Keep if originally installed
winget uninstall --id StrawberryPerl.StrawberryPerl
winget uninstall --id NASM.NASM
winget uninstall --id Python.Python.3.9
winget uninstall --id NSIS.NSIS

# Remove junction symlinks
rmdir "C:\Python39"
rmdir "C:\perl"
rmdir "C:\nasm"

6.6 Remove Permanent Environment Variables

# Run as Administrator

[Environment]::SetEnvironmentVariable("INCLUDE", $null, "Machine")
[Environment]::SetEnvironmentVariable("LIB", $null, "Machine")

# Verify they are empty
[Environment]::GetEnvironmentVariable("INCLUDE", "Machine")
[Environment]::GetEnvironmentVariable("LIB", "Machine")

6.7 Uninstall Visual Studio 2022

Use the Visual Studio Installer.

6.8 Revert WSL Configuration

# /etc/wsl.conf
[interop]
appendWindowsPath = false

Run wsl --shutdown to apply.

6.9 Remove Source Directory (Optional)

Remove-Item -Recurse -Force "D:\vcxsrv" -ErrorAction SilentlyContinue

6.10 Verify WSL Still Works

# Verify WSL2 Required Features Are Functional
Get-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform
# Expected: State = Enabled

wsl --list --verbose
# Should list your WSL distribution

wsl --status

6.11 Estimated Disk Space Recovery

Cleanup Item Space Freed
VcXsrv source + build output ~5-6 GB
VS2022 + Windows SDK ~5-10 GB
Python + Perl + NASM + NSIS ~1-2 GB
GnuWin32 + jom + winflexbison ~100 MB
Total ~15-20 GB

Clone this wiki locally