备注:这是一篇无赞助的客座文章,由微软首席项目经理Marc Goodner和Toradex创新工程师Jeremias Cordoba撰写。
今天,有很多嵌入式设备都将Linux作为其主要操作系统。这一点对于在开发机器上运行 Windows 的开发人员来说构成了挑战。本文我们将介绍一种新方法,让用户可以在嵌入式Arm设备上使用新版的Visual Studio进行C++开发,并在Windows主机电脑上使用容器来构建环境。我们要部署的设备是来自Toradex Colibri系列的系统模块,使用的是搭载了Arm Cortex A-7的恩智浦i.MX 6ULL SoC。接下来我们将使用Toradex Colibri模块连接蓝牙传感器从而来进行项目演示。
请注意,Visual Studio对这种项目的支持还处于早期的开发状态,未来几个月大家会看到微软和Toradex在不断改进。
前提条件
- 配备Wi-Fi/BT的Colibri i.MX 6ULL和 Aster载板
- TI SensorTag(低功耗蓝牙)
- 安装了Linux workload(版本不限)的Visual Studio 2017
- 适用于Windows系统的Docker
设置Toradex Colibri系统模块(SOM)
- 按照指南一步步进行安装,直到你可使用Toradex Easy installer安装操作系统。(如下图所示,可以选择任意一个Toradex Embedded Linux Demo镜像)
- 在设备上运行以下指令:
1 2 3 |
opkg update opkg install bluez5-noinst-tools connmanctl enable Bluetooth |
现在应该可以开始了!
创建一个Visual Studio项目
首先创建一个空白Linux项目。转到File > New > Project,然后选择Visual C++ > Cross Platform > Linux并选择空白模板。在这里,我们将项目命名为imx6-Bluetooth。

创建一个构建容器
对于该项目演示,我们会使用容器来设置构建环境。首先,从注册表本地拉取容器镜像。
1 |
docker pull jeremiascordoba/development:SDK |
我们首先创建了项目,所以我们有了源代码所在的路径。我们将把它映射到容器中。我的保存路径是: C:\source\repos\imx6-Bluetooth\imx6-Bluetooth。请注意,这是项目路径,而不是上层解决方案的路径。在下一个指令中,大家记得调整该值与存储项目的路径一致。
1 |
docker run -d -p 2222:22 --name colibri_sdk -v C:\source\repos\imx6-Bluetooth\imx6-Bluetooth:/root/projects/imx6-Bluetooth jeremiascordoba/development:SDK |
到了这一步,你的系统上应该有一个名为colibri_sdk的容器正在运行,其中包含构建工具,还有一个供Visual Studio发出指令的开放SSH端口。
将Visual Studio连接到容器和设备。在Visual Studio中,转到Tools > Options > Connection Manager。

点击“添加”并输入,如下图:
- 主机名:本地主机
- 端口:2222
- 用户:root
- 密码:toradex_sdk

Visual Studio会自动查询编译器,从而来获得包含路径和编译器标记等信息,这可以为设备提供专属的IntelliSense。然而,我们所使用的交叉编译器并不包含这些内容。不过我们可以通过手动设置来提供路径等内容。连接完成后,展开Connection Manager选项卡,选择Remote Headers IntelliSense Manager。

选择Explore。这将会打开Windows Explorer(资源管理器)。复制文件settings.xml.unused并将其命名为settings.xml。在文本编辑器中打开文件并将useCompiler的值更改为false。现在将以下路径添加到CDATA块开头的includeDirs中:
1 |
/usr/local/oecore-x86_64/sysroots/armv7at2hf-neon-angstrom-linux-gnueabi/usr/include; |
保存文件。不要关闭该资源管理器窗口,因为你们在后面的说明中会需要此路径。对于某些Windows 用户名较长的用户,可能需要使其CDATA块仅包含上述路径。此更改将防止在以后的步骤中出现长文件路径错误。
在Visual Studio的Remote Headers IntelliSense Manager窗口中单击Update(上图)。你们会注意到这比我们建立连接时花费的时间更长,因为我们现在正在等待整套headers返回。完成后单击Connection Manager并将连接添加到自己的设备中。使用IP地址,用户为root,密码留空。这时,你们会收到如下错误消息,显示Visual Studio找不到编译器,需要从目标路径获取headers。这种情况没关系,因为我们不会在这个设备上进行编译,只需要进行部署。

直接忽略该错误信息,点击Close,再点击OK退出Options对话框。
添加一些源代码并在容器中对其进行交叉编译
我们正在使用名称为durovsky/SensorTag2650的SensorTag存储库中的示例。我们仅使用此处的源代码与SensorTag对话,并不是整个项目。将src\senortag.cpp和include\filepaths.h在本地复制到你的Visual Studio项目路径中。右键单击Solution Explorer中的项目,然后单击add > existing item。选择你刚刚添加的文件。这时候,你的项目应该会如下图所示:

