Visual Studio 2017 with an Embedded Linux Arm Device

This is a non-sponsored guest post written by Marc Goodner: Principal Program Manager, Microsoft, and Jeremias Cordoba: Innovation Engineer, Toradex.

Today many embedded devices run some flavor of Linux as their primary operating system. This poses a challenge to developers who run Windows on their development machine. This article explains a new way to use the latest Visual Studio for C++ development on an embedded Arm Devices from a Windows Host PC using containers for the build environment. The device we are deploying to is from the Toradex Colibri Family of System on Modules using the NXP i.MX 6ULL SoC, which features an Arm Cortex A-7. As a demo project we will connect a Bluetooth Sensor with the Toradex Colibri Module.

Please note that Visual Studio support for this case is in an early state, you will see improvements from Microsoft and Toradex in the coming months.


Set up Toradex Colibri System-on-Module

  • You should now be good to go!

Create a VS Project

Get started by creating a blank Linux project. Go to File > New > Project, then select Visual C++ > Cross Platform > Linux and select the blank template. Here we are naming the project imx6-Bluetooth.

Click to Enlarge

Create a build container

For this demo we are going to use containers for setting up our build environment. First pull the container image locally from the registry.

We created the project first, so we have our directory where our source will live. We will map that into the container. I saved mine here: C:\source\repos\imx6-Bluetooth\imx6-Bluetooth. Note that is the project directory, not the top level solution directory. In the next command adjust that value to match where you saved your project.

You should now have a running container named colibri_sdk on your system that contains the build tools and has an open SSH port for Visual Studio to issue commands over.

Connect Visual Studio to the container and device

In Visual Studio go to Tools > Options > Connection Manager.


Click add and enter

  • Host name: localhost
  • Port: 2222
  • User: root
  • Password: toradex_sdk

Visual-Studio-Connect-to-Remote-SystemVisual Studio automatically queries the compiler to get include locations and compiler flags to provide machine specific IntelliSense. However, the cross compilers we are using are not built with this information. We can manually provide the include locations though. After the connection is complete expand the node under Connection Manager and select Remote Headers IntelliSense Manager.

Visual-Studio-IntelliSense-ManagerSelect Explore. This brings up Windows Explorer. Copy the file settings.xml.unused and name it settings.xml. Open the file in a text editor and change the value of useCompiler to false. Now add the following location to includeDirs at the beginning of the CDATA block:

Save the file. Keep this explorer window open though as you will need this path later in the instructions. For some with long Windows usernames, it might be necessary to make it such that the CDATA block only contains the above location. This change will prevent long file path errors in future steps.

In Visual Studio, click Update in the Remote Headers IntelliSense Manager. You’ll notice this will take a moment longer than when we established the connection as we’re now getting a full set of headers back. When it is done click Connection Manager and add the connection to your device. Use the IP address, root for the user and leave password blank. You will get an error that Visual Studio could not find the compiler to get the headers from the target. That’s OK as we’re not going to compile on this device, only deploy.


Select Close to dismiss the error, and OK again to exit the Options dialog.

Add some source and cross compile it in a container

We’re using a sample from this SensorTag repo: durovsky/SensorTag2650. We are only using the source here for talking to the SensorTag, not the whole project. Copy src\senortag.cpp and include\filepaths.h locally into your VS project directory. Right click the project in the solution explorer and click add > existing item. Select the files you just added. You project should now look like this.


Look at filepaths.h. Make sure the path to where the file will live on your device exists.

Now we need to tell Visual Studio how to compile for the ARM target board. Right click the project and click properties. We have mapped our project directory into the container, so select the copy sources node and change the default to no. The build container we are using has aliased gcc to the cross compilers, so we do not need to override the default values for the compiler in this project. Expand the C++ node and select command line. Add the following:

Expand the Linker node and under General change Copy Output to No. Select command line and add the same line as above.

Now try and build the project to validate things work so far. If anything is amiss carefully check your settings against the above.

So far we have setup a build container, connected it and our device to Visual Studio, and cross compiled an executable in the container that can run on the ARM development board. Now we need to get the output to the board.

Copying the cross compiled output to the Colibri i.MX 6ULL device

We are going to add another project to copy the cross compiled output to our remote device. In the Solution Explorer, right click the solution, then Add > New Project. In the dialog select Makefile.

Click to Enlarge

We are organizing our solution such that there is a project used for building and debugging source (imx6-Bluetooth), and another (CopyFiles) to copy outputs to a remote ARM target. The trick here is that we use the x64 configuration for build and ARM for debug. In the solution properties under Project Dependencies we will set the project CopyFiles to depend on CrossCompileProject. Right click the solution and select properties. Now select Project Dependencies and set CopyFiles to depend on imx6-Bluetooth.

Click to Enlarge

Now under configuration properties change CopyFiles to use ARM but leave everything else x64.

