Join Walt Ritscher for an in-depth discussion in this video Understand the debug build settings, part of Visual Studio 2015 Essentials 06 : Debug and Troubleshoot Code.
- View Offline
- Debugging an app in Visual Studio is easier if you have the debug build option enabled. To learn more, I'll need to look at the build configurations in Visual Studio. To do that, I'll use this ConsoleApp here and I'll look in this dropdown. Now I'm inside a C# project, I'm in a console application, and this dropdown contains two items: Debug and Release. Depending on which type of language you're working with and what project type, you may see more than this. For C# I just have these two. Debug is the default.
There are more options available, I can create more configurations by choosing this Configuration Manager, but for this chapter I'll just talk about these two. I'm ready to do a debug build in my application. I choose Debug from the menu and then I go to my Build menu and choose Build ConsoleApp. That's all I need to do. If I want to do a release version of the application, I choose from the dropdown, pick Release, and go through the same steps. In Release mode, your output code is optimized by the compiler.
It can rearrange your code for increased performance and memory optimization. But imagine what impact this has on your code when you are trying to step through multiple lines in the debugger. It makes it harder for Visual Studio and for you to determine what is really happening. Plus, local variables are sometimes optimized in strange ways, which makes it hard for debug watch windows to show the local variable values during a debug session. In Debug mode, there are no optimizations, which means debug builds can run slower than Release build.
There's one other difference between the two build choices, and it is related to something called a debug symbols file. You may have heard me talk about this. I mention symbol files elsewhere in this course. A symbols file allows the debugger to figure out which compiled instructions correspond to which line of uncompiled code. Having a symbols file makes your debugging life a whole lot easier. When compiling a build, the compiler creates a separate debug file which contains extensive debug symbol information. In Visual Studio, this is called a PDB file which is an abbreviation for program database.
The amount of information contained in this PDB file depends on which build option you choose, Release or Debug. I should point out that the C# and VB build engines create debug symbols for both Release and Debug builds. Let me show you where they live. I need to show all the files in Solution Explorer. To do that, I'll click on this Show All Files button in Solution Explorer. You'll see these ghost folders. These are files that are on my hard drive but are not normally shown inside the Solution Explorer.
This is the location for my compiled files. There's one folder for Debug, and one folder for Release. These match the items here, Debug and Release. When I look inside the Debug folder, I see my exe file, a config file, and a pdb file. You may see more files than this. The two important ones here are the exe and the pdb file. This is the debug symbols file. It has the same name as the executable. That's how Visual Studio and the debugger find it.
If I look in the Release folder, I'll see there's an exe and a pdb file too. Why have a pdb file for a release build? Well, you might need to debug a problem after you've released your application. What you'll do is you'll keep a copy of this pdb file. In fact, you should keep a copy of this pdb file for every public release of your application. If you've released three versions of your application, you should have three copies of the pdb file, one for each version, saved up somewhere safe.
That way, if you find a bug in version two of your application and you're currently on version three, you can go back to source control, pull out your source code, pull out your pdb file, and debug that released version of your software. Another way of saying this is let's say you have a crash dump from your user. You can use the pdb file for that release to debug it. Let's take a look at where the settings are that set up what happens in a release and debug build.
They're over here in the properties section. I'll double-click on Properties. I'll look at the Debug build. What happens when I choose the Debug build and choose to build a ConsoleApp? We're going to put a debug constant inside the code. This allows me to write branching code to say if I'm in a debug build, do this bit of code, if I'm in a release build, do this bit of code. It doesn't optimize the code and down here in this Advanced section, I can see what kind of output is put into that pdb file.
I'm using the full amount of information in there for the debug build. Now let's look at the release build. Choose the Release from this dropdown. We're no longer defining the debug constant, we are optimizing the code. Over here we're using a pdb only. I could choose none, that would mean that it would not create that pdb file. Now you have no way of debugging a crash dump from your users. You haven't kept that information around. Usually in the release configuration you want to have pdb only set.
That, again, is the default. While we're here, let's look at some of the settings you can set for the debugger. They're over here in the Debug menu in this section, Options. There's a lot more than I can talk about in this video in this dialogue. Let me just touch on a couple items. You've heard me mention symbol servers. Microsoft creates pdb files for everything that they create. For Office, for their server, operating systems, for Visual Studio, so somewhere on Microsoft servers is a copy of the pdb file for every executable and DOL that they create.
If you want to be able to use that, you can click here and then accept the items in this dialogue, and then you can pull their pdb files over from one of their servers and use it to help debug or step through some of their code. You can also this for .NET assemblies. If you go into the general section here, and check this check box here, you can enable .NET framework source code stepping. I'll be talking about some of these settings elsewhere in this chapter like I'll be talking about just in time, debugging later.
Let me just point out a few items in here. Some of them are obvious, like ask before deleting all breakpoints. Let's say you have a multiple process application. You're debugging and you've got two processes running. When you hit a break point in one of your processes, this will force Visual Studio to stop the other process. One of the features I'll show later in this course is breakpoint filters. You want to make sure you have this turned on. Enable the exception assistant is also important, I'll show that. This is a little pop-up dialogue that lets you see when an unhandled exception happens while you're debugging your application.
Enable just My Code, this says that when you're stepping through your code, if you have any third-party libraries, you'll skip over those. You won't waste any time looking through third-party code because you can't change it. You got to assume that it works correctly. Also, one of my favorite features is Edit and Continue. I'll talk about that later in this course. One of my favorite features here is this Enable UI Debugging Tools for XAML. I do a lot of XAML development, so I like to have this new debugging tool turned on so make sure this is checked.
Let's review. Visual Studio has two default build options, Debug and Release. The release build is the optimized version of your app and it has its associated pdb file. The debug build is the one that you interact with most when you're creating the application. Finally, there are a host of debug options available that let you fine-tune the debugging experience and get it set up just the way you want.
- Understanding the debugging vocabulary
- Understanding the defect categories
- Stepping through code
- Working with DataTips and visualizers
- Traversing the call stack
- Attaching debuggers to running processes
- Using the Just-in-Time debugger