Importing a Qt Project Into Torizon Using VS Code

Tuesday, May 11, 2021

If you are reading this article, you may already know the basics about Torizon, the Easy-to-use Industrial Linux Software Platform. You are aware that it uses containers to provide a platform where you can focus on writing your own application, while Toradex takes care of making sure the underlying OS is always up-to-date – and this is where Torizon over-the-air update capabilities come into play.

Figure 1: Torizon, the Easy-to-use Industrial Linux Software Platform
Torizon OTA
Figure 2: Torizon Remote Update and Device Management Web UI

If you were an early adopter of Torizon, you may have started developing from the command-line and noticed that, while it is great for learning more about containers, it also has a learning curve. I must say that, to my personal opinion, it isn’t as steep as learning Yocto and how to generate SDKs suited for your use case then writing a layer and recipes for your application. Don’t get me wrong, I know that comparing Yocto and Torizon is heavily dependent on the use case you are working at and that both have their advantages.

The Torizon documentation highlights the features supported by the IDE Extensions
Figure 3: The Torizon documentation highlights the features supported by the IDE Extensions
But back to the point of still having a learning curve on Torizon, thinking about how to make our customers' lives easier, we have started developing IDE Extensions for Visual Studio and Visual Studio Code. Please don’t tell my friends at R&D that I’m calling VS Code an IDE, they like to refer to it as a text editor on steroids. I see it more as a DE with a myriad of extensions that you can install to make it into your own custom IDE. And as you decided to invest some time into this article, I’ll assume you are interested in trying out VS Code. If you haven’t started yet, check out those amazing resources:

Since Qt is a GUI framework widely chosen for embedded systems, from now on we’ll dive into the main purpose of this article, which is to guide you through how to import a Qt project to Torizon. This is a very useful use case to work on, as while focusing on it, you will also learn more about the VS Code Extension for Torizon.

So, what project do we choose? A few weeks ago, I was reading a post on Hackaday about Serial Studio: Easily Visualise And Log Serial Data and I thought, why not? It looks nice and doesn’t seem to be utterly complex, so a great project for a quick port.

Serial Studio UI

But don’t worry, if you want to be more adventurous after you finish this read, we have an application porting example for Fuse, an emulator for the Sinclair Zx-Spectrum with around 100k lines of code, a home computer that was very popular in the 80s. I was not around back then, but I trust the previous generations on that statement.

