#import "XCPBuildSystem.h"
#import "XCPDependencyGraph.h"
#if XCODE_VERSION != 23
#error Only works with Xcode 2.3 interface definitions.
#endif
@interface PBXTargetBuildContext (DependencyGraphEvents)
- (void)processDependencyGraphEvents;
@end
static BOOL args_profile = false;
static BOOL args_verbose = false;
@interface NSString (DBDebug)
- (NSString*)lastTwoPathComponents;
@end
@interface DBDebugBuildContext : PBXBuildContext
@end
@interface DBDebugTargetBuildContext : PBXTargetBuildContext
@end
@interface DBDebugDependencyNode : XCDependencyNode
@end
@interface DBDebugDependencyCommand : XCDependencyCommand
@end
@implementation NSString (DBDebug)
- (NSString*)lastTwoPathComponents {
return [NSString stringWithFormat:@"%@/%@", [[self stringByDeletingLastPathComponent] lastPathComponent], [self lastPathComponent]];
}
@end
@implementation DBDebugBuildContext
- (void)setStringValue:(NSString*)value forDynamicSetting:(NSString*)settingName {
if(args_profile) NSLog(@"setting-set: %@ <- %@",settingName,value);
[super setStringValue:value forDynamicSetting:settingName];
}
- (void)removeDynamicSetting:(NSString*)settingName {
if(args_profile) NSLog(@"setting-remove: %@",settingName);
[super removeDynamicSetting:settingName];
}
- (void)prependStringOrStringListValue:(NSString*)value toDynamicSetting:(NSString*)settingName {
if(args_profile) NSLog(@"setting-prepend: %@ <- %@",settingName,value);
[super prependStringOrStringListValue:value toDynamicSetting:settingName];
}
- (void)appendStringOrStringListValue:(NSString*)value toDynamicSetting:(NSString*)settingName {
if(args_profile) NSLog(@"setting-append: %@ <- %@",settingName,value);
[super appendStringOrStringListValue:value toDynamicSetting:settingName];
}
#if XCODE_VERSION < 30
- (void)removeStringOrStringListValue:(NSString*)value fromDynamicSetting:(NSString*)settingName {
if(args_profile) NSLog(@"setting-remove: %@ <-x- %@",settingName,value);
[super removeStringOrStringListValue:value fromDynamicSetting:settingName];
}
#endif
- (void)removeAllDynamicSettings {
if(args_profile) NSLog(@"setting-removeall");
[super removeAllDynamicSettings];
}
- (NSString*)expandedValueForString:(NSString*)string {
NSString* res = [super expandedValueForString:string];
if(args_verbose && ![res isEqualToString:string]) NSLog(@"expand: %@ -> %@",string,res);
return res;
}
@end
@implementation DBDebugTargetBuildContext
- (void)createDependencyGraphWithTargetDGSnapshot:(id)dgs {
if(args_profile) NSLog(@"=== create dependency graph ===");
[super createDependencyGraphWithTargetDGSnapshot:dgs];
[self writeToGraphVizFileAtPath:[self expandedValueForString:@"$(TEMP_DIR)/depend-bis.dot"]];
if(args_profile) NSLog(@"=== end of dependency graph creation ===");
}
- (void)processDependencyGraphEvents {
[super processDependencyGraphEvents];
[self writeToGraphVizFileAtPath:[self expandedValueForString:@"$(TEMP_DIR)/depend.dot"]];
}
- (XCDependencyNode*)dependencyNodeForName:(NSString*)name createIfNeeded:(BOOL)create {
if(args_verbose) NSLog(@"node-get: %@", [name lastTwoPathComponents]);
return [super dependencyNodeForName:name createIfNeeded:create];
}
- (void)addProductNode:(XCDependencyNode*)node {
if(args_profile) NSLog(@"node-addproduct: <%@>", [node shortNameForDebugging]);
[super addProductNode:node];
}
- (XCDependencyCommand*)createCommandWithRuleInfo:(NSArray*)info commandPath:(NSString*)path arguments:(NSArray*)args forNode:(XCDependencyNode*)node {
XCDependencyCommand* com = [super createCommandWithRuleInfo:info commandPath:path arguments:args forNode:node];
if(args_profile) NSLog(@"command-create: <%@> for <%@>", [com shortNameForDebugging], [node shortNameForDebugging]);
return com;
}
- (void)setCompiledFilePath:(NSString*)compiledPath forSourceFilePath:(NSString*)sourcePath {
if(args_profile) NSLog(@"build-setcompiled: %@ for source %@", [compiledPath lastTwoPathComponents], [sourcePath lastTwoPathComponents]);
[super setCompiledFilePath:compiledPath forSourceFilePath:sourcePath];
}
- (id)createDirectoryAtPath:(NSString*)path {
if(args_profile) NSLog(@"build-createdir: %@", [path lastTwoPathComponents]);
return [super createDirectoryAtPath:path];
}
- (id)touchFileAtPath:(NSString*)path {
if(args_profile) NSLog(@"build-createfile: %@", [path lastTwoPathComponents]);
return [super touchFileAtPath:path];
}
- (id)copyFileAtPath:(NSString*)srcPath toPath:(NSString*)dstPath {
if(args_profile) NSLog(@"build-copyfile: %@ to %@", [srcPath lastTwoPathComponents], [dstPath lastTwoPathComponents]);
return [super copyFileAtPath:srcPath toPath:dstPath];
}
- (id)dittoFileAtPath:(NSString*)srcPath toPath:(NSString*)dstPath {
if(args_profile) NSLog(@"build-dittofile: %@ to %@", [srcPath lastTwoPathComponents], [dstPath lastTwoPathComponents]);
return [super dittoFileAtPath:srcPath toPath:dstPath];
}
- (id)moveFileAtPath:(NSString*)srcPath toPath:(NSString*)dstPath {
if(args_profile) NSLog(@"build-movefile: %@ to %@", [srcPath lastTwoPathComponents], [dstPath lastTwoPathComponents]);
return [super moveFileAtPath:srcPath toPath:dstPath];
}
- (id)makeSymlinkToFileAtPath:(NSString*)originalPath atPath:(NSString*)linkPath {
if(args_profile) NSLog(@"build-makesymlink: %@ to %@", [linkPath lastTwoPathComponents], [originalPath lastTwoPathComponents]);
return [super makeSymlinkToFileAtPath:originalPath atPath:linkPath];
}
- (BOOL)shouldScanHeadersOfFileAtPath:(NSString*)path {
BOOL scan = [super shouldScanHeadersOfFileAtPath:path];
if(scan && args_profile) NSLog(@"build-shouldscanheader: %@",[path lastTwoPathComponents]);
return scan;
}
- (id)importedFilesForPath:(NSString*)path ensureFilesExist:(BOOL)ensure {
NSArray* importedFiles = [super importedFilesForPath:path ensureFilesExist:ensure];
if(args_profile) NSLog(@"build-importedfiles: %@ for %@ (%@)",importedFiles,[path lastTwoPathComponents],(ensure ? @"true" : @"false"));
return importedFiles;
}
- (id)importedFilesForPath:(NSString*)path {
NSArray* importedFiles = [super importedFilesForPath:path];
if(args_profile) NSLog(@"build-importedfiles: %@ for %@",importedFiles,[path lastTwoPathComponents]);
return importedFiles;
}
@end
@implementation DBDebugDependencyNode
- (NSString*)shortNameForDebugging {
return [[super shortNameForDebugging] lastTwoPathComponents];
}
- (void)addDependedNode:(XCDependencyNode*)node {
if(args_profile) NSLog(@"node-adddepend: <%@> to <%@>",[node shortNameForDebugging],[self shortNameForDebugging]);
[super addDependedNode:node];
}
- (void)addIncludedNode:(XCDependencyNode*)node {
if(args_profile) NSLog(@"node-addinclude: <%@> to <%@>",[node shortNameForDebugging],[self shortNameForDebugging]);
[super addIncludedNode:node];
}
- (void)removeAllIncludedNodes {
if(args_profile) NSLog(@"node-removeallinclude: <%@>",[self shortNameForDebugging]);
[super removeAllIncludedNodes];
}
- (void)setScansFileContentsForIncludes:(BOOL)scan {
if(args_profile) NSLog(@"node-%@scaninclude: <%@>",(scan ? @"" : @"dont"),[self shortNameForDebugging]);
[super setScansFileContentsForIncludes:scan];
}
@end
@implementation DBDebugDependencyCommand
- (void)setPhaseNumber:(unsigned)number {
if(args_profile) NSLog(@"command-setphase: %d to <%@>",number,[self shortNameForDebugging]);
[super setPhaseNumber:number];
}
- (void)addInputNode:(DBDebugDependencyNode*)node {
if(args_profile) NSLog(@"command-addinput: <%@> to <%@>",[node shortNameForDebugging],[self shortNameForDebugging]);
[super addInputNode:node];
}
- (void)addOutputNode:(DBDebugDependencyNode*)node {
if(args_profile) NSLog(@"command-addoutput: <%@> to <%@>",[node shortNameForDebugging],[self shortNameForDebugging]);
[super addOutputNode:node];
}
- (BOOL)caresAboutIncludes {
BOOL care = [super caresAboutIncludes];
if(care && args_profile) NSLog(@"command-returncareinclude: <%@>",[self shortNameForDebugging]);
return care;
}
- (void)setCaresAboutIncludes:(BOOL)care {
if(args_profile) NSLog(@"command-%@careinclude: <%@>",(care ? @"" : @"dont"),[self shortNameForDebugging]);
[super setCaresAboutIncludes:care];
}
@end
void xcodeprofile_init() {
NSAutoreleasePool* pool = [NSAutoreleasePool new];
// Only express us inside the Xcode application
if(![[[NSProcessInfo processInfo] processName] isEqualToString:@"Xcode"]) goto exit;
// Read arguments
NSDictionary* env = [[NSProcessInfo processInfo] environment];
args_profile = [[env objectForKey:@"XCPLUGIN_PROFILE"] isEqualToString:@"YES"];
args_verbose = args_profile && [[env objectForKey:@"XCPLUGIN_VERBOSE"] isEqualToString:@"YES"];
// Setup
[[DBDebugBuildContext class] poseAsClass:[PBXBuildContext class]];
[[DBDebugTargetBuildContext class] poseAsClass:[PBXTargetBuildContext class]];
[[DBDebugDependencyNode class] poseAsClass:[XCDependencyNode class]];
[[DBDebugDependencyCommand class] poseAsClass:[XCDependencyCommand class]];
NSLog(@"Xcode Debugging Tools loaded (%s profiling)", (args_profile?args_verbose?"verbose":"normal":"no"));
exit:
//return;
[pool release];
}