查看文件filepaths.h,并确保设备的存储路径里存在该文件。
现在我们需要知道Visual Studio如何编译ARM Target Board。右键单击项目并单击“属性”。因为之前我们已经将我们的项目路径映射到了容器中,所以选择“copy sources” 选项卡并将默认值改为no。我们使用的构建容器已经将gcc映射到交叉编译器,所以我们不需要在这个项目中覆盖编译器的默认值。展开C++选项卡,选择Command line。添加以下指令。
1 |
-march=armv7-a -mthumb -mfpu=neon -mfloat-abi=hard --sysroot=/usr/local/oecore-x86_64/sysroots/armv7at2hf-neon-angstrom-linux-gnueabi |
展开Linker选项卡并在General选项下将Copy Output更改为No。选择Command line并添加与上述相同指令。
1 |
-march=armv7-a -mthumb -mfpu=neon -mfloat-abi=hard --sysroot=/usr/local/oecore-x86_64/sysroots/armv7at2hf-neon-angstrom-linux-gnueabi |
以验证此时系统的设置情况,现在来尝试构建项目。如果有任何不妥之处,请仔细依照上述内容检查你的设置。
到目前为止,我们已经设置了一个构建容器,将它和我们的设备连接到Visual Studio,并在容器中交叉编译了一个可以在ARM开发板上运行的可执行文件。下面,我们需要将输出复制到设备上。
将交叉编译输出复制到Colibri i.MX 6ULL设备上
我们添加另一个项目从而将交叉编译的输出复制到我们的远程设备上。在Solution Explorer中,右键单击Solution,然后点击Add > New Project。在对话框中选择 Makefile Project(Linux)。

目前我们正在完善我们的解决方案,以便有一个项目可以用于构建和调试源代码(imx6-Bluetooth),也有另一个项目(CopyFiles)可以用于复制输出到远程ARM目标设备。这里的诀窍是,我们使用x64配置进行构建,使用ARM进行调试。右击Solution,选择属性,在Solution属性中的Project Dependencies,我们将把项目CopyFiles设置为依赖CrossCompileProject。现在选择Project Dependencies,并将CopyFiles设置为依赖imx6-Bluetooth。

现在Configuration Properties将 CopyFiles更改为使用ARM,但其他所有属性都保留为x64。

在这里,我们将Platform更改为ARM,如果选 Build并取消所有属性内容。这允许我们将imx6-Bluetooth平台更改为ARM平台以调试设备,但不会启动构建。这就是我们的x64项目在容器中使用交叉编译器的目的。

关闭Solution property(解决方案属性)页面。
现在,右键单击 imx6-Bluetooth项目并选择属性。确保 x64 平台处于激活状态。转到Build events > Post Build Events并添加以下指令行。
1 |
copy "$(ProjectDir)bin\$(Platform)\$(Configuration)\$(ProjectName).out" "$(ProjectDir)bin\ARM\$(Configuration)\$(ProjectName).out" |
这样做的目的是将输出的二进制文件存储在默认路径,以便我们稍后调试时由 gdb使用。如果已经覆盖ARM平台配置的项目属性中的默认值,则可以跳过此步骤。
现在,在CopyFiles的项目属性中的General页面上,可以远程构建设备并更改为你自己的设备了。

现在转到Build Events > Pre-Build Event。并确保ARM平台已激活。将以下指令添加到Additional Files to Copy栏框内。
1 |
..\imx6-Bluetooth\bin\x64\Debug\imx6-Bluetooth.out:=/home/root/projects/imx6-Bluetooth/imx6-Bluetooth.out |

现在,在Remote Post-Build Event页面,我们需要为二进制文件设置执行指令。
1 |
chmod +x /home/root/projects/imx6-Bluetooth/bin/ARM/Debug/imx6-Bluetooth.out |
我们先确认所有构建和复制设置都正确无误。右键单击Solution,然后单击Build Solution。
如果你收到错误提示,提示你路径无效、无法复制x64 项目输出,请在Explorer中打开项目位置并在bin文件夹下创建子目录ARM\Debug。
一旦一切都可以构建之后,我们开始进行调试。
在Colibri i.MX 6ULL设备上部署和调试
首先打开SensorTag,连接到 Colibri IMX6ULL 设备,并运行以下指令:
1 |
hcitool lescan |
记下从SensorTag返回的路径内容。
1 2 3 |
root@colibri-imx6ull:~# hcitool lescan LE Scan ... A0:E6:F8:C3:2C:84 (unknown) |
现在,在Visual Studio中将平台选项更改为 ARM。

现在,在General选项卡内imx6-Bluetooth 的Project Properties中,将远程计算机从本地主机更改为你的设备。

要设置Debugging,请转到Debugging Property页。在程序参数栏中提供你的 SensorTag地址。设备没有安装gdb,因此将Debugging Mode更改为gdbserver。

由于此连接没有Headers,因此你的设备不会有IntelliSense。如果你想取回它,需要转到 VC++ Directories的Project Properties。转到为容器连接保存Headers的路径。然后导航到子目录
usr\local\oecore-x86_64\sysroots\armv7at2hf-neon-angstrom-linux-gnueabi\usr\include。现在复制整个路径并将其值放入Include Directories栏。

在清除new_measurement标记的第319行附近设置一个间断点。现在按F5键启动调试器。这时候,你应该会看到如下图所示的内容:
结论
虽然这是一个相当小的项目,但它确实突出了在Windows上进行嵌入式开发的未来前景。随着时间的推移,从 Visual Studio将应用程序部署和调试到Linux嵌入式设备的能力将得到提升。嵌入式设备的未来似乎牢牢地扎根于Linux了,但目前的情况来说,人们还无需放弃其 Windows环境。
如果你们想要进一步了解,可以阅读Visual Studio的Linux C++文档。

文章翻译者:Rita Wang,CNX中文站翻译人员,文字功底扎实,将科技文献以通俗易懂的形式呈现给读者,对开源硬件、AI、IoT等领域多有涉猎。