Speeding up Development Build Times With Conditional dSYM Generation
There's been a lot of advice about speeding up build times during the past few years. Most authors suggest changing
Debug Information Format to DWARF for
Debug configuration. These days it's the default in Xcode. With this setting, debug symbols (think: names of classes and methods) are put directly inside the binary.
Alternatively, there's DWARF with dSYM file option. It has two pros over
- the binary is obfuscated
- the binary has a smaller size
and a big con:
- it leads to longer build times because a separate
dSYMfile has to be generated during each build ☹️
That's the default in
Release configuration. It makes a total sense in that case.
The setup described above is completely fine in many cases. It fails, though, when we start to use an app built with
DWARF configuration not attached to the debugger 1. When we do that, we end up with unsymbolicated crash reports, like this one:
0 YourApp 0x00000001001e1594 0x100058000 + 1611156 1 YourApp 0x00000001000ed74c 0x100058000 + 612172 2 UIKit 0x000000018f2b67b0 -[UIApplication sendAction:to:from:forEvent:] + 96 3 UIKit 0x000000018f42a5ec -[UIBarButtonItem(UIInternal) _sendAction:withEvent:] + 168
We have to symbolicate them manually using
symbolicatecrash tool, e.g.:
symbolicatecrash YourApp\ \ 17-10-16\ 23-15.crash YourApp.app/YourApp > symbolicated.crash
Note that we need to have an access to the
.app) file for the build that crashed.
.ipa files aren't created automatically except for the
Archive action. This makes symbolication process of those crashes cumbersome. That's why services like Crashlytics encourage us to generate dSYM files on each build:
The default set up process ensures that we get your app’s dSYMs on every build (assuming a code change). This is the preferred configuration, so that if a crash comes while you develop and do internal testing, we can show you the exact line of code that caused the crash.
I thought that it should be possible to symbolicate crashes directly on the device but it doesn't seem so anymore because:
- Cocoa SDKs methods end up being redacted
- with Bitcode enabled Apple recompiles an app on its servers
I think that's why third party crash reporters require dSYM files in each case. So, since we now know why dSYM files are needed, let's see how to save those precious build time seconds.
It seems like the choice is absolute, we either generate a dSYM file or not. All hope is lost…
It turns out that it's possible to set different
Debug Information Format values based on a target SDK!
What this setup gives us is:
- faster simulator builds (for which we almost always have a debugger attached, so crash reports aren't that needed anyway)
- full crash reports for device builds (which have a higher probability of being run outside of the debugger)
We cut our simulator build times in a really easy way. In my case, it's a difference of 1.5s (or about 15% of the overall build time) in incremental builds. It doesn't seem like much but each second matters when you try to keep staying in the zone.
Ideally, you'd have a separate version built on your CI for that such use but I'm sure there are cases when you'll use that
Debugbuild and encounter crashes on it (I sure do on my device). ↩