/ docs / mac_breakpad_starter_guide.md
mac_breakpad_starter_guide.md
  1  # How To Add Breakpad To Your Mac Client Application
  2  
  3  This document is a step-by-step recipe to get your Mac client app to build with
  4  Breakpad.
  5  
  6  ## Preparing a binary build of Breakpad for use in your tree
  7  
  8  You can either check in a binary build of the Breakpad framework & tools or
  9  build it as a dependency of your project. The former is recommended, and
 10  detailed here, since building dependencies through other projects is
 11  problematic(matching up configuration names), and the Breakpad code doesn't
 12  change nearly often enough as your application's will.
 13  
 14  ## Building the requisite targets
 15  
 16  All 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  
 27  Inside your application's framework, add the Breakpad.Framework to your
 28  project's framework settings. When you select it from the file chooser, it will
 29  let you pick a target to add it to; go ahead and check the one that's relevant
 30  to your application.
 31  
 32  ## Copy Breakpad into your Application Package
 33  
 34  Copy Breakpad into your Application Package, so it will be around at run time.
 35  
 36  Go to the Targets section of your Xcode Project window. Hit the disclosure
 37  triangle to reveal the build phases of your application. Add a new Copy Files
 38  phase 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'
 41  Now drag Breakpad again into this Copy Frameworks phase. Drag it from whereever
 42  it appears in the project file tree.
 43  
 44  ## Add a New Run Script build phase
 45  
 46  Near the end of the build phases, add a new Run Script build phase. This will be
 47  run before Xcode calls /usr/bin/strip on your project. This is where you'll be
 48  calling dump\_sym to output the symbols for each architecture of your build. In
 49  my 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  
 67  You'll need to have an object that acts as the delegate for NSApplication.
 68  Inside this object's header, you'll need to add
 69  
 70  1.  add an ivar for Breakpad and
 71  2.  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  
 94  Inside your object's implementation file,
 95  
 96  1.  add the following method InitBreakpad
 97  2.  modify your awakeFromNib method to look like the one below,
 98  3.  modify/add your application's delegate method to look like the one below
 99  
100  ```
101  static 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  
126  Configure Breakpad for your application.
127  
128  1.  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().
130  2.  Add/Edit the Breakpad specific entries in the dictionary passed to
131      BreakpadCreate() -- typically your application's info plist.
132  
133  Example 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  
140  Almost done!
141  
142  ## Verify
143  
144  Double-check:
145  
146  Your app should have in its package contents:
147  myApp.app/Contents/Frameworks/Breakpad.framework.
148  
149  The symbol files have reasonable contents (you can look at them with a text
150  editor.)
151  
152  Look again at the Copy Frameworks phase of your project. Are you leaking .h
153  files? Select them and delete them. (If you drag a bunch of files into your
154  project, Xcode often wants to copy your .h files into the build, revealing
155  Google secrets. Be vigilant!)
156  
157  ## Upload the symbol file
158  
159  You'll need to configure your build process to store symbols in a location that
160  is accessible by the minidump processor. There is a tool in tools/mac/symupload
161  that can be used to send the symbol file via HTTP post.
162  
163  1.  Test
164  
165  Configure 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  
176  Breakpad checks whether it is being run under a debugger, and if so, normally
177  does nothing. But, you can force Breakpad to function under a debugger by
178  setting the Unix shell variable BREAKPAD\_IGNORE\_DEBUGGER to a non-zero value.
179  You can bracket the source code in the above Write The Code step with #if DEBUG
180  to completely eliminate it from Debug builds. See
181  //depot/googlemac/GoogleNotifier/main.m for an example. FYI, when your process
182  forks(), exception handlers are reset to the default for child processes. So
183  they must reinitialize Breakpad, otherwise exceptions will be handled by Apple's
184  Crash Reporter.