深入了解TorizonExtension

供稿:韬睿(上海)计算机科技有限公司

  • 关键词:Torizon,docker,vscode
  • 摘要:Torizon 是一种基于容器形式开发应用的操作系统。这不仅是指用户的应用在容器里面运行,应用的编译和调试也是需要借助容器。为了便于用户开发,Toradex 推出的Visual Studio Code/ Visual Studio Torizon Extension 能够完成后台的容器配置,便于用户使用。本文将介绍 Torizon Extension 后台实现的流程,从而帮助用户更好地调试应用程序。

By Toradex胡珊逢


Torizon 是一种基于容器形式开发应用的操作系统。这不仅是指用户的应用在容器里面运行,应用的编译和调试也是需要借助容器。为了便于用户开发,Toradex 推出的Visual Studio Code/ Visual Studio Torizon Extension 能够完成后台的容器配置,便于用户使用。本文将介绍 Torizon Extension 后台实现的流程,从而帮助用户更好地调试应用程序。

 

总体来讲,开发语言可以分为两类,一种需要编译后在目标设备上运行,例如 C/C++Qt  ,另外一种是可以直接解释运行,如 Python。这里我们以需要编译的开发语言 C/C++ 为例进行说明。对于传统的嵌入式 Linux C/C++ 应用开发,首先要在开发电脑上安装交叉编译工具或者包含交叉编译工具的 SDK,然后编写应用代码,用编译工具进行交叉编译,最后把编译好的二进制文件部署到目标设备上进行调试,常见的工具如 GDBTorizon 的总体流程也是如此,但最大的区别是交叉编译工具的安装、编译和调试并不需要用户手动运行相关指令,而是 Torizon Extension 会在开发电脑上自动创建一个 SDK 容器,里面包含所需的交叉编译工具和头文件等,用户的代码在容器里面进行编译并通过 GDB 调试。由于采用的是容器形式,因此 Torizon 的开发电脑可以是 Linux,也可以是 Windows 系统,Windows 需要安装 WSL

 

构建 SDK 容器

当用户在 Visual Studio Code/ Visual Studio 上安装了 Torizon Extension 之后,总体情况如下。在开发电脑和计算机模块上都将运行 DockerTorizon Extension 会根据用户代码类型,如 C/C++.Net 自动生成合适的 SDK 容器。用户代码文件通过 Torizon Extension 在 SDK 容器中使用合适的编译工具进行编译。然后 Torizon Extension 再生成一个可以部署到计算机模块上运行的 release 或者 debug 版本容器。对于 debug 版本容器,Torizon Extension 通过 SDK 容器对其进行调试,如使用 GDB 工具。

深入了解TorizonExtension_web1024.png 

 

下面我们将使用 Visual Studio Code 创建一个单 C 文件的 Hello World 工程,完成编译、调试和部署流程,并介绍这背后 Torizon Extension 是如何生成 SDK 容器、目标设备的 release/debug 版本容器以及如何执行编译、调试和部署任务。

 

首先在 Visual Studio Code 中创建一个 C/C++ 项目,选择 arm64v8-debian-no-ssh_bullseys 平台。

深入了解TorizonExtension_web1251.png 





深入了解TorizonExtension_web1253.png

创建完毕后,点击 Visual Studio Code 中 Terminal → New Terminal, 点击右边 Torizon IDE backend process 标签。在这个终端中会输出 SDK 容器构建时后台日志。  


 

 

当 SDK 容器构建成功后,可以在开发电脑的终端上输入下面命令,查看正在运行的容器。

--------------------------------------

$ docker container ls

--------------------------------------

深入了解TorizonExtension_web1517.png 

这里名为 keen_yalow 即为 Torizon Extension 生成的 SDK 容器。使用下面命令进入 SDK 容器,在容器的 /workspaces/HelloWorld 位置可以看到 Hello World 项目文件,包括 C 文件等。

--------------------------------------

$ docker exec -it keen_yalow bash

 

