1*7c3d14c8STreehugger Robot// 2*7c3d14c8STreehugger Robot// The LLVM Compiler Infrastructure 3*7c3d14c8STreehugger Robot// 4*7c3d14c8STreehugger Robot// This file is distributed under the University of Illinois Open Source 5*7c3d14c8STreehugger Robot// License. See LICENSE.TXT for details. 6*7c3d14c8STreehugger Robot 7*7c3d14c8STreehugger Robot// 8*7c3d14c8STreehugger Robot// testfilerunner.m 9*7c3d14c8STreehugger Robot// testObjects 10*7c3d14c8STreehugger Robot// 11*7c3d14c8STreehugger Robot// Created by Blaine Garst on 9/24/08. 12*7c3d14c8STreehugger Robot// 13*7c3d14c8STreehugger Robot 14*7c3d14c8STreehugger Robot#import "testfilerunner.h" 15*7c3d14c8STreehugger Robot#import <Foundation/Foundation.h> 16*7c3d14c8STreehugger Robot#include <stdio.h> 17*7c3d14c8STreehugger Robot#include <unistd.h> 18*7c3d14c8STreehugger Robot#include <fcntl.h> 19*7c3d14c8STreehugger Robot#include <string.h> 20*7c3d14c8STreehugger Robot#include <stdlib.h> 21*7c3d14c8STreehugger Robot#include <stdbool.h> 22*7c3d14c8STreehugger Robot 23*7c3d14c8STreehugger Robotbool Everything = false; // do it also with 3 levels of optimization 24*7c3d14c8STreehugger Robotbool DoClang = false; 25*7c3d14c8STreehugger Robot 26*7c3d14c8STreehugger Robotstatic bool isDirectory(char *path); 27*7c3d14c8STreehugger Robotstatic bool isExecutable(char *path); 28*7c3d14c8STreehugger Robotstatic bool isYounger(char *source, char *binary); 29*7c3d14c8STreehugger Robotstatic bool readErrorFile(char *buffer, const char *from); 30*7c3d14c8STreehugger Robot 31*7c3d14c8STreehugger Robot__strong char *gcstrcpy2(__strong const char *arg, char *endp) { 32*7c3d14c8STreehugger Robot unsigned size = endp - arg + 1; 33*7c3d14c8STreehugger Robot __strong char *result = NSAllocateCollectable(size, 0); 34*7c3d14c8STreehugger Robot strncpy(result, arg, size); 35*7c3d14c8STreehugger Robot result[size-1] = 0; 36*7c3d14c8STreehugger Robot return result; 37*7c3d14c8STreehugger Robot} 38*7c3d14c8STreehugger Robot__strong char *gcstrcpy1(__strong char *arg) { 39*7c3d14c8STreehugger Robot unsigned size = strlen(arg) + 1; 40*7c3d14c8STreehugger Robot __strong char *result = NSAllocateCollectable(size, 0); 41*7c3d14c8STreehugger Robot strncpy(result, arg, size); 42*7c3d14c8STreehugger Robot result[size-1] = 0; 43*7c3d14c8STreehugger Robot return result; 44*7c3d14c8STreehugger Robot} 45*7c3d14c8STreehugger Robot 46*7c3d14c8STreehugger Robot@implementation TestFileExe 47*7c3d14c8STreehugger Robot 48*7c3d14c8STreehugger Robot@synthesize options, compileLine, shouldFail, binaryName, sourceName; 49*7c3d14c8STreehugger Robot@synthesize generator; 50*7c3d14c8STreehugger Robot@synthesize libraryPath, frameworkPath; 51*7c3d14c8STreehugger Robot 52*7c3d14c8STreehugger Robot- (NSString *)description { 53*7c3d14c8STreehugger Robot NSMutableString *result = [NSMutableString new]; 54*7c3d14c8STreehugger Robot if (shouldFail) [result appendString:@"fail"]; 55*7c3d14c8STreehugger Robot for (id x in compileLine) { 56*7c3d14c8STreehugger Robot [result appendString:[NSString stringWithFormat:@" %s", (char *)x]]; 57*7c3d14c8STreehugger Robot } 58*7c3d14c8STreehugger Robot return result; 59*7c3d14c8STreehugger Robot} 60*7c3d14c8STreehugger Robot 61*7c3d14c8STreehugger Robot- (__strong char *)radar { 62*7c3d14c8STreehugger Robot return generator.radar; 63*7c3d14c8STreehugger Robot} 64*7c3d14c8STreehugger Robot 65*7c3d14c8STreehugger Robot- (bool) compileUnlessExists:(bool)skip { 66*7c3d14c8STreehugger Robot if (shouldFail) { 67*7c3d14c8STreehugger Robot printf("don't use this to compile anymore!\n"); 68*7c3d14c8STreehugger Robot return false; 69*7c3d14c8STreehugger Robot } 70*7c3d14c8STreehugger Robot if (skip && isExecutable(binaryName) && !isYounger(sourceName, binaryName)) return true; 71*7c3d14c8STreehugger Robot int argc = [compileLine count]; 72*7c3d14c8STreehugger Robot char *argv[argc+1]; 73*7c3d14c8STreehugger Robot for (int i = 0; i < argc; ++i) 74*7c3d14c8STreehugger Robot argv[i] = (char *)[compileLine pointerAtIndex:i]; 75*7c3d14c8STreehugger Robot argv[argc] = NULL; 76*7c3d14c8STreehugger Robot pid_t child = fork(); 77*7c3d14c8STreehugger Robot if (child == 0) { 78*7c3d14c8STreehugger Robot execv(argv[0], argv); 79*7c3d14c8STreehugger Robot exit(10); // shouldn't happen 80*7c3d14c8STreehugger Robot } 81*7c3d14c8STreehugger Robot if (child < 0) { 82*7c3d14c8STreehugger Robot printf("fork failed\n"); 83*7c3d14c8STreehugger Robot return false; 84*7c3d14c8STreehugger Robot } 85*7c3d14c8STreehugger Robot int status = 0; 86*7c3d14c8STreehugger Robot pid_t deadchild = wait(&status); 87*7c3d14c8STreehugger Robot if (deadchild != child) { 88*7c3d14c8STreehugger Robot printf("wait got %d instead of %d\n", deadchild, child); 89*7c3d14c8STreehugger Robot exit(1); 90*7c3d14c8STreehugger Robot } 91*7c3d14c8STreehugger Robot if (WEXITSTATUS(status) == 0) { 92*7c3d14c8STreehugger Robot return true; 93*7c3d14c8STreehugger Robot } 94*7c3d14c8STreehugger Robot printf("run failed\n"); 95*7c3d14c8STreehugger Robot return false; 96*7c3d14c8STreehugger Robot} 97*7c3d14c8STreehugger Robot 98*7c3d14c8STreehugger Robotbool lookforIn(char *lookfor, const char *format, pid_t child) { 99*7c3d14c8STreehugger Robot char buffer[512]; 100*7c3d14c8STreehugger Robot char got[512]; 101*7c3d14c8STreehugger Robot sprintf(buffer, format, child); 102*7c3d14c8STreehugger Robot bool gotOutput = readErrorFile(got, buffer); 103*7c3d14c8STreehugger Robot if (!gotOutput) { 104*7c3d14c8STreehugger Robot printf("**** didn't get an output file %s to analyze!!??\n", buffer); 105*7c3d14c8STreehugger Robot return false; 106*7c3d14c8STreehugger Robot } 107*7c3d14c8STreehugger Robot char *where = strstr(got, lookfor); 108*7c3d14c8STreehugger Robot if (!where) { 109*7c3d14c8STreehugger Robot printf("didn't find '%s' in output file %s\n", lookfor, buffer); 110*7c3d14c8STreehugger Robot return false; 111*7c3d14c8STreehugger Robot } 112*7c3d14c8STreehugger Robot unlink(buffer); 113*7c3d14c8STreehugger Robot return true; 114*7c3d14c8STreehugger Robot} 115*7c3d14c8STreehugger Robot 116*7c3d14c8STreehugger Robot- (bool) compileWithExpectedFailure { 117*7c3d14c8STreehugger Robot if (!shouldFail) { 118*7c3d14c8STreehugger Robot printf("Why am I being called?\n"); 119*7c3d14c8STreehugger Robot return false; 120*7c3d14c8STreehugger Robot } 121*7c3d14c8STreehugger Robot int argc = [compileLine count]; 122*7c3d14c8STreehugger Robot char *argv[argc+1]; 123*7c3d14c8STreehugger Robot for (int i = 0; i < argc; ++i) 124*7c3d14c8STreehugger Robot argv[i] = (char *)[compileLine pointerAtIndex:i]; 125*7c3d14c8STreehugger Robot argv[argc] = NULL; 126*7c3d14c8STreehugger Robot pid_t child = fork(); 127*7c3d14c8STreehugger Robot char buffer[512]; 128*7c3d14c8STreehugger Robot if (child == 0) { 129*7c3d14c8STreehugger Robot // in child 130*7c3d14c8STreehugger Robot sprintf(buffer, "/tmp/errorfile_%d", getpid()); 131*7c3d14c8STreehugger Robot close(1); 132*7c3d14c8STreehugger Robot int fd = creat(buffer, 0777); 133*7c3d14c8STreehugger Robot if (fd != 1) { 134*7c3d14c8STreehugger Robot fprintf(stderr, "didn't open custom error file %s as 1, got %d\n", buffer, fd); 135*7c3d14c8STreehugger Robot exit(1); 136*7c3d14c8STreehugger Robot } 137*7c3d14c8STreehugger Robot close(2); 138*7c3d14c8STreehugger Robot dup(1); 139*7c3d14c8STreehugger Robot int result = execv(argv[0], argv); 140*7c3d14c8STreehugger Robot exit(10); 141*7c3d14c8STreehugger Robot } 142*7c3d14c8STreehugger Robot if (child < 0) { 143*7c3d14c8STreehugger Robot printf("fork failed\n"); 144*7c3d14c8STreehugger Robot return false; 145*7c3d14c8STreehugger Robot } 146*7c3d14c8STreehugger Robot int status = 0; 147*7c3d14c8STreehugger Robot pid_t deadchild = wait(&status); 148*7c3d14c8STreehugger Robot if (deadchild != child) { 149*7c3d14c8STreehugger Robot printf("wait got %d instead of %d\n", deadchild, child); 150*7c3d14c8STreehugger Robot exit(11); 151*7c3d14c8STreehugger Robot } 152*7c3d14c8STreehugger Robot if (WIFEXITED(status)) { 153*7c3d14c8STreehugger Robot if (WEXITSTATUS(status) == 0) { 154*7c3d14c8STreehugger Robot return false; 155*7c3d14c8STreehugger Robot } 156*7c3d14c8STreehugger Robot } 157*7c3d14c8STreehugger Robot else { 158*7c3d14c8STreehugger Robot printf("***** compiler borked/ICEd/died unexpectedly (status %x)\n", status); 159*7c3d14c8STreehugger Robot return false; 160*7c3d14c8STreehugger Robot } 161*7c3d14c8STreehugger Robot char *error = generator.errorString; 162*7c3d14c8STreehugger Robot 163*7c3d14c8STreehugger Robot if (!error) return true; 164*7c3d14c8STreehugger Robot#if 0 165*7c3d14c8STreehugger Robot char got[512]; 166*7c3d14c8STreehugger Robot sprintf(buffer, "/tmp/errorfile_%d", child); 167*7c3d14c8STreehugger Robot bool gotOutput = readErrorFile(got, buffer); 168*7c3d14c8STreehugger Robot if (!gotOutput) { 169*7c3d14c8STreehugger Robot printf("**** didn't get an error file %s to analyze!!??\n", buffer); 170*7c3d14c8STreehugger Robot return false; 171*7c3d14c8STreehugger Robot } 172*7c3d14c8STreehugger Robot char *where = strstr(got, error); 173*7c3d14c8STreehugger Robot if (!where) { 174*7c3d14c8STreehugger Robot printf("didn't find '%s' in error file %s\n", error, buffer); 175*7c3d14c8STreehugger Robot return false; 176*7c3d14c8STreehugger Robot } 177*7c3d14c8STreehugger Robot unlink(buffer); 178*7c3d14c8STreehugger Robot#else 179*7c3d14c8STreehugger Robot if (!lookforIn(error, "/tmp/errorfile_%d", child)) return false; 180*7c3d14c8STreehugger Robot#endif 181*7c3d14c8STreehugger Robot return true; 182*7c3d14c8STreehugger Robot} 183*7c3d14c8STreehugger Robot 184*7c3d14c8STreehugger Robot- (bool) run { 185*7c3d14c8STreehugger Robot if (shouldFail) return true; 186*7c3d14c8STreehugger Robot if (sizeof(long) == 4 && options & Do64) { 187*7c3d14c8STreehugger Robot return true; // skip 64-bit tests 188*7c3d14c8STreehugger Robot } 189*7c3d14c8STreehugger Robot int argc = 1; 190*7c3d14c8STreehugger Robot char *argv[argc+1]; 191*7c3d14c8STreehugger Robot argv[0] = binaryName; 192*7c3d14c8STreehugger Robot argv[argc] = NULL; 193*7c3d14c8STreehugger Robot pid_t child = fork(); 194*7c3d14c8STreehugger Robot if (child == 0) { 195*7c3d14c8STreehugger Robot // set up environment 196*7c3d14c8STreehugger Robot char lpath[1024]; 197*7c3d14c8STreehugger Robot char fpath[1024]; 198*7c3d14c8STreehugger Robot char *myenv[3]; 199*7c3d14c8STreehugger Robot int counter = 0; 200*7c3d14c8STreehugger Robot if (libraryPath) { 201*7c3d14c8STreehugger Robot sprintf(lpath, "DYLD_LIBRARY_PATH=%s", libraryPath); 202*7c3d14c8STreehugger Robot myenv[counter++] = lpath; 203*7c3d14c8STreehugger Robot } 204*7c3d14c8STreehugger Robot if (frameworkPath) { 205*7c3d14c8STreehugger Robot sprintf(fpath, "DYLD_FRAMEWORK_PATH=%s", frameworkPath); 206*7c3d14c8STreehugger Robot myenv[counter++] = fpath; 207*7c3d14c8STreehugger Robot } 208*7c3d14c8STreehugger Robot myenv[counter] = NULL; 209*7c3d14c8STreehugger Robot if (generator.warningString) { 210*7c3d14c8STreehugger Robot // set up stdout/stderr 211*7c3d14c8STreehugger Robot char outfile[1024]; 212*7c3d14c8STreehugger Robot sprintf(outfile, "/tmp/stdout_%d", getpid()); 213*7c3d14c8STreehugger Robot close(2); 214*7c3d14c8STreehugger Robot close(1); 215*7c3d14c8STreehugger Robot creat(outfile, 0700); 216*7c3d14c8STreehugger Robot dup(1); 217*7c3d14c8STreehugger Robot } 218*7c3d14c8STreehugger Robot execve(argv[0], argv, myenv); 219*7c3d14c8STreehugger Robot exit(10); // shouldn't happen 220*7c3d14c8STreehugger Robot } 221*7c3d14c8STreehugger Robot if (child < 0) { 222*7c3d14c8STreehugger Robot printf("fork failed\n"); 223*7c3d14c8STreehugger Robot return false; 224*7c3d14c8STreehugger Robot } 225*7c3d14c8STreehugger Robot int status = 0; 226*7c3d14c8STreehugger Robot pid_t deadchild = wait(&status); 227*7c3d14c8STreehugger Robot if (deadchild != child) { 228*7c3d14c8STreehugger Robot printf("wait got %d instead of %d\n", deadchild, child); 229*7c3d14c8STreehugger Robot exit(1); 230*7c3d14c8STreehugger Robot } 231*7c3d14c8STreehugger Robot if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { 232*7c3d14c8STreehugger Robot if (generator.warningString) { 233*7c3d14c8STreehugger Robot if (!lookforIn(generator.warningString, "/tmp/stdout_%d", child)) return false; 234*7c3d14c8STreehugger Robot } 235*7c3d14c8STreehugger Robot return true; 236*7c3d14c8STreehugger Robot } 237*7c3d14c8STreehugger Robot printf("**** run failed for %s\n", binaryName); 238*7c3d14c8STreehugger Robot return false; 239*7c3d14c8STreehugger Robot} 240*7c3d14c8STreehugger Robot 241*7c3d14c8STreehugger Robot@end 242*7c3d14c8STreehugger Robot 243*7c3d14c8STreehugger Robot@implementation TestFileExeGenerator 244*7c3d14c8STreehugger Robot@synthesize filename, compilerPath, errorString; 245*7c3d14c8STreehugger Robot@synthesize hasObjC, hasRR, hasGC, hasCPlusPlus, wantsC99, supposedToNotCompile, open, wants32, wants64; 246*7c3d14c8STreehugger Robot@synthesize radar; 247*7c3d14c8STreehugger Robot@synthesize warningString; 248*7c3d14c8STreehugger Robot 249*7c3d14c8STreehugger Robot- (void)setFilename:(__strong char *)name { 250*7c3d14c8STreehugger Robot filename = gcstrcpy1(name); 251*7c3d14c8STreehugger Robot} 252*7c3d14c8STreehugger Robot- (void)setCompilerPath:(__strong char *)name { 253*7c3d14c8STreehugger Robot compilerPath = gcstrcpy1(name); 254*7c3d14c8STreehugger Robot} 255*7c3d14c8STreehugger Robot 256*7c3d14c8STreehugger Robot- (void)forMostThings:(NSMutableArray *)lines options:(int)options { 257*7c3d14c8STreehugger Robot TestFileExe *item = nil; 258*7c3d14c8STreehugger Robot item = [self lineForOptions:options]; 259*7c3d14c8STreehugger Robot if (item) [lines addObject:item]; 260*7c3d14c8STreehugger Robot item = [self lineForOptions:options|Do64]; 261*7c3d14c8STreehugger Robot if (item) [lines addObject:item]; 262*7c3d14c8STreehugger Robot item = [self lineForOptions:options|DoCPP]; 263*7c3d14c8STreehugger Robot if (item) [lines addObject:item]; 264*7c3d14c8STreehugger Robot item = [self lineForOptions:options|Do64|DoCPP]; 265*7c3d14c8STreehugger Robot if (item) [lines addObject:item]; 266*7c3d14c8STreehugger Robot} 267*7c3d14c8STreehugger Robot 268*7c3d14c8STreehugger Robot/* 269*7c3d14c8STreehugger Robot DoDashG = (1 << 8), 270*7c3d14c8STreehugger Robot DoDashO = (1 << 9), 271*7c3d14c8STreehugger Robot DoDashOs = (1 << 10), 272*7c3d14c8STreehugger Robot DoDashO2 = (1 << 11), 273*7c3d14c8STreehugger Robot*/ 274*7c3d14c8STreehugger Robot 275*7c3d14c8STreehugger Robot- (void)forAllThings:(NSMutableArray *)lines options:(int)options { 276*7c3d14c8STreehugger Robot [self forMostThings:lines options:options]; 277*7c3d14c8STreehugger Robot if (!Everything) { 278*7c3d14c8STreehugger Robot return; 279*7c3d14c8STreehugger Robot } 280*7c3d14c8STreehugger Robot // now do it with three explicit optimization flags 281*7c3d14c8STreehugger Robot [self forMostThings:lines options:options | DoDashO]; 282*7c3d14c8STreehugger Robot [self forMostThings:lines options:options | DoDashOs]; 283*7c3d14c8STreehugger Robot [self forMostThings:lines options:options | DoDashO2]; 284*7c3d14c8STreehugger Robot} 285*7c3d14c8STreehugger Robot 286*7c3d14c8STreehugger Robot- (NSArray *)allLines { 287*7c3d14c8STreehugger Robot NSMutableArray *result = [NSMutableArray new]; 288*7c3d14c8STreehugger Robot TestFileExe *item = nil; 289*7c3d14c8STreehugger Robot 290*7c3d14c8STreehugger Robot int options = 0; 291*7c3d14c8STreehugger Robot [self forAllThings:result options:0]; 292*7c3d14c8STreehugger Robot [self forAllThings:result options:DoOBJC | DoRR]; 293*7c3d14c8STreehugger Robot [self forAllThings:result options:DoOBJC | DoGC]; 294*7c3d14c8STreehugger Robot [self forAllThings:result options:DoOBJC | DoGCRR]; 295*7c3d14c8STreehugger Robot //[self forAllThings:result options:DoOBJC | DoRRGC]; 296*7c3d14c8STreehugger Robot 297*7c3d14c8STreehugger Robot return result; 298*7c3d14c8STreehugger Robot} 299*7c3d14c8STreehugger Robot 300*7c3d14c8STreehugger Robot- (void)addLibrary:(const char *)dashLSomething { 301*7c3d14c8STreehugger Robot if (!extraLibraries) { 302*7c3d14c8STreehugger Robot extraLibraries = [NSPointerArray pointerArrayWithOptions: 303*7c3d14c8STreehugger Robot NSPointerFunctionsStrongMemory | 304*7c3d14c8STreehugger Robot NSPointerFunctionsCStringPersonality]; 305*7c3d14c8STreehugger Robot } 306*7c3d14c8STreehugger Robot [extraLibraries addPointer:(void *)dashLSomething]; 307*7c3d14c8STreehugger Robot} 308*7c3d14c8STreehugger Robot 309*7c3d14c8STreehugger Robot- (TestFileExe *)lineForOptions:(int)options { // nil if no can do 310*7c3d14c8STreehugger Robot if (hasObjC && !(options & DoOBJC)) return nil; 311*7c3d14c8STreehugger Robot if (hasCPlusPlus && !(options & DoCPP)) return nil; 312*7c3d14c8STreehugger Robot if (hasObjC) { 313*7c3d14c8STreehugger Robot if (!hasGC && (options & (DoGC|DoGCRR))) return nil; // not smart enough 314*7c3d14c8STreehugger Robot if (!hasRR && (options & (DoRR|DoRRGC))) return nil; 315*7c3d14c8STreehugger Robot } 316*7c3d14c8STreehugger Robot NSPointerArray *pa = [NSPointerArray pointerArrayWithOptions: 317*7c3d14c8STreehugger Robot NSPointerFunctionsStrongMemory | 318*7c3d14c8STreehugger Robot NSPointerFunctionsCStringPersonality]; 319*7c3d14c8STreehugger Robot // construct path 320*7c3d14c8STreehugger Robot char path[512]; 321*7c3d14c8STreehugger Robot path[0] = 0; 322*7c3d14c8STreehugger Robot if (!compilerPath) compilerPath = "/usr/bin"; 323*7c3d14c8STreehugger Robot if (compilerPath) { 324*7c3d14c8STreehugger Robot strcat(path, compilerPath); 325*7c3d14c8STreehugger Robot strcat(path, "/"); 326*7c3d14c8STreehugger Robot } 327*7c3d14c8STreehugger Robot if (options & DoCPP) { 328*7c3d14c8STreehugger Robot strcat(path, DoClang ? "clang++" : "g++-4.2"); 329*7c3d14c8STreehugger Robot } 330*7c3d14c8STreehugger Robot else { 331*7c3d14c8STreehugger Robot strcat(path, DoClang ? "clang" : "gcc-4.2"); 332*7c3d14c8STreehugger Robot } 333*7c3d14c8STreehugger Robot [pa addPointer:gcstrcpy1(path)]; 334*7c3d14c8STreehugger Robot if (options & DoOBJC) { 335*7c3d14c8STreehugger Robot if (options & DoCPP) { 336*7c3d14c8STreehugger Robot [pa addPointer:"-ObjC++"]; 337*7c3d14c8STreehugger Robot } 338*7c3d14c8STreehugger Robot else { 339*7c3d14c8STreehugger Robot [pa addPointer:"-ObjC"]; 340*7c3d14c8STreehugger Robot } 341*7c3d14c8STreehugger Robot } 342*7c3d14c8STreehugger Robot [pa addPointer:"-g"]; 343*7c3d14c8STreehugger Robot if (options & DoDashO) [pa addPointer:"-O"]; 344*7c3d14c8STreehugger Robot else if (options & DoDashO2) [pa addPointer:"-O2"]; 345*7c3d14c8STreehugger Robot else if (options & DoDashOs) [pa addPointer:"-Os"]; 346*7c3d14c8STreehugger Robot if (wantsC99 && (! (options & DoCPP))) { 347*7c3d14c8STreehugger Robot [pa addPointer:"-std=c99"]; 348*7c3d14c8STreehugger Robot [pa addPointer:"-fblocks"]; 349*7c3d14c8STreehugger Robot } 350*7c3d14c8STreehugger Robot [pa addPointer:"-arch"]; 351*7c3d14c8STreehugger Robot [pa addPointer: (options & Do64) ? "x86_64" : "i386"]; 352*7c3d14c8STreehugger Robot 353*7c3d14c8STreehugger Robot if (options & DoOBJC) { 354*7c3d14c8STreehugger Robot switch (options & (DoRR|DoGC|DoGCRR|DoRRGC)) { 355*7c3d14c8STreehugger Robot case DoRR: 356*7c3d14c8STreehugger Robot break; 357*7c3d14c8STreehugger Robot case DoGC: 358*7c3d14c8STreehugger Robot [pa addPointer:"-fobjc-gc-only"]; 359*7c3d14c8STreehugger Robot break; 360*7c3d14c8STreehugger Robot case DoGCRR: 361*7c3d14c8STreehugger Robot [pa addPointer:"-fobjc-gc"]; 362*7c3d14c8STreehugger Robot break; 363*7c3d14c8STreehugger Robot case DoRRGC: 364*7c3d14c8STreehugger Robot printf("DoRRGC unsupported right now\n"); 365*7c3d14c8STreehugger Robot [pa addPointer:"-c"]; 366*7c3d14c8STreehugger Robot return nil; 367*7c3d14c8STreehugger Robot } 368*7c3d14c8STreehugger Robot [pa addPointer:"-framework"]; 369*7c3d14c8STreehugger Robot [pa addPointer:"Foundation"]; 370*7c3d14c8STreehugger Robot } 371*7c3d14c8STreehugger Robot [pa addPointer:gcstrcpy1(filename)]; 372*7c3d14c8STreehugger Robot [pa addPointer:"-o"]; 373*7c3d14c8STreehugger Robot 374*7c3d14c8STreehugger Robot path[0] = 0; 375*7c3d14c8STreehugger Robot strcat(path, filename); 376*7c3d14c8STreehugger Robot strcat(path, "."); 377*7c3d14c8STreehugger Robot strcat(path, (options & Do64) ? "64" : "32"); 378*7c3d14c8STreehugger Robot if (options & DoOBJC) { 379*7c3d14c8STreehugger Robot switch (options & (DoRR|DoGC|DoGCRR|DoRRGC)) { 380*7c3d14c8STreehugger Robot case DoRR: strcat(path, "-rr"); break; 381*7c3d14c8STreehugger Robot case DoGC: strcat(path, "-gconly"); break; 382*7c3d14c8STreehugger Robot case DoGCRR: strcat(path, "-gcrr"); break; 383*7c3d14c8STreehugger Robot case DoRRGC: strcat(path, "-rrgc"); break; 384*7c3d14c8STreehugger Robot } 385*7c3d14c8STreehugger Robot } 386*7c3d14c8STreehugger Robot if (options & DoCPP) strcat(path, "++"); 387*7c3d14c8STreehugger Robot if (options & DoDashO) strcat(path, "-O"); 388*7c3d14c8STreehugger Robot else if (options & DoDashO2) strcat(path, "-O2"); 389*7c3d14c8STreehugger Robot else if (options & DoDashOs) strcat(path, "-Os"); 390*7c3d14c8STreehugger Robot if (wantsC99) strcat(path, "-C99"); 391*7c3d14c8STreehugger Robot strcat(path, DoClang ? "-clang" : "-gcc"); 392*7c3d14c8STreehugger Robot strcat(path, "-bin"); 393*7c3d14c8STreehugger Robot TestFileExe *result = [TestFileExe new]; 394*7c3d14c8STreehugger Robot result.binaryName = gcstrcpy1(path); // could snarf copy in pa 395*7c3d14c8STreehugger Robot [pa addPointer:result.binaryName]; 396*7c3d14c8STreehugger Robot for (id cString in extraLibraries) { 397*7c3d14c8STreehugger Robot [pa addPointer:cString]; 398*7c3d14c8STreehugger Robot } 399*7c3d14c8STreehugger Robot 400*7c3d14c8STreehugger Robot result.sourceName = gcstrcpy1(filename); // could snarf copy in pa 401*7c3d14c8STreehugger Robot result.compileLine = pa; 402*7c3d14c8STreehugger Robot result.options = options; 403*7c3d14c8STreehugger Robot result.shouldFail = supposedToNotCompile; 404*7c3d14c8STreehugger Robot result.generator = self; 405*7c3d14c8STreehugger Robot return result; 406*7c3d14c8STreehugger Robot} 407*7c3d14c8STreehugger Robot 408*7c3d14c8STreehugger Robot+ (NSArray *)generatorsFromPath:(NSString *)path { 409*7c3d14c8STreehugger Robot FILE *fp = fopen([path fileSystemRepresentation], "r"); 410*7c3d14c8STreehugger Robot if (fp == NULL) return nil; 411*7c3d14c8STreehugger Robot NSArray *result = [self generatorsFromFILE:fp]; 412*7c3d14c8STreehugger Robot fclose(fp); 413*7c3d14c8STreehugger Robot return result; 414*7c3d14c8STreehugger Robot} 415*7c3d14c8STreehugger Robot 416*7c3d14c8STreehugger Robot#define LOOKFOR "CON" "FIG" 417*7c3d14c8STreehugger Robot 418*7c3d14c8STreehugger Robotchar *__strong parseRadar(char *line) { 419*7c3d14c8STreehugger Robot line = strstr(line, "rdar:"); // returns beginning 420*7c3d14c8STreehugger Robot char *endp = line + strlen("rdar:"); 421*7c3d14c8STreehugger Robot while (*endp && *endp != ' ' && *endp != '\n') 422*7c3d14c8STreehugger Robot ++endp; 423*7c3d14c8STreehugger Robot return gcstrcpy2(line, endp); 424*7c3d14c8STreehugger Robot} 425*7c3d14c8STreehugger Robot 426*7c3d14c8STreehugger Robot- (void)parseLibraries:(const char *)line { 427*7c3d14c8STreehugger Robot start: 428*7c3d14c8STreehugger Robot line = strstr(line, "-l"); 429*7c3d14c8STreehugger Robot char *endp = (char *)line + 2; 430*7c3d14c8STreehugger Robot while (*endp && *endp != ' ' && *endp != '\n') 431*7c3d14c8STreehugger Robot ++endp; 432*7c3d14c8STreehugger Robot [self addLibrary:gcstrcpy2(line, endp)]; 433*7c3d14c8STreehugger Robot if (strstr(endp, "-l")) { 434*7c3d14c8STreehugger Robot line = endp; 435*7c3d14c8STreehugger Robot goto start; 436*7c3d14c8STreehugger Robot } 437*7c3d14c8STreehugger Robot} 438*7c3d14c8STreehugger Robot 439*7c3d14c8STreehugger Robot+ (TestFileExeGenerator *)generatorFromLine:(char *)line filename:(char *)filename { 440*7c3d14c8STreehugger Robot TestFileExeGenerator *item = [TestFileExeGenerator new]; 441*7c3d14c8STreehugger Robot item.filename = gcstrcpy1(filename); 442*7c3d14c8STreehugger Robot if (strstr(line, "GC")) item.hasGC = true; 443*7c3d14c8STreehugger Robot if (strstr(line, "RR")) item.hasRR = true; 444*7c3d14c8STreehugger Robot if (strstr(line, "C++")) item.hasCPlusPlus = true; 445*7c3d14c8STreehugger Robot if (strstr(line, "-C99")) { 446*7c3d14c8STreehugger Robot item.wantsC99 = true; 447*7c3d14c8STreehugger Robot } 448*7c3d14c8STreehugger Robot if (strstr(line, "64")) item.wants64 = true; 449*7c3d14c8STreehugger Robot if (strstr(line, "32")) item.wants32 = true; 450*7c3d14c8STreehugger Robot if (strstr(line, "-l")) [item parseLibraries:line]; 451*7c3d14c8STreehugger Robot if (strstr(line, "open")) item.open = true; 452*7c3d14c8STreehugger Robot if (strstr(line, "FAIL")) item.supposedToNotCompile = true; // old 453*7c3d14c8STreehugger Robot // compile time error 454*7c3d14c8STreehugger Robot if (strstr(line, "error:")) { 455*7c3d14c8STreehugger Robot item.supposedToNotCompile = true; 456*7c3d14c8STreehugger Robot // zap newline 457*7c3d14c8STreehugger Robot char *error = strstr(line, "error:") + strlen("error:"); 458*7c3d14c8STreehugger Robot // make sure we have something before the newline 459*7c3d14c8STreehugger Robot char *newline = strstr(error, "\n"); 460*7c3d14c8STreehugger Robot if (newline && ((newline-error) > 1)) { 461*7c3d14c8STreehugger Robot *newline = 0; 462*7c3d14c8STreehugger Robot item.errorString = gcstrcpy1(strstr(line, "error:") + strlen("error: ")); 463*7c3d14c8STreehugger Robot } 464*7c3d14c8STreehugger Robot } 465*7c3d14c8STreehugger Robot // run time warning 466*7c3d14c8STreehugger Robot if (strstr(line, "runtime:")) { 467*7c3d14c8STreehugger Robot // zap newline 468*7c3d14c8STreehugger Robot char *error = strstr(line, "runtime:") + strlen("runtime:"); 469*7c3d14c8STreehugger Robot // make sure we have something before the newline 470*7c3d14c8STreehugger Robot char *newline = strstr(error, "\n"); 471*7c3d14c8STreehugger Robot if (newline && ((newline-error) > 1)) { 472*7c3d14c8STreehugger Robot *newline = 0; 473*7c3d14c8STreehugger Robot item.warningString = gcstrcpy1(strstr(line, "runtime:") + strlen("runtime:")); 474*7c3d14c8STreehugger Robot } 475*7c3d14c8STreehugger Robot } 476*7c3d14c8STreehugger Robot if (strstr(line, "rdar:")) item.radar = parseRadar(line); 477*7c3d14c8STreehugger Robot if (item.hasGC || item.hasRR) item.hasObjC = true; 478*7c3d14c8STreehugger Robot if (!item.wants32 && !item.wants64) { // give them both if they ask for neither 479*7c3d14c8STreehugger Robot item.wants32 = item.wants64 = true; 480*7c3d14c8STreehugger Robot } 481*7c3d14c8STreehugger Robot return item; 482*7c3d14c8STreehugger Robot} 483*7c3d14c8STreehugger Robot 484*7c3d14c8STreehugger Robot+ (NSArray *)generatorsFromFILE:(FILE *)fp { 485*7c3d14c8STreehugger Robot NSMutableArray *result = [NSMutableArray new]; 486*7c3d14c8STreehugger Robot // pretend this is a grep LOOKFOR *.[cmCM][cmCM] input 487*7c3d14c8STreehugger Robot // look for 488*7c3d14c8STreehugger Robot // filename: ... LOOKFOR [GC] [RR] [C++] [FAIL ...] 489*7c3d14c8STreehugger Robot char buf[512]; 490*7c3d14c8STreehugger Robot while (fgets(buf, 512, fp)) { 491*7c3d14c8STreehugger Robot char *config = strstr(buf, LOOKFOR); 492*7c3d14c8STreehugger Robot if (!config) continue; 493*7c3d14c8STreehugger Robot char *filename = buf; 494*7c3d14c8STreehugger Robot char *end = strchr(buf, ':'); 495*7c3d14c8STreehugger Robot *end = 0; 496*7c3d14c8STreehugger Robot [result addObject:[self generatorFromLine:config filename:filename]]; 497*7c3d14c8STreehugger Robot } 498*7c3d14c8STreehugger Robot return result; 499*7c3d14c8STreehugger Robot} 500*7c3d14c8STreehugger Robot 501*7c3d14c8STreehugger Robot+ (TestFileExeGenerator *)generatorFromFilename:(char *)filename { 502*7c3d14c8STreehugger Robot FILE *fp = fopen(filename, "r"); 503*7c3d14c8STreehugger Robot if (!fp) { 504*7c3d14c8STreehugger Robot printf("didn't open %s!!\n", filename); 505*7c3d14c8STreehugger Robot return nil; 506*7c3d14c8STreehugger Robot } 507*7c3d14c8STreehugger Robot char buf[512]; 508*7c3d14c8STreehugger Robot while (fgets(buf, 512, fp)) { 509*7c3d14c8STreehugger Robot char *config = strstr(buf, LOOKFOR); 510*7c3d14c8STreehugger Robot if (!config) continue; 511*7c3d14c8STreehugger Robot fclose(fp); 512*7c3d14c8STreehugger Robot return [self generatorFromLine:config filename:filename]; 513*7c3d14c8STreehugger Robot } 514*7c3d14c8STreehugger Robot fclose(fp); 515*7c3d14c8STreehugger Robot // guess from filename 516*7c3d14c8STreehugger Robot char *ext = strrchr(filename, '.'); 517*7c3d14c8STreehugger Robot if (!ext) return nil; 518*7c3d14c8STreehugger Robot TestFileExeGenerator *result = [TestFileExeGenerator new]; 519*7c3d14c8STreehugger Robot result.filename = gcstrcpy1(filename); 520*7c3d14c8STreehugger Robot if (!strncmp(ext, ".m", 2)) { 521*7c3d14c8STreehugger Robot result.hasObjC = true; 522*7c3d14c8STreehugger Robot result.hasRR = true; 523*7c3d14c8STreehugger Robot result.hasGC = true; 524*7c3d14c8STreehugger Robot } 525*7c3d14c8STreehugger Robot else if (!strcmp(ext, ".c")) { 526*7c3d14c8STreehugger Robot ; 527*7c3d14c8STreehugger Robot } 528*7c3d14c8STreehugger Robot else if (!strcmp(ext, ".M") || !strcmp(ext, ".mm")) { 529*7c3d14c8STreehugger Robot result.hasObjC = true; 530*7c3d14c8STreehugger Robot result.hasRR = true; 531*7c3d14c8STreehugger Robot result.hasGC = true; 532*7c3d14c8STreehugger Robot result.hasCPlusPlus = true; 533*7c3d14c8STreehugger Robot } 534*7c3d14c8STreehugger Robot else if (!strcmp(ext, ".cc") 535*7c3d14c8STreehugger Robot || !strcmp(ext, ".cp") 536*7c3d14c8STreehugger Robot || !strcmp(ext, ".cxx") 537*7c3d14c8STreehugger Robot || !strcmp(ext, ".cpp") 538*7c3d14c8STreehugger Robot || !strcmp(ext, ".CPP") 539*7c3d14c8STreehugger Robot || !strcmp(ext, ".c++") 540*7c3d14c8STreehugger Robot || !strcmp(ext, ".C")) { 541*7c3d14c8STreehugger Robot result.hasCPlusPlus = true; 542*7c3d14c8STreehugger Robot } 543*7c3d14c8STreehugger Robot else { 544*7c3d14c8STreehugger Robot printf("unknown extension, file %s ignored\n", filename); 545*7c3d14c8STreehugger Robot result = nil; 546*7c3d14c8STreehugger Robot } 547*7c3d14c8STreehugger Robot return result; 548*7c3d14c8STreehugger Robot 549*7c3d14c8STreehugger Robot} 550*7c3d14c8STreehugger Robot 551*7c3d14c8STreehugger Robot- (NSString *)description { 552*7c3d14c8STreehugger Robot return [NSString stringWithFormat:@"%s: %s%s%s%s%s%s", 553*7c3d14c8STreehugger Robot filename, 554*7c3d14c8STreehugger Robot LOOKFOR, 555*7c3d14c8STreehugger Robot hasGC ? " GC" : "", 556*7c3d14c8STreehugger Robot hasRR ? " RR" : "", 557*7c3d14c8STreehugger Robot hasCPlusPlus ? " C++" : "", 558*7c3d14c8STreehugger Robot wantsC99 ? "C99" : "", 559*7c3d14c8STreehugger Robot supposedToNotCompile ? " FAIL" : ""]; 560*7c3d14c8STreehugger Robot} 561*7c3d14c8STreehugger Robot 562*7c3d14c8STreehugger Robot@end 563*7c3d14c8STreehugger Robot 564*7c3d14c8STreehugger Robotvoid printDetails(NSArray *failures, const char *whatAreThey) { 565*7c3d14c8STreehugger Robot if ([failures count]) { 566*7c3d14c8STreehugger Robot NSMutableString *output = [NSMutableString new]; 567*7c3d14c8STreehugger Robot printf("%s:\n", whatAreThey); 568*7c3d14c8STreehugger Robot for (TestFileExe *line in failures) { 569*7c3d14c8STreehugger Robot printf("%s", line.binaryName); 570*7c3d14c8STreehugger Robot char *radar = line.generator.radar; 571*7c3d14c8STreehugger Robot if (radar) 572*7c3d14c8STreehugger Robot printf(" (due to %s?),", radar); 573*7c3d14c8STreehugger Robot printf(" recompile via:\n%s\n\n", line.description.UTF8String); 574*7c3d14c8STreehugger Robot } 575*7c3d14c8STreehugger Robot printf("\n"); 576*7c3d14c8STreehugger Robot } 577*7c3d14c8STreehugger Robot} 578*7c3d14c8STreehugger Robot 579*7c3d14c8STreehugger Robotvoid help(const char *whoami) { 580*7c3d14c8STreehugger Robot printf("Usage: %s [-fast] [-e] [-dyld librarypath] [gcc4.2dir] [-- | source1 ...]\n", whoami); 581*7c3d14c8STreehugger Robot printf(" -fast don't recompile if binary younger than source\n"); 582*7c3d14c8STreehugger Robot printf(" -open only run tests that are thought to still be unresolved\n"); 583*7c3d14c8STreehugger Robot printf(" -clang use the clang and clang++ compilers\n"); 584*7c3d14c8STreehugger Robot printf(" -e compile all variations also with -Os, -O2, -O3\n"); 585*7c3d14c8STreehugger Robot printf(" -dyld p override DYLD_LIBRARY_PATH and DYLD_FRAMEWORK_PATH to p when running tests\n"); 586*7c3d14c8STreehugger Robot printf(" <compilerpath> directory containing gcc-4.2 (or clang) that you wish to use to compile the tests\n"); 587*7c3d14c8STreehugger Robot printf(" -- assume stdin is a grep CON" "FIG across the test sources\n"); 588*7c3d14c8STreehugger Robot printf(" otherwise treat each remaining argument as a single test file source\n"); 589*7c3d14c8STreehugger Robot printf("%s will compile and run individual test files under a variety of compilers, c, obj-c, c++, and objc++\n", whoami); 590*7c3d14c8STreehugger Robot printf(" .c files are compiled with all four compilers\n"); 591*7c3d14c8STreehugger Robot printf(" .m files are compiled with objc and objc++ compilers\n"); 592*7c3d14c8STreehugger Robot printf(" .C files are compiled with c++ and objc++ compilers\n"); 593*7c3d14c8STreehugger Robot printf(" .M files are compiled only with the objc++ compiler\n"); 594*7c3d14c8STreehugger Robot printf("(actually all forms of extensions recognized by the compilers are honored, .cc, .c++ etc.)\n"); 595*7c3d14c8STreehugger Robot printf("\nTest files should run to completion with no output and exit (return) 0 on success.\n"); 596*7c3d14c8STreehugger Robot printf("Further they should be able to be compiled and run with GC on or off and by the C++ compilers\n"); 597*7c3d14c8STreehugger Robot printf("A line containing the string CON" "FIG within the source enables restrictions to the above assumptions\n"); 598*7c3d14c8STreehugger Robot printf("and other options.\n"); 599*7c3d14c8STreehugger Robot printf("Following CON" "FIG the string\n"); 600*7c3d14c8STreehugger Robot printf(" C++ restricts the test to only be run by c++ and objc++ compilers\n"); 601*7c3d14c8STreehugger Robot printf(" GC restricts the test to only be compiled and run with GC on\n"); 602*7c3d14c8STreehugger Robot printf(" RR (retain/release) restricts the test to only be compiled and run with GC off\n"); 603*7c3d14c8STreehugger Robot printf("Additionally,\n"); 604*7c3d14c8STreehugger Robot printf(" -C99 restricts the C versions of the test to -fstd=c99 -fblocks\n"); 605*7c3d14c8STreehugger Robot printf(" -O adds the -O optimization level\n"); 606*7c3d14c8STreehugger Robot printf(" -O2 adds the -O2 optimization level\n"); 607*7c3d14c8STreehugger Robot printf(" -Os adds the -Os optimization level\n"); 608*7c3d14c8STreehugger Robot printf("Files that are known to exhibit unresolved problems can provide the term \"open\" and this can"); 609*7c3d14c8STreehugger Robot printf("in turn allow highlighting of fixes that have regressed as well as identify that fixes are now available.\n"); 610*7c3d14c8STreehugger Robot printf("Files that exhibit known bugs may provide\n"); 611*7c3d14c8STreehugger Robot printf(" rdar://whatever such that if they fail the rdar will get cited\n"); 612*7c3d14c8STreehugger Robot printf("Files that are expected to fail to compile should provide, as their last token sequence,\n"); 613*7c3d14c8STreehugger Robot printf(" error:\n"); 614*7c3d14c8STreehugger Robot printf(" or error: substring to match.\n"); 615*7c3d14c8STreehugger Robot printf("Files that are expected to produce a runtime error message should provide, as their last token sequence,\n"); 616*7c3d14c8STreehugger Robot printf(" warning: string to match\n"); 617*7c3d14c8STreehugger Robot printf("\n%s will compile and run all configurations of the test files and report a summary at the end. Good luck.\n", whoami); 618*7c3d14c8STreehugger Robot printf(" Blaine Garst [email protected]\n"); 619*7c3d14c8STreehugger Robot} 620*7c3d14c8STreehugger Robot 621*7c3d14c8STreehugger Robotint main(int argc, char *argv[]) { 622*7c3d14c8STreehugger Robot printf("running on %s-bit architecture\n", sizeof(long) == 4 ? "32" : "64"); 623*7c3d14c8STreehugger Robot char *compilerDir = "/usr/bin"; 624*7c3d14c8STreehugger Robot NSMutableArray *generators = [NSMutableArray new]; 625*7c3d14c8STreehugger Robot bool doFast = false; 626*7c3d14c8STreehugger Robot bool doStdin = false; 627*7c3d14c8STreehugger Robot bool onlyOpen = false; 628*7c3d14c8STreehugger Robot char *libraryPath = getenv("DYLD_LIBRARY_PATH"); 629*7c3d14c8STreehugger Robot char *frameworkPath = getenv("DYLD_FRAMEWORK_PATH"); 630*7c3d14c8STreehugger Robot // process options 631*7c3d14c8STreehugger Robot while (argc > 1) { 632*7c3d14c8STreehugger Robot if (!strcmp(argv[1], "-fast")) { 633*7c3d14c8STreehugger Robot doFast = true; 634*7c3d14c8STreehugger Robot --argc; 635*7c3d14c8STreehugger Robot ++argv; 636*7c3d14c8STreehugger Robot } 637*7c3d14c8STreehugger Robot else if (!strcmp(argv[1], "-dyld")) { 638*7c3d14c8STreehugger Robot doFast = true; 639*7c3d14c8STreehugger Robot --argc; 640*7c3d14c8STreehugger Robot ++argv; 641*7c3d14c8STreehugger Robot frameworkPath = argv[1]; 642*7c3d14c8STreehugger Robot libraryPath = argv[1]; 643*7c3d14c8STreehugger Robot --argc; 644*7c3d14c8STreehugger Robot ++argv; 645*7c3d14c8STreehugger Robot } 646*7c3d14c8STreehugger Robot else if (!strcmp(argv[1], "-open")) { 647*7c3d14c8STreehugger Robot onlyOpen = true; 648*7c3d14c8STreehugger Robot --argc; 649*7c3d14c8STreehugger Robot ++argv; 650*7c3d14c8STreehugger Robot } 651*7c3d14c8STreehugger Robot else if (!strcmp(argv[1], "-clang")) { 652*7c3d14c8STreehugger Robot DoClang = true; 653*7c3d14c8STreehugger Robot --argc; 654*7c3d14c8STreehugger Robot ++argv; 655*7c3d14c8STreehugger Robot } 656*7c3d14c8STreehugger Robot else if (!strcmp(argv[1], "-e")) { 657*7c3d14c8STreehugger Robot Everything = true; 658*7c3d14c8STreehugger Robot --argc; 659*7c3d14c8STreehugger Robot ++argv; 660*7c3d14c8STreehugger Robot } 661*7c3d14c8STreehugger Robot else if (!strcmp(argv[1], "--")) { 662*7c3d14c8STreehugger Robot doStdin = true; 663*7c3d14c8STreehugger Robot --argc; 664*7c3d14c8STreehugger Robot ++argv; 665*7c3d14c8STreehugger Robot } 666*7c3d14c8STreehugger Robot else if (!strcmp(argv[1], "-")) { 667*7c3d14c8STreehugger Robot help(argv[0]); 668*7c3d14c8STreehugger Robot return 1; 669*7c3d14c8STreehugger Robot } 670*7c3d14c8STreehugger Robot else if (argc > 1 && isDirectory(argv[1])) { 671*7c3d14c8STreehugger Robot compilerDir = argv[1]; 672*7c3d14c8STreehugger Robot ++argv; 673*7c3d14c8STreehugger Robot --argc; 674*7c3d14c8STreehugger Robot } 675*7c3d14c8STreehugger Robot else 676*7c3d14c8STreehugger Robot break; 677*7c3d14c8STreehugger Robot } 678*7c3d14c8STreehugger Robot // process remaining arguments, or stdin 679*7c3d14c8STreehugger Robot if (argc == 1) { 680*7c3d14c8STreehugger Robot if (doStdin) 681*7c3d14c8STreehugger Robot generators = (NSMutableArray *)[TestFileExeGenerator generatorsFromFILE:stdin]; 682*7c3d14c8STreehugger Robot else { 683*7c3d14c8STreehugger Robot help(argv[0]); 684*7c3d14c8STreehugger Robot return 1; 685*7c3d14c8STreehugger Robot } 686*7c3d14c8STreehugger Robot } 687*7c3d14c8STreehugger Robot else while (argc > 1) { 688*7c3d14c8STreehugger Robot TestFileExeGenerator *generator = [TestFileExeGenerator generatorFromFilename:argv[1]]; 689*7c3d14c8STreehugger Robot if (generator) [generators addObject:generator]; 690*7c3d14c8STreehugger Robot ++argv; 691*7c3d14c8STreehugger Robot --argc; 692*7c3d14c8STreehugger Robot } 693*7c3d14c8STreehugger Robot // see if we can generate all possibilities 694*7c3d14c8STreehugger Robot NSMutableArray *failureToCompile = [NSMutableArray new]; 695*7c3d14c8STreehugger Robot NSMutableArray *failureToFailToCompile = [NSMutableArray new]; 696*7c3d14c8STreehugger Robot NSMutableArray *failureToRun = [NSMutableArray new]; 697*7c3d14c8STreehugger Robot NSMutableArray *successes = [NSMutableArray new]; 698*7c3d14c8STreehugger Robot for (TestFileExeGenerator *generator in generators) { 699*7c3d14c8STreehugger Robot //NSLog(@"got %@", generator); 700*7c3d14c8STreehugger Robot if (onlyOpen && !generator.open) { 701*7c3d14c8STreehugger Robot //printf("skipping resolved test %s\n", generator.filename); 702*7c3d14c8STreehugger Robot continue; // skip closed if onlyOpen 703*7c3d14c8STreehugger Robot } 704*7c3d14c8STreehugger Robot if (!onlyOpen && generator.open) { 705*7c3d14c8STreehugger Robot //printf("skipping open test %s\n", generator.filename); 706*7c3d14c8STreehugger Robot continue; // skip open if not asked for onlyOpen 707*7c3d14c8STreehugger Robot } 708*7c3d14c8STreehugger Robot generator.compilerPath = compilerDir; 709*7c3d14c8STreehugger Robot NSArray *tests = [generator allLines]; 710*7c3d14c8STreehugger Robot for (TestFileExe *line in tests) { 711*7c3d14c8STreehugger Robot line.frameworkPath = frameworkPath; // tell generators about it instead XXX 712*7c3d14c8STreehugger Robot line.libraryPath = libraryPath; // tell generators about it instead XXX 713*7c3d14c8STreehugger Robot if ([line shouldFail]) { 714*7c3d14c8STreehugger Robot if (doFast) continue; // don't recompile & don't count as success 715*7c3d14c8STreehugger Robot if ([line compileWithExpectedFailure]) { 716*7c3d14c8STreehugger Robot [successes addObject:line]; 717*7c3d14c8STreehugger Robot } 718*7c3d14c8STreehugger Robot else 719*7c3d14c8STreehugger Robot [failureToFailToCompile addObject:line]; 720*7c3d14c8STreehugger Robot } 721*7c3d14c8STreehugger Robot else if ([line compileUnlessExists:doFast]) { 722*7c3d14c8STreehugger Robot if ([line run]) { 723*7c3d14c8STreehugger Robot printf("%s ran successfully\n", line.binaryName); 724*7c3d14c8STreehugger Robot [successes addObject:line]; 725*7c3d14c8STreehugger Robot } 726*7c3d14c8STreehugger Robot else { 727*7c3d14c8STreehugger Robot [failureToRun addObject:line]; 728*7c3d14c8STreehugger Robot } 729*7c3d14c8STreehugger Robot } 730*7c3d14c8STreehugger Robot else { 731*7c3d14c8STreehugger Robot [failureToCompile addObject:line]; 732*7c3d14c8STreehugger Robot } 733*7c3d14c8STreehugger Robot } 734*7c3d14c8STreehugger Robot } 735*7c3d14c8STreehugger Robot printf("\n--- results ---\n\n%lu successes\n%lu unexpected compile failures\n%lu failure to fail to compile errors\n%lu run failures\n", 736*7c3d14c8STreehugger Robot [successes count], [failureToCompile count], [failureToFailToCompile count], [failureToRun count]); 737*7c3d14c8STreehugger Robot printDetails(failureToCompile, "unexpected compile failures"); 738*7c3d14c8STreehugger Robot printDetails(failureToFailToCompile, "should have failed to compile but didn't failures"); 739*7c3d14c8STreehugger Robot printDetails(failureToRun, "run failures"); 740*7c3d14c8STreehugger Robot 741*7c3d14c8STreehugger Robot if (onlyOpen && [successes count]) { 742*7c3d14c8STreehugger Robot NSMutableSet *radars = [NSMutableSet new]; 743*7c3d14c8STreehugger Robot printf("The following tests ran successfully suggesting that they are now resolved:\n"); 744*7c3d14c8STreehugger Robot for (TestFileExe *line in successes) { 745*7c3d14c8STreehugger Robot printf("%s\n", line.binaryName); 746*7c3d14c8STreehugger Robot if (line.radar) [radars addObject:line.generator]; 747*7c3d14c8STreehugger Robot } 748*7c3d14c8STreehugger Robot if ([radars count]) { 749*7c3d14c8STreehugger Robot printf("The following radars may be resolved:\n"); 750*7c3d14c8STreehugger Robot for (TestFileExeGenerator *line in radars) { 751*7c3d14c8STreehugger Robot printf("%s\n", line.radar); 752*7c3d14c8STreehugger Robot } 753*7c3d14c8STreehugger Robot } 754*7c3d14c8STreehugger Robot } 755*7c3d14c8STreehugger Robot 756*7c3d14c8STreehugger Robot return [failureToCompile count] + [failureToRun count]; 757*7c3d14c8STreehugger Robot} 758*7c3d14c8STreehugger Robot 759*7c3d14c8STreehugger Robot#include <sys/stat.h> 760*7c3d14c8STreehugger Robot 761*7c3d14c8STreehugger Robotstatic bool isDirectory(char *path) { 762*7c3d14c8STreehugger Robot struct stat statb; 763*7c3d14c8STreehugger Robot int retval = stat(path, &statb); 764*7c3d14c8STreehugger Robot if (retval != 0) return false; 765*7c3d14c8STreehugger Robot if (statb.st_mode & S_IFDIR) return true; 766*7c3d14c8STreehugger Robot return false; 767*7c3d14c8STreehugger Robot} 768*7c3d14c8STreehugger Robot 769*7c3d14c8STreehugger Robotstatic bool isExecutable(char *path) { 770*7c3d14c8STreehugger Robot struct stat statb; 771*7c3d14c8STreehugger Robot int retval = stat(path, &statb); 772*7c3d14c8STreehugger Robot if (retval != 0) return false; 773*7c3d14c8STreehugger Robot if (!(statb.st_mode & S_IFREG)) return false; 774*7c3d14c8STreehugger Robot if (statb.st_mode & S_IXUSR) return true; 775*7c3d14c8STreehugger Robot return false; 776*7c3d14c8STreehugger Robot} 777*7c3d14c8STreehugger Robot 778*7c3d14c8STreehugger Robotstatic bool isYounger(char *source, char *binary) { 779*7c3d14c8STreehugger Robot struct stat statb; 780*7c3d14c8STreehugger Robot int retval = stat(binary, &statb); 781*7c3d14c8STreehugger Robot if (retval != 0) return true; // if doesn't exit, lie 782*7c3d14c8STreehugger Robot 783*7c3d14c8STreehugger Robot struct stat stata; 784*7c3d14c8STreehugger Robot retval = stat(source, &stata); 785*7c3d14c8STreehugger Robot if (retval != 0) return true; // we're hosed 786*7c3d14c8STreehugger Robot // the greater the timeval the younger it is 787*7c3d14c8STreehugger Robot if (stata.st_mtimespec.tv_sec > statb.st_mtimespec.tv_sec) return true; 788*7c3d14c8STreehugger Robot if (stata.st_mtimespec.tv_nsec > statb.st_mtimespec.tv_nsec) return true; 789*7c3d14c8STreehugger Robot return false; 790*7c3d14c8STreehugger Robot} 791*7c3d14c8STreehugger Robot 792*7c3d14c8STreehugger Robotstatic bool readErrorFile(char *buffer, const char *from) { 793*7c3d14c8STreehugger Robot int fd = open(from, 0); 794*7c3d14c8STreehugger Robot if (fd < 0) { 795*7c3d14c8STreehugger Robot printf("didn't open %s, (might not have been created?)\n", buffer); 796*7c3d14c8STreehugger Robot return false; 797*7c3d14c8STreehugger Robot } 798*7c3d14c8STreehugger Robot int count = read(fd, buffer, 512); 799*7c3d14c8STreehugger Robot if (count < 1) { 800*7c3d14c8STreehugger Robot printf("read error on %s\n", buffer); 801*7c3d14c8STreehugger Robot return false; 802*7c3d14c8STreehugger Robot } 803*7c3d14c8STreehugger Robot buffer[count-1] = 0; // zap newline 804*7c3d14c8STreehugger Robot return true; 805*7c3d14c8STreehugger Robot} 806