W S L Template Stacks

A WSL C++ Template Project for GLFW-Skia applications

View project on GitHub


GLFW-Skia C++ Template - Linux Setup Instruction

MIT License Commercial Services Available

Introduction

This template is designed for use in conjunction with a WSL (Windows Subsystem for Linux) distribution running on a Windows 11 host. This section provides step-by-step instructions for setting up the Linux build environment in WSL. It includes building the GLFW and Skia libraries from source. Because this environment creates a graphical build environment that generates GUI applications, we need a way to display the GUI on the screen. In WSL, this can be done in two ways: using the built-in WSLg subsystem (the default) or using the X11 protocol in combination with forwarding to the Windows host. We will use the WSLg option. For more background information, see the background section ‘Which Graphics Engine’ details below.

The setup process involves:

  • Building GLFW 3.4 with CMake
  • Building Skia graphics library with debug and release configurations
  • Configuring dependencies for your development environment

Which Graphics Engine

Graphics Engine Used

This GLFW-Skia C++ Template uses WSLg by default - Microsoft’s built-in graphics subsystem for WSL2 that provides native OpenGL support up to version 4.6.

Two Graphics Options Available

  1. WSLg (Recommended & Default)
    • Built into modern WSL2 installations
    • Native OpenGL 4.6 support
    • Individual GUI applications display on Windows desktop
    • This is what this template is configured for
  2. X11 Forwarding (Alternative)
    • Requires separate X11 server (XLaunch/VcXsrv)
    • Limited to OpenGL 1.4
    • Full desktop environment available
    • See separate repository for setup

Unless you specifically need a full Linux desktop environment, stick with the default WSLg setup.

─── ✦ ───


Setup Instructions

This is the Linux component of a dual-platform development environment:

  • Windows Setup: Native development tools, Visual Studio, debugging → Windows Setup Guide
  • WSL Linux Setup (This Page): Cross-platform builds and Linux testing

Why both? Development is done primarily on Windows, but you can build and test Linux versions seamlessly through WSL.

Prepare the WSL

Start your WSL, or create one first. Alternatively, you can import a default one if you have an exported version. In that case, use a command like:

# From project root, import new WSL based on existing exported WSL.
wsl --import NewDist  .\_wsl_data\NewDist\ D:\WSL\WSL-Exports\Debian-clean.tar

# This command creates the directory `NewDist` automatically
# Note that '_wsl_data' must exist

When you need to create a new WSL from scratch, use these recommended manual installation instructions. See here in the sub-paragraph WSL Notes & Background Information, which contains the instructions

Alternative X11 Forwarding Setup Available

Note: This template uses WSLg by default, but I also provide an alternative X11 forwarding setup.

For a full Linux desktop experience, I provide a Debian-based WSL distribution that includes the MATE X11 desktop environment. This setup requires XLaunch (an X11 server) to be installed on the Windows host. To get started with this alternative setup, see this repository.

Important limitation: X11 forwarding only supports older OpenGL versions (typically 1.4), while WSLg supports OpenGL up to 4.6. For GLFW-Skia development, WSLg provides much better graphics performance.

Tip: Check your current OpenGL version
glxinfo | grep "OpenGL version"

Recommendation:
Stick with the default WSLg setup unless you specifically need a full Linux desktop environment.

When starting WSL, make sure you use a WSL user that you have created. Don’t use the root account! For instructions when needed, see Notes, Warnings & Background Information. Throughout the rest of this document, we will use apt install to install the required packages. Supported Linux distributions are mentioned in the link above.

Decisions made

The following decisions that have been made, regarding project location and library locations:

  • Project locations
    This Linux setup uses the same project source directory as the Windows setup. This allows you to build the application for both Linux and Windows using a shared codebase, with only minimal setup required for each platform
  • Library locations
    The libraries (depot_tools, GLFW, and Skia) for Windows are installed inside the project folder: \dependencies\win Under Linux, these packages are easier to install system-wide. Therefore, the Linux versions are installed globally where possible. For libraries that must be built manually (currently only depot_tools), they are installed in the user’s home folder as part of the Linux development build.

WSL Notes

This paragraph contains some background information about the WSL, in case your are less familiar The WSL creation and usage.

Debian-based Linux distributions🐧