root@dell-5400:/# cd /workspaces/HelloWorld/

root@dell-5400:/workspaces/HelloWorld# ls

HelloWorld.c  appconfig_0

--------------------------------------

 

除了开发电脑的终端里使用 docker 命令进入 SDK 容器外,还可以在 Visual Studio Code 中 Terminal → New Terminal 新建一个 bash 终端直接进入 SDK 容器,同样也可以看到项目文件。

深入了解TorizonExtension_web1992.png 

 

这些项目文件同样也位于 Visual Studio Code 的文件浏览器中,用户可以直接对其进行修改。

深入了解TorizonExtension_web2048.png 

 

在开发电脑的终端中使用下面命令,看到 SDK 容器中 /workspaces/HelloWorld 目录实际上 bind 到开发电脑上创建项目时选择的保存目录。

--------------------------------------

$ docker inspect keen_yalow

--------------------------------------

 

深入了解TorizonExtension_web2239.png 

 

回到 Visual Studio Code 中打开的终端中,可以看到 SDK 容器中已经安装了 aarch64-linux-gnu-gcc 等交叉编译工具。这是 Torizon Extension 在创建 SDK 容器时自动安装的工具。用户无需手动安装。

深入了解TorizonExtension_web2370.png 

 

 

那么 Torizon Extension 是如何构建该 SDK 容器呢?得益于 Torizon Extension 的开源,我们可以一窥其中究竟。在一开始使用 Visual Studio Code 创建一个 C/C++ 项目,我们选择了 arm64v8-debian-no-ssh_bullseys 平台,Torizon Extension 则使用对应的模板文件。其中的 sdk.dockerfile 就是用于生成 SDK 容器的 dockerfile 文件,以及 config.yaml 配置文件。

sdk.dockerfile 中的 FROM #%platform.sdkbaseimage%# 指定 SDK 容器构建的基础容器镜像,sdkbaseimage 的配置位于 config.yaml 文件,即使用 torizon/debian:2-bullseye

--------------------------------------

baseimage:

  common:

    - "torizon/debian"

    - "2-bullseye"

--------------------------------------

 

 

然后通过 apt-get 命令继续安装其他调试所需的软件,如 gdb-multiarch 等。在 sdk.dockerfile 中还有一些其他参数,如 #%application.sdkpreinstallcommands%#,这就允许用户使用 dockerfile 文件编写语法在构建 SDK 容器时能够添加其他的软件和第三方库文件,甚至修改 SDK 容器本身的配置,如更改 debian 下载源。这些具体的参数可以参考这里。当然用户并不需要直接修改这里的配置文件,在 Visual Studio Code 的 Torizon Extension 插件中可以十分方便地进行更改。

深入了解TorizonExtension_web3875.png 

至此,我们已经阐释了 Torizon Extension 是如果构建 SDK 容器。用到的工具大致和传统嵌入式 Linux 开发类似,只是这操作都由 Torizon Extension 在容器内完成,并为用户提供灵活的配置功能。上述过程总体如下图。

深入了解TorizonExtension_web4002.png 

接下我们将看看编译是如何完成的。

 

 

应用程序编译

点击 Terminal -> Run Task -> build_debug 即开始编译 Debug 版本的应用编译。编译的时候在 Visual Studio Code 可以看到下面输出日志。

深入了解TorizonExtension_web4127.png 

在 SDK 容器中实际上执行了 aarch64-linux-gnu-gcc -g HelloWorld.c -o HelloWord 命令对 C 进行编译。本文创建项目是选了单个 C 文件的项目类型,所以编译时仅使用 HelloWorld.c

进入 SDK 容器的 /workspaces/HelloWorld目录,我们可以看到编译生成的二进制可执行文件 HelloWorld。它是针对 ARM aarch64 处理器进行交叉编译的。

深入了解TorizonExtension_web4348.png 

之所以能够完成上述编译任务,是由于在创建项目时,Torizon Extension 自动生成了 Visual Studio Code 配置文件 tasks.json。这里定义了 build_debug 任务具体执行的命令参数。用户因此只需要像上面提到的步骤,点击 build_debug 即可开始编译。

