Visual C++ for Linux Development

⏱ Updated on March 7, 2017 to cover inclusion of Linux development with C++ workload in Visual Studio 2017, content edited for clarity and reduced reliance on images.

The Linux Development with C++ workload  in Visual Studio 2017 enables you to author C++ code for Linux servers, desktops and devices. You can manage your connections to these machines from within Visual Studio. Visual Studio will automatically copy and remotely build your sources and can launch your application with the debugger. The Linux C++ project system supports targeting specific architectures, including ARM. Read on for how to get started with Linux C++ projects.

Today Visual Studio only supports building remotely on the Linux target machine. It is not limited to specific Linux distros, but we do have dependencies on the presence of some tools. Specifically, we need openssh-server, g++, gdb and gdbserver. Use your favorite package manager to install them, e.g. on Debian based systems:

sudo apt-get install openssh-server g++ gdb gdbserver

The best way to reach us is via our GitHub hosted issue list, directly via mail at vcpplinux-support@microsoft.com or find me on Twitter @robotdad.

This post is updated with content from update posts on this workload when they occur. As it has become lengthy here are the sections within this post.

Installation

Launch the Visual Studio 2017 installer and start a new installation or Modify an existing one. In the Workloads selection screen, scroll to Other Toolsets and select Linux development with C++ and click Install. That’s it.

For Visual Studio 2015 you can download the Visual C++ for Linux Development extension or get it from the extension manager in Visual Studio.

Your First VS Linux Project

To get started create a new project by going to File, New Project then expand Visual C++, Cross Platform, Linux.

Today we have four templates available; Blink for IoT devices like the Raspberry Pi, Console Application as a bare application, Empty for you to add sources and configure from a clean slate, and Makefile to leverage your own remote build process.

Let’s get started by creating a Console app. By default, the Console Application is set to a debug/x64 configuration. If your remote target is x86 or ARM you will want to change those options first. We have a detailed guide on using the Windows Subsystem for Linux with the C++ Linux workload as well.

After creating your project from that template set a break point on the printf statement, then select the menu item Debug, Start Debugging (F5) or the Remote GDB Debugger button on the menu bar.

If is your first time targeting a Linux machine you will be prompted for connection information.  This is triggered by building the project. We support both password and certificate based authentication, including the use of passphrases with certificates. Upon a successful connection, we save your connection information for subsequent connections. Yes, passwords/passphrases are encrypted when stored. You can manage your saved connections under Tools, Options, Cross Platform, Connection Manager. You can alternatively search for Connection Manager in the quick launch box in the upper right.

Upon connecting, your sources will be copied to the remote Linux machine, and we will invoke gcc to build the sources with the options from the Project Properties. After the build successfully completes, your code will be launched on the remote machine, and you will hit the break point you set earlier.

Linux development with C++ demo

Linux development with C++

Linux Project Properties

Let’s look at the Project Properties to understand where things got deployed on the remote Linux machine. Right click the project in the Solution Explorer and select Properties to bring up the Property Pages dialog.

Looking at the General Property Page settings for the project, you will see the remote build root is set to ~/projects/ by default and that we are setting the remote project directory to match your project name in that location. If you look on the Linux machine, you will find main.cpp as well as your build artifacts in ~/projects/ConsoleApplication1. You can see how the output and intermediate directories were configured here as well. Additionally, you will see that this project was configured as an application, thus your executable is under bin/x64/Debug/ as ConsoleApplication1.out. Notice that for configuration types static and dynamic libraries are also supported.

Under the Debugging Property Page, you have options for controlling the debugger. Here you can specify things like pre-launch commands to execute before starting debugging, program arguments to pass, as well as more advanced options for finer control.

The VC++ Directories Property Page is where you would specify paths for additional headers to enable IntelliSense for your own libraries.

Copy Sources allows you at a project level to control whether Visual Studio should copy files. By default, this is yes, but if you are controlling this through other means this is where you can disable that.

The C++ and Linker Property Pages are where you can control the parameters passed to GCC.

The Build Events Property Pages enables you to specify additional actions to take during all stages of the build locally and on the remote target machine. Even more control is possible through the Custom Build Step Property Page.

Console window

The Linux workload has a console window tailored for interacting with your remote executables. This window shows not just the output of your program but can also take input. To activate this window, use the menu Debug, Linux Console.

Here is a simple program you can try these features out with.

#include <cstdio>

void log(char filename[], char visitor[])
{
	FILE * pLog;
	pLog = fopen(filename, "a");
	if (pLog != NULL)
	{
		fputs(visitor, pLog);
		fputs("\n", pLog);
		fclose(pLog);
	}
}