These distributions are based on Debian and use apt

  • Ubuntu,
  • Linux Mint,
  • Kali Linux,
  • Pop!_OS,
  • Zorin OS,
  • Elementary OS,
  • Parrot OS,
  • and others

Did you know? WSL Export & Import

📍You can export and import WSL distributions? This can be very convenient: you can create a standard base WSL, export it, rename and import it for different projects. This also makes it easy to archive your WSL environment once you’re done with a project.

Manual Create WSL Environment🔧

Introduction

This chapter explains how to set up a WSL backend environment manual by using the .Appx or .AppxBundle packages

Download the WSL packages

  • From here.
  • Scroll to the *“Downloading distributions” section.
  • Download the Ubuntu 24.04 .AppxBundle (this guide assumes this version).
  • Unpack the package, like, assuming you downloaded Ubuntu2404-240425.AppxBundle:

Get the right WSL Import file

  • Rename Ubuntu2404-240425.AppxBundle to Ubuntu2404-240425.zip
  • Unpack it using 7zip or similar
  • Find Ubuntu_2404.0.5.0_x64.appx
    • Rename it to: Ubuntu_2404.0.5.0_x64.zip unpack it.
    • Unpack it.
      Result you’ll get the file: install.tar.gz this is what you’ll use in the next step,

Create the WSL

To create the WSL file finally, Use:

  • Place the WSL file in centralized location, i.e. /My-wsl-environments/wsl-sample/
  • In that location execute:
    • wsl --import wsl-sample /My-wsl-environments/wsl-sample install.tar.gz
      (wsl –import [name wsl] [destination] [location-to/install.tar.gz] )

Other WSL commands

Some supporting WSL commands

wsl -l -v               # List all distributions with status
wsl -d [name]           # starts it
wsl --unregister [name] # Remove a distribution
wsl --export DistributionName BackupFile.tar
wsl --import NewDistributionName InstallLocation BackupFile.tar

─── ✦ ───

Create User / Start WSL💫

Why not use the root user

Avoid running WSL as the root user. Instead, create a normal user account, many GUI apps and build tools expect a standard user environment with a home directory, correct permissions, and access to sudo. Running as root can cause permission issues, misconfigured environments, or unexpected behavior during builds.

Create a user

  • adduser nico # create user with password & home directory
  • usermod -aG sudo nico # add to sudo group — allows use of sudo
  • su - nico # switch to the new user
  • cut -d: -f1 /etc/passwd # list all users (optional check)
  • getent group sudo # user member of su.
  • groups nico # groups user belongs to
  • id nico # ~same

Start WSL with the new user

  • wsl -d debian-gui -u nico # start WSL as this user
  • wsl --manage debian-gui --set-default-user nico # set default user

─── ✦ ───


💫 New Setup with VSC Agent See here
This will try to use the VS Co-pilot agent to install the installation, mentioned below (Experimental)


Install the GLFW library

Make sure you have a WSL environment installed and started, the following command are in the Bash shell of the WSL, installation is done with root user, alternatively you can create a user and install all under that user (see section WSL-Notes)

  • wsl -d [wsl-name]          # starts it 
  • Install these libraries with:
    sudo apt update 
    sudo apt install cmake g++ libglfw3-dev libgl1-mesa-dev libx11-dev gdb libxkbcommon-dev libxinerama-dev libxcursor-dev libxi-dev 
  • Find the the include folder, note down the include folder, cause it is need below:
    dpkg -L libglfw3-dev | grep '\.h$' 

    this may result something like:
    /usr/include/GLFW/glfw3.h
    /usr/include/GLFW/glfw3native.h
    In that case make sure to to note down: /usr/include/GLFW

  • Find the the lib folder, note it down library folder, cause it is need below:
    dpkg -L libglfw3-dev | grep '\.so' 

    this may result something like:
    /usr/lib/x86_64-linux-gnu/libglfw.so In that case make sure to to note down: /usr/lib/x86_64-linux-gnu/

  • Now Check and if need update the file ${PROJECT_SOURCE_DIR}cmake/linux.cmake to update it with the include and library folders found earlier. The Items below can be found in the cmake function: SetLinuxDirectories.
    • GLFW_LINUX_INCLUDE_DIR Update this with the found include folder found (in our example:/usr/include/GLFW )
    • GLFW_LINUX_LIB_DIR Update this with the found library folder found (in our example:/usr/lib/x86_64-linux-gnu/)

