wsl2 and vscode setup - walkingeyerobot/pokeemerald GitHub Wiki

1. Install WSL2 and Ubuntu

I had some issues here where I had to enable virtualization in my bios in order to get WSL2 to work.

2. Follow INSTALL.md

Follow the instructions for Linux, even though you're on Windows. Do everything inside a WSL2 shell.

I had a problem where I had to create a symlink for devkitPro. From /opt I ran sudo ln -s devkitpro/ devkitPro.

When you're done, make sure you can build specifically with the command make DINFO=1 modern -j$(nproc).

  • DINFO=1 turns on debugging information
  • modern builds with a more modern compiler, enabling more optimizations and language features.
  • -j$(nproc) calculates how many processors your computer has and then builds using all of them. This will greatly speed up your build.

3. Install the "Remote - WSL" extension for vscode.

4. Open your repository folder in vscode

The folder you should open is named "pokeemerald".

5. Install syntax highlighting extension

There's a vscode extension for syntax highlighting of .inc scripts you can grab here.

6. Add the .vscode folder

This should be an immediate child of the pokeemerald directory. Then create 3 new files inside your new .vscode directory:

  1. c_cpp_properties.json
  2. tasks.json
  3. launch.json

7. c_cpp_properties.json contents

This file is going to tell vscode how to tell us about errors and warnings. It will also enable intelliSense.

{
    "configurations": [
        {
            "name": "GBA",
            "includePath": [
                "${workspaceFolder}",
                "${workspaceFolder}/include",
                "${workspaceFolder}/gflib",
                "${workspaceFolder}/tools/agbcc/include"
            ],
            "defines": [
                "_DEBUG",
                "UNICODE",
                "_UNICODE",
                "DEBUG",
                "DINFO",
                "_MSC_VER"
            ],
            "intelliSenseMode": "gcc-arm",
            "browse": {
                "path": [
                    "${workspaceFolder}"
                ],
                "limitSymbolsToIncludedHeaders": true,
                "databaseFilename": ""
            },        
            "cStandard": "c99",
            "compilerPath": "/opt/devkitpro/devkitARM/bin/arm-none-eabi-gcc"
        }
    ],
    "version": 4
}

8. tasks.json contents

This is where we define our build task, which lets us build directly from vscode.

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "build",
            "type": "shell",
            "command": "make",
            "args": [
                "DINFO=1",
                "modern",
                "-j$(nproc)"
            ],
            "group": {
                "kind": "build",
                "isDefault": true
            },
            "problemMatcher": [
                "$gcc"
            ]
        },
    ]
}

9. launch.json contents

This allows the use of the vscode debugger. Support isn't perfect, but it's still quite powerful.

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Debug",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceRoot}/pokeemerald_modern.elf",
            "args": [
                "target remote ${env:TODAYSIP}:2345"
            ],
            "stopAtEntry": true,
            "cwd": "${workspaceRoot}",
            "environment": [],
            "externalConsole": false,
            "miDebuggerServerAddress": "${env:TODAYSIP}:2345",
            "debugServerArgs": "${workspaceRoot}/pokeemerald_modern.elf -g",
            "serverStarted": "started",
            "preLaunchTask": "${defaultBuildTask}",
            "logging": {
                "moduleLoad": true,
                "trace": true,
                "engineLogging": true,
                "programOutput": true,
                "exceptions": true
            },
            "linux": {
                "MIMode": "gdb",
                "miDebuggerPath": "/opt/devkitpro/devkitARM/bin/arm-none-eabi-gdb",
                "debugServerPath": "${workspaceRoot}/mgba.sh"
            }
        }
    ]
}

10. Get mGBA

It's an emulator that has very good debugging support. Get a copy of it for windows. As of the writing of this article, the latest version for windows is 0.8.3.

11. mGBA wrapper script

In order to attach to a remote debugger, vscode scans stdout of the remote debug server (which mGBA functions as) for a started message as defined by the serverStarted property in launch.json above. mGBA doesn't print anything to stdout, so we need to wrap it in a script that does output something. Put this at the root of your workspace in a file called mgba.sh. Make sure to mark the file as executable after you save it with chmod +x mgba.sh. Also do not use notepad to edit this file; you'll get bad newlines, which bash won't understand. Use something like vim from WSL2 or Notepad++ from Windows.

#!/bin/bash

