Search by Tags

C/C++ Development and Debugging on TorizonCore Using Visual Studio Code

 

Article updated at 10 Dec 2020
Compare with Revision


Select the version of your OS from the tabs below. If you don't know the version you are using, run the command cat /etc/os-release or cat /etc/issue on the board.



Remember that you can always refer to the Torizon Documentation, there you can find a lot of relevant articles that might help you in the application development.

Torizon 5.0.0

Introduction

This article explains How to do C/C++ Development on Torizon, including running and debugging applications on the device, using the Visual Studio Code Extension for Torizon. It briefs on how to create a new project, add development libraries to the SDK and runtime libraries to the target, switch between debug and release configuration, and more.

Through the article, we configure the project as if we want to use a GPIO. It is a good use case because you have to:

  • Add a development package to the SDK
  • Add a library to the application
  • Grant hardware access to the GPIO banks.

Optional: Notes About the GPIO Example

If you are actually interested in using a GPIO in C, after going through this article you can replace the hello-world source-code with the GPIO example in C provided in our torizon-samples repository, disregarding the Dockerfiles. You can learn more about the libgpiod examples and API calls on How to Use GPIO on TorizonCore: C Language Examples.

Import an Existing Project

Please refer to the dedicated article How to Import a C/C++ Application to Torizon, but before you do it, it is still recommended that you go through the current article steps and create a hello world, to get used to the Torizon practical workflow.

This article complies to the Typographic Conventions for Torizon Documentation.

Prerequisites

Create a New Project

Watch a short video summarizing the process described in this section:

  • Creating a Torizon C/C++ Project on VS Code

In summary, you must open the command palette on Visual Studio Code and then type Torizon/C-C++: Create C/C++ application to create an application:


  • Creating a C/C++ Application

    Creating a C/C++ Application

You will be prompted some extra information before the project is fully setup:

  • Application name.
  • Parent directory to create your application under. The extension will create a new directory with your project name under it.
  • Select the application template that is the best fit for your project.
    • It will setup VS Code to use the buildsystem from the template, saving you a lot of initial configuration time.
    • In the example above, we have selected Makefile-based Project but feel free to choose the most appropriate for you.
  • Select the right target architecture (arm32v7 for 32-bit processors and arm64v8 for 64-bit) and purpose, depending on if your application has a graphical interface or not.
  • Choose a user. This is the user that will run the application inside the container.
    • By default, the Toradex containers provide you with two options: torizon and root.
    • Even inside the container, for security reasons, you are advised to run as torizon whenever possible. Learn more on the Torizon Best Practices Guide.
  • Select a configuration between debug and release. Since we want to deploy and debug our test application, please select debug.
    • Later on in this article you will learn how to switch between debug and release.

The extension will build an SDK container, running on your development machine, that will provide the toolchain and all the libraries needed to build your application.

After a few minutes, your folder will be re-opened inside the container (notice the green box in the bottom-left corner of the Visual Studio Code window) and you'll be ready to start developing:


  • C/C++ project

    C/C++ project

Configure Project

Understand how to add libraries and more in the next subsections.

Switch Between Debug and Release Modes

Warning: don't confuse release container with debug and release modes, which only affect the binary that will be compiled by the SDK. You are allowed to deploy a debug binary into a release container, though it may not be the best idea.

If you are in the debug configuration, run the command Torizon C/C++: Switch to release configuration:


  • Switch To Release Configuration

    Switch To Release Configuration

If you are in the release configuration, run the command Torizon C/C++: Switch to debug configuration:


  • Switch To Debug Configuration

    Switch To Debug Configuration

How the compiler will be invoked for each mode is defined in the file .vscode/tasks.json created by the new project template. You may need to make adjustments either to this file or to the build files (Makefile, CMake file, Autotools file) according to your project's peculiarities.

Add Libraries Available on Debian Feeds

