Yocto Programming with VSCode: Difference between revisions

From Variscite Wiki
No edit summary
(Add mx6 specific make options)
(14 intermediate revisions by 2 users not shown)
Line 2: Line 2:
--> {{#vardefine:RELEASE_PARAM|{{#urlget:release}}}} <!--
--> {{#vardefine:RELEASE_PARAM|{{#urlget:release}}}} <!--
--> {{#lst:Yocto_Platform_Customization|{{#var:RELEASE_PARAM|RELEASE_DUNFELL_V1.5_DART-MX8M-MINI}}}} <!--
--> {{#lst:Yocto_Platform_Customization|{{#var:RELEASE_PARAM|RELEASE_DUNFELL_V1.5_DART-MX8M-MINI}}}} <!--
SOC Specific Make options
-->{{#vardefine:MAKE_OPTIONS_mx6|-march=armv7-a -mthumb -mfpu=neon -mfloat-abi=hard}}<!--
--> {{PageHeader|{{#var:HARDWARE_NAME}} - Yocto Programming with Visual Studio Code}} {{DocImage|category1={{#var:HARDWARE_NAME}}|category2=Yocto}}
--> {{PageHeader|{{#var:HARDWARE_NAME}} - Yocto Programming with Visual Studio Code}} {{DocImage|category1={{#var:HARDWARE_NAME}}|category2=Yocto}}


Visual Studio Code (VSCode) is a powerful, modern code editor that can be used to develop and debug C/C++ applications on Variscite System on Modules.
Visual Studio Code (VS Code) is a powerful, modern, open-source 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 VSCode on the {{#var:HARDWARE_NAME}}.
This guide demonstrates how to create and debug a C++ application using VS Code on the {{#var:HARDWARE_NAME}}.




__toc__
__toc__
= Create your rootfs with VS Code debug support =
Debugging with VS Code requires your preferred SSH server (openssh, dropbear, etc), gdb, and gdbserver installed on the target device. Append the following to the conf/local.conf file in your Yocto build directory:
EXTRA_IMAGE_FEATURES = " \
    tools-debug \
    ssh-server-dropbear \
    "
Now bitbake your image.


= Setup Host Computer Environment =
= Setup Host Computer Environment =


Please follow the steps below to prepare a fresh Ubuntu 20.04 installation for VSCode debugging:
Please follow the steps below to prepare a fresh Ubuntu 20.04 installation for VS Code debugging:


== Install Dependencies ==
== Install Dependencies ==
Line 20: Line 36:
  $ sudo apt-get -y install build-essential gdb gdb-multiarch git
  $ sudo apt-get -y install build-essential gdb gdb-multiarch git


== Install VSCode ==
== Install VS Code ==


  $ sudo snap install --classic code
  $ sudo snap install --classic code


== Install VSCode Extensions ==
== Install VS Code Extensions ==


VSCode has a graphical interface for installing and managing extensions. To learn more, please see [https://code.visualstudio.com/docs/introvideos/extend Using extensions in Visual Studio Code]
VS Code has a graphical interface for installing and managing extensions. To learn more, please see [https://code.visualstudio.com/docs/introvideos/extend Using extensions in Visual Studio Code]


For this guide, we will install the required extensions using the command line:
For this guide, we will install the required extensions using the command line:
Line 38: Line 54:
= Create, cross compile, and run a new "Hello, World!" project =
= Create, cross compile, and run a new "Hello, World!" project =


First, open a new terminal and configure the environment with the toolchain setup script:
Open a new terminal, create an empty project directory and open VS Code:
 
$ source {{#var:TOOLCHAIN_LOCATION}}
 
From the same terminal, create an empty project directory and open VSCode:


  $ mkdir ~/var-hello-world
  $ mkdir ~/var-hello-world
Line 48: Line 60:
  $ code .
  $ code .


This will launch VSCode with ''~/var-hello-world'' as working directory (which is currently empty):
This will launch VS Code with ''~/var-hello-world'' as working directory (which is currently empty):


[[File:Vscode_start.png]]
[[File:Vscode_start.png]]
Line 56: Line 68:
{| class="wikitable"
{| class="wikitable"
|-
|-
|'''main.cpp''' || Source code for hello.bin
|'''main.cpp''' || Source code for the demo program '''hello.bin'''
|-
|-
|'''Makefile''' || Makefile to cross compile '''main.cpp'''
|'''Makefile''' || Makefile to cross compile '''main.cpp''' to '''hello.bin'''
|-
|-
|'''.vscode/tasks.json''' || VSCode file to override or add new tasks. Runs <code>Makefile</code> when VSCode build command is executed.
|'''.vscode/settings.json''' || VS Code file to configure global environment variables for the SDK/toolchain
|-
|-
|'''.vscode/c_cpp_properties.json''' || VSCode file to configure include path for IntelliSense.
|'''.vscode/tasks.json''' || VS Code file to override or add new tasks. Runs <code>Makefile</code> 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''':
To create a new file or folder in VSCode, right click in the VSCode explorer view and select '''New File''' or '''New Folder''':


[[File:Vscode_start_newfile.png]]
[[File:Vscode_start_newfile.png]]
Line 84: Line 97:
'''Makefile:'''
'''Makefile:'''
  all: main.cpp
  all: main.cpp
  $(CXX) $(CXXFLAGS) -Og main.cpp -g -o hello.bin
  $(CXX) $(CXXFLAGS) -Og main.cpp -g -o hello.bin {{#var:MAKE_OPTIONS_{{#var:SOC}}}}
  clean:
  clean:
  rm -f hello.bin
  rm -f hello.bin


Create a new folder named '''.vscode'''. Then, create a new file '''.vscode/tasks.json'''
Create a new folder named '''.vscode'''. Then, create a new file '''.vscode/settings.json'''
 
'''.vscode/settings.json:'''
{
"VARISCITE": {
/* Target Device Settings */
"TARGET_IP":"192.168.0.141",
/* Project Settings */
"PROGRAM":"hello.bin",
/* Yocto SDK Configuration */
"ARCH":"{{#var:TOOLCHAIN_TYPE}}",
"OECORE_NATIVE_SYSROOT":"{{#var:TOOLCHAIN_HOST_SYSROOT_LOCATION}}",
"SDKTARGETSYSROOT": "{{#var:TOOLCHAIN_TARGET_SYSROOT_LOCATION}}",
/* Yocto SDK Constants */
"CC_PREFIX": "${config:VARISCITE.OECORE_NATIVE_SYSROOT}/usr/bin/${config:VARISCITE.ARCH}/${config:VARISCITE.ARCH}-",
"CXX": "${config:VARISCITE.CC_PREFIX}g++ --sysroot=${config:VARISCITE.SDKTARGETSYSROOT}",
"CC": "${config:VARISCITE.CC_PREFIX}gcc --sysroot=${config:VARISCITE.SDKTARGETSYSROOT}",
}
}
 
The table below describes the global variables in settings.json. They can be accessed in other json files, for example ''${config:VARISCITE.TARGET_IP}'':
 
{| class="wikitable"
|-
|'''TARGET_IP''' || The IP Address of the {{#var:HARDWARE_NAME}} target device
|-
|'''PROGRAM''' || Must match the name of the binary generated by Makefile
|-
|'''ARCH''' || Architecture prefix for gcc, g++, gdb, etc. Align with CXX variable set by {{#var:TOOLCHAIN_LOCATION}}
|-
|'''OECORE_NATIVE_SYSROOT''' || Align with OECORE_NATIVE_SYSROOT variable set by {{#var:TOOLCHAIN_LOCATION}}
|-
|'''SDKTARGETSYSROOT''' || Align with SDKTARGETSYSROOT variable set by {{#var:TOOLCHAIN_LOCATION}}
|-
|'''CC_PREFIX''' || Full path to toolchain gcc, g++, etc binaries.
|-
|'''CXX''' || Path to cross g++ binary and sysroot
|-
|'''CC''' || Path to cross gcc binary and sysroot
|}
 
Create a new file '''.vscode/tasks.json'''. tasks.json has three root objects:
 
* '''options:''' Define CC and CXX environment variables for the Makefile.
* '''presentation:''' Configures the behavior of VS Code's integrated Terminal for all tasks.
* '''tasks:''' An array of task configurations. The example below creates a single 'build'' task that runs the Makefile when the VS Code build task is executed.


'''.vscode/tasks.json:'''
'''.vscode/tasks.json:'''
  {
  {
     "version": "2.0.0",
     "version": "2.0.0",
     "tasks": [{
    /* Configure Yocto SDK Constants from settings.json */
        "label": "build",
    "options": {
        "type": "shell",
        "env": {
        "command": "make clean; make -j$(nproc)",
            "CXX": "${config:VARISCITE.CXX}",        /* Used by Makefile */
        "problemMatcher": [],
            "CC": "${config:VARISCITE.CC}",          /* Used by Makefile */
     }]
        }
      },
      /* Configure integrated VS Code Terminal */
      "presentation": {
        "echo": false,
        "reveal": "always",
        "focus": true,
        "panel": "dedicated",
        "showReuseMessage": true,
    },
     "tasks": [
        /* Configure Build Task */
        {
            "label": "build",
            "type": "shell",
            "command": "make clean; make -j$(nproc)",
            "problemMatcher": ["$gcc"]
        },
     ]
  }
  }


Configure the include path for IntelliSense by creating '''vscode/c_cpp_properties.json'''.
Create '''vscode/c_cpp_properties.json''' to configure the include path for IntelliSense.


'''vscode/c_cpp_properties.json:'''
'''.vscode/c_cpp_properties.json:'''


  {
  {
Line 111: Line 190:
             "includePath": [
             "includePath": [
                 "${workspaceFolder}/**",
                 "${workspaceFolder}/**",
                 "${SDKTARGETSYSROOT}/usr/include/"
                 "${config:VARISCITE.SDKTARGETSYSROOT}/usr/include/**"
             ]
             ]
         }
         }
Line 121: Line 200:
Your workspace should look similar to this:
Your workspace should look similar to this:


[[File:vscode-gdb-build.png]]
[[File:vscode-gdb-build-2.png]]


Compile the project by selecting '''Terminal->Run Build Task...''' or entering <code>Ctrl+Shift+B</code> and selecting '''Build''':
Cross compile the project by selecting '''Terminal->Run Build Task...''' or entering <code>Ctrl+Shift+B</code> and selecting '''Build''':


[[File:vscode_run_build_task.png]]
[[File:vscode_run_build_task_2.png]]


Open a new VSCode terminal by selecting '''Terminal->New Terminal''' or entering <code>Ctrl+Shift+`</code>.
Open a new VS Code terminal by selecting '''Terminal->New Terminal''' or entering <code>Ctrl+Shift+`</code>.


Send '''hello.bin''' to the target device using SCP:
Deploy '''hello.bin''' to the target device using SCP:


  $ scp hello.bin root@<ip addr>:/home/root/
  $ scp hello.bin root@<ip addr>:/home/root/


[[File:Vscode_new_terminal.png]]
[[File:Vscode_new_terminal_2.png]]


Launch '''hello.bin''' on the target device:
Launch '''hello.bin''' on the target device:
Line 140: Line 219:
  Hello, World!
  Hello, World!


= Remote Debugging with VSCode =
= Remote Debugging with VS Code =


After verifying hello.bin runs on the target device, we can now setup VSCode for remote debugging.
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:
The working directory should currently have these files:


  variscite@ubuntu:~/var-hello-world$ find  
  variscite@ubuntu:~/var-hello-world$ find  
  ./.vscode/tasks.json
  .vscode/settings.json
.vscode/tasks.json
  ./Makefile
  ./Makefile
  ./main.cpp
  ./main.cpp
  ./hello.bin
  ./hello.bin


To enable debugging, ww will edit '''.vscode/tasks.json''' and add two additional files to the project:
To enable debugging, we will edit '''.vscode/tasks.json''' to add a ''var-deploy-gdb'' debug task and add two additional files to the project:


{| class="wikitable"
{| class="wikitable"
|-
|-
|'''var-build-and-debug.sh''' || Generic script to build, deploy, and launch gdbserver
|'''var-deploy-gdb.sh''' || Generic script to deploy and launch gdbserver
|-
|-
|'''.vscode/launch.json''' || VSCode file to configure debug settings. Runs <code>var-build-and-debug</code> in tasks.json
|'''.vscode/launch.json''' || VS Code file to configure debug settings. Runs <code>var-build-and-debug</code> in tasks.json
|-
|-
|'''.vscode/tasks.json''' || Edit to call <code>var-debug-and-debug.sh</code> prior to debugging.
|'''.vscode/tasks.json''' || Edit to call <code>var-deploy-gdb.sh</code> prior to debugging.
|}
|}




== Create var-build-and-debug.sh ==
== Create var-deploy-gdb.sh ==


First, add a generic script to build, deploy, and launch gdbserver. The script requires two arguments:
First, add a generic script deploy a program and launch gdbserver. The script requires two arguments:


# <code>TARGET_IP</code>: The IP Address of the target device
# <code>TARGET_IP</code>: The IP Address of the target device
Line 173: Line 253:
In the end, tasks.json will run this script at the beginning of each debug session.
In the end, tasks.json will run this script at the beginning of each debug session.


'''var-build-and-debug.sh:'''
'''var-deploy-gdb.sh:'''
  #!/bin/bash
  #!/bin/bash
  readonly TARGET_IP="$1"
  readonly TARGET_IP="$1"
Line 179: Line 259:
  readonly TARGET_DIR="/home/root"
  readonly TARGET_DIR="/home/root"
   
   
  # rebuild project
  # Must match startsPattern in tasks.json
  make clean; make -j$(nproc)
  echo "Deploying to target"
   
   
  # kill gdbserver on target
  # kill gdbserver on target and delete old binary
  ssh root@${TARGET_IP} "sh -c '/usr/bin/killall -q gdbserver; exit 0'"
  ssh root@${TARGET_IP} "sh -c '/usr/bin/killall -q gdbserver; rm -rf ${TARGET_DIR}/${PROGRAM}  exit 0'"
   
   
  # send the program to the target
  # send the program to the target
  scp ${PROGRAM} root@${TARGET_IP}:${TARGET_DIR}
  scp ${PROGRAM} root@${TARGET_IP}:${TARGET_DIR}
# Must match endsPattern in tasks.json
echo "Starting GDB Server on Target"
   
   
  # start gdbserver on target
  # start gdbserver on target
  REMOTE_GDB_CMD="ssh -t root@${TARGET_IP} \"sh -c 'cd ${TARGET_DIR}; gdbserver localhost:3000 ${PROGRAM}'\""
  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 ==
== Create launch.json ==


VSCode has a powerful built in debugger capable of debugging many programming languages. In this step, we will add a configuration for debugging CPP:
VS Code has a powerful built in debugger capable of debugging many programming languages. In this step, we will add a configuration for debugging using the C/C++ extension:


'''.vscode/launch.json:'''
'''.vscode/launch.json:'''
Line 203: Line 285:
         "type": "cppdbg",
         "type": "cppdbg",
         "request": "launch",
         "request": "launch",
         "program": "hello.bin",
         "program": "${config:VARISCITE.PROGRAM}",
         "args": [],
         "args": [],
         "stopAtEntry": true,
         "stopAtEntry": true,
Line 211: Line 293:
         "MIMode": "gdb",
         "MIMode": "gdb",
         "targetArchitecture": "arm64",
         "targetArchitecture": "arm64",
         "preLaunchTask": "var-build-and-debug",
         "preLaunchTask": "var-deploy-gdb",
         "setupCommands": [{
         "setupCommands": [{
             "description": "Enable pretty-printing for gdb",
             "description": "Enable pretty-printing for gdb",
Line 218: Line 300:
         }],
         }],
         "miDebuggerPath": "/usr/bin/gdb-multiarch",
         "miDebuggerPath": "/usr/bin/gdb-multiarch",
         "miDebuggerServerAddress": "192.168.0.118:3000",
         "miDebuggerServerAddress": "${config:VARISCITE.TARGET_IP}:3000",
     }]
     }]
  }
  }
Line 234: Line 316:




== Create tasks.json ==
== Edit tasks.json ==


In <code>launch.json</code>, we created a <code>preLaunchTask</code> to run a task named <code>var-build-and-debug</code> at the beginning of each debugging session. This task is configured by adding a new task to '''.vscode/tasks.json''':
In <code>launch.json</code>, we created a <code>preLaunchTask</code> to run a task named <code>var-deploy-gdb</code> at the beginning of each debugging session. This task is configured by adding a new task '''var-deploy-gdb''' to '''.vscode/tasks.json''':


'''.vscode/tasks.json:'''
'''.vscode/tasks.json:'''
  {
  {
     "version": "2.0.0",
     "version": "2.0.0",
     "tasks": [{
    /* Configure Yocto SDK Constants from settings.json */
        "label": "var-build-and-debug",
    "options": {
        "type": "shell",
        "env": {
        "command": "sh",
            "CXX": "${config:VARISCITE.CXX}",
        "args": [
            "CC": "${config:VARISCITE.CC}",
            "var-build-and-debug.sh",
        }
            "192.168.0.118",
      },
             "hello.bin"
      /* Configure integrated VS Code Terminal */
        ],
      "presentation": {
    },{
        "echo": false,
        "label": "build",
        "reveal": "always",
        "type": "shell",
        "focus": true,
        "command": "make clean; make -j$(nproc)",
        "panel": "dedicated",
        "problemMatcher": [],
        "showReuseMessage": true,
     }]
    },
     "tasks": [
        /* Configure launch.json (debug) preLaunchTask Task */
        {
            "label": "var-deploy-gdb",
            "isBackground": true,
            "problemMatcher":{
                "base": "$gcc",
                "background": {
                    "activeOnStart": true,
                    "beginsPattern":  "Deploying to target",
                    "endsPattern":  "Starting GDB Server on Target"
                }
            },
            "type": "shell",
            "command": "sh",
            "args": [
                "var-deploy-gdb.sh",
                "${config:VARISCITE.TARGET_IP}",
                "${config:VARISCITE.PROGRAM}"
            ],
             "dependsOn": ["build"],
        },
        /* Configure Build Task */
        {
            "label": "build",
            "type": "shell",
            "command": "make clean; make -j$(nproc)",
            "problemMatcher": ["$gcc"]
        },
     ]
  }
  }


The following table summarizes the var-build-and-debug configuration in tasks.json:
 
The following table summarizes the var-deploy-gdb configuration in tasks.json:


{| class="wikitable"
{| class="wikitable"
Line 268: Line 381:
|<code>command</code> || Launch <code>sh</code>, with arguments <code>var-build-and-debug.sh 192.168.0.136 hello.bin</code>
|<code>command</code> || Launch <code>sh</code>, with arguments <code>var-build-and-debug.sh 192.168.0.136 hello.bin</code>
|}
|}
Note: The IP Address must match the IP address of the target device, as defined in '''.vscode/launch.json'''


== Launch a Debugging Session ==
== Launch a Debugging Session ==
Line 276: Line 387:


  ~/var-hello-world$ find
  ~/var-hello-world$ find
  ./.vscode/launch.json
  .vscode/c_cpp_properties.json
  ./.vscode/tasks.json
.vscode/launch.json
  .vscode/settings.json
.vscode/tasks.json
  ./Makefile
  ./Makefile
  ./var-build-and-debug.sh
  ./var-deploy-gdb.sh
  ./main.cpp
  ./main.cpp
  ./hello.bin
  ./hello.bin


A new debugging session can be started by selecting '''Run->Start Debugging''' or by pressing 'F5' on the keyboard. Please click on the image below for a real time debugging demonstration:
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:
 
[[File:Vscode_debug_2.png]]


= Example Project Source Code =
= Example Project Source Code =
Line 289: Line 404:
The source code for this example is available from Variscite's Github repository:
The source code for this example is available from Variscite's Github repository:


  $ git clone https://github.com/nsdrude-varigit/var-demos
  $ git clone https://github.com/varigit/var-demos
  $ cd var-demos/hello-world
  $ cd var-demos/vscode-demos/hello-world
 
Setup the toolchain environment:
 
$ source {{#var:TOOLCHAIN_LOCATION}}


Launch VSCode:
Launch VS Code:


  $ code .
  $ code .


Configure the target device IP Address in '''.vscode/tasks.json''' and '''.vscode/launch.json'''
Configure the target device IP Address and SDK variables in '''.vscode/settings.json'''


Finally, start a debugging session by selecting '''Run->Start Debugging''' or pressing 'F5' on the keyboard.
Finally, start a debugging session by selecting '''Run->Start Debugging''' or pressing 'F5' on the keyboard.

Revision as of 15:42, 14 October 2021

DART-MX8M-MINI - Yocto Programming with Visual Studio Code

Visual Studio Code (VS Code) is a powerful, modern, open-source 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.


Create your rootfs with VS Code debug support

Debugging with VS Code requires your preferred SSH server (openssh, dropbear, etc), gdb, and gdbserver installed on the target device. Append the following to the conf/local.conf file in your Yocto build directory:

EXTRA_IMAGE_FEATURES = " \
    tools-debug \
    ssh-server-dropbear \
    "

Now bitbake your image.

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

Open a new 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):

Vscode start.png

Next, we will create the following files:

main.cpp Source code for the demo program hello.bin
Makefile Makefile to cross compile main.cpp to hello.bin
.vscode/settings.json VS Code file to configure global environment variables for the SDK/toolchain
.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:

Vscode start newfile.png

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/settings.json

.vscode/settings.json:

{
	"VARISCITE": {
		/* Target Device Settings */
		"TARGET_IP":"192.168.0.141",

		/* Project Settings */
		"PROGRAM":"hello.bin",

		/* Yocto SDK Configuration */
		"ARCH":"aarch64-fslc-linux",
		"OECORE_NATIVE_SYSROOT":"/opt/fslc-xwayland/3.1/sysroots/x86_64-fslcsdk-linux",
		"SDKTARGETSYSROOT": "/opt/fslc-xwayland/3.1/sysroots/aarch64-fslc-linux",

		/* Yocto SDK Constants */
		"CC_PREFIX": "${config:VARISCITE.OECORE_NATIVE_SYSROOT}/usr/bin/${config:VARISCITE.ARCH}/${config:VARISCITE.ARCH}-",
		"CXX": "${config:VARISCITE.CC_PREFIX}g++ --sysroot=${config:VARISCITE.SDKTARGETSYSROOT}",
		"CC": "${config:VARISCITE.CC_PREFIX}gcc --sysroot=${config:VARISCITE.SDKTARGETSYSROOT}",
	}
}

The table below describes the global variables in settings.json. They can be accessed in other json files, for example ${config:VARISCITE.TARGET_IP}:

TARGET_IP The IP Address of the DART-MX8M-MINI target device
PROGRAM Must match the name of the binary generated by Makefile
ARCH Architecture prefix for gcc, g++, gdb, etc. Align with CXX variable set by /opt/fslc-xwayland/3.1/environment-setup-aarch64-fslc-linux
OECORE_NATIVE_SYSROOT Align with OECORE_NATIVE_SYSROOT variable set by /opt/fslc-xwayland/3.1/environment-setup-aarch64-fslc-linux
SDKTARGETSYSROOT Align with SDKTARGETSYSROOT variable set by /opt/fslc-xwayland/3.1/environment-setup-aarch64-fslc-linux
CC_PREFIX Full path to toolchain gcc, g++, etc binaries.
CXX Path to cross g++ binary and sysroot
CC Path to cross gcc binary and sysroot

Create a new file .vscode/tasks.json. tasks.json has three root objects:

  • options: Define CC and CXX environment variables for the Makefile.
  • presentation: Configures the behavior of VS Code's integrated Terminal for all tasks.
  • tasks: An array of task configurations. The example below creates a single 'build task that runs the Makefile when the VS Code build task is executed.

.vscode/tasks.json:

{
    "version": "2.0.0",
    /* Configure Yocto SDK Constants from settings.json */
    "options": {
        "env": {
            "CXX": "${config:VARISCITE.CXX}",         /* Used by Makefile */
            "CC": "${config:VARISCITE.CC}",           /* Used by Makefile */
        }
     },
     /* Configure integrated VS Code Terminal */
     "presentation": {
        "echo": false,
        "reveal": "always",
        "focus": true,
        "panel": "dedicated",
        "showReuseMessage": true,
    },
    "tasks": [
        /* Configure Build Task */
        {
            "label": "build",
            "type": "shell",
            "command": "make clean; make -j$(nproc)",
            "problemMatcher": ["$gcc"]
        },
    ]
}

Create vscode/c_cpp_properties.json to configure the include path for IntelliSense.

.vscode/c_cpp_properties.json:

{
    "configurations": [
        {
            "name": "Linux",
            "includePath": [
                "${workspaceFolder}/**",
                "${config:VARISCITE.SDKTARGETSYSROOT}/usr/include/**"
            ]
        }
    ],
    "version": 4
}


Your workspace should look similar to this:

Vscode-gdb-build-2.png

Cross compile the project by selecting Terminal->Run Build Task... or entering Ctrl+Shift+B and selecting Build:

Vscode run build task 2.png

Open a new VS Code terminal by selecting Terminal->New Terminal or entering Ctrl+Shift+`.

Deploy hello.bin to the target device using SCP:

$ scp hello.bin root@<ip addr>:/home/root/

Vscode new terminal 2.png

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/settings.json
.vscode/tasks.json
./Makefile
./main.cpp
./hello.bin

To enable debugging, we will edit .vscode/tasks.json to add a var-deploy-gdb debug task and add two additional files to the project:

var-deploy-gdb.sh Generic script to 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-deploy-gdb.sh prior to debugging.


Create var-deploy-gdb.sh

First, add a generic script deploy a program and launch gdbserver. The script requires two arguments:

  1. TARGET_IP: The IP Address of the target device
  2. PROGRAM: 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-deploy-gdb.sh:

#!/bin/bash
readonly TARGET_IP="$1"
readonly PROGRAM="$2"
readonly TARGET_DIR="/home/root"

# Must match startsPattern in tasks.json
echo "Deploying to target"

# kill gdbserver on target and delete old binary
ssh root@${TARGET_IP} "sh -c '/usr/bin/killall -q gdbserver; rm -rf ${TARGET_DIR}/${PROGRAM}  exit 0'"

# send the program to the target
scp ${PROGRAM} root@${TARGET_IP}:${TARGET_DIR}

# Must match endsPattern in tasks.json
echo "Starting GDB Server on Target"

# start gdbserver on target
ssh -t root@${TARGET_IP} "sh -c 'cd ${TARGET_DIR}; gdbserver localhost:3000 ${PROGRAM}'"

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 using the C/C++ extension:

.vscode/launch.json:

{
    "version": "0.2.0",
    "configurations": [{
        "name": "GDB debug",
        "type": "cppdbg",
        "request": "launch",
        "program": "${config:VARISCITE.PROGRAM}",
        "args": [],
        "stopAtEntry": true,
        "cwd": "${workspaceFolder}",
        "environment": [],
        "console": "integratedTerminal",
        "MIMode": "gdb",
        "targetArchitecture": "arm64",
        "preLaunchTask": "var-deploy-gdb",
        "setupCommands": [{
            "description": "Enable pretty-printing for gdb",
            "text": "-enable-pretty-printing",
            "ignoreFailures": true
        }],
        "miDebuggerPath": "/usr/bin/gdb-multiarch",
        "miDebuggerServerAddress": "${config:VARISCITE.TARGET_IP}: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


Edit tasks.json

In launch.json, we created a preLaunchTask to run a task named var-deploy-gdb at the beginning of each debugging session. This task is configured by adding a new task var-deploy-gdb to .vscode/tasks.json:

.vscode/tasks.json:

{
    "version": "2.0.0",
    /* Configure Yocto SDK Constants from settings.json */
    "options": {
        "env": {
            "CXX": "${config:VARISCITE.CXX}",
            "CC": "${config:VARISCITE.CC}",
        }
     },
     /* Configure integrated VS Code Terminal */
     "presentation": {
        "echo": false,
        "reveal": "always",
        "focus": true,
        "panel": "dedicated",
        "showReuseMessage": true,
    },
    "tasks": [
        /* Configure launch.json (debug) preLaunchTask Task */
        {
            "label": "var-deploy-gdb",
            "isBackground": true,
            "problemMatcher":{
                "base": "$gcc",
                "background": {
                    "activeOnStart": true,
                    "beginsPattern":  "Deploying to target",
                    "endsPattern":  "Starting GDB Server on Target"
                }
            },
            "type": "shell",
            "command": "sh",
            "args": [
                "var-deploy-gdb.sh",
                "${config:VARISCITE.TARGET_IP}",
                "${config:VARISCITE.PROGRAM}"
            ],
            "dependsOn": ["build"],
        },
        /* Configure Build Task */
        {
            "label": "build",
            "type": "shell",
            "command": "make clean; make -j$(nproc)",
            "problemMatcher": ["$gcc"]
        },
    ]
}


The following table summarizes the var-deploy-gdb 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

Launch a Debugging Session

After following the steps above, the working directory should now have these files:

~/var-hello-world$ find
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/settings.json
.vscode/tasks.json
./Makefile
./var-deploy-gdb.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:

Vscode debug 2.png

Example Project Source Code

The source code for this example is available from Variscite's Github repository:

$ git clone https://github.com/varigit/var-demos
$ cd var-demos/vscode-demos/hello-world

Launch VS Code:

$ code .

Configure the target device IP Address and SDK variables in .vscode/settings.json

Finally, start a debugging session by selecting Run->Start Debugging or pressing 'F5' on the keyboard.