1# How To Add Breakpad To Your Mac Client Application 2 3This document is a step-by-step recipe to get your Mac client app to build with 4Breakpad. 5 6## Preparing a binary build of Breakpad for use in your tree 7 8You can either check in a binary build of the Breakpad framework & tools or 9build it as a dependency of your project. The former is recommended, and 10detailed here, since building dependencies through other projects is 11problematic(matching up configuration names), and the Breakpad code doesn't 12change nearly often enough as your application's will. 13 14## Building the requisite targets 15 16All directories are relative to the `src` directory of the Breakpad checkout. 17 18* Build the 'All' target of `client/mac/Breakpad.xcodeproj` in Release mode. 19* Execute `cp -R client/mac/build/Release/Breakpad.framework <location in your 20 source tree>` 21* Inside `tools/mac/dump_syms` directory, build dump\_syms.xcodeproj, and copy 22 tools/mac/dump\_syms/build/Release/dump\_syms to a safe location where it 23 can be run during the build process. 24 25## Adding Breakpad.framework 26 27Inside your application's framework, add the Breakpad.Framework to your 28project's framework settings. When you select it from the file chooser, it will 29let you pick a target to add it to; go ahead and check the one that's relevant 30to your application. 31 32## Copy Breakpad into your Application Package 33 34Copy Breakpad into your Application Package, so it will be around at run time. 35 36Go to the Targets section of your Xcode Project window. Hit the disclosure 37triangle to reveal the build phases of your application. Add a new Copy Files 38phase using the Contextual menu (Control Click). On the General panel of the new 39'Get Info' of this new phase, set the destination to 'Frameworks' Close the 40'Info' panel. Use the Contextual Menu to Rename your new phase 'Copy Frameworks' 41Now drag Breakpad again into this Copy Frameworks phase. Drag it from whereever 42it appears in the project file tree. 43 44## Add a New Run Script build phase 45 46Near the end of the build phases, add a new Run Script build phase. This will be 47run before Xcode calls /usr/bin/strip on your project. This is where you'll be 48calling dump\_sym to output the symbols for each architecture of your build. In 49my case, the relevant lines read: 50 51``` 52#!/bin/sh 53$TOOL_DIR=<location of dump_syms from step 3 above> 54 55"$TOOL_DIR/dump_syms" -a ppc "$PROD" > "$TARGET_NAME ppc.breakpad" 56 57"$TOOL_DIR/dump_syms" -a i386 "$PROD" > "$TARGET_NAME i386.breakpad" 58``` 59 60## Adjust the Project Settings 61 62* Turn on Separate Strip, 63* Set the Strip Style to Non-Global Symbols. 64 65## Write Code! 66 67You'll need to have an object that acts as the delegate for NSApplication. 68Inside this object's header, you'll need to add 69 701. add an ivar for Breakpad and 712. a declaration for the applicationShouldTerminate:(NSApplication`*` sender) 72 message. 73 74``` 75#import <Breakpad/Breakpad.h> 76 77@interface BreakpadTest : NSObject { 78 . 79 . 80 . 81 BreakpadRef breakpad; 82 . 83 . 84 . 85} 86. 87. 88- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender; 89. 90. 91@end 92``` 93 94Inside your object's implementation file, 95 961. add the following method InitBreakpad 972. modify your awakeFromNib method to look like the one below, 983. modify/add your application's delegate method to look like the one below 99 100``` 101static BreakpadRef InitBreakpad(void) { 102 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 103 BreakpadRef breakpad = 0; 104 NSDictionary *plist = [[NSBundle mainBundle] infoDictionary]; 105 if (plist) { 106 // Note: version 1.0.0.4 of the framework changed the type of the argument 107 // from CFDictionaryRef to NSDictionary * on the next line: 108 breakpad = BreakpadCreate(plist); 109 } 110 [pool release]; 111 return breakpad; 112} 113 114- (void)awakeFromNib { 115 breakpad = InitBreakpad(); 116} 117 118- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender { 119 BreakpadRelease(breakpad); 120 return NSTerminateNow; 121} 122``` 123 124## Configure Breakpad 125 126Configure Breakpad for your application. 127 1281. Take a look inside the Breakpad.framework at the Breakpad.h file for the 129 keys, default values, and descriptions to be passed to BreakpadCreate(). 1302. Add/Edit the Breakpad specific entries in the dictionary passed to 131 BreakpadCreate() -- typically your application's info plist. 132 133Example from the Notifier Info.plist: 134`<key>BreakpadProduct</key><string>Google_Notifier_Mac</string> 135<key>BreakpadProductDisplay</key><string>${PRODUCT_NAME}</string> 136` 137 138## Build Your Application 139 140Almost done! 141 142## Verify 143 144Double-check: 145 146Your app should have in its package contents: 147myApp.app/Contents/Frameworks/Breakpad.framework. 148 149The symbol files have reasonable contents (you can look at them with a text 150editor.) 151 152Look again at the Copy Frameworks phase of your project. Are you leaking .h 153files? Select them and delete them. (If you drag a bunch of files into your 154project, Xcode often wants to copy your .h files into the build, revealing 155Google secrets. Be vigilant!) 156 157## Upload the symbol file 158 159You'll need to configure your build process to store symbols in a location that 160is accessible by the minidump processor. There is a tool in tools/mac/symupload 161that can be used to send the symbol file via HTTP post. 162 1631. Test 164 165Configure breakpad to send reports to a URL by adding to your app's Info.plist: 166 167``` 168<key>BreakpadURL</key> 169<string>upload URL</string> 170<key>BreakpadReportInterval</key> 171<string>30</string> 172``` 173 174## Final Notes 175 176Breakpad checks whether it is being run under a debugger, and if so, normally 177does nothing. But, you can force Breakpad to function under a debugger by 178setting the Unix shell variable BREAKPAD\_IGNORE\_DEBUGGER to a non-zero value. 179You can bracket the source code in the above Write The Code step with #if DEBUG 180to completely eliminate it from Debug builds. See 181//depot/googlemac/GoogleNotifier/main.m for an example. FYI, when your process 182forks(), exception handlers are reset to the default for child processes. So 183they must reinitialize Breakpad, otherwise exceptions will be handled by Apple's 184Crash Reporter. 185