For a C/C++ application, we will need to add packages:

  • `devpackages: headers and libraries that should be linked at build time. They are added to the SDK container.
  • extrapackages: libraries and components that are dynamically linked with our application or executed on the target.

As an example, we will add support for libgpiod, used to access GPIO pins from user mode.

To add devpackages:

  • Open the Torizon configuration page and edit the devpackages configuration by clicking on the pen icon.
  • As an example, add the package libgpiod-dev:#%platform.debian-arch%#
    • Notice that you have to specify CPU architecture. The expression #%platform.debian-arch%# will evaluate to either arm64 or armhf depending on the project configuration.
    • If you only foresee using one architecture while developing your project, you can use it instead of #%platform.debian-arch%#.
  • You can add a list of space-separated packages, as package1:#%platform.debian-arch%# package2:#%platform.debian-arch%# package3:#%platform.debian-arch%#
  • Once you changed this setting the editor will ask you if you want to rebuild the SDK container. We will need an updated container to be able to build our application using libgpiod, so select the option that will rebuild the SDK container immediately.

devpackages are installed inside the SDK container (this is why you need to specify an architecture suffix if they are not multi-architecture), they will allow you to build your code on your development machine.
Thanks to Debian multi-architecture support, all the native libraries we will need to cross-compile our application will be installed and ready to use.

To add extrapackages:

  • Open the Torizon configuration page and edit the extrapackages configuration by clicking on the pen icon.
  • As an example, add the package libgpiod2
    • Notice that you don't need to specify a suffix, since the container will be built for the same architecture than the device.
  • You can add a list of space-separated packages, as package1 package2 package3

extrapackages are installed inside the container that will run on the target and provide runtime components required to run your application. Usually, you will have one devpackage (headers and libs) and one extrapackage (runtime components), but this is not a strict rule. Some libraries may have a single development package but may be splitted in multiple runtime ones, each one with some "sub-features".

  • Adding Devpackages and Extrapackages

Tip: You are responsible for including headers and linking to libraries. For example, in the GPIO demo, you must include -lgpiod. It depends on how you are building your project, invoking GCC directly, or using different build methods - Makefiles, Cmake, make, and possibly others.

Add Debug Symbols and Source Code From Debian Feeds

Later on, during debugging, you may find out that you need to debug a library that you have installed from the Debian feeds. To do that with GDB, you will need:

  • Debug symbols: at least, provides a better stack trace
  • Source code: provides the ability to step into library functions

Tip: This information is only useful if you need to step into functions from libraries installed from the Debian feeds while debugging. For most projects, this is not required.

To enable debug symbols, the easiest way is to use debuginfod. It will automatically download the symbols for all libraries loaded by GDB on-demand.

While this is very convenient, keep in mind that it will increase the startup time of the debug session every time you need to rebuild the SDK, until the cache is populated. In a complex project with several libraries, it may take about 10 additional minutes.

In the IDE Extensions, open the file .devcontainer/devcontainer.json and add the "DEBUGINFOD_URLS": "https://debuginfod.debian.net" environment variable to containerEnv:

.devcontainer/devcontainer.json
    "containerEnv": {
        "DEBUGINFOD_URLS": "https://debuginfod.debian.net"
    },

To add source code, you must use apt-source to download the source for each library individually.

While debuginfod should be able to download the sources for you, due to the way Debian packaging is setup, this is not possible.

The libsdl2 package will be used as an example. Add the following content to the property sdkpreinstallcommands:

RUN printf "deb-src http://deb.debian.org/debian bullseye main\ndeb-src http://security.debian.org/debian-security bullseye-security main\ndeb-src http://deb.debian.org/debian bullseye-updates main\n" >> /etc/apt/sources.list && cd /usr/src && apt-get -y update && apt-get source libsdl2-2.0-0

You must also pass the path to the library source to GDB by creating a .gdbinit file. Add the following content to the property sdkpostinstallcommands:

RUN printf "directory /usr/src/\ndirectory /usr/src/libsdl2-2.0.14+dfsg2\n" > home/torizon/.gdbinit

To apply the new configuration, rebuild the SDK container by running Remote-Containers: Rebuild container from the command palette.

Hardware Access

Note: The content from this section is a case study from the Torizon Best Practices Guide, therefore you must read it for a better understanding of why it must be done.

Earlier in this article, you have set the user to torizon. To access hardware from the container you will need to mount gpiochip devices inside the container and add the torizon user to the gpio group, allowing applications to access gpio.

In the configuration window press the + icon next to the [ ] devices entry and insert the device path /dev/gpiochip0.


  • Add device

    Add device


  • Gpio device

    GPIO device

Repeat the operation for all the gpiochip devices you need to access. For example, on Colibri iMX7 you have 7 devices, numbered from 0 to 6:

# ls /dev/gpiochip* -la
crw-rw-r-- 1 root gpio 254, 0 Jun 17 06:39 /dev/gpiochip0
crw-rw-r-- 1 root gpio 254, 1 Jun 17 06:39 /dev/gpiochip1
crw-rw-r-- 1 root gpio 254, 2 Jun 17 06:39 /dev/gpiochip2
crw-rw-r-- 1 root gpio 254, 3 Jun 17 06:39 /dev/gpiochip3
crw-rw-r-- 1 root gpio 254, 4 Jun 17 06:39 /dev/gpiochip4
crw-rw-r-- 1 root gpio 254, 5 Jun 17 06:39 /dev/gpiochip5
crw-rw-r-- 1 root gpio 254, 6 Jun 17 06:39 /dev/gpiochip6

You also need to add the torizon user to the gpio group. Groups are mirrored between the base OS and the Debian containers for Torizon. Edit the buildcommands property and set it to RUN usermod -a -G gpio torizon:


  • Add user to the gpio group

    Add user to the gpio group

Build, Clean, Deploy and Other Tasks

When creating a Torizon project, some useful commands are set by default on .vscode/tasks.json to invoke the buildsystem commands to build, clean, deploy, install and possibly other commands or variations. Our "higher level" commands described in the next sections will often call them under the hood, and you won't need to run them.

But, if you are importing an existing project and adapting it to the Torizon extension, or if you want to make sure your binaries are being rebuilt from scratch while switching between debug and release modes, it may be useful to run those commands. You will need to run on the command palette Tasks: Run Task and it will list the available commands to be run. For our Makefile-base project we have deploy, build_debug, build_release and clean:


  • Run tasks

    Run tasks

The build command is bind by default to Ctrl + Shift + B, which is a useful means to run it.

Run Build Commands From the Command-line

Remember that the SDK runs inside a container, therefore you cannot enter the project directory on your PC and simply run those commands. Accessing the command-line inside the container is made easy by VS Code, just click the + button New Terminal. Keep in mind that the applications installed on your computer will not be available, if you need to install any package with apt, add it to the devpackages on the Configurations view of the Torizon tab.

All terminals you open from Visual Studio Code will run inside your Debian-based SDK container, even if you are running Windows as your main OS. You can execute build commands directly there, such as make clean for instance. Some advantages of using Visual Studio code tasks:

  • The command output will be parsed and you could reach a code line reported in an error message by just clicking on the message itself.
  • You don't need to remember the commands.
  • Run Tasks From the Terminal

Deploy and Debug

After configuring your project, you can now deploy and debug it.

By default, the debugger breaks on the entry point of the application. If you don't want it, just change the value of the variable stopAtEntry on .vscode/launch.json, inside your project folder, from true to false.

Since the rest is common to all languages supported by the extension, please refer to the section Deploy and Debug from the article Visual Studio Code Extension for Torizon.

Deploy and Release

Note: Before focusing on the process, you can optionally switch to release mode and clean the build, as described in previous sections of this article, to make sure that the binaries added to the release container are actually also stripped of debug symbols.

After going through the process of deploying and debugging the application, you can now deploy and release it. Since this is common to all languages supported by the extension, please refer to the section Deploy and Release from the article Visual Studio Code Extension for Torizon.

Torizon Configuration

This section shows the possible settings for the extension.

Those tags can usually be modified using the IDEs plugins user interface, but for some specific scenarios, it may be required to edit them manually inside the YAML configuration files.

Tag Type Description
platform.id string Unique id of the platform (folder name)
platform.name string Mnemonic name of the platform
platform.version string Version of the platform
platform.folder path Absolute path of the folder where platform configuration is stored (can be used to add files to a container)
platform.baseimage string Base image of the container template (used in FROM clause of Dockerfile)
platform.sdkbaseimage string Base image of the SDK template (can be empty if the platform does not support an SDK)
platform.runtimes string[] Runtimes supported by the image. Currently supported runtimes are: ccpp, ccpp-no-ssh, python3, dotnet, aspnet
platform/application.ports key/value pairs Ports exposed by the container (those configured by application configuration will be merged with those provided by the platform, replacing those with same keys and adding others )
platform/application.volumes key/value pairs Volumes mounted in the container (where "key "is the local path or volume name, "value" is the path inside the container and, optionally, ",ro" to mount read-only)
platform/application.devices string[] List of paths of devices that should be mapped inside the container (ex: /dev/gpiochip0)
platform/application.networks string[] List of networks that should be connected to the container. For a network created by a docker-compose script associated with the appplication configuration you've to prepend "#%application.id%#_" to the actual name)
platform/application.extraparams key/value pairs This tag can be used to add specify some additional custom settings. Check docker python API documentation of container.run method for a list of the supported parameter. "Key" should be parameter name, "value" must be YAML representation of the value. For example to set host network mode, add "network_mode" as key and "host" as value.
platform/application.startupscript relative path The script that will be launched before starting the container, tags can be used inside the script. The script must be in the same folder as platform/application config file or in a subfolder, path must be relative. If the script is specified for both platform and application, only the application one is executed (but it can invoke the platform one that will be parsed and copied to the target anyway).
platform/application.shutdownscript relative path A script that will be launched after the container has been stopped. Tags can be used inside the script. The script must be in the same folder as platform/application config file or in a subfolder. If the script is specified for both platform and application, only the application one is executed (but it can invoke the platform one that will be parsed and copied to the target anyway).
platform/application.dockercomposefile relative path The docker-compose script that will be used to start other containers required to run the application, tags can be used inside the script. The script must be in the same folder as platform/application config file or in a subfolder. The path must be relative. If the compose file is specified for both platform and application, only the application one is used.
application.id string Application unique id (used also as a prefix for docker-compose created resources like volumes or networks)
application.expose docker command Ports exposed by the application in the format: "EXPOSE NN NN" Where NN are port number (ex: "EXPOSE 80 8080)
application.arg docker command Docker build arguments in the format: ARG NAME=VALUE. You can also specify multiple values. This can be useful only if you plan to use the generated dockerfile in a standalone build
application.env docker command Environment variables in the format: ENV NAME=VALUE. Multiple entries can be specified and VALUE can contain other tags (ex: ENV FOLDER="/home/dummy" FILE="filename")
application.preinstallcommands docker command Commands that will be executed during container build before any package installation. The format must be the one used in Dockerfiles. This can be used to add Debian package feeds to apt list, add security keys, etc.
application.extrapackages string Additional packages that should be installed inside the container. You can specify multiple packages separated by spaces.
application.devpackages string Development packages that will be installed in the SDK container. If a package has architecture-specific versions you’ll have to specify the correct architecture. ex: libopencv:armhf or libopencvf:aarch64
application.sdkpackages string Additional packages that will be installed in the SDK container. This can be used to install additional tools or compilers.
application.buildfiles docker command This command can be used to add additional files to the image using the ADD or COPY command. Files must be placed inside the application configuration folder.
application.buildcommands docker command Command that will be executed after having installed all packages and having configured the debugger and the services. This will give you a chance to change configuration before the actual command is executed
application.targetfiles docker command Command that will be executed at the end of the build, can be used to add files to the container (ex: providing pre-configuration for services or overriding the default configuration files)
application.targetcommands docker command Command executed when the container runs, this may be used to override execution of the application in release containers
application.appname string mnemonic name of the application, for application create using Visual Studio Code it will match folder name
application.exename string relative path (from application install folder) of the exe started when the container starts. Used only by VSCode
application.appargs string optional arguments that should be passed to the application
application.username string username used to run the container CMD. Other commands will be executed as root.
application.sdkpreinstallcommands docker command Command executed before installing packages into the SDK container can be used to add Debian feeds or keys
application.sdkpostinstallcommands docker command Command executed after devpackages and skdpackages have been installed
application.main string Used only for python application. Provides the name of the python file that container the main entry point

Both applications and platforms provide a generic entry named “props” where you can specify your own properties that will be replaced as tags using the same logic applied for standard tags.
In the extension UI, those will be referenced as "custom properties".
You can define your custom tags and use them in your dockerfile templates or inside other tags.

Example: How to Use a GPIO: Source Code and Makefile

First of all, move to the folder created on the previous steps and replace the content of your C file with the GPIO example in C provided in our torizon-samples repository. You can ignore the Dockerfiles.

You will also need to add a reference to libgpiod in your Makefile. Open "Makefile" in the editor and locate the following lines:

helloworld: $(OBJ)
    $(CC) -o $@ $^ $(CFLAGS) 

Change them to:

helloworld: $(OBJ)
    $(CC) -o $@ $^ $(CFLAGS) -lgpiod

You can learn more about the libgpiod examples and API calls on How to Use GPIO on TorizonCore: C Language Examples.

Torizon 4.0.0

Update to a Newer Debian Container Version

Debian Containers for Torizon are subject to updates, including major updates to newer versions of Debian. Learn more about it, including how to update your VS Code project:

Introduction

This article explains how to run and debug C/C++ Applications on TorizonCore using the Visual Studio Code extension provided by Toradex.

This article complies to the Typographic Conventions for Torizon Documentation.

Prerequisites

Getting Started

Create a New Project

Press F1 on Visual Studio Code and then type Torizon/C-C++: Create C/C++ application to create an application:


  • Creating a C/C++ Application

    Creating a C/C++ Application

After creating it, write the application name on the same command bar:


  • Naming your C/C++ Project

    Naming your C/C++ Project

You will be asked to browse for a folder, select the parent folder for your new project (for example your home folder).

You'll have to select an application template from a list, select "Makefile template".


  • Template selection

    Template Selection

A bunch of options will appear, make sure to select the right target architecture:


  • Selecting target architecture

    Selecting target architecture

Our latest platforms are based on debian bullseye, please use those unless you are aware of specific issues that could prevent you from using this release for your own application

Type torizon on the username label:


  • Set Username

    Set Username

In the last step you'll be required to select a configuration between debug and release, since we want to deploy and debug our test application, please select "debug".


  • Select Configuration

    Select Configuration

The system will build the SDK container. For C/C++ application the extension will build an SDK container, running on your development machine, that will provide the toolchain and all the libraries needed to build your application.


  • Building SDK container

    Building SDK container

After a few minutes, your folder will be re-opened inside the container (notice the green box in the bottom-left corner of the Visual Studio Code window) and you'll be ready to start developing.


  • C/C++ project

    C/C++ project

Configure Project

Understand how to add libraries and more in the next subsections.

Add Libraries Available on Debian Feeds

For a C/C++ application, we will need to add packages to the SDK container (headers and libraries that should be linked at build time) and to the runtime container (libraries and components that are dynamically linked with our application or executed on the target).

In this case, we will add support for libgpiod, used to access GPIO pins from user mode.

Open the Torizon configuration page and edit the devpackages configuration, you just need to click on the pen icon:


  • Dev packages

    Dev packages

As an example, add the package libgpiod-dev:armhf (notice that you have to specify CPU architecture here, if you selected a 64-bit platform you'have to add the "arm64" suffix instead of "armhf"):


  • libgpiod-dev package

    libgpiod-dev package

Once you changed this setting the editor will ask you if you want to rebuild the SDK container, we will need an updated container to be able to build our application using libgpiod, so select the option that will rebuild the SDK container immediately.
Devpackages are installed inside the SDK container (this is why you need to specify an architecture suffix if they are not multi-architecture), they will allow you to build your code on your development machine.
Thanks to Debian multi-architecture support, all the native libraries we will need to cross-compile our application will be installed and ready to use.


  • Prompt to rebuild SDK container

    Prompt to rebuild SDK container

Open the Torizon configuration page and edit the extrapackages configuration, you just need to click on the pen icon and add libgpio2 package:


  • Extra packages

    Extra packages

Extrapackages are installed inside the container that will run on the target (notice that you don't need to specify a suffix, since the container won't be multi-architecture) and provide runtime components required to run your application. Usually you will have one devpackage (headers and libs) and one extrapackage (runtime components), but this is not a strict rule. Some libraries may have a single development package but may be splitted in multiple runtime ones, each one with some "sub-features".

Deploy and Debug

code and makefile

First of all, move to the folder created on the previous steps and replace the content of your C file with the following:

main.c
#include <stdio.h>
#include <unistd.h>
#include <gpiod.h>
 
#include "helloworld.h"
 
// change this value to use a different pin
// if you use Colibri or Verdin prefix is SODIMM_
// if you use Apalis it's MXM3_
#define GPIO_PIN_NAME "SODIMM_127"
 
int main(int argc, char const *argv[])
{
    int retcode=-1;
    char chipname[32];
    unsigned int offset;
    struct gpiod_chip* chip=NULL;
    struct gpiod_line* line=NULL;
    int state=0;
 
    // translate pin name into GPIO chip+offset
    if (gpiod_ctxless_find_line(GPIO_PIN_NAME,chipname,sizeof(chipname),&offset)<0) {
        printf("Error finding GPIO corresponding to pin %s\n",GPIO_PIN_NAME);
    }
 
    // access gpio chip
    chip=gpiod_chip_open_by_name(chipname);
 
    if (chip==NULL) {
        printf("Error opening chip %s\n",chipname);
        goto error;
    }
 
    // get access to GPIO line 
    line=gpiod_chip_get_line(chip,offset);
 
    if (line==NULL) {
        printf("Error getting line %d of chip %s\n",offset,chipname);
        goto error;
    }
 
    // configure pin as output and set it to low
    if (gpiod_line_request_output(line, "helloworld", GPIOD_LINE_ACTIVE_STATE_LOW)) {
        printf("Error getting configuring line %d of chip %s\n",offset,chipname);
        goto error;
    }
 
    // changes pin state every second
    for (;;) {
        state=state?0:1;
        gpiod_line_set_value(line,state);
        sleep(1);
    }
 
 
error:
 
    if (line==NULL) {
        gpiod_line_release(line);
    }
 
    if (chip!=NULL) {
        gpiod_chip_close(chip);
    }
    return retcode;
}

Feel free to change and edit the code to try how intellisense, refactoring and the other Visual Studio Code features work with your code.

You will also need to add a reference to libgpiod in your makefile.

Open "Makefile" in the editor, locate the following lines:

helloworld: $(OBJ)
    $(CC) -o $@ $^ $(CFLAGS) 

and change them to:

helloworld: $(OBJ)
    $(CC) -o $@ $^ $(CFLAGS) -l gpiod

container execution

To access hardware from our container we will need to add some configuration settings. We will need to mount gpiochip devices inside the container and add torizon user inside the container to the gpio group, allowing applications running with that account to access the devices.

To mount devices inside the container you will have to add all the /dev/gpiochip* devices to your configuration.

In the configuration window press the "+" icon next to the "[] devices" entry.


  • Add device

    Add device

Then insert the device path:

/dev/gpiochip0

  • Gpio device

    GPIO device

Repeat the operation for all the gpiochip devices you need to access. For example, on imx7 you have 7 devices, numbered from 0 to 6:

# ls /dev/gpiochip* -la
crw-rw-r-- 1 root gpio 254, 0 Jun 17 06:39 /dev/gpiochip0
crw-rw-r-- 1 root gpio 254, 1 Jun 17 06:39 /dev/gpiochip1
crw-rw-r-- 1 root gpio 254, 2 Jun 17 06:39 /dev/gpiochip2
crw-rw-r-- 1 root gpio 254, 3 Jun 17 06:39 /dev/gpiochip3
crw-rw-r-- 1 root gpio 254, 4 Jun 17 06:39 /dev/gpiochip4
crw-rw-r-- 1 root gpio 254, 5 Jun 17 06:39 /dev/gpiochip5
crw-rw-r-- 1 root gpio 254, 6 Jun 17 06:39 /dev/gpiochip6

You also need to add the torizon user to the gpio group (groups are mirrored between the base OS and torizon-debian containers).

To do this, edit the "buildcommands" property and set it to:

RUN usermod -a -G gpio torizon

  • Add user to the gpio group

    Add user to the gpio group

deploy and debug

Let the debug process begin! Press F5 and the IDE will build and deploy the debug container image to the computer on module. The first time you run the application, the system needs to build and deploy the container image, this may take a few minutes.

Following executions will be much faster since only your application will be deployed.

The system will break on the first instruction of your main function.


  • Runtime breakpoint

    Runtime breakpoint

Now you can execute your code step by step, add new breakpoints, inspect variables etc.

If you don't want that the debugger breaks on the first instruction, just change:

"stopAtEntry": true,

to

"stopAtEntry": false,

in .vscode/launch.json inside your project folder.

The application has an infinite loop, you can just stop the debugger to kill it.

Deploy and Release

After going on the process of deploying and debugging the application, you can now deploy and release it.

Press F1 in Visual Studio Code to open the command bar and write the command Torizon C/C++: Switch to release configuration. Visual studio code will reload the workspace and will be ready to rebuild your app in release mode.


  • Switch to release configuration

    Switch to release configuration

First you need to clean the current build output, to ensure that everything will be rebuilt from scratch. You can press F1 again, select "Tasks: Run Task" and then select the "clean" task from the list.


  • Run clean task

    Run clean task

You can also open a new terminal and type:

$ make clean

at the prompt. All terminals you open from Visual Studio Code will run inside your container (on a Linux system, even if you are running Windows as your main OS) and you can execute build commands directly there. The main advantage of using Visual Studio code tasks is that output will be parsed and you could reach a code line reported in an error message by just clicking on the message itself.

Now you can press ctrl+shift+B to build your code.

If build completes successfully you can now build a release container for your application. Press F1 and select "Torizon: Build release container for the application".

Note: This entire process can take a few minutes.


  • Build release container command

    Build release container command

Your terminal output should be like the following:

Building release container for C/C++ application...
Deploying application to local folder...
Building release image (this may take some time)...
Release image has been built successfully.

Attention: Just note that the building process can take some time.

Now that your container was successfully built, you can press F1 again and enter the Torizon: Deploy release container, which deploys your container.

Deploying release container...
Please select a device.
Device XXXXXXXX selected.
Deploying image to target (this may take a few minutes).
Container has been deployed.

You can confirm if the image was actually deployed to your Torizon device by running the following command on the module:

# docker images

If you want to run your new container you need to check your configuration id and platformid properties in the configuration view. Then you can run your container:

docker run --device /dev/gpiochip0 --device /dev/gpiochip1 --device /dev/gpiochip2 --device /dev/gpiochip3 --device /dev/gpiochip4 --device /dev/gpiochip5 --device /dev/gpiochip6 <platformid>_<id>_release:latest

If you connected an LED to your GPIO pin, you should see it blinking.

To get more information about Docker Containers and their commands, please refer to Docker Oficial Documentation.

Torizon Configuration

This section shows the possible settings for the extension.

Those tags can usually be modified using the IDEs plugins user interface, but for some specific scenarios, it may be required to edit them manually inside the YAML configuration files.

Tag Type Description
platform.id string Unique id of the platform (folder name)
platform.name string Mnemonic name of the platform
platform.version string Version of the platform
platform.folder path Absolute path of the folder where platform configuration is stored (can be used to add files to a container)
platform.baseimage string Base image of the container template (used in FROM clause of Dockerfile)
platform.sdkbaseimage string Base image of the SDK template (can be empty if the platform does not support an SDK)
platform.runtimes string[] Runtimes supported by the image. Currently supported runtimes are: ccpp, ccpp-no-ssh, python3, dotnet, aspnet
platform/application.ports key/value pairs Ports exposed by the container (those configured by application configuration will be merged with those provided by the platform, replacing those with same keys and adding others )
platform/application.volumes key/value pairs Volumes mounted in the container (where "key "is the local path or volume name, "value" is the path inside the container and, optionally, ",ro" to mount read-only)
platform/application.devices string[] List of paths of devices that should be mapped inside the container (ex: /dev/gpiochip0)
platform/application.networks string[] List of networks that should be connected to the container. For a network created by a docker-compose script associated with the appplication configuration you've to prepend "#%application.id%#_" to the actual name)
platform/application.extraparams key/value pairs This tag can be used to add specify some additional custom settings. Check docker python API documentation of container.run method for a list of the supported parameter. "Key" should be parameter name, "value" must be YAML representation of the value. For example to set host network mode, add "network_mode" as key and "host" as value.
platform/application.startupscript relative path The script that will be launched before starting the container, tags can be used inside the script. The script must be in the same folder as platform/application config file or in a subfolder, path must be relative. If the script is specified for both platform and application, only the application one is executed (but it can invoke the platform one that will be parsed and copied to the target anyway).
platform/application.shutdownscript relative path A script that will be launched after the container has been stopped. Tags can be used inside the script. The script must be in the same folder as platform/application config file or in a subfolder. If the script is specified for both platform and application, only the application one is executed (but it can invoke the platform one that will be parsed and copied to the target anyway).
platform/application.dockercomposefile relative path The docker-compose script that will be used to start other containers required to run the application, tags can be used inside the script. The script must be in the same folder as platform/application config file or in a subfolder. The path must be relative. If the compose file is specified for both platform and application, only the application one is used.
application.id string Application unique id (used also as a prefix for docker-compose created resources like volumes or networks)
application.expose docker command Ports exposed by the application in the format: "EXPOSE NN NN" Where NN are port number (ex: "EXPOSE 80 8080)
application.arg docker command Docker build arguments in the format: ARG NAME=VALUE. You can also specify multiple values. This can be useful only if you plan to use the generated dockerfile in a standalone build
application.env docker command Environment variables in the format: ENV NAME=VALUE. Multiple entries can be specified and VALUE can contain other tags (ex: ENV FOLDER="/home/dummy" FILE="filename")
application.preinstallcommands docker command Commands that will be executed during container build before any package installation. The format must be the one used in Dockerfiles. This can be used to add Debian package feeds to apt list, add security keys, etc.
application.extrapackages string Additional packages that should be installed inside the container. You can specify multiple packages separated by spaces.
application.devpackages string Development packages that will be installed in the SDK container. If a package has architecture-specific versions you’ll have to specify the correct architecture. ex: libopencv:armhf or libopencvf:aarch64
application.sdkpackages string Additional packages that will be installed in the SDK container. This can be used to install additional tools or compilers.
application.buildfiles docker command This command can be used to add additional files to the image using the ADD or COPY command. Files must be placed inside the application configuration folder.
application.buildcommands docker command Command that will be executed after having installed all packages and having configured the debugger and the services. This will give you a chance to change configuration before the actual command is executed
application.targetfiles docker command Command that will be executed at the end of the build, can be used to add files to the container (ex: providing pre-configuration for services or overriding the default configuration files)
application.targetcommands docker command Command executed when the container runs, this may be used to override execution of the application in release containers
application.appname string mnemonic name of the application, for application create using Visual Studio Code it will match folder name
application.exename string relative path (from application install folder) of the exe started when the container starts. Used only by VSCode
application.appargs string optional arguments that should be passed to the application
application.username string username used to run the container CMD. Other commands will be executed as root.
application.sdkpreinstallcommands docker command Command executed before installing packages into the SDK container can be used to add Debian feeds or keys
application.sdkpostinstallcommands docker command Command executed after devpackages and skdpackages have been installed
application.main string Used only for python application. Provides the name of the python file that container the main entry point

Both applications and platforms provide a generic entry named “props” where you can specify your own properties that will be replaced as tags using the same logic applied for standard tags.
In the extension UI, those will be referenced as "custom properties".
You can define your custom tags and use them in your dockerfile templates or inside other tags.