Developing with Windows Subsystem for Linux (WSL2)

Windows Subsystem for Linux (WSL2) allows you to run a Linux environment directly on Windows without the overhead of Hyper-V on Windows 10 or a dual-boot setup. You can run many Linux command-line tools, utilities, and applications on a special lightweight virtual machine running on Windows. It is possible to run a complete FogLAMP system on WSL2. This includes the FogLAMP GUI which can be accessed from a browser running on the host Windows environment.

Microsoft’s Visual Studio Code is a cross-platform editor that supports extensions for building and debugging software in a variety of languages and environments. This article describes how to configure Visual Studio Code to edit, build and debug FogLAMP plugins written in C++ running in Linux under WSL2.

Note

It is possible to configure Visual Studio Code to build and test Python code in WSL2 but this is not covered in this article.

Preparing the Development Environment

This section outlines the steps to configure WSL2 and the Linux environment.

Installing Windows Subsystem for Linux (WSL2)

You must be running Windows 10 version 2004 and higher (Build 19041 and higher) or Windows 11 to install WSL2. The easiest way to install is to open a Windows Command Prompt as Administrator and run this command:

wsl --install

Windows will perform all the necessary steps for you. It will install the default Linux distribution which is the latest version of Ubuntu. If you wish to perform the steps manually, or install a Linux distribution other than the default, see the Microsoft documentation on Installing WSL.

When the installation completes, the Linux distribution will launch in a new window. It will prompt you for a username to serve as the root account and password. This username has nothing to do with your Windows environment so it can be any name you choose.

You can start the Linux distribution at any time by finding it in the Windows Start Menu. If you hit the Windows key and type the name of your Linux distribution (default: “Ubuntu”), you should see it immediately.

Some Useful Features of WSL2

A Linux distribution running in WSL2 is a lightweight virtual machine but is well integrated with the Windows environment. Here are some useful features:

  • Cut and paste text into and out of the Linux window:
    The Linux window behaves just like a Command Prompt window or a Powershell window. You can copy text from any window and paste it into any other.

  • Access the Linux file system from Windows:
    The Linux file system appears as a Network drive in Windows. Open the Windows File Explorer and navigate to “\\wsl$.” You will see your Linux distributions appear as network folders.

  • Access the Windows file system from Linux:
    From the bash command line, navigate to the mount point “/mnt.” You will see your Windows drive letters in this directory.

  • Access the Linux environment from the Windows host through the network:
    From the bash command line, run the command hostname -I. The external IP address returned by this command can be used in the Windows host to reach Linux.

  • Access the Windows host from the Linux environment through the network:
    From the bash command line, run the command cat /etc/resolv.conf. The IP address after the label nameserver can be used in the Linux environment to reach the Windows host.

Preparing the Linux Distribution for FogLAMP

The systemd service manager is not configured by default in an Ubuntu distribution running in WSL2. Since FogLAMP relies on systemd, you must run a script to enable it. From your home directory in the Ubuntu window, enter the commands:

git clone https://github.com/DamionGans/ubuntu-wsl2-systemd-script.git
cd ubuntu-wsl2-systemd-script
bash ubuntu-wsl2-systemd-script.sh

Restart the Ubuntu distribution using sudo reboot or sudo systemctl reboot. When the distribution has restarted, run the command systemctl. You should see no error and a list of units. The script must be run one time only. Whenever you start up your Ubuntu distribution, systemd should be ready.

Installing FogLAMP

Following the normal instructions for Installing FogLAMP on Ubuntu. Make sure the package repository matches your version of Ubuntu. You can check the operating system version in your distribution with the command hostnamectl or cat /etc/os-release.

Installing Visual Studio Code

Navigate to the Visual Studio Code webpage in your Windows browser. Click the Download for Windows button. Run the installer to install Visual Studio Code.

Visual Studio Code is available for Microsoft Windows, Apple MacOS, and several Linux distributions. Do not install the Linux build of Visual Studio Code in your Linux distribution in WSL2. You will actually be launching Visual Studio Code for Windows from your Linux distribution!

Starting the Linux Distribution

Perform these steps every time you start your Linux distribution if you plan to run FogLAMP:

Starting syslog

The system log /var/log/syslog is not configured to run automatically in a Linux distribution in WSL2. Start syslog with the command:

sudo service rsyslog start

You must do this at every startup.

Starting Nginx

FogLAMP uses Nginx as a web server to host the FogLAMP GUI. If you plan to run FogLAMP GUI during your Linux distribution session, enter the command:

sudo service nginx start

You must do this at every startup if you plan to run the FogLAMP GUI.

Starting FogLAMP

Start FogLAMP normally. You can start it from the normal run directory, or from your build directory by following the directions on the webpage Testing Your Plugin.

Starting FogLAMP GUI

If Nginx is running, you can run the FogLAMP GUI in a browser in your host Windows environment. Find the external IP address for your Linux distribution using the command:

hostname -I

This address is reachable from your Windows environment. Copy the IP address to a new tab in your browser and hit Enter. You should see the FogLAMP GUI Dashboard page.

Note

The Linux distribution’s external IP address is (usually) different every time you start it. You will need to run the hostname -I command every time to obtain the current IP address.