(
	sleep 4
	echo "started"
)&

/path/to/your/mGBA.exe $1 -g

The $1 will be the rom file as passed in by vscode. -g tells mGBA to immediately start the gdb debug server.

Here you'll have to fill in /path/to/your/mGBA.exe. Since this is a windows application, the path will be in the windows filesystem, which is mounted at /mnt/c.

12. Define $TODAYSIP

Every time WSL2 starts, it gets a new IP address. Since we're debugging over IP, we'll need to know what that address is. Open up ~/.bashrc in your WSL2 home directory and put this line at the bottom:

export TODAYSIP=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2}')

13. Allow PowerShell Scripts

By default, windows does not allow PowerShell scripts to be run. They're quite powerful, and a malicious one can be dangerous and cause serious harm to your system. However, they're also quite useful, and we need to be able to run them to automate the firewall rules. Open your start menu and type "powershell" without the quotes. Don't hit enter; instead, right click on the Windows PowerShell icon and select "Run as administrator". You should have a blue and white terminal open up. Inside that terminal, type Set-ExecutionPolicy RemoteSigned and hit enter. You're all set here now and can close the window.

14. Configure Windows Firewall

By default, all network traffic between WSL2 and Windows is blocked by Windows Firewall. We need to unblock it. In your Windows filesystem, create a file called firewall.ps1 and paste the following contents in:

$remoteport = wsl -- cat /etc/resolv.conf `| grep nameserver
$found = $remoteport -match '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}';

if( $found ){
  $remoteport = $matches[0];
} else{
  echo "cannot determine ip";
  exit;
}

iex "Remove-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' ";

iex "New-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' -Direction Inbound -LocalAddress $remoteport -Action Allow";

This script will add an exception for our debugging network traffic as well as remove any old rules we had since the last time we ran the script. This script needs to be run as administrator, and it needs to be run each time WSL2 starts.

Open Task Scheduler (this is built into Windows) and do the following:

  1. Click Action -> Create Task.
  2. In the General tab, give your task the name "WSL firewall exception".
  3. Still in the General tab, check the box "Run with highest privileges".
  4. In the Triggers tab, click New...
  5. In the Begin the task dropdown, select At log on.
  6. In Advanced settings (about halfway down the dialogue box), check Delay task for: and set it to 30 seconds.
  7. Click OK to go back to the Triggers tab.
  8. In the Actions tab, click New...
  9. Enter "powershell" (without the quotes) as the Program/script.
  10. Enter "-File C:\path\to\your\firewall.ps1" (without the quotes) under Add arguments.
  11. Click OK until all the dialogue boxes are gone.

15. Restart your computer

This will set up the firewall configuration when you log in again. It will also allow vscode to read the changes we made to .bashrc.

16. Install some additional debugging prerequisites.

Run sudo apt-get install libtinfo5 libpython2.7. This will install some libraries necessary for debugging. If apt reports that these are already installed then you're all set.

17. Done!

Now in vscode you should be able to debug by simply pressing F5. Try setting a breakpoint!

18. Bonus section: Set up Porymap

Almost any hack is going to require the use of Porymap. We cannot practically run Porymap directly from WSL2 because it is a graphical application. However running it from Windows mostly just works! Reading and writing files is a bit slow, but that's due to the nature of WSL2, so there's nothing we can do about that.

Open Porymap and select your project. You can navigate to the WSL2 filesystem by manually entering \\wsl$\Ubuntu\path\to\your\pokeemerald.

The next step is to get the "Open Map Scripts" button to work. We could simply set VSCode as our default editor, but this would always open the file from the \\wsl$\Ubuntu path, which is slow and won't ever open in our existing VSCode window.

First, create a new file somewhere in your wsl2 filesystem named wslcode.sh and put the following in it:

#!/bin/bash

echo $@ | sed 's/\\/\//g' | sed 's/\/\/wsl\$\/Ubuntu//' | xargs code

Make sure to chmod +x wslcode.sh so it's executable.

This script will rewrite paths from the Windows version to the Linux version, allowing VSCode to read them via the WSL2 extension.

Now in Porymap, go to Options -> Edit Preferences. For "Open Directory Command", set the value to wsl /path/to/your/wslcode.sh %D. For "Goto Line Command", set the value to wsl /path/to/your/wslcode.sh -r --goto %F:%L. Then click OK and you're done!