Yocto Programming with VSCode
Visual Studio Code (VS Code) is a powerful, modern code editor that can be used to develop and debug C/C++ applications on Variscite System on Modules.
This guide demonstrates how to create and debug a C++ application using VS Code on the DART-MX8M-MINI.
Setup Host Computer Environment
Please follow the steps below to prepare a fresh Ubuntu 20.04 installation for VS Code debugging:
Install Dependencies
$ sudo apt-get -y update $ sudo apt-get -y install build-essential gdb gdb-multiarch git
Install VS Code
$ sudo snap install --classic code
Install VS Code Extensions
VS Code has a graphical interface for installing and managing extensions. To learn more, please see Using extensions in Visual Studio Code
For this guide, we will install the required extensions using the command line:
$ code --install-extension ms-vscode.cpptools
Install Yocto Toolchain
A toolchain is necessary for cross compiling applications. To install the toolchain, follow Variscite's Yocto Toolchain installation guide.
Create, cross compile, and run a new "Hello, World!" project
First, open a new terminal and configure the environment with the toolchain setup script:
$ source /opt/fslc-xwayland/3.1/environment-setup-aarch64-fslc-linux
From the same terminal, create an empty project directory and open VS Code:
$ mkdir ~/var-hello-world $ cd ~/var-hello-world $ code .
This will launch VS Code with ~/var-hello-world as working directory (which is currently empty):
Next, we will create the following files:
main.cpp | Source code for hello.bin |
Makefile | Makefile to cross compile main.cpp |
.vscode/tasks.json | VS Code file to override or add new tasks. Runs Makefile when VS Code build command is executed.
|
.vscode/c_cpp_properties.json | VS Code file to configure include path for IntelliSense. |
To create a new file or folder in VS Code, right click in the VS Code explorer view and select New File or New Folder:
Create a new file called main.cpp:
main.cpp:
#include <stdio.h> int main(int argc, char *argv[]) { printf("Hello, World!\n"); return 0; }
Create a new Makefile to build hello.bin:
Makefile:
all: main.cpp $(CXX) $(CXXFLAGS) -Og main.cpp -g -o hello.bin clean: rm -f hello.bin
Create a new folder named .vscode. Then, create a new file .vscode/tasks.json
.vscode/tasks.json:
{ "version": "2.0.0", "tasks": [{ "label": "build", "type": "shell", "command": "make clean; make -j$(nproc)", "problemMatcher": [], }] }
Configure the include path for IntelliSense by creating vscode/c_cpp_properties.json.
.vscode/c_cpp_properties.json:
{ "configurations": [ { "name": "Linux", "includePath": [ "${workspaceFolder}/**", "${SDKTARGETSYSROOT}/usr/include/" ] } ], "version": 4 }
Your workspace should look similar to this:
Compile the project by selecting Terminal->Run Build Task... or entering Ctrl+Shift+B
and selecting Build:
Open a new VS Code terminal by selecting Terminal->New Terminal or entering Ctrl+Shift+`
.
Send hello.bin to the target device using SCP:
$ scp hello.bin root@<ip addr>:/home/root/
Launch hello.bin on the target device:
# ./hello.bin Hello, World!
Remote Debugging with VS Code
After verifying hello.bin runs on the target device, we can now setup VS Code for remote debugging.
The working directory should currently have these files:
variscite@ubuntu:~/var-hello-world$ find ./.vscode/tasks.json ./Makefile ./main.cpp ./hello.bin
To enable debugging, ww will edit .vscode/tasks.json and add two additional files to the project:
var-build-and-debug.sh | Generic script to build, deploy, and launch gdbserver |
.vscode/launch.json | VS Code file to configure debug settings. Runs var-build-and-debug in tasks.json
|
.vscode/tasks.json | Edit to call var-debug-and-debug.sh prior to debugging.
|
Create var-build-and-debug.sh
First, add a generic script to build, deploy, and launch gdbserver. The script requires two arguments:
TARGET_IP
: The IP Address of the target devicePROGRAM
: The name of the binary executable,hello.bin
in this example
In the end, tasks.json will run this script at the beginning of each debug session.
var-build-and-debug.sh:
#!/bin/bash readonly TARGET_IP="$1" readonly PROGRAM="$2" readonly TARGET_DIR="/home/root" # rebuild project make clean; make -j$(nproc) # kill gdbserver on target ssh root@${TARGET_IP} "sh -c '/usr/bin/killall -q gdbserver; exit 0'" # send the program to the target scp ${PROGRAM} root@${TARGET_IP}:${TARGET_DIR} # start gdbserver on target REMOTE_GDB_CMD="ssh -t root@${TARGET_IP} \"sh -c 'cd ${TARGET_DIR}; gdbserver localhost:3000 ${PROGRAM}'\"" gnome-terminal -x bash -c "${REMOTE_GDB_CMD}"
Create launch.json
VS Code has a powerful built in debugger capable of debugging many programming languages. In this step, we will add a configuration for debugging CPP:
.vscode/launch.json:
{ "version": "0.2.0", "configurations": [{ "name": "GDB debug", "type": "cppdbg", "request": "launch", "program": "hello.bin", "args": [], "stopAtEntry": true, "cwd": "${workspaceFolder}", "environment": [], "console": "integratedTerminal", "MIMode": "gdb", "targetArchitecture": "arm64", "preLaunchTask": "var-build-and-debug", "setupCommands": [{ "description": "Enable pretty-printing for gdb", "text": "-enable-pretty-printing", "ignoreFailures": true }], "miDebuggerPath": "/usr/bin/gdb-multiarch", "miDebuggerServerAddress": "192.168.0.118:3000", }] }
See the table below for important details regarding launch.json variables:
miDebuggerServerAddress |
Must match the IP Address of the target device |
program |
Must match the name of the binary generated by the the Makefile |
preLaunchTask |
Must match the name of the task in .vscode/tasks.json in the following step
|
Create tasks.json
In launch.json
, we created a preLaunchTask
to run a task named var-build-and-debug
at the beginning of each debugging session. This task is configured by adding a new task to .vscode/tasks.json:
.vscode/tasks.json:
{ "version": "2.0.0", "tasks": [{ "label": "var-build-and-debug", "type": "shell", "command": "sh", "args": [ "var-build-and-debug.sh", "192.168.0.118", "hello.bin" ], },{ "label": "build", "type": "shell", "command": "make clean; make -j$(nproc)", "problemMatcher": [], }] }
The following table summarizes the var-build-and-debug configuration in tasks.json:
label |
Must match preLaunchTask in launch.json |
type |
This task will launch a shell |
command |
Launch sh , with arguments var-build-and-debug.sh 192.168.0.136 hello.bin
|
Note: The IP Address must match the IP address of the target device, as defined in .vscode/launch.json
Launch a Debugging Session
After following the steps above, the working directory should now have these files:
~/var-hello-world$ find ./.vscode/launch.json ./.vscode/tasks.json ./Makefile ./var-build-and-debug.sh ./main.cpp ./hello.bin
A new debugging session can be started by selecting Run->Start Debugging or by pressing 'F5' on the keyboard. VS Code will switch to the debug perspective and launch a gnome-terminal running gdbserver on the target device:
Example Project Source Code
The source code for this example is available from Variscite's Github repository:
$ git clone https://github.com/nsdrude-varigit/var-demos $ cd var-demos/hello-world
Setup the toolchain environment:
$ source /opt/fslc-xwayland/3.1/environment-setup-aarch64-fslc-linux
Launch VS Code:
$ code .
Configure the target device IP Address in .vscode/tasks.json and .vscode/launch.json
Finally, start a debugging session by selecting Run->Start Debugging or pressing 'F5' on the keyboard.