深入了解TorizonExtension_web4502.png 

 

编译总体过程如下图。

深入了解TorizonExtension_web4516.png 

完成编译后,接下来就是开始调试。

 

 

应用程序调试

在编译完成后点击 F开始调试用于程序。在 Torizon 上应用是以容器形式运行的,调试过程实际上将应用打包成一个可以在目标设备上运行的容器,并在容器里面启动调试工具。所以在按 F5 之后,Torizon Extension 会开始构建一个包含应用的新容器。

深入了解TorizonExtension_web4676.png 

当容器构建完毕并部署到目标设备后在 Visual Studio Code 会进入单步调试界面。

深入了解TorizonExtension_web4726.png 

此时我们查看设备上的的镜像 Images 和容器 Containers 会发现一个 debug 版本的 helloworld 镜像和一个正在运行的 debug 版本的 helloworld 容器。这些就是刚才按 F开始调试时,Torizon Extension 自动部署过来的。

深入了解TorizonExtension_web4870.png 

 

目标设备上的容器和开发电脑上的 SDK 容器之间通过 gdb 实现调试功能。使用 SSH 登录目标设备,运行下面命令查看正在运行的容器信息。

--------------------------------------

$ docker container ls

--------------------------------------

 

 

目标设备上 0.0.0.0:32768 映射到容器内部的 6502 端口。

深入了解TorizonExtension_web5084.png 

 

查看容器 ID 并进入容器。通过 ps 命令列出容器中所有运行的进程。这里可以看到有个 gdbserver 进程正在运行并监听 6502 端口。通过该进程,连接开发电脑上SDK 容器中的 gdb 客户端从而实现 Visual Studio Code 的调试功能。

深入了解TorizonExtension_web5219.png 

 

同样在开发电脑查看 SDK 容器内运行的进程,其中另一个是 gdb-multiarch 就是 gdb 客户端。

深入了解TorizonExtension_web5278.png 

那么现在我们将揭示 Torizon Extension 是如何为目标设备构建 debug 版本容器,以及在 VS Code 中是如何启动调试任务的。我们回到 Torizon Extension 的开源项目中的 arm64v8-debian-no-ssh_bullseye 模板。其中 debug.dockerfile就是用于生成 debug 版本容器的文件。

 

首先,FROM --platform=#%platform.architecture%# #%platform.baseimage%# 指定了 debug 版本容器使用的基础镜像,对应在 config.yaml 中配置属性参数。EXPOSE 6502 指定 gbdserver 监听端口。接下来 apt-get 命令安装 gdbserver。这期间还可以通过 #%application.extrapackages%# 来安装第三方软件和库文件,这些具体的参数可以参考这里。最后设置 debug 版本容器启动时运行的命令,CMD stdbuf -oL -eL gdbserver 0.0.0.0:6502 /#%application.appname%#/#%application.exename%# #%application.appargs%#。这里看到启动 gdbserver,并可以接收执行应用程序的参数。最终通过该容器即可在目标设备上启动一个 debug 版本容器,并在容器内使用 gdbserver VS Code 连接,调试用户应用程序。

 

仔细的你可能发现,debug.dockerfile 中并没有将编译好的应用二进制文件包含进来。使用 SSH 登录目标设备,运行下面命令查看正在运行的容器的详细信息。ec85215a7553 为正在运行的 debug 版本容器 ID

--------------------------------------

$ docker container inspect ec85215a7553

--------------------------------------

 

深入了解TorizonExtension_web6618.png 

