Xcode: using the “Debug executable” checkbox to step through app release versions

Here’s an Xcode setting, but what does it do for developers?

There’s a checkbox named “Debug executable” on the “Info” pane for Xcode’s “Debugging Options in the Scheme Editor.” Why is there such a dearth of information on this checkbox, a “simple” Xcode scheme option? Apple has little to say about the feature. Information about it is scarce on the web. I’ve heard all sorts of different opinions about what the checkbox does or doesn’t do. (Some of this may be exacerbated by Apple releasing buggy versions of Xcode.)

I’ll discover and explain, using the scientific method, how the “Debug executable” checkbox works. You may be thinking this is much ado about one checkbox, but my purpose is to get you to think about and learn a lot about debugging with Xcode. The absolute best developers are the ones with great and instinctive debugging, nay, TROUBLESHOOTING, skills.


Note that I’ve peppered this article with many links defining the terms I’m using in my discussion, especially regarding debugging with Xcode. I encourage you to follow those links. Debugging is a huge topic — a science in and of itself.

I’m going to clear up a lot of confusion about this Xcode feature that most of you have seen, but that many of you never use and probably don’t understand. I’m not picking on you. I’m speaking from my own experience and from interacting with hundreds of other Xcode users. Way back, I didn’t know that this this feature was extremely useful, but I figured it out.

NOTE: I will fully explain the “Debug executable” checkbox here. But I’m going to emphasize a scenario in which a developer is at a point in development when she/he is pretty much done debugging a first draft or initial bug patch and wants to concentrate on “Release” version behavior.

Why are people confused?
Read Apple’s explanation for the “Debug executable” checkbox:

Select the “Debug executable” checkbox if you want to run with the debugger enabled. With the debugger running, you can use Debug > Attach to Process on a process that has been launched with debugging disabled, if needed.

The first sentence, “Select the ‘Debug executable’ checkbox if you want to run with the debugger enabled,” makes sense. 1) If I want to debug — set and stop at breakpoints and get info from the “Debug Navigator” — I tick the “Debug executable” checkbox and the debugger is truly enabled. 2) If I don’t tick the “Debug executable” checkbox, then no debugging features are enabled; in other words, the debugger is disabled.

Things get more confusing when the active scheme’s “Build Configuration” dropdown box is set to a value of “Release” and you’re trying to understand what checking/ticking the “Debug executable” checkbox does. I’ll explain below.

The second sentence, “With the debugger running, you can use Debug > Attach to Process on a process that has been launched with debugging disabled, if needed,” doesn’t make sense. I have no idea what Apple is talking about. You’ll see what I mean as I explain the experiment I performed.

Introduction

For clearly explaining the “Debug executable” checkbox, I’m using a simple Xcode 9 project named “CrashLogDemo” which has one target, also named “CrashLogDemo.” My “CrashLogDemo” target is the active scheme. You’ll see this in Figures 2 and 3 shown below.

I always start design and development with my active scheme’s “Build Configuration” set to “Debug.” That way, I can set breakpoints anytime I want to walk through my code, examine paths of execution, determine the flow (especially if threading is involved), inspect variables, examine the call stack, find problems, and fix problems. Let’s say that I’ve reached a point in time in which I’ve done enough development and debugging and am pondering releasing my app to a customer for testing, perhaps using TestFlight.

When I want to see how my app behaves after optimizations are applied, debug symbols are stripped out, and hopefully my app has a smaller memory footprint and runs faster than a debug version would run, I set my active scheme’s “Build Configuration” to “Release,” again as shown in Figures 2 and 3 below.

Wouldn’t it be nice if I could still debug the “Release” version of my app without jumping back and forth between active schemes: I’m testing my release, something goes wrong, I have to change my active scheme’s “Build Configuration” back to “Debug,” I figure things out, I change back to “Release,” I find something else, I jump back to “Debug,” and yada, yada, yada… Software development can involve a lot of pressure. Time is always at a premium. I like to cut down on unnecessary steps when I can.

You’ll see that the “Debug executable” checkbox can provide a convenient configuration. I can debug the release version of my app FROM Xcode and make use of many of its awesome features. I can stil use: the Simulator, where I can interact with my app; the Debug Navigator, where I can examine CPU, memory, energy, disk, and network usage, especially if connected to a device; the Debug View Hierarchy 3D viewer, where I can inspect my user interface components and Auto Layout constraints; and, the Issue Navigator, to see if I’ve got some warnings I need to take care of or can safely ignore.