Be-aware: skim through the file: ${PROJECT_SOURCE_DIR}cmake/linux.cmake, it also contains linkage settings which may need to change, by default it is prepared for debug

More general method to look for a specific library

A more general method to look for a specific library is:
sudo find /usr/lib /usr/local/lib -name “libGL.so (remember to drop the ‘lib’ and ‘.so’ part when using the library in CMake\Make, just saying)


Install Skia library

The following Bash command assume the your inside the WSL, if not start it with:

wsl -d [wsl-name]   # starts it 
  • Install the libraries with:
    sudo apt update 
     sudo apt install build-essential git python3 pkg-config libglu1-mesa-dev libgl1-mesa-dev ninja-build \
      libfontconfig1-dev libexpat1-dev libfreetype6-dev libpng-dev libjpeg-dev libharfbuzz-dev libwebp-dev mesa-utils vulkan-tools
    

Install the library depot_tools

  • Make a directory tools/libs in for the user home directory( cd ~/) and make sure user owns it. This is used to install the depot_tools into, for example: /home/name/tools/libs and cd to it. Note that for our root user the directory is /root so create: /root/tools/libs
  • In the Libs directory clone:
    git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
  • Add the path to begin of the path environment (so it will have priority):
      echo 'export PATH="$HOME/tools/libs/depot_tools:$PATH"' >> ~/.bashrc  
      source ~/.bashrc 

Setup amd configure Skia

  • Use the new created tools/libs directory to install Skia into, thus make sure your in: cd $HOME/tools/libs
  • clone:
    git clone https://skia.googlesource.com/skia.git 
  • Navigate to sub directory: cd skia run:
    git checkout chrome/m126  # To checkout a stable build instead a the master(Use Same as on Windows!) 
  • Sync dependencies with, run:
    python3 tools/git-sync-deps # this will install tools like ***gn*** and others 
    • Check with the command:
      which gn      # should display location of gn 

Creating build versions

All combinations can be found here but obvious choice is the Shared Debug
The command assume your in the WSL in the directory: cd $HOME/tools/libs/skia

  • Generate Static Release build files with:
    ./bin/gn gen out/release/static --args='is_official_build=true is_component_build=false is_debug=false skia_use_gl=true' 
    • Build it with:
      ninja -C out/release/static 
  • Generate Static Debug build files with:
    ./bin/gn gen out/debug/static --args='is_debug=true is_official_build=false is_component_build=false skia_use_gl=true'
    • Build it with:
      ninja -C out/debug/static 
  • Generate Shared Release build files with:
    ./bin/gn gen out/release/shared --args='is_debug=false is_official_build=true is_component_build=true skia_use_gl=true'
    • Build it with:
      ninja -C out/release/shared 
  • Generate Shared Debug build files with:
    ./bin/gn gen out/debug/shared --args='is_debug=true is_official_build=false is_component_build=true skia_use_gl=true' 
    • Build it with:
      ninja -C out/debug/shared

Check\Update ./cmake/linux.cmake file for Skia

  • Now Check and if need update the file ${PROJECT_SOURCE_DIR}cmake/linux.cmake to update it with the include and library folders found earlier. The Items below can be found in the cmake function: SetLinuxDirectories.
    • SKIA_LINUX_CORE_INCLUDE_DIR Update this with: ${ENV:HOME}/tools/libs/skia
    • SKIA_LINUX_LIBS_DIR Update this with: ${ENV:HOME}/tools/libs/skia/out/debug/shared
    • Check also the SKIA_LIBS_LOCAL which specifies the use library name(s)

Be-aware: skim through the file: ${PROJECT_SOURCE_DIR}cmake/linux.cmake, it also contains linkage settings which may need to change, by default it is prepared for debug

Use the the build documentation to build the sample project


License
This file is part of: GLFW-Skia C++ Template Stack Copyright (c) 2025-2026 Nico Jan Eelhart.This repository is MIT licensed and free to use. For optional commercial support, customization, training, or long-term maintenance, see COMMERCIAL.md.


─── ✦ ───
















Maintained by NicoJanE. Generated by GitHub Pages.