int main(int argc, char* argv[])
{
	if (argc != 2) 
	{
		printf("Please pass filename as input parameter\n");
		return 1;
	}
	char input[20];
	printf("What IDE are you using?\n");
	scanf("%19[0-9a-zA-Z ]", input);
       printf("%s! You can use that with me?!\n", input);
	log(argv[1], input);
       return 0;
}

Specify a filename in the Command Arguments input on your project’s Debugging property page. You can set a working directory on that page as well; if it is not set your home directory will be the working directory.

Linux IoT Projects

Now let’s look at an IoT device, the Raspberry Pi. You can use any type of Pi running Raspbian. For the blink sample wiringPi is required. If you don’t have this setup on your device already you can either install it via apt or from source.

Go to File, New Project and under Visual C++, Cross Platform, Linux select Blink (Raspberry). This template comes preconfigured to export the GPIO pin for the LED so that the executable does not need to run as root. Right click your project in Solution Explorer and select Properties. Look under Build Events at Remote Post-Build Events and you will see a command specified to run on the remote Linux target after build that does this.

Now connect an LED to pin 17 on your Raspberry Pi as shown here.

LEDWiring

Open main.cpp and set a breakpoint on the delay call after the first digitalWrite and hit F5. You should see your LED light up and execution will pause at your breakpoint. Step through your code over the next digitalWrite call and you will see your LED turn off.

To enable IntelliSense for all of the libraries you have on your Pi follow the instructions below for copying your include files locally from your Raspberry Pi.

How to use the VC++ for Linux with the Intel Edison board

Using the VC++ for Linux extension with the Intel Edison board is largely like any other Linux system. First, you will want to make sure you have setup your device following Intel’s instructions. You should be able to connect to your Edison via the Visual Studio connection manager once you have connected it to your Wi-Fi network. If you need a direct connection to your Edison use these instructions for using Ethernet over USB with your Edison which will also work with the Connection Manager in Visual Studio.

The Edison makes it easy to start building an IoT application with sensor data. Accessories like the Arduino shield open make it easy to connect add-ons like the Grove shield from Seeed Studios. That shield lets you use any of the many available Grove sensors without having to worry about wiring a circuit on a breadboard, you can just get straight to your code. Intel has made this even easier to use with their UPM sensor library that covers a broad range of sensor including the Grove ones.

Shown here is an Edison compute module on an Arduino expansion board with a Grove shield attached and a temperature sensor plugged in.Edison module

In Visual Studio, create a new project, and under Visual C++, Cross Platform, Linux and select Empty Project. Make sure that you set your solution platform to x86 when targeting the Edison. Add a C++ file to the project and use the code from this Grove Temperature Sample from Intel. The UPM libraries are part of the default Yocto Linux image used on the Edison so no additional setup is needed to acquire them. You should change the include statement in the sample to properly reference their location as follows:

#include <upm/grove.h>

With that change, you are ready to build and run your code. You can see the output of this sample in Visual Studio’s debug mode in the Linux Console window.

To enable IntelliSense follow the instructions below for copying your include files locally from your Edison.

In a future post we’ll cover taking this sample further by connecting it to Azure IoT Hub.

Desktop Applications

We’ve covered headless and device Linux applications, what about desktop? Well, we have something special here: we’re going to launch an OpenGL app on a Linux desktop. First make sure your Linux desktop has been configured for OpenGL development. Here are the apt packages we used:

sudo apt-get install libgles1-mesa libgles1-mesa-dev freeglut3 freeglut3-dev

Create an empty Linux project and go grab the source for Spinning Cube from Julien Guertault’s OpenGL tutorial. Extract it and add main.c to your project. To enable Intellisense you will need to add the OpenGL headers to the VC++ Directories, you can get them from the OpenGL Registry or follow the instructions below for copying your include files locally from your Linux machine after you have installed the developer packages there.

Now open your Project Properties and on the Debugging Property Page add export DISPLAY=:0.0 to the Pre-Launch command. Under the Linker Input Property Page add the library dependencies: m;GL;GLU;glut.

Now hit F5.

Demo of Linux development C++ OpenGL

Linux development with C++ OpenGL demo

A couple of interesting places to put breakpoints are around line 80 where the cube rotation is set (try changing the alpha value) or in KeyboardFunc where you can inspect the values of the pressed key.

Makefile Project Template

