⏱ Updated on March 06, 2017 with the latest functionality in Visual Studio 2017 RTW
Welcome to Visual Studio 2017! Starting with this release, Visual Studio supports opening folders containing source code without the need to create any solutions or projects. This makes it a lot simpler to get started with Visual Studio, even if your project is not an MSBuild-based project. The new functionality, “Open Folder”, also offers a more natural source file management as well as access to the powerful code understanding, editing, building and debugging capabilities that Visual Studio already provides for MSBuild projects.
This post describes the “Open Folder” support for C++ codebases. You will learn how to use “Open Folder” to easily:
- read C++ code
- edit C++ code
- customize the reading and editing experience
- build C++ projects
- debug C++ binaries
All this without having to create and maintain any .vcxproj or .sln files.
Getting started with “Open Folder” for C++
The new functionality in Visual Studio 2017 called “Open Folder” has full support for C++. If you have a CMake-based project, take a look also at this post describing our Visual Studio’s streamlined “Open Folder” experience for CMake. If your project is using another build system, read on.
When you install the product, make sure to install one of the C++ workloads e.g. “Desktop development with C++” or “Game development with C++”.
After that, all you have to do is run the “Open Folder” command and select the folder you want to browse (either from File > Open > Folder or Quick Launch) or directly launch devenv.exe <foldername> from the command prompt.
Reading C++ code
As soon as you open the folder, Solution Explorer will immediately display the files in that folder and you can open any files in the editor. In the background, Visual Studio will start indexing the C++ sources in your folder.
You now have access to all the Visual Studio capabilities of reading and browsing C++ code (e.g. Find all references, Go to symbol, Peek definition, Semantic colorization and highlighting, Class View, Call Hierarchy, to name a few).
Editing C++ code
All these C++ browsing and navigation services work without you having to create any Visual C++ projects like you would’ve in previous Visual Studio releases (through the “Create Project from Existing Code” wizard).
As you create, rename or remove source files from your project, you don’t have to worry anymore about updating the Visual C++ projects as well – Visual Studio will rely on the folder structure and monitor changes on disk as needed. Also, when you edit code, Visual Studio’s IntelliSense will continue updating and assisting you with the latest information from your sources.
While editing your code, you can also use all of the refactoring features that Visual Studio supports for C++ e.g. Rename symbol, Extract function, Move definition location, Change signature, Convert to raw string literals, etc.
Customizing C++ configuration settings
By default, VS will provide two C++ configurations for IntelliSense and browsing: Debug and Release. These configurations are consistent with the configurations provided by Single File IntelliSense functionality introduced in VS 2015.
Depending on the project, you may need to customize these configurations with more information about your source code e.g. additional include paths, additional defines or compiler switches. To do that, create a file called CppProperties.json in the root folder – this file will aid in configuring C++ IntelliSense and browsing.
CppProperties.json:
{ "configurations": [ { "name": "Windows x64", "includePath": [ "include" ], "defines": [ "_DEBUG" ], "compilerSwitches": "/std:c++14", "intelliSenseMode": "msvc-x64", "forcedInclude": [ "pch.h" ], "undefines": [] } ] }
The following properties are available for a given configuration:
- name: is the configuration name that will show up in the C++ configuration dropdown
- includePath: the list of folders that should be specified in the include path (maps to /I for most compilers)
- defines: the list of macros that should be defined (maps to /D for most compilers)
- compilerSwitches: to specify one or more additional switches that can influence IntelliSense behavior
- forcedInclude: specifies a header to be automatically included in every compilation unit (maps to /FI for MSVC or -include for clang)
- undefines: list of macros to be undefined (maps to /U for MSVC)
- intelliSenseMode: specifies the IntelliSense engine to be used. You can specify the architecture specific variants for either MSVC or Clang:
- msvc-x86 (the default)
- msvc-x64
- msvc-arm
- windows-clang-x86
- windows-clang-x64
- windows-clang-arm
This file supports environment variable expansion for include paths and other property values. The syntax is ${env.FOODIR} to expand an environment variable %FOODIR%.
You also have access to built-in macros inside this file:
- ${workspaceRoot} – provides the full path to the workspace folder
- ${projectRoot} – full path to the folder where CppProperties.json is placed
- ${vsInstallDir} – full path to the folder where the running instance of VS 2017 is installed
For example, if your project has an include folder and also includes windows.h and friends from the Windows SDK (which is common), you may want to update your configuration file with these includes:
CppProperties.json:
{ "configurations": [ { "name": "Windows", "includePath": [ // local include folder "${workspaceRoot}\\include", // Windows SDK and CRT headers "${env.WindowsSdkDir}include\\${env.WindowsSDKVersion}\\ucrt", "${env.NETFXSDKDir}\\include\\um", "${env.WindowsSdkDir}include\\${env.WindowsSDKVersion}\\um", "${env.WindowsSdkDir}include\\${env.WindowsSDKVersion}\\shared", "${env.VCToolsInstallDir}include" ] } ] }
Note: %WindowsSdkDir% and %VCToolsInstallDir% are not set as global environment variables so make sure you start devenv.exe from a “Developer Command Prompt for VS 2017 ” that defines these variables.
Tip: In general, the Error List window is a good starting point to review any IntelliSense errors caused by missing includes – filter its content to “IntelliSense only” and error code E1696:
You can create as many configurations as you want in the CppProperties.json file and easily switch between them from the C++ configuration dropdown in the Standard toolbar
CppProperties.json
{ "configurations": [ { "name": "Windows", ... }, { "name": "with EXTERNAL_CODECS", ... } ] }
Building C++ projects
You can automate build scripts or any other external operations on the files you have in your current workspace by running them as tasks directly in the IDE. You can configure a new task by right-clicking on a file or folder and select “Customize Task Settings”.
This will create a new file tasks.vs.json under the hidden .vs folder in your workspace and a new task that you can customize.
By default, a task can be executed from the context menu of the file in Solution Explorer. For each task, you will find a new entry at the bottom of the context menu.
Tasks.vs.json
{ "version": "0.2.1", "tasks": [ { "taskName": "Echo filename", "appliesTo": "makefile", "type": "command", "command": "${env.COMSPEC}", "args": ["echo ${file}"] } ] }
Just like CppProperties.json, in tasks.vs.json you can consume environment variables by using the syntax ${env.VARIABLE}.
Additionally, you can use built-in macros inside your task properties:
- ${workspaceRoot} – provides the full path to the workspace folder (e.g. “C:\sources\hello”)
- ${file} – provides the full path of the file or folder selected to run this task against (e.g. “C:\sources\hello\src\hello.cpp”)
- ${relativeFile} – provides the relative path to the file or folder (e.g. “src\hello.cpp”)
- ${fileBasename} – provides the name of the file without path or extension (e.g. “hello”)
- ${fileDirname} – provides the the full path to the file, excluding the filename (e.g. “C:\sources\hello\src”)
- ${fileExtname} – provides the extension of the selected file (e.g. “.cpp”)
You can also specify additional user macros yourself that you can use in the task properties e.g. ${outDir} in the example below:
Tasks.vs.json
{ "version": "0.2.1", "outDir": "${workspaceRoot}\\bin", "tasks": [ { "taskName": "List outputs", "appliesTo": "*", "type": "command", "command": "${env.COMSPEC}", "args": [ "dir ${outDir}" ] } ] }
By specifying the “contextType” for a given task to equal “build“, “clean” or “rebuild” you can wire up the VS build-in commands for Build, Clean and Rebuild that can be invoked from the context menu.
Tasks.vs.json
{ "version": "0.2.1", "tasks": [ { "taskName": "makefile-build", "appliesTo": "makefile", "type": "command", "contextType": "build", "command": "nmake" }, { "taskName": "makefile-clean", "appliesTo": "makefile", "type": "command", "contextType": "clean", "command": "nmake", "args": ["clean"] } ] }
You can create tasks for any file or folder by specifying its name in the “appliesTo” field. But to create more generic tasks you can use file masks. For example:
- “appliesTo”: “*” – task is available to all files and folders in the workspace
- “appliesTo”: “*/” – task is available to all folders in the workspace
- “appliesTo”: “*.cpp” – task is available to all files with the extension .cpp in the workspace
- “appliesTo”: “/*.cpp” – task is available to all files with the extension .cpp in the root of the workspace
- “appliesTo”: “src/*/” – task is available to all subfolders of the “src” folder
- “appliesTo”: “makefile” – task is available to all makefile files in the workspace
- “appliesTo”: “/makefile” – task is available only on the makefile in the root of the workspace
Debugging C++ binaries
To get started with debugging in Visual Studio, you want to navigate in Solution Explorer to your executable. Then right click, and select “Debug” – this will immediately start a debugging session for this executable.
Alternatively, you can specify an output binary in your task definition (via “output”). Once you do that, this binary will be automatically launched under the debugger if you select the source file as a startup item (right click, “Set as Startup Item”) or just right-click on the source file and choose “Debug”.
Tasks.vs.json
{ "version": "0.2.1", "tasks": [ { "taskName": "makefile-build", "appliesTo": "makefile", "type": "command", "contextType": "build", "command": "nmake", "output": "${workspaceRoot}\\bin\\hellomake.exe" } ] }
If you want to customize your program’s arguments, select “Debug and Launch Settings” instead. This will create a new launch.vs.json file prepopulated with the information about the program you have selected.
To specify additional arguments, just add them in the “args” JSON array as in the example below
launch.vs.json:
{ "version": "0.2.1", "defaults": {}, "configurations": [ { "type": "default", "project": "CPP\\7zip\\Bundles\\Alone\\O\\7za.exe", "name": "7za.exe list content of helloworld.zip", "args": [ "l", "d:\\sources\\helloworld.zip" ] } ] }
As soon as you save this file, a new entry in the Debug Target dropdown will be available and you can select it to start the debugger. By editing the launch.vs.json file, you can create as many debug configurations as you like, for any number of executables. If you press F5 now, the debugger will launch and hit any breakpoint you may have already set. All the familiar debugger windows and functionality is now available.
What’s next
Download Visual Studio 2017 today and give “Open Folder” a try – no need to create VS projects and solution files anymore to become productive in VS.
We’re continuing work on making this experience even better. In upcoming releases, you will see us enhance the way the C++ browsing and navigation works, as well as supporting more debugger types, eventually reaching parity with our MSBuild-based project functionality. Your feedback is really important in informing our next steps so don’t hesitate to share it. We’re listening!
0 comments