Figuring out how the “Debug executable” checkbox works

You probably already noticed that I’ve provided some hints as to what the “Debug executable” checkbox can do. I want to show you the steps I used to figure out what it can do. I want to convey to you the fact that sometimes you have no other choice than to perform a controlled experiment, logically organized to narrow a process down to its most basic purpose. That’s what I’ll do next: use a step-by-step process to figure this checkbox out.

Prerequisites
In order for debugging to work for the purposes of this post, and for most developers’ workflows, you should configure your target’s “Build Settings” -> “Build Options” -> “Debug Information Format” -> “Release” setting to “DWARF with dSYM File.” This is the Xcode default and it makes sense that it is. When you build a “Release” version of your app, you should always keep a copy of your symbol file, called a “.dSYM”. If you don’t know what I’m talking about, please read my tutorial on “Debugging: symbolicating crash reports manually (stack trace, backtrace).” Here’s the setting I’m referring to:

Click to enlarge


Figure 1. “Build Settings” for .dSYM creation.

Run “Release” app with “Debug executable” checkbox disabled

The first thing I did to figure out the “Debug executable” checkbox was to select/edit my active scheme:

Click to enlarge


Figure 2. Edit my active scheme.

Then I left “Debug executable” unchecked:

Click to enlarge


Figure 3. Leave “Debug executable” option unchecked.

I built my project to see what products were created. Watch as a release version of my app (.app) bundle and its corresponding symbol bundle (.dSYM) were generated by Xcode. Remember how important it is to have that .dSYM for debugging?

Click to enlarge


Figure 4. Release app version and .dSYM created.


Remember that I configured the scheme for a “Release” app with the “Debug executable” checkbox disabled. I set a breakpoint in my code and then ran the app. Guess what happened… Xcode didn’t stop at my breakpoint. Watch:

Click to enlarge


Figure 5. No breakpoints when “Debug executable” checkbox disabled.

At this point, I should’ve been able to make some preliminary determinations about the checkbox we’re discussing. I guess it started making some sense. “Debug executable” was not checked so Xcode didn’t stop at any breakpoint(s). The debugger didn’t seem to be “enabled” as Apple puts it in its definition of the checkbox.

Apple’s definition becomes really confusing when the “Debug executable” checkbox is enabled.

Run “Release” app with “Debug executable” checkbox enabled

To me, checking a box labelled “Debug executable” right under a “Build Configuration” dropdown box with value “Release” is a bit confusing. Are we building a release-debug or debug-release bundle? I doubt it. We’re most likely building a release version. Remember our “Build Settings” for a release version in Figure 1 above with the value “DWARF with dSYM File?”

So I went to my scheme settings and checked the “Debug executable” checkbox:

Click to enlarge


Figure 6. Tick the “Debug executable” checkbox to enabled.

Just to verify that a release build is being created (a “DWARF with dSYM File”), I renamed the existing .dSYM bundle and performed a full rebuild. Watch what happened:

Click to enlarge


Figure 7. Full rebuild proves this is a release version.

Then I set a breakpoint in my code — the same one I set before; the one at which Xcode didn’t stop. Hey, since I ticked the “Debug executable” checkbox, wouldn’t you think Xcode would stop in code? Let’s watch:

Click to enlarge


Figure 8. Breakpoint hit when “Debug executable” checkbox enabled.

We hit the breakpoint!

Run “Debug” app with “Debug executable” checkbox disabled

If I build and run an app where I’ve set the active scheme’s “Build Configuration” dropdown box to a value of “Debug,” and I uncheck/untick the “Debug executable” checkbox, then no debugging features are enabled; in other words, the debugger is disabled. I can’t think of a situation where this would be useful.

Run “Debug” app with “Debug executable” checkbox enabled

If I build and run an app where I’ve set the active scheme’s “Build Configuration” dropdown box to a value of “Debug,” and I check/tick the “Debug executable” checkbox, then debugging features are enabled; in other words, the debugger is enabled and I can debug to my heart’s content. This is not only useful but essential.

My “official” statement on the “Debug executable” checkbox

I’ve performed a step-by-step analysis of how Xcode’s “Debug executable” checkbox works. Here’s how I would explain the functionality of the checkbox:

1) When you run a “Release” app with the “Debug executable” checkbox set to disabled/unchecked:

  • the release version of the app is run by Xcode, no debug symbols are loaded, no breakpoints are hit, and debugger features are disabled.

2) When you run a “Release” app with the “Debug executable” checkbox set to enabled/checked:

  • the release version of the app is run by Xcode, debug symbols are loaded, breakpoints are hit, and all debugger features are enabled.

3) When you run a “Debug” app with the “Debug executable” checkbox set to disabled/unchecked:

  • the debug version of the app is run by Xcode, debug symbols are part of the build (by definition of a debug build), but no breakpoints are hit and debugger features are disabled. The debugger is disabled.

4) When you run a “Debug” app with the “Debug executable” checkbox set to enabled/checked:

  • the debug version of the app is run by Xcode, debug symbols are loaded, breakpoints are hit and debugger features are enabled. The debugger is enabled.

Making sense out of Apple’s documentation

Let’s parse Apple’s explanation for the “Debug executable” checkbox:

Select the “Debug executable” checkbox if you want to run with the debugger enabled. With the debugger running, you can use Debug > Attach to Process on a process that has been launched with debugging disabled, if needed.

OK, the first sentence makes sense. If I check the “Debug executable” checkbox, that means turn on the debugger so that it’s “running.” If I don’t tick the checkbox, the debugger is not turned on and is not running.

The second sentence doesn’t make any sense — especially the phrase “a process that has been launched with debugging disabled.” If the debugger is running, and I ticked the “Debug executable” checkbox, and ran an app for which I know I had the .dSYM, then Xcode is already running a release app with symbols loaded. If I try to “Debug > Attach to Process,” I find that I’m already attached to the process I ran in the first place:

Click to enlarge


Figure 9. Can’t attach to a process to which we’re already attached.

Finally, I’m still struggling with this statement: “With the debugger running, you can use Debug > Attach to Process on a process that has been launched with debugging disabled, if needed.” What is “a process that has been launched with debugging disabled?” If the debugger in Xcode is running, how do I launch a process from Xcode with “debugging disabled?” That’s a contradiction.

If “launched with debugging disabled” means launching a release process outside of Xcode, then I’d have to run Xcode and load symbols at LLDB if I have the symbols for that release process.

I just don’t understand what Apple is saying. I’ll just stick with my “official” statement on the “Debug executable” checkbox — I know that’s right.

Moral of the story

Sometimes software documentation isn’t worth the paper on which it’s written. This is one of those cases. My purpose here was to find some awkward part of Xcode that is badly documented and get you to use it as a springboard to learning about Xcode debugging in general. Xcode can be a wonderful product, and I’m not a dogmatic or cult member, so I’m not bashing Apple. I’ve never seen a perfect IDE/compiler, and the obvious comparison people generally make is to Visual Studio, which is certainly not perfect, but I still use it and enjoy it just as I use and enjoy Xcode. I’ve used lots of mainstream development tools for years and had generally good experiences. Yes, I’ve met some bad products, but who hasn’t?

Don’t sweat the small stuff. Don’t let little obstacles drive you to distraction. Make the best and keep a positive outlook. “Don’t let the sound of your own wheels drive you crazy” as the Eagles once sang.

Keep on practicing and learning, don’t drive yourselves crazy, don’t overwork yourselves, and please, ENJOY yourselves!

Author: Andrew Jaffee

Avid and well-published author, software engineer, designer, and developer, now specializing in iOS mobile app development in Objective-C and Swift, but with a strong background in C#, C++, .NET, JavaScript, HTML, CSS, jQuery, SQL Server, MySQL, Oracle, Agile, Test Driven Development, Git, Continuous Integration, Responsive Web Design, blah, blah, blah ... Did I miss any fad-based catch phrases? My brain avatar was kindly provided by http://icons8.com under a Creative Commons Attribution-NoDerivs 3.0 Unported license.

2 thoughts on “Xcode: using the “Debug executable” checkbox to step through app release versions”

  1. I have an (untested) hypothesis about the “With the debugger running, you can use Debug > Attach to Process on a process that has been launched with debugging disabled, if needed.” part. Have you considered it in the context of an app extension? I.e you’re running your main app target, and then you’re testing a widget extension or notification content extension or whatever. With “Debug executable” enabled, you would be able to attach to the process of the extension. This process has been started automatically by iOS when you launched the extension, but you’d still be able to debug it.

Leave a Reply

Your email address will not be published. Required fields are marked *