Port C++ exception handling support over from PLCrashReporter's non-merged implementation. Includes changes to auto-link C++ with client apps where possible. Correctly handles cases where client apps use libstdc++.

This commit is contained in:
Gwynne Raskind
2015-06-10 11:32:03 -05:00
parent 9843da612a
commit 7ccfe6aac7
6 changed files with 278 additions and 18 deletions

View File

@@ -0,0 +1,48 @@
/*
* Author: Gwynne Raskind <gwraskin@microsoft.com>
*
* Copyright (c) 2015 HockeyApp, Bit Stadium GmbH.
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#import <Foundation/Foundation.h>
typedef struct {
const void * __nullable exception;
const char * __nullable exception_type_name;
const char * __nullable exception_message;
uint32_t exception_frames_count;
const uintptr_t * __nonnull exception_frames;
} BITCrashUncaughtCXXExceptionInfo;
typedef void (*BITCrashUncaughtCXXExceptionHandler)(
const BITCrashUncaughtCXXExceptionInfo * __nonnull info
);
@interface BITCrashUncaughtCXXExceptionHandlerManager : NSObject
+ (void)addCXXExceptionHandler:(nonnull BITCrashUncaughtCXXExceptionHandler)handler;
+ (void)removeCXXExceptionHandler:(nonnull BITCrashUncaughtCXXExceptionHandler)handler;
@end

View File

@@ -0,0 +1,150 @@
/*
* Author: Gwynne Raskind <gwraskin@microsoft.com>
*
* Copyright (c) 2015 HockeyApp, Bit Stadium GmbH.
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
#import "BITCrashCXXExceptionHandler.h"
#import <vector>
#import <cxxabi.h>
#import <exception>
#import <stdexcept>
#import <typeinfo>
#import <string>
#import <pthread.h>
#import <dlfcn.h>
#import <execinfo.h>
#import <libkern/OSAtomic.h>
typedef std::vector<BITCrashUncaughtCXXExceptionHandler> BITCrashUncaughtCXXExceptionHandlerList;
static bool _BITCrashIsOurTerminateHandlerInstalled = false;
static std::terminate_handler _BITCrashOriginalTerminateHandler = nullptr;
static BITCrashUncaughtCXXExceptionHandlerList _BITCrashUncaughtExceptionHandlerList;
static OSSpinLock _BITCrashCXXExceptionHandlingLock = OS_SPINLOCK_INIT;
@implementation BITCrashUncaughtCXXExceptionHandlerManager
__attribute__((always_inline))
static inline void BITCrashIterateExceptionHandlers_unlocked(const BITCrashUncaughtCXXExceptionInfo &info)
{
for (const auto &handler : _BITCrashUncaughtExceptionHandlerList) {
handler(&info);
}
}
static void BITCrashUncaughtCXXTerminateHandler(void)
{
BITCrashUncaughtCXXExceptionInfo info = {
.exception = nullptr,
.exception_type_name = nullptr,
.exception_message = nullptr,
.exception_frames_count = 0,
.exception_frames = nullptr,
};
auto p = std::current_exception();
OSSpinLockLock(&_BITCrashCXXExceptionHandlingLock); {
if (p) { // explicit operator bool
info.exception = reinterpret_cast<const void *>(&p);
info.exception_type_name = __cxxabiv1::__cxa_current_exception_type()->name();
void *frames[128] = { nullptr };
info.exception_frames_count = backtrace(&frames[0], sizeof(frames) / sizeof(frames[0])) - 1;
info.exception_frames = reinterpret_cast<uintptr_t *>(&frames[1]);
try {
std::rethrow_exception(p);
} catch (const std::exception &e) { // C++ exception.
info.exception_message = e.what();
BITCrashIterateExceptionHandlers_unlocked(info);
} catch (const std::exception *e) { // C++ exception by pointer.
info.exception_message = e->what();
BITCrashIterateExceptionHandlers_unlocked(info);
} catch (const std::string &e) { // C++ string as exception.
info.exception_message = e.c_str();
BITCrashIterateExceptionHandlers_unlocked(info);
} catch (const std::string *e) { // C++ string pointer as exception.
info.exception_message = e->c_str();
BITCrashIterateExceptionHandlers_unlocked(info);
} catch (const char *e) { // Plain string as exception.
info.exception_message = e;
BITCrashIterateExceptionHandlers_unlocked(info);
} catch (id e) { // Objective-C exception. Pass it on to Foundation.
OSSpinLockUnlock(&_BITCrashCXXExceptionHandlingLock);
if (_BITCrashOriginalTerminateHandler != nullptr) {
_BITCrashOriginalTerminateHandler();
}
return;
} catch (...) { // Any other kind of exception. No message.
BITCrashIterateExceptionHandlers_unlocked(info);
}
}
} OSSpinLockUnlock(&_BITCrashCXXExceptionHandlingLock); // In case terminate is called reentrantly by pasing it on
if (_BITCrashOriginalTerminateHandler != nullptr) {
_BITCrashOriginalTerminateHandler();
} else {
abort();
}
}
+ (void)addCXXExceptionHandler:(BITCrashUncaughtCXXExceptionHandler)handler
{
OSSpinLockLock(&_BITCrashCXXExceptionHandlingLock); {
if (!_BITCrashIsOurTerminateHandlerInstalled) {
_BITCrashOriginalTerminateHandler = std::set_terminate(BITCrashUncaughtCXXTerminateHandler);
_BITCrashIsOurTerminateHandlerInstalled = true;
}
_BITCrashUncaughtExceptionHandlerList.push_back(handler);
} OSSpinLockUnlock(&_BITCrashCXXExceptionHandlingLock);
}
+ (void)removeCXXExceptionHandler:(BITCrashUncaughtCXXExceptionHandler)handler
{
OSSpinLockLock(&_BITCrashCXXExceptionHandlingLock); {
auto i = std::find(_BITCrashUncaughtExceptionHandlerList.begin(), _BITCrashUncaughtExceptionHandlerList.end(), handler);
if (i != _BITCrashUncaughtExceptionHandlerList.end()) {
_BITCrashUncaughtExceptionHandlerList.erase(i);
}
if (_BITCrashIsOurTerminateHandlerInstalled) {
if (_BITCrashUncaughtExceptionHandlerList.empty()) {
std::terminate_handler previous_handler = std::set_terminate(_BITCrashOriginalTerminateHandler);
if (previous_handler != BITCrashUncaughtCXXTerminateHandler) {
std::set_terminate(previous_handler);
} else {
_BITCrashIsOurTerminateHandlerInstalled = false;
_BITCrashOriginalTerminateHandler = nullptr;
}
}
}
} OSSpinLockUnlock(&_BITCrashCXXExceptionHandlingLock);
}
@end

View File

@@ -44,6 +44,7 @@
#import "BITCrashManagerPrivate.h"
#import "BITCrashReportTextFormatter.h"
#import "BITCrashDetailsPrivate.h"
#import "BITCrashCXXExceptionHandler.h"
#include <sys/sysctl.h>
@@ -97,6 +98,47 @@ static PLCrashReporterCallbacks plCrashCallbacks = {
};
// Temporary routine until PLCR catches up
// We trick PLCR with an Objective-C exception. It's ugly but it works.
@interface BITCrashCXXExceptionWrapperException : NSException
- (instancetype)initWithCXXExceptionInfo:(const BITCrashUncaughtCXXExceptionInfo *)info;
@end
@implementation BITCrashCXXExceptionWrapperException
{
const BITCrashUncaughtCXXExceptionInfo *_info;
}
- (instancetype)initWithCXXExceptionInfo:(const BITCrashUncaughtCXXExceptionInfo *)info
{
extern char* __cxa_demangle(const char* mangled_name, char* output_buffer, size_t* length, int* status);
char *demangled_name = __cxa_demangle ? __cxa_demangle(info->exception_type_name ?: "", NULL, NULL, NULL) : NULL;
if ((self = [super
initWithName:[NSString stringWithUTF8String:demangled_name ?: info->exception_type_name ?: ""]
reason:[NSString stringWithUTF8String:info->exception_message ?: ""]
userInfo:nil])) {
_info = info;
}
return self;
}
- (NSArray *)callStackReturnAddresses
{
NSMutableArray *cxxFrames = [NSMutableArray arrayWithCapacity:_info->exception_frames_count];
for (uint32_t i = 0; i < _info->exception_frames_count; ++i) {
[cxxFrames addObject:[NSNumber numberWithUnsignedLongLong:_info->exception_frames[i]]];
}
return cxxFrames;
}
@end
static void uncaught_cxx_exception_handler(const BITCrashUncaughtCXXExceptionInfo *info)
{
// This relies on a LOT of sneaky internal knowledge of how PLCR works and should not be considered a long-term solution.
NSGetUncaughtExceptionHandler()([[BITCrashCXXExceptionWrapperException alloc] initWithCXXExceptionInfo:info]);
abort();
}
@implementation BITCrashManager {
NSMutableDictionary *_approvedCrashReports;
@@ -1091,6 +1133,9 @@ static PLCrashReporterCallbacks plCrashCallbacks = {
// this should never happen, theoretically only if NSSetUncaugtExceptionHandler() has some internal issues
NSLog(@"[HockeySDK] ERROR: Exception handler could not be set. Make sure there is no other exception handler set up!");
}
// Add the C++ uncaught exception handler, which is currently not handled by PLCrashReporter internally
[BITCrashUncaughtCXXExceptionHandlerManager addCXXExceptionHandler:uncaught_cxx_exception_handler];
}
_isSetup = YES;
});

View File

@@ -27,9 +27,6 @@
* OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef HockeySDK_h
#define HockeySDK_h
#import "HockeySDKFeatureConfig.h"
#import "BITHockeyManager.h"
@@ -208,5 +205,3 @@ typedef NS_ENUM(NSInteger, BITHockeyErrorReason) {
};
extern NSString *const __attribute__((unused)) kBITHockeyErrorDomain;
#endif

View File

@@ -14,7 +14,7 @@
1E4F61ED1621ADE70033EFC5 /* Build universal embedded framework */,
);
dependencies = (
1E754E431621F6290070AB92 /* PBXTargetDependency */,
846A906B1B20D4BB0076BB80 /* PBXTargetDependency */,
);
name = "HockeySDK Distribution";
productName = "HockeySDK Framework";
@@ -272,6 +272,10 @@
1EF95CA7162CB037000AE3AD /* BITFeedbackActivity.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EF95CA5162CB036000AE3AD /* BITFeedbackActivity.m */; };
1EF95CAA162CB314000AE3AD /* BITFeedbackComposeViewControllerDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 1EF95CA9162CB313000AE3AD /* BITFeedbackComposeViewControllerDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
1EFF03E517F2485500A5F13C /* BITCrashManagerTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 1EFF03E417F2485500A5F13C /* BITCrashManagerTests.m */; };
846A901F1B20B0EB0076BB80 /* BITCrashCXXExceptionHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 846A901D1B20B0EB0076BB80 /* BITCrashCXXExceptionHandler.h */; };
846A90201B20B0EB0076BB80 /* BITCrashCXXExceptionHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 846A901D1B20B0EB0076BB80 /* BITCrashCXXExceptionHandler.h */; };
846A90211B20B0EB0076BB80 /* BITCrashCXXExceptionHandler.mm in Sources */ = {isa = PBXBuildFile; fileRef = 846A901E1B20B0EB0076BB80 /* BITCrashCXXExceptionHandler.mm */; };
846A90221B20B0EB0076BB80 /* BITCrashCXXExceptionHandler.mm in Sources */ = {isa = PBXBuildFile; fileRef = 846A901E1B20B0EB0076BB80 /* BITCrashCXXExceptionHandler.mm */; };
973EC8B418BCA7BC00DBFFBB /* BITImageAnnotationViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 97F0FA0018AE375E00EF50AA /* BITImageAnnotationViewController.m */; };
973EC8B718BCA8A200DBFFBB /* BITRectangleImageAnnotation.h in Headers */ = {isa = PBXBuildFile; fileRef = 973EC8B518BCA8A200DBFFBB /* BITRectangleImageAnnotation.h */; };
973EC8B818BCA8A200DBFFBB /* BITRectangleImageAnnotation.m in Sources */ = {isa = PBXBuildFile; fileRef = 973EC8B618BCA8A200DBFFBB /* BITRectangleImageAnnotation.m */; };
@@ -323,13 +327,6 @@
remoteGlobalIDString = 1E59550915B6F45800A03429;
remoteInfo = HockeySDKResources;
};
1E754E421621F6290070AB92 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = E4005611148D79B500EB22B9 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 1E8E66AD15BC3D7700632A2E;
remoteInfo = "HockeySDK Documentation";
};
1EA116FE16F4D302001C015C /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = E4005611148D79B500EB22B9 /* Project object */;
@@ -358,6 +355,13 @@
remoteGlobalIDString = 1E59550915B6F45800A03429;
remoteInfo = HockeySDKResources;
};
846A906A1B20D4BB0076BB80 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = E4005611148D79B500EB22B9 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 1E8E66AD15BC3D7700632A2E;
remoteInfo = "HockeySDK Documentation";
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
@@ -500,6 +504,8 @@
1EF95CA9162CB313000AE3AD /* BITFeedbackComposeViewControllerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITFeedbackComposeViewControllerDelegate.h; sourceTree = "<group>"; };
1EFF03D717F20F8300A5F13C /* BITCrashManagerPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BITCrashManagerPrivate.h; sourceTree = "<group>"; };
1EFF03E417F2485500A5F13C /* BITCrashManagerTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITCrashManagerTests.m; sourceTree = "<group>"; };
846A901D1B20B0EB0076BB80 /* BITCrashCXXExceptionHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITCrashCXXExceptionHandler.h; sourceTree = "<group>"; };
846A901E1B20B0EB0076BB80 /* BITCrashCXXExceptionHandler.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = BITCrashCXXExceptionHandler.mm; sourceTree = "<group>"; };
973EC8B518BCA8A200DBFFBB /* BITRectangleImageAnnotation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITRectangleImageAnnotation.h; sourceTree = "<group>"; };
973EC8B618BCA8A200DBFFBB /* BITRectangleImageAnnotation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BITRectangleImageAnnotation.m; sourceTree = "<group>"; };
973EC8B918BDE29800DBFFBB /* BITArrowImageAnnotation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BITArrowImageAnnotation.h; sourceTree = "<group>"; };
@@ -790,6 +796,8 @@
1ED570C618BF878C00AB3350 /* BITCrashAttachment.m */,
1E754E5A1621FBB70070AB92 /* BITCrashReportTextFormatter.h */,
1E754E5B1621FBB70070AB92 /* BITCrashReportTextFormatter.m */,
846A901D1B20B0EB0076BB80 /* BITCrashCXXExceptionHandler.h */,
846A901E1B20B0EB0076BB80 /* BITCrashCXXExceptionHandler.mm */,
);
name = CrashReports;
sourceTree = "<group>";
@@ -1011,6 +1019,7 @@
1E90FD7318EDB86400CF0417 /* BITCrashDetails.h in Headers */,
1E49A4731612226D00463151 /* BITUpdateManager.h in Headers */,
1E49A4791612226D00463151 /* BITUpdateManagerDelegate.h in Headers */,
846A901F1B20B0EB0076BB80 /* BITCrashCXXExceptionHandler.h in Headers */,
1E49A44E1612223B00463151 /* BITFeedbackManager.h in Headers */,
E405266217A2AD300096359C /* BITFeedbackManagerDelegate.h in Headers */,
973EC8BF18BE2B5B00DBFFBB /* BITBlurImageAnnotation.h in Headers */,
@@ -1069,6 +1078,7 @@
1EB617991B0A31650035A986 /* BITFeedbackComposeViewController.h in Headers */,
1EB617651B0A30B30035A986 /* BITKeychainUtils.h in Headers */,
1EB617821B0A31310035A986 /* BITImageAnnotation.h in Headers */,
846A90201B20B0EB0076BB80 /* BITCrashCXXExceptionHandler.h in Headers */,
1EB617961B0A31550035A986 /* BITArrowImageAnnotation.h in Headers */,
1EB617801B0A31260035A986 /* BITCrashReportTextFormatter.h in Headers */,
1EB6179C1B0A31730035A986 /* BITFeedbackListViewCell.h in Headers */,
@@ -1431,6 +1441,7 @@
1E754E5D1621FBB70070AB92 /* BITCrashManager.m in Sources */,
1E754E611621FBB70070AB92 /* BITCrashReportTextFormatter.m in Sources */,
1EF95CA7162CB037000AE3AD /* BITFeedbackActivity.m in Sources */,
846A90211B20B0EB0076BB80 /* BITCrashCXXExceptionHandler.mm in Sources */,
1EACC97C162F041E007578C5 /* BITAttributedLabel.m in Sources */,
973EC8BC18BDE29800DBFFBB /* BITArrowImageAnnotation.m in Sources */,
973EC8B418BCA7BC00DBFFBB /* BITImageAnnotationViewController.m in Sources */,
@@ -1499,6 +1510,7 @@
1EB617831B0A31350035A986 /* BITImageAnnotation.m in Sources */,
1EB617681B0A30BD0035A986 /* BITAttributedLabel.m in Sources */,
1EB617621B0A30AA0035A986 /* BITHockeyBaseViewController.m in Sources */,
846A90221B20B0EB0076BB80 /* BITCrashCXXExceptionHandler.mm in Sources */,
1EB6178A1B0A31510035A986 /* BITFeedbackComposeViewController.m in Sources */,
1EB617701B0A30D70035A986 /* BITHockeyAttachment.m in Sources */,
1EB617881B0A31510035A986 /* BITFeedbackMessage.m in Sources */,
@@ -1531,11 +1543,6 @@
target = 1E59550915B6F45800A03429 /* HockeySDKResources */;
targetProxy = 1E59557D15B6F97100A03429 /* PBXContainerItemProxy */;
};
1E754E431621F6290070AB92 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 1E8E66AD15BC3D7700632A2E /* HockeySDK Documentation */;
targetProxy = 1E754E421621F6290070AB92 /* PBXContainerItemProxy */;
};
1EA116FF16F4D302001C015C /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 1E5954CB15B6F24A00A03429 /* HockeySDK */;
@@ -1556,6 +1563,11 @@
target = 1E59550915B6F45800A03429 /* HockeySDKResources */;
targetProxy = 1EB618191B0A3C380035A986 /* PBXContainerItemProxy */;
};
846A906B1B20D4BB0076BB80 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 1E8E66AD15BC3D7700632A2E /* HockeySDK Documentation */;
targetProxy = 846A906A1B20D4BB0076BB80 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
@@ -1608,6 +1620,8 @@
isa = XCBuildConfiguration;
buildSettings = {
"ARCHS[sdk=iphonesimulator*]" = "$(BIT_SIM_ARCHS)";
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
DSTROOT = /tmp/HockeySDK.dst;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
@@ -1625,6 +1639,8 @@
isa = XCBuildConfiguration;
buildSettings = {
"ARCHS[sdk=iphonesimulator*]" = "$(BIT_SIM_ARCHS)";
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
DSTROOT = /tmp/HockeySDK.dst;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
@@ -1781,6 +1797,8 @@
isa = XCBuildConfiguration;
buildSettings = {
"ARCHS[sdk=iphonesimulator*]" = "$(BIT_SIM_ARCHS)";
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
DSTROOT = /tmp/HockeySDK.dst;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
@@ -1900,6 +1918,8 @@
isa = XCBuildConfiguration;
buildSettings = {
"ARCHS[sdk=iphonesimulator*]" = "$(BIT_SIM_ARCHS)";
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
DSTROOT = /tmp/HockeySDK.dst;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",

View File

@@ -3,4 +3,6 @@ framework module HockeySDK {
export *
module * { export * }
link "c++"
}