Torizon 系统的 /home/torizon/HelloWorld 目录被映射到 debug 版本容器的 /HelloWorld 目录。Torizon Extension通过 rsync 将开发电脑上编译好的二进制文件 HelloWorld 复制到目标设备上默认用户 toriozn 的用户目录下 /home/torizon/HelloWorld。因此在上面的截图中我们能够看到 debug 版本容器中 gdbserver 其指向的应用路径位于 /HelloWorld/HelloWorld。之所以不将二进制应用直接放入容器的原因是,在调试期间用户应用代码可能会经常做修改,采用这样的方式只需要重新编译应用代码本身,而不必重新构建和部署整个 debug 版本容器。重新编译生成的二进制文件可以重新映射到原来的容器,这样的设计能够极大提高了调试效率。

 

在 Visual Studio Code 上按 F启动调试时,该任务是在  launch.json 文件中配置的。这里指定 gdb 作为调试器,具体为 gdbmultiarch。详细说明可以参考 VS Code Configuring C/C++ debugging

深入了解TorizonExtension_web7213.png 

调试总体过程如下。

深入了解TorizonExtension_web7225.png 

 

 

最终应用部署

当完成应用调试后,通常生成一个 release 版本最终发布容器。在上面的 debug 版本容器虽然已经包含了用户开发的应用,但也包含了 gdbserver 等额外的工具,并且应用通过 gdbserver 启动。这样的容器显然不适合用于最终的发布。因此我们需要在 VS Code 依次点击 Torizon C/C++:Switch to release configuration -> build_release ->Torizon: Build release container for the application -> Torizon: Deploy release container 生成一个包含用户应用的最终发布版本容器。

 

进行上面步骤前,在 Torizon Extension 插件中我们先删除之前已经部署和运行的 debug 版本镜像和容器。

深入了解TorizonExtension_web7620.png 

 

然后完成上述构建并部署发布版本容器。在开发电脑的终端上使用 docker images 可以查看到生成的发布版本容器。相比于 debug 版本容器,由于不再安装部分软件,因此发布版本容器体积也会小一些。

深入了解TorizonExtension_web7725.png 

 

部署完毕后,在目标设备上也可以看到这个发布版本容器。

深入了解TorizonExtension_web7755.png 

 

如果你已经看到这里,恭喜,你已经了解 Torizon Extension 后台运行的大部分过程。现在只剩下发布版本容器是如何构建的。这部分则相对简单些。继续回到Torizon Extension 的开源项目中的 arm64v8-debian-no-ssh_bullseye 模板。其中 release.dockerfile 就是用于生成发布版本容器的文件。发布版本容器使用的基础镜像和 debug 版本一样,FROM --platform=#%platform.architecture%# #%platform.baseimage%#,但不再使用 apt-get 安装 gdbserver 等工具。用户指定的第三方软件和库通过 "#%application.extrapackages%#" 仍可以安装。COPY work/#%application.appname%# /#%application.appname%# 将之前编译好的二进制应用文件复制到容器中。最后设置容器启动时运行的命令 CMD /#%application.appname%#/#%application.exename%# #%application.appargs%#。这里我们看到发布版本容器已经不再像 debug.dockerfile 使用 gdbserver 启动应用,而是直接执行用户的应用。这是发布版本容器和debug 版本容器最大的不同。

 

当通过 VS Code 运行发布版本容器后,在 Torizon Extension 界面中可以看到该容器相关信息。由于演示代码中执行完 printf 函数后程序会直接退出,因此这里看到的容器是停止状态。在下方容器信息窗口中,默认运行的程序是 /HelloWorld/HelloWorld,即上通过 release.dockerfile 生成容器时所添加的二进制文件。

深入了解TorizonExtension_web8857.png 

 

构建和部署发布版本容器总体过程如下。

深入了解TorizonExtension_web8879.png 

 

 

 

总结

Torizon Extension 简化了在嵌入式系统上使用容器进行应用开发,在代码编写、调试、部署各个阶段都提供了丰富的功能,采用容器形式的开发方式也有别于传统嵌入式 Linux,希望通过本文的介绍能够使您了解 Torizon Extension 背后的任务流程,从而更好地使用 Torizon。当然 Torizon Extension 的功能也远不止如此。



发布时间:2021年12月14日 15:13  人气:   审核编辑(王静 )
相关链接

我有需求