Figure 5: Fuse (source:
Environment Setup
Let’s list what is required on a high level:
  • A Computer on Module with TorizonCore
  • Visual Studio Code
  • Visual Studio Code Extension for Torizon

For the initial hardware setup, we recommend going through the Toradex Quickstart Guide. It explains with step-by-step lessons what peripherals are required and how to assemble the hardware and install TorizonCore.

The Toradex Quickstart Guide
Figure 6: The Toradex Quickstart Guide

The environment setup on the host PC varies slightly, depending on whether you are using a Windows or a Linux PC. While the Quickstart also covers how to do it, there is also a dedicated article on how to Configure Build Environment for Torizon Containers. In summary, you must install Docker and, if on Windows, the Windows Subsystem for Linux 2 (WSL2).

Install Visual Studio Code, the Visual Studio Code Extension for Torizon and the Remote Containers extension from Microsoft. Once the Torizon extension is set up, add your board as a target device. It is interesting to validate that the setup is working by creating a new Qt5 project, and then deploying and debugging it on the target. Did it work? You are good to go!

Visual Studio Code - Adding a Device
Figure 7: Adding a device
Port Serial Studio to Torizon with VS Code

Making the application compile and run correctly requires a few steps. We must adapt the build settings in a way that they make sense to our extension, then we must solve the build and runtime dependencies and finally we must grant access to the serial (UART) interfaces that we plan to use.

At the end of this section, a video illustrates the entire process, making it easier for you to follow it.

Download the Source-Code and Import the Project

The source-code for Serial Studio can be found on the Serial-Studio repository on GitHub. Clone this project and its submodules into your computer:

git clone
cd Serial-Studio
git checkout 3ebe6b8c74dd0f07ba04a3e0fd55baa512b28b68
git submodule init
git submodule update

In our example, we use a fixed commit to guarantee the reproducibility, since this project depends on Qt 5.15 and newer versions of Serial Studio use functions not available on the Qt version available on Debian Bullseye.

Open VS Code and wait for the Torizon extension to be loaded. Open the command palette and run the import command:

Torizon C/C++: Import existing C/C++ application
You will be prompted with a series of choices to configure your soon-to-be imported project:
  • Path to the directory where you have cloned Serial Studio
  • Application name: you can use the default
  • Qt QML sample
  • Target platform: depends on your SoM being 32-bit or 64-bit
  • Username: torizon
  • Configuration: either, I’ll choose debug
  • Name of the main executable: you can choose the default and we can change it later on
Import an existing C/C++ application
Figure 8: Import an existing C/C++ application
Adapt the Build Settings

The article Qt C++ Application Development on Torizon Using Visual Studio Code has a few invaluable tips on importing an existing Qt 5 project. We’ll start editing the project file to make sure the project binaries and resources are installed into the directory automatically set by the environment variable $$(QMAKE_DESTIDIR):

leonardo@leonardoveiga-pc:Serial-Studio$ git diff
diff --git a/ b/
index 878e552..d9ca17c 100644
--- a/
+++ b/
@@ -92,9 +92,9 @@ macx* {
linux:!android {
-    target.path = /usr/bin
-    icon.path = /usr/share/pixmaps
-    desktop.path = /usr/share/applications
+    target.path = $$(QMAKE_DESTIDIR)/usr/bin
+    icon.path = $$(QMAKE_DESTIDIR)/usr/share/pixmaps
+    desktop.path = $$(QMAKE_DESTIDIR)/usr/share/applications
     icon.files += deploy/linux/serial-studio.png
     desktop.files += deploy/linux/serial-studio.desktop
@@ -158,3 +158,5 @@ TRANSLATIONS += \
     assets/translations/es.ts \
     assets/translations/zh.ts \
\ No newline at end of file

In summary, we have added a line to set the DESTDIR and updated the paths where the target, icon and desktop files will be installed. The icon and desktop don’t matter too much for us, since we will run the application directly without a desktop environment.

Install resources into QMAKE_DESTDIR
Figure 9: Install resources into QMAKE_DESTDIR

As you can see in the diff above, the target binary is installed under /usr/bin relative to QMAKE_DESTDIR. Also, the binary name will be serial-studio with lowercase letters. Therefore, you need to edit the name of the main executable in the Torizon property exename to usr/bin/serial-studio.

Set the binary relative path on exename
Figure 10: Set the binary relative path on exename
Solve the Build and Runtime Dependencies

Under the hood we are using a container based on Debian Bullseye on Torizon 5, therefore, all regular Debian packages for Arm or Arm64, depending on your SoM, are available for you to use. There is also a Debian packages feed from Toradex, mostly either because they are not generally available or because they are compiled with hardware acceleration for a specific platform. You can learn more about how to find Debian packages in our conceptual article How to do C/C++ Development on Torizon.

In the Serial Studio README, we can get a clue about the project dependencies. You may also either read the source-code and try to understand any additional dependencies, or try to run the project and act on the error messages that will pop up during compile or runtime. In such a case, which I did for this project, you just have to press F5 and the deploy and debug process will start.

Build error due to missing development dependencies
Figure 11: Build error due to missing development dependencies

As you discover the dependencies, you’ll iteratively add packages to the SDK container, which we name devpackages (headers and libraries that should be linked at build time) and to the runtime container, which we name extrapackages (libraries and components that are dynamically linked with our application or executed on the target). This is covered in more detail on how to configure a C/C++ project, thus I’ll not dive into it.

Runtime error due to missing runtime dependencies
Figure 12: Runtime error due to missing runtime dependencies
Here are the dependencies I’ve found for this project so far, including the ones that were automatically added by the extension during the project import. I mean so far because I haven’t fully explored the potential of the project yet:
# devpackages


# extrapackages


You must explicitly tell the architecture in the devpackages, by appending all of them with :#%platform.debian-arch%#, for example qtdeclarative5-dev:#%platform.debian-arch%#, as they are installed in an x86 SDK container for cross-compilation. Learn more about it on Cross-compilation and Debian and the practical steps covering VS Code on Add Libraries Available on Debian Feeds.

How to add a build dependency for the target architecture
Figure 13: How to add a build dependency for the target architecture
Enable Hardware Access to the UART Interface

When using a container, you must explicitly allow it to access hardware interfaces. This adds a layer of security to your system as you can use multiple containers to limit the hardware access to a critical part of the application. The Torizon Best Practices Guide has a section dedicated to Hardware Access, and it is where I’ve learned how to grant access to the UART interface.

In summary, TorizonCore has a group named dialout, and you have to add the torizon user to this group. It can be done by editing the buildcommands property to include the statement RUN usermod -a -G dialout torizon.

Allow the application to access the target UARTs
Figure 14: Allow the application to access the target UARTs

Those are the last steps for importing the application. You can press F5 and VS Code will build, deploy and run your application in debug mode.

Running Serial Studio on Colibri iMX8X and a 7” 800x480 display
Figure 15: Running Serial Studio on Colibri iMX8X and a 7” 800x480 display

The Qt Debian Container for Torizon depends on the Weston Container for Torizon, as explained on the article Qt Debian Container for Torizon. The Visual Studio Code Extension for Torizon abstracts this by creating a Docker Compose file with the Weston container that is started before the application. You can override the default Docker Compose to add other containers that may be dependencies to your project, or tweak the existing configuration. One concrete example among endless possibilities would be to enable Remote Access the TorizonCore GUI Using VNC or RDP.

I’ve run Serial Studio first on the Colibri iMX8X + Iris Carrier Board + Resistive Touch Display 7” Parallel, but then I’ve noticed that the application is meant to run on something with at least 1040x620. Ok, let’s try on a bigger screen, but for that, I’ve used another hardware combination with HDMI, composed by the Apalis iMX8 + Ixora Carrier Board.

Running Serial Studio on Apalis iMX8 and an HDMI display
Figure 16: Running Serial Studio on Apalis iMX8 and an HDMI display

For a visual summary of the entire process of importing Serial Studio into Torizon using VS Code, watch the video below:


After going through the entire process, we noticed that solving dependencies is the most laborious and time-intensive part. Overall, importing was made straightforward with the aid of the VS Code extension, as we didn’t have to do things such as writing and building a Dockerfile or focusing on containers all the time. Instead, we were able to focus on configuring the application.

Given the various references provided along with the article, you may have noticed that a mix of learning and searching is a powerful strategy to achieve your goals faster. While I hope the inline references are good enough, I’ll leave them logically organized in a list at the end of the article and motivate you to go through the list of Torizon articles in the Torizon Documentation. Ultimately, if you don’t find what you are looking for, you can always post a question in our community.

There are additional steps for running and maintaining a graphical user interface (GUI) application that are inherent to embedded systems design. They are backed up by the Torizon platform and, to wrap up, I’ll give you a few tips on where to look. You can use the powerful and flexible TorizonCore Builder Tool to customize the base TorizonCore OS to your needs, including configuring and enabling your display of choice, adding a splash screen, pre-provisioning your application for production programming and pushing your custom OS image to Torizon OTA for long-term, scalable and secure over-the-air updates during the lifetime of your product. The VS Code extension helps you to easily connect your application to TorizonCore Builder and Torizon OTA by allowing you to push images to a container registry and export a Docker Compose file.

I hope you have enjoyed this read and that it helped you glimpse how powerful the Torizon platform is, going far beyond the base operating system – TorizonCore. See you in the next read!

Overview references

 1. The Torizon Platform
 2. Toradex Embedded Linux - Yocto and Torizon
 3. Serial Studio: Easily Visualise And Log Serial Data
 4. Serial-Studio repository on GitHub
 5. Webinar: Why containers aren’t just for hipsters!
 6. Webinar: Zero to Hero: Visual Studio Code for Embedded Linux Development

Technical references for Torizon, from the Torizon Documentation list

 7. Toradex Quickstart Guide
 8. Configure Build Environment for Torizon Containers
 9. Visual Studio Code Extension for Torizon
10. How to do C/C++ Development on Torizon
11. C/C++ Development and Debugging on TorizonCore Using Visual Studio Code
12. Qt C++ Application Development on Torizon Using Visual Studio Code
13. Debian Containers for Torizon
14. Using Multiple Containers with TorizonCore
15. Torizon Best Practices Guide
16. How to Import a C/C++ Application to Torizon
17. Remote Access the TorizonCore GUI Using VNC or RDP

Suggestions for future reads and next steps

18. TorizonCore Builder Tool
19. Setting up Displays With Torizon
20. Splash Screen Customization on TorizonCore
21. Pre-provisioning Docker Containers Onto a TorizonCore Image
22. Torizon OTA
23. Signing and pushing TorizonCore images to Torizon OTA

Author: Leonardo Veiga, Technical Marketing Lead, Toradex
Share this on:

Leave a comment

Please login to leave a comment!
Have a Question?