The Makefile project template supports using external build systems on your remote machine (make, gmake, CMake, bash script etc.). This works as you would expect under the C++ project Property Pages you can set your local Intellisense paths, then on the remote build Property Page you add the commands, semicolon separated, to trigger your build on the remote machine.

I have put together some bash scripts that can generate Visual C++ Linux makefile projects with your sources based on the directory structure. These scripts do assume that the source code on the Linux machine is in a directory that has been mapped to Windows. They do set the flag in the Project Properties to not copy files remotely. These are unlikely to meet all needs but should give you a good starting point if you have a large project.

Usage tips

In this section we’re going to provide tips on using the extension to make you more productive.

Verbose build output

We’ve gotten a lot of questions about what exactly are the arguments being passed to GCC. Our build output doesn’t make this obvious, but you can enable it. There are two ways to get to the same place to change this setting. In the quick input window search for “verbosity”, or under Tools, Options go to Projects and Solutions, Build and Run. Now for the option of MSBuild Project output verbosity change it to diagnostic to see everything in your output window when you build. This can really help you find what exactly was passed to GCC to build your program if you are having issues.

Getting your include files

Everyone loves IntelliSense, but we’re not yet synchronizing the include files from your Linux system. Everyone has their own ways to either share or copy these files which is great. I wanted to share a really simple way to accomplish this I used in prepping the next section on the Intel Edison. I simply grab the whole folder locally onto my Windows box using PSCP. If you are on Windows 10 and have the Windows Subsystem for Linux installed you can do the exact same thing using scp.

pscp -r root@192.168.2.15:/usr/include .

Now on your project properties go to the VC++ Directories page and add your local path.

Remote file copy management

It is possible to specify at the file and project level whether or not a file should be remotely copied. This means you can use your existing build mechanisms just by mapping your existing sources locally and adding them to your project for editing and debugging. You can change either on the Property Page Copy Sources, either select the project or the individual file in Solution Explorer and choose Properties.

Overridable C/C++ Compiler Path

You can override the compiler commands used on the remote machine in the Property Pages on the C/C++ General Property Page. That will enable you to point to specific versions of GCC if needed or even point to an alternate compiler like clang. You can use either full paths or a command available on your path.

Build Events

Under Build Events node of the Project Properties there are also pre-build and pre-link remote build events as well as options for arbitrary file copy in all build events to provide greater flexibility.

Debugging Options

In addition to supporting gdbserver we have a gdb mode to improve compatibility where we may not have the correct client gdb bits on Windows for the remote target.

You can also override the debugger command itself, this is useful for debugging external programs compiled outside of Visual Studio.

The Debugging Property Page has support for additional gdb commands to be passed to the debugger to run when starting debugging. One example of where this can come in handy is Azure IoT projects. If you’ve used the Azure IoT C SDK on the Raspberry Pi you may have run into seeing an illegal exception being thrown when you start debugging. This is caused by some interactions between libcrypto and gdb. You can find some discussion of this issue here. While debugging can continue you can avoid this error by passing an instruction to the debugger before it starts, in this case “handle SIGILL nostop noprint”.

Reporting issues

In addition to our support email alias, vcpplinux-support, VC++ for Linux has a public issue list on GitHub. This is a great option for having public discussion or reporting bugs. We have added our backlog for the extension here as well. You can see what we are targeting for a release by looking at the milestone tagged to an issue.

So please do follow our GitHub issue list and use it by either submitting feedback or +1 existing feedback there. We love hearing about how and where our extension is being used. Feel free to use our support email alias if you want to share that with us even if you don’t have any issues.

Changes

For Visual Studio 2017 we will post individual updates on new features as they become available and integrate content here as appropriate. We will also update changes in the Visual Studio change log as appropriate. For Visual Studio 2015 we will continue to post our change logs on the Visual Studio Gallery page for the Linux extension when it is updated.

Go Write Some Native Linux Code

We hope you are as excited by the possibilities this opens up as we are.

Install the Linux Development with C++ workload in Visual Studio 2017, try it out and let us know what works for you, what doesn’t or if you encounter any issues. You can reach us here through the blog, via the Visual Studio Feedback channel, or find our team @visualc or me, @robotdad, on Twitter.

– Marc Goodner

Post Changelog

March 7, 2017 to cover inclusion of Linux development with C++ workload in Visual Studio 2017, content edited for clarity and reduced reliance on images.

September 13, 2016 to include content from the 1.0.5 Update, added a TOC, and updated how to report issues.

 June 17, 2016 to remove mention of a dependency no longer needed and pull contact info to top.

June 14, 2016 to include content from the 1.0.3 Update.