-
Notifications
You must be signed in to change notification settings - Fork 0
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.
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 |
buildall.sh is a bash script and must be executed within a WSL environment.
Enable inheritance of Windows environment variables:
[interop]
appendWindowsPath = trueAfter building, revert this to
falseand runwsl --shutdownif desired.
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.
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 --shutdownThis 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# 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-agreementsNote: 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"wget https://download.qt.io/official_releases/jom/jom.zipExtract to C:\jom and add C:\jom to the Windows system PATH.
wget https://github.com/lexxmark/winflexbison/releases/download/v2.5.25/win_flex_bison-2.5.25.zipExtract to C:\winflexbison and add C:\winflexbison to the Windows system PATH.
C:\Python39\python.exe -m pip install lxml mako pyyamlsudo apt install gawk # usually pre-installed
sudo apt install gperf
sudo apt install mesonsetenv.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:
- coreutils-5.3.0.exe
- sed-4.2.1-setup.exe
- gawk-3.1.6-1-setup.exe
- gperf-3.0.1.exe
- gzip-1.3.12-1-setup.exe
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# WSL Terminal
cd /mnt/d/vcxsrv
git clone https://github.com/marchaesen/vcxsrv.git
# Create a feature branch
git checkout -b feature/my-fixbuildall.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 |
# 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 igncrtells bash to ignore\rcharacters 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# 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.exeCopy 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 -clipboardRemove via Windows "Apps & features" or delete C:\gnuwin32.
sudo apt remove gperf
sudo apt remove mesonC:\Python39\python.exe -m pip uninstall lxml mako pyyamlrmdir "C:\winflexbison"
rmdir "C:\jom"Also remove
C:\winflexbisonandC:\jomfrom the Windows system PATH.
# 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"# 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")Use the Visual Studio Installer.
# /etc/wsl.conf
[interop]
appendWindowsPath = falseRun wsl --shutdown to apply.
Remove-Item -Recurse -Force "D:\vcxsrv" -ErrorAction SilentlyContinue# Verify WSL2 Required Features Are Functional
Get-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform
# Expected: State = Enabled
wsl --list --verbose
# Should list your WSL distribution
wsl --status| 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 |