Configuring Visual Studio Code

This section describes how to configure Visual Studio Code to edit, build and debug your C++ Linux projects. These instructions are summarized from the Visual Studio Code tutorial Using C++ and WSL in VS Code.

Installing Extensions

Navigate to a directory containing your C++ source code files and issue the command:

code .

This will launch Visual Studio Code in your Windows environment but it will be looking at the current directory in your Linux distribution. Since you are launching Visual Studio Code from your Linux distribution, Code should prompt you to install two Extensions:

If you are not prompted, follow these links to install the extensions and restart Visual Studio Code. If the extensions are installed and working, you should see a green label in the lower left-hand corner of the Visual Studio Code window with the text WSL: followed by the name of your Linux distribution.

Configuring your Workspace

Visual Studio Code refers to your directory of source code files as the Workspace. In order to edit, build and debug your code, you must create 3 Json files in a Workspace subdirectory called .vscode:

  • c_cpp_properties.json: compiler path, IntelliSense settings, and include file paths

  • tasks.json: build instructions

  • launch.json: debugger settings

You can create these files manually or use Visual Studio Code’s configuration wizards. These subsections describe creation and required contents of each of these three files.

Code Editor Configuration: c_cpp_properties.json

  • Open the Command Palette using the key sequence Ctrl+Shift+P.

  • Choose the command C/C++: Edit Configurations (JSON).

  • This will create the .vscode subdirectory (if it doesn’t already exist) and the c_cpp_properties.json file.

  • This Json file will be opened for editing.

  • You will see a new array called configurations with a single configuration object defined.

  • This configuration will have a string array called includePath.

  • Add the paths to your own include files, and those required by the FogLAMP API to the includePath array.

  • You can use Linux environment variables in your paths. For example:

    "${FOGLAMP_ROOT}/C/common/include"
    
  • You can find the list of include files by running your make command:

    make --just-print
    

which will list all commands defined by make without executing them. You will see the include file list in every instance of the gcc compiler command.

Build Configuration: tasks.json

  • From the Visual Studio Code main menu, choose Terminal -> Configure Default Build Task.

  • A dropdown will display of available tasks for C++ projects.

  • Choose g++ build active file.

  • This will create the .vscode subdirectory (if it doesn’t already exist) and the tasks.json file.

  • Open the Json file for editing.

Building the project will be done using the make file rather than the gcc compiler. To make this change, edit the command and args entries as follows:

"command": "make",
"args": [
   "-C",
   "${workspaceFolder}/build"
],

The “-C” argument for make will move into the specified directory before doing anything.

You can invoke a build from Visual Studio Code at any time with the key sequence Ctrl+Shift+B.

Debugger Configuration: launch.json

  • From the Visual Studio Code main menu, choose Run -> Add Configuration...

  • Choose C++ (GDB/LLDB).

  • This will create the .vscode subdirectory (if it doesn’t already exist) and the launch.json file.

  • Edit the launch.json file so it looks like this:

{
   "version": "0.2.0",
   "configurations": [
      {
         "name": "Debug Plugin",
         "type": "cppdbg",
         "request": "launch",
         "targetArchitecture": "x86_64",
         "cwd": "${fileDirname}",
         "program": "/full/path/to/foglamp.services.north",
         "externalConsole": false,
         "stopAtEntry": true,
         "MIMode": "gdb",
         "avoidWindowsConsoleRedirection": false,
         "args": [
             "--port=42467",
             "--address=0.0.0.0",
             "--name=MyPluginInstance",
             "-d"
         ]
      }
    ]
}

Note

  • The program attribute holds the program that the gdb debugger should launch. For FogLAMP plugin development, this is either foglamp.services.north or foglamp.services.south depending on which one you are building. These service executables will dynamically load your plugin library when they run.

  • The args attribute has the arguments normally passed to the service executable. Since the TCP/IP port changes every time FogLAMP starts up, you must edit this file to update the port number before starting your debug session.

Start your debug session from the Visual Studio Code main menu. Choose Run -> Start Debugging or by hitting the F5 key.

Known Problems

  • Environment variables in launch.json:
    Support for environment variables in the program attribute is inconsistent. Variables created by Visual Studio Code itself will work but user-defined environment variables like FOGLAMP_ROOT will not.

  • gdb startup errors:
    It can occur that gdb stops with error 42 and exits immediately when you start a debugging session. To fix this, shut down your Linux distributions and reinstall Visual Studio Code in Windows. You will not lose your configuration settings or your installed extensions.

  • Inconsistent breakpoint lists:
    Visual Studio Code shows a list of breakpoints in the lower left corner of the window. The gdb debugger maintains its own list of breakpoints. It can occur that the two lists fall out of sync. You can still create, view and delete breakpoints from the Debug Console tab at the bottom of the screen which gives you access to the gdb command line. When using the Debug Console, you must precede all gdb commands with “-exec.”

    To manipulate breakpoints:
    • Set a breakpoint: -exec b functionName.

    • View breakpoints: -exec info b. This will display an ordinal number for each breakpoint.

    • Delete breakpoints: -exec del ##. Use the original number returned by -exec info b as “##.”