Yocto Programming with VSCode: Difference between revisions
(47 intermediate revisions by 4 users not shown) | |||
Line 1: | Line 1: | ||
<!-- Set release according to "release" parameter in URL and use RELEASE_DUNFELL_V1.5_DART-MX8M-MINI as default | <!-- Set release according to "release" parameter in URL and use RELEASE_DUNFELL_V1.5_DART-MX8M-MINI as default | ||
--> {{ | --> {{INIT_RELEASE_PARAM|RELEASE_DUNFELL_V1.5_DART-MX8M-MINI}}<!-- | ||
--> {{#lst:Yocto_Platform_Customization|{{#var:RELEASE_PARAM | --> {{#lst:Yocto_Platform_Customization|{{#var:RELEASE_PARAM}}}} <!-- | ||
--> {{ | --> {{#lst:B2QT_Platform_Customization|{{#var:RELEASE_PARAM}}}} <!-- | ||
--> {{#lst:Debian_Platform_Customization|{{#var:RELEASE_PARAM}}}} <!-- | |||
Platform-specific variables | |||
--> {{#vardefine:PLATFORM_OS|Yocto}} <!-- Yocto specific variables (default) | |||
--> {{#vardefine:TOOLCHAIN_SYSROOT_PATH|{{#var:TOOLCHAIN_TARGET_SYSROOT_LOCATION}}}} <!-- | |||
--> {{#vardefine:TARGET_ROOT_HOME|/home/root}} <!-- | |||
--> {{#varexists:DEBIAN_NAME| <!-- Debian specific variables | |||
--> {{#vardefine:PLATFORM_OS|Debian}} <!-- | |||
--> {{#vardefine:TOOLCHAIN_TYPE|{{#sub:{{#var:CROSS_COMPILE}}|0|{{#expr:{{#Len:{{#var:CROSS_COMPILE}}}}-1}}}}}} <!-- | |||
--> {{#vardefine:CROSS_COMPILER_PATH|/home/user/{{#var:BUILD_FOLDER_NAME}}/toolchain/{{#var:TOOLCHAIN}}}} <!-- | |||
--> {{#vardefine:TOOLCHAIN_SYSROOT_PATH|/home/user/{{#var:BUILD_FOLDER_NAME}}/toolchain/sysroot}} <!-- | |||
--> {{#vardefine:TARGET_ROOT_HOME|/root}} <!-- | |||
--> }} <!-- | |||
This guide demonstrates how to create and debug a C++ application using | SOC Specific Make options | ||
-->{{#vardefine:MAKE_OPTIONS_mx6|-march=armv7-a -mthumb -mfpu=neon -mfloat-abi=hard}}<!-- | |||
--> {{PageHeader|{{#var:HARDWARE_NAME}} - {{#var:PLATFORM_OS}} Programming with Visual Studio Code}} {{DocImage|category1=Yocto|category2=Debian}} [[category:{{#var:HARDWARE_NAME}}]] | |||
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 {{#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. | |||
{{#switch:{{#var:PLATFORM_OS}} | |||
| Yocto= | |||
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. | |||
| Debian= | |||
The packages can be installed by running the following commands on the target: | |||
# apt-get update | |||
# apt-get -y install gdbserver openssh-server killall | |||
{{Note|'''Note:''' The package '''openssh-server''' may possibly already be installed.|info}} | |||
If you want to learn how to add the packages at compile time, please refer to {{Varlink2|Adding Debian packages|{{#var:RELEASE_LINK}}}}. | |||
}} | |||
= Setup Host Computer Environment = | = Setup Host Computer Environment = | ||
Please follow the steps below to prepare a fresh Ubuntu 20.04 installation for | Please follow the steps below to prepare a fresh Ubuntu 20.04 installation for VS Code debugging: | ||
== Install Dependencies == | == Install Dependencies == | ||
$ sudo apt-get -y update | $ sudo apt-get -y update | ||
$ sudo apt-get -y install build-essential gdb gdb-multiarch git | $ sudo apt-get -y install build-essential gdb gdb-multiarch git {{#varexists:DEBIAN_NAME|sshpass}} | ||
== Install | == Install VS Code == | ||
$ sudo snap install --classic code | $ sudo snap install --classic code | ||
== Install | == Install VS Code Extensions == | ||
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 77: | ||
= Create, cross compile, and run a new "Hello, World!" project = | = 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 | $ mkdir ~/var-hello-world | ||
$ cd ~/var-hello-world | $ cd ~/var-hello-world | ||
$ code . | $ code . | ||
This will launch VS Code with ''~/var-hello-world'' as working directory (which is currently empty): | |||
[[File:Vscode_start.png]] | |||
Next, we will create the following files: | |||
{| class="wikitable" | |||
|- | |||
|'''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 <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''': | |||
[[File:Vscode_start_newfile.png]] | |||
Create a new file called '''main.cpp''': | Create a new file called '''main.cpp''': | ||
Line 62: | Line 120: | ||
'''Makefile:''' | '''Makefile:''' | ||
all: main.cpp | all: main.cpp | ||
$(CXX) $(CXXFLAGS) - | $(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/settings.json''' | |||
'''.vscode/settings.json:''' | |||
{ | |||
"VARISCITE": { | |||
/* Target Device Settings */ | |||
"TARGET_IP":"192.168.0.141", | |||
/* Project Settings */ | |||
"PROGRAM":"hello.bin", | |||
/* {{#var:PLATFORM_OS}} SDK Configuration */ | |||
"ARCH":"{{#var:TOOLCHAIN_TYPE}}", | |||
{{#switch:{{#var:PLATFORM_OS}} | |||
| Yocto="OECORE_NATIVE_SYSROOT":"{{#var:TOOLCHAIN_HOST_SYSROOT_LOCATION}}", | |||
| Debian="TOOLCHAIN":"{{#var:CROSS_COMPILER_PATH}}", | |||
}} | |||
{{#switch:{{#var:PLATFORM_OS}} | |||
| Yocto="SDKTARGETSYSROOT": "{{#var:TOOLCHAIN_SYSROOT_PATH}}", | |||
| Debian="TARGETSYSROOT":"{{#var:TOOLCHAIN_SYSROOT_PATH}}", | |||
}} | |||
/* {{#var:PLATFORM_OS}} SDK Constants */ | |||
{{#switch:{{#var:PLATFORM_OS}} | |||
| Yocto="CC_PREFIX": "${config:VARISCITE.OECORE_NATIVE_SYSROOT}/usr/bin/${config:VARISCITE.ARCH}/${config:VARISCITE.ARCH}-", | |||
| Debian="CC_PREFIX": "${config:VARISCITE.TOOLCHAIN_PATH}/bin/${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}'': | |||
$ make | {| 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 | |||
{{#switch:{{#var:PLATFORM_OS}} | |||
| Yocto= | |||
<tr><td>'''ARCH'''</td> <td> Architecture prefix for gcc, g++, gdb, etc. Align with CXX variable set by {{#var:TOOLCHAIN_LOCATION}}</td></tr> | |||
<tr><td>'''OECORE_NATIVE_SYSROOT'''</td> <td>Align with OECORE_NATIVE_SYSROOT variable set by {{#var:TOOLCHAIN_LOCATION}}</td></tr> | |||
<tr><td>'''SDKTARGETSYSROOT'''</td> <td>Align with SDKTARGETSYSROOT variable set by {{#var:TOOLCHAIN_LOCATION}}</td></tr> | |||
| Debian= | |||
<tr><td>'''ARCH'''</td> <td> Architecture prefix for gcc, g++, gdb, etc.</td></tr> | |||
<tr><td>'''TOOLCHAIN_PATH'''</td> <td>Path to the cross compiler</td></tr> | |||
<tr><td>'''TARGETSYSROOT'''</td> <td>Path to the sysroot</td></tr> | |||
}} | |||
|- | |||
|'''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 {{#var:PLATFORM_OS}} 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.{{#switch:{{#var:PLATFORM_OS}}|Yocto=SDK|Debian=}}TARGETSYSROOT}/usr/include/**" | |||
] | |||
} | |||
], | |||
"version": 4 | |||
} | |||
Your workspace should look similar to this: | |||
{{#switch:{{#var:PLATFORM_OS}} | |||
| Yocto=[[File:vscode-gdb-build-2.png]] | |||
| Debian=[[File:vscode-gdb-build-debian-v1.png|1600px]] | |||
}} | |||
Cross compile the project by selecting '''Terminal->Run Build Task...''' or entering <code>Ctrl+Shift+B</code> and selecting '''Build''': | |||
{{#switch:{{#var:PLATFORM_OS}} | |||
| Yocto=[[File:vscode_run_build_task_2.png]] | |||
| Debian=[[File:vscode-run-build-task-debian-v1.png|1600px]] | |||
}} | |||
Open a new VS Code terminal by selecting '''Terminal->New Terminal''' or entering <code>Ctrl+Shift+`</code>. | |||
Deploy '''hello.bin''' to the target device using SCP: | |||
$ scp hello.bin root@<ip addr>:{{#var:TARGET_ROOT_HOME}} | |||
[[File:Vscode_new_terminal_2.png]] | |||
Launch '''hello.bin''' on the target device: | Launch '''hello.bin''' on the target device: | ||
Line 83: | Line 261: | ||
Hello, World! | Hello, World! | ||
= Remote Debugging with | = Remote Debugging with VS Code = | ||
After verifying hello.bin runs on the target device, we can now setup | 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: | ||
~/var-hello-world$ find | variscite@ubuntu:~/var-hello-world$ find | ||
. | .vscode/settings.json | ||
.vscode/tasks.json | |||
./Makefile | ./Makefile | ||
./main.cpp | ./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: | |||
{| class="wikitable" | {| class="wikitable" | ||
|- | |- | ||
|'''var- | |'''var-deploy-gdb.sh''' || Generic script to deploy and launch gdbserver | ||
|- | |- | ||
|'''.vscode/launch.json''' || | |'''.vscode/launch.json''' || VS Code file to configure debug settings. Runs <code>var-build-and-debug</code> in tasks.json | ||
|- | |- | ||
|'''.vscode/tasks.json''' || | |'''.vscode/tasks.json''' || Edit to call <code>var-deploy-gdb.sh</code> prior to debugging. | ||
|} | |} | ||
== Create var- | == Create var-deploy-gdb.sh == | ||
First, add a generic script | 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 115: | Line 295: | ||
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- | '''var-deploy-gdb.sh:''' | ||
#!/bin/bash | #!/bin/bash | ||
readonly TARGET_IP="$1" | readonly TARGET_IP="$1" | ||
readonly PROGRAM="$2" | readonly PROGRAM="$2" | ||
readonly TARGET_DIR=" | readonly TARGET_DIR="{{#var:TARGET_ROOT_HOME}}" | ||
{{#switch:{{#var:PLATFORM_OS}}|Debian=readonly TARGET_PASSWORD="root"}} | |||
{{#switch:{{#var:PLATFORM_OS}} | |||
| Debian= | |||
SSHPASS="" | |||
# Use sshpass if TARGET_PASSWORD not empty | |||
if [ ! -z "${TARGET_PASSWORD}" ]; then | |||
SSHPASS="sshpass -p ${TARGET_PASSWORD}" | |||
fi | |||
}} | |||
# Must match startsPattern in tasks.json | |||
echo "Deploying to target" | |||
# | # kill gdbserver on target and delete old binary | ||
{{#switch:{{#var:PLATFORM_OS}}|Debian=${SSHPASS}|}} ssh root@${TARGET_IP} "sh -c '/usr/bin/killall -q gdbserver; rm -rf ${TARGET_DIR}/${PROGRAM} exit 0'" | |||
# | # send the program to the target | ||
{{#switch:{{#var:PLATFORM_OS}}|Debian=${SSHPASS}|}} 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 | ||
{{#switch:{{#var:PLATFORM_OS}}|Debian=${SSHPASS}|}} ssh -t root@${TARGET_IP} "sh -c 'cd ${TARGET_DIR}; gdbserver localhost:3000 ${PROGRAM}'" | |||
== Create launch.json == | == 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:''' | '''.vscode/launch.json:''' | ||
Line 145: | Line 335: | ||
"type": "cppdbg", | "type": "cppdbg", | ||
"request": "launch", | "request": "launch", | ||
"program": " | "program": "${config:VARISCITE.PROGRAM}", | ||
"args": [], | "args": [], | ||
"stopAtEntry": true, | "stopAtEntry": true, | ||
"cwd": "${workspaceFolder}", | "cwd": "${workspaceFolder}", | ||
"environment": [], | "environment": [], | ||
"MIMode": "gdb", | "MIMode": "gdb", | ||
"targetArchitecture": "arm64", | "targetArchitecture": "arm64", | ||
"preLaunchTask": "var- | "preLaunchTask": "var-deploy-gdb", | ||
"setupCommands": [{ | "setupCommands": [{ | ||
"description": "Enable pretty-printing for gdb", | "description": "Enable pretty-printing for gdb", | ||
Line 160: | Line 349: | ||
}], | }], | ||
"miDebuggerPath": "/usr/bin/gdb-multiarch", | "miDebuggerPath": "/usr/bin/gdb-multiarch", | ||
"miDebuggerServerAddress": " | "miDebuggerServerAddress": "${config:VARISCITE.TARGET_IP}:3000", | ||
}] | }] | ||
} | } | ||
Line 175: | Line 364: | ||
|} | |} | ||
== Edit 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''': | |||
In <code>launch.json</code>, we created a <code>preLaunchTask</code> to run a task named <code>var- | |||
'''.vscode/tasks.json:''' | '''.vscode/tasks.json:''' | ||
{ | { | ||
"version": "2.0.0", | "version": "2.0.0", | ||
"tasks": [{ | /* Configure {{#var:PLATFORM_OS}} 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 following table summarizes the var-deploy-gdb configuration in tasks.json: | ||
{| class="wikitable" | {| class="wikitable" | ||
Line 206: | Line 429: | ||
|<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> | ||
|} | |} | ||
== Launch a Debugging Session == | == Launch a Debugging Session == | ||
Line 214: | Line 435: | ||
~/var-hello-world$ find | ~/var-hello-world$ find | ||
. | .vscode/c_cpp_properties.json | ||
./. | .vscode/launch.json | ||
.vscode/settings.json | |||
.vscode/tasks.json | |||
./Makefile | ./Makefile | ||
./var- | ./var-deploy-gdb.sh | ||
./main.cpp | ./main.cpp | ||
./hello.bin | ./hello.bin | ||
A new debugging session can be started by pressing 'F5' on the keyboard. | 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: | [[File:Vscode_debug_2.png]] | ||
{{#switch:{{#var:PLATFORM_OS}}|Yocto= | |||
= Example Project Source Code = | = Example Project Source Code = | ||
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/ | $ git clone https://github.com/varigit/var-demos | ||
$ cd var-demos/hello-world | $ cd var-demos/vscode-demos/hello-world | ||
Launch | Launch VS Code: | ||
$ code . | $ code . | ||
Configure the target device IP Address in '''.vscode/ | Configure the target device IP Address and SDK variables in '''.vscode/settings.json''' | ||
Finally, start a debugging session by pressing 'F5' on the keyboard. | Finally, start a debugging session by selecting '''Run->Start Debugging''' or pressing 'F5' on the keyboard. | ||
}} |
Latest revision as of 21:54, 15 May 2024
This page is using the default release RELEASE_DUNFELL_V1.5_DART-MX8M-MINI.
To view this page for a specific Variscite SoM and software release, please follow these steps:
- Visit variwiki.com
- Select your SoM
- Select the software release
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):
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:
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:
Cross 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+`
.
Deploy 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/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:
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-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": [], "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:
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.