Click to Enlarge

While we are here change Platform to ARM and unselect Build for everything. This allows us to change the imx6-Bluetooth platform to ARM for debugging the device but not kick off a build. That’s what our x64 project using the cross compilers in the container is for.

Click to Enlarge

Close the solution property pages.

Now, right click the imx6-Bluetooth project and select properties. Make sure the x64 platform is active. Go to Build events > Post Build Events and add the following command line.

Click to Enlarge

What this is going to do is put the output binary in a default location for use by gdb when we are debugging later. You could skip this if you overrode the defaults in the project properties for the ARM platform configuration.

Now in the project properties for CopyFiles on the General page change the remote build machine to your device.

Click to Enlarge

Now go to Build Events > Pre-Build Event. Make sure the platform has ARM active. Add the following command to additional files to copy.

Click to Enlarge

Now under Remote Post-Build Event we need to set the execute bit for the binary.


Let’s make sure everything builds and copies correctly. Right click the solution and click Build Solution.

If you get an error that the output of the x64 project could not be copied because of a path not found, open the project location in Explorer and create the subdirectories ARM\Debug under the bin folder.

Once everything is building let’s get Debugging working.

Deploy and debug on the Colibri i.MX 6ULL device

First turn on your SensorTag and connect to your Colibri IMX6ULL device and run the following command

Make a note of the address your get back for your SensorTag.

Now in Visual Studio change the platform to ARM.


Now in the project properties for imx6-Bluetooth on the General tab change the remote computer from local host to your device.

Click to Enlarge

To configure debugging go to the Debugging property page. In program arguments provide your SensorTag address. The device does not have gdb installed, so change debugging mode to gdbserver.

Click to Enlarge

Since this connection doesn’t have headers you won’t have IntelliSense. If you would like to get it back, go to VC++ Directories project properties. Go to the location where your headers were saved for the container connection. Navigate to the subdirectory usr\local\oecore-x86_64\sysroots\armv7at2hf-neon-angstrom-linux-gnueabi\usr\include. Now copy the entire path and put the value into the Include Directories field.

Click to Enlarge

Set a breakpoint around line 319 where the flag for new_measurement is cleared. Now launch the debugger via F5.

You should see something like the following.

visual studio debugger
Click to Enlarge


While this was a rather small project, it does highlight the future prospect of embedded development on Windows. The ability to deploy and debug applications to Linux embedded devices from Visual Studio will improve as time goes on. The future of embedded devices appears to be firmly rooted in Linux but, for now one does not need abandon their Windows environment.

To go further you can read Visual Studio’s Linux C++ documentation.

Leave a Reply

5 Comment threads
5 Thread replies
Most reacted comment
Hottest comment thread
8 Comment authors
cnxsoftJeroenDimnotzed Recent comment authors
newest oldest most voted
Notify of

Any thoughts on how this compares with VisualGDB? A commercial add-on to Visual Studio, but optimized for embedded programming.. albeit with limited debugger support (ex. no Black Magic Probe).


“This is a non-sponsored guest post written by Marc Goodner: Principal Program Manager, Microsoft, and Jeremias Cordoba: Innovation Engineer, Toradex.” … Cool! Nice to see Microsoft outside the traditional Microsoft world.


It’s amusing to see that certain things have still not evolved in this “other” world. The procedure to perform the actions on the linux side requires 13 copy-pastable lines while the windows side requires 19 full-screen screenshots, some non-obvious or with areas circled to show precisely where to click. Sadly, scripting, work factoring and reproducibility seem still not to be a concern over there, and I don’t miss the old days where I was forced to repeat the same painful gestures under windows 3.11 for every attempt at doing something which repeatedly failed. Nowadays, I just have to paste the 13 lines from my mouse buffer into a terminal, or to press up-arrow then enter to restart the failed command. In the 21th century the machine is expected to the repetitive work for you, not the reverse. I’m really surprised that and environment made for developers doesn’t support scripting to make their lives easier.


Hey when you get paid by the hour, why would you do it any other way?


This is actually an excellent point I hadn’t thought about! Suddenly it makes a lot of sense and reminds me quite a number of situations with consultants not seeminng happy that I was helping them stop wasting their time by typing 3 lines that provide in 5 seconds what they planned to do for the whole day with a mouse in the right hand and a cup of coffee in the left one!


For hobbyists I guess is ok. But I would expect from professional developers to be able to do this development on Linux. I would never hire someone who’s experience on developing Linux software was on Windows. Even if it was a cross platform framework like Qt.

And generally this thing “Microsoft loves Linux” is a joke.


Maybe its time for a Visual Studio for Linux, because most linux dev’s probably won’t like going to windows to code.


Visual Studio for Linux is already there:

Formats: deb, rpm, tar.gz


It’s Visual Studio Code, not Visual Studio 2017….