]>
git.saurik.com Git - apple/objc4.git/blob - test/test.pl
10 chomp (my $DIR = `pwd`);
12 my $TESTLIBNAME = "libobjc.A.dylib";
13 my $TESTLIBPATH = "/usr/lib/$TESTLIBNAME";
15 my $BUILDDIR = "/tmp/test-$TESTLIBNAME-build";
18 my $red = "\e[41;37m";
19 my $yellow = "\e[43;37m";
23 if (scalar(@ARGV) == 1) {
25 if ($arg eq "clean") {
26 my $cmd = "rm -rf $BUILDDIR *~";
31 elsif ($arg eq "-h" || $arg eq "-H" || $arg eq "-help" || $arg eq "help") {
33 usage: $0 [options] [testname ...]
38 `testname
` runs a specific test. If no testnames are given, runs all tests.
43 ROOT=/path/to/project.roots/
48 STDLIB=libc++,libstdc++
57 test installed library, x86_64, no gc
60 test buildit-built root, i386 and x86_64, MRC and ARC and GC, clang compiler
61 $0 ARCH=i386,x86_64 ROOT=/tmp/libclosure.roots MEM=mrc,arc,gc CC=clang
63 test buildit-built root with iOS simulator
64 $0 ARCH=i386 ROOT=/tmp/libclosure.roots SDK=iphonesimulator
66 test buildit-built root on attached iOS device
67 $0 ARCH=armv7 ROOT=/tmp/libclosure.roots SDK=iphoneos
73 #########################################################################
78 #########################################################################
79 ## Variables for use in complex build and run rules
81 # variable # example value
83 # things you can multiplex on the command line
84 # ARCH=i386,x86_64,armv6,armv7
85 # SDK=system,macosx,iphoneos,iphonesimulator
86 # LANGUAGE=c,c++,objective-c,objective-c++
87 # CC=clang,gcc-4.2,llvm-gcc-4.2
89 # STDLIB=libc++,libstdc++
92 # things you can set once on the command line
93 # ROOT=/path/to/project.roots
104 my $crashcatch = <<'END';
105 // interpose-able code to catch crashes, print, and exit cleanly
110 // from dyld-interposing.h
111 #define DYLD_INTERPOSE(_replacement,_replacee) __attribute__((used)) static struct{ const void* replacement; const void* replacee; } _interpose_##_replacee __attribute__ ((section ("__DATA,__interpose"))) = { (const void*)(unsigned long)&_replacement, (const void*)(unsigned long)&_replacee };
113 static void catchcrash(int sig)
117 case SIGILL: msg = "CRASHED: SIGILL\\n"; break;
118 case SIGBUS: msg = "CRASHED: SIGBUS\\n"; break;
119 case SIGSYS: msg = "CRASHED: SIGSYS\\n"; break;
120 case SIGSEGV: msg = "CRASHED: SIGSEGV\\n"; break;
121 case SIGTRAP: msg = "CRASHED: SIGTRAP\\n"; break;
122 case SIGABRT: msg = "CRASHED: SIGABRT\\n"; break;
123 default: msg = "SIG\?\?\?\?\\n"; break;
125 write(STDERR_FILENO, msg, strlen(msg));
129 static void setupcrash(void) __attribute__((constructor));
130 static void setupcrash(void)
132 signal(SIGILL, &catchcrash);
133 signal(SIGBUS, &catchcrash);
134 signal(SIGSYS, &catchcrash);
135 signal(SIGSEGV, &catchcrash);
136 signal(SIGTRAP, &catchcrash);
137 signal(SIGABRT, &catchcrash);
141 static int hacked = 0;
142 ssize_t hacked_write(int fildes, const void *buf, size_t nbyte)
148 return write(fildes, buf, nbyte);
151 DYLD_INTERPOSE(hacked_write, write);
156 #########################################################################
160 # map language to buildable extensions for that language
161 my %extensions_for_language = (
163 "objective-c" => ["c", "m"],
164 "c++" => ["c", "cc", "cp", "cpp", "cxx", "c++"],
165 "objective-c++" => ["c", "m", "cc", "cp", "cpp", "cxx", "c++", "mm"],
167 "any" => ["c", "m", "cc", "cp", "cpp", "cxx", "c++", "mm"],
170 # map extension to languages
171 my %languages_for_extension = (
172 "c" => ["c", "objective-c", "c++", "objective-c++"],
173 "m" => ["objective-c", "objective-c++"],
174 "mm" => ["objective-c++"],
175 "cc" => ["c++", "objective-c++"],
176 "cp" => ["c++", "objective-c++"],
177 "cpp" => ["c++", "objective-c++"],
178 "cxx" => ["c++", "objective-c++"],
179 "c++" => ["c++", "objective-c++"],
182 # Run some newline-separated commands like `make` would, stopping if any fail
183 # run("cmd1 \n cmd2 \n cmd3")
186 my @cmds = split("\n", $_[0]);
187 die if scalar(@cmds) == 0;
189 foreach my $cmd (@cmds) {
191 next if $cmd =~ /^\s*$/;
193 print "$cmd\n" if $VERBOSE;
197 print "$output\n" if $VERBOSE;
204 print "cd $dir\n" if $VERBOSE;
208 # Return test names from the command line.
209 # Returns all tests if no tests were named.
213 foreach my $arg (@ARGV) {
214 push @tests, $arg if ($arg !~ /=/ && $arg !~ /^-/);
217 opendir(my $dir, $DIR) || die;
218 while (my $file = readdir($dir)) {
219 my ($name, $ext) = ($file =~ /^([^.]+)\.([^.]+)$/);
220 next if ! $languages_for_extension{$ext};
222 open(my $in, "< $file") || die "$file";
223 my $contents = join "", <$in>;
224 die if defined $ALL_TESTS{$name};
225 $ALL_TESTS{$name} = $ext if ($contents =~ m#^[/*\s]*TEST_#m);
230 if (scalar(@tests) == 0) {
231 @tests = keys %ALL_TESTS;
234 @tests = sort @tests;
240 # Turn a C compiler name into a C++ compiler name.
247 return $c . "++"; # e.g. clang => clang++
250 # Returns an array of all sdks from `xcodebuild
-showsdks
`
254 @sdks_memo = ("system", `xcodebuild
-showsdks
` =~ /-sdk (.+)$/mg);
259 # Returns whether the given sdk supports -lauto
260 sub supportslibauto {
262 return 1 if $sdk eq "system";
263 return 1 if $sdk =~ /^macosx/;
264 return 0 if $sdk =~ /^iphone/;
268 # print text with a colored prefix on each line
271 while (my @lines = split("\n", shift)) {
272 for my $line (@lines) {
274 print "$color $def$line\n";
283 # parse name=value,value pairs
285 my ($conditionstring) = @_;
288 my @conditions = ($conditionstring =~ /\w+=(?:[^\s,]+,?)+/g);
289 for my $condition (@conditions) {
290 my ($name, $values) = ($condition =~ /(\w+)=(.+)/);
291 $results{$name} = [split ',', $values];
297 # Get the name of the system SDK from sw_vers
299 my @lines = `/usr/bin
/sw_vers
`;
302 for my $line (@lines) {
303 ($name) = ($line =~ /^ProductName:\s+(.*)/) if !$name;
304 ($vers) = ($line =~ /^ProductVersion:\s+(.*)/) if !$vers;
310 if (-d "/usr/local/include/objc") {
311 if ($name eq "macosx") {
312 $internal = "internal";
314 $internal = ".internal";
317 return $name . $vers . $internal;
325 my %T = %{$C{"TEST_$name"}};
326 my @original_output = @output;
328 # Run result-checking passes, reducing @output each time
332 my $runerror = $T{TEST_RUN_OUTPUT};
333 filter_verbose(\@output);
334 $warn = filter_warn(\@output);
335 $bad |= filter_guardmalloc(\@output) if ($C{GUARDMALLOC});
336 $bad |= filter_valgrind(\@output) if ($C{VALGRIND});
337 $bad = filter_expected(\@output, \%C, $name) if ($bad eq "");
338 $bad = filter_bad(\@output) if ($bad eq "");
340 # OK line should be the only one left
341 $bad = "(output not 'OK: $name')" if ($bad eq "" && (scalar(@output) != 1 || $output[0] !~ /^OK: $name/));
344 my $red = "\e[41;37m";
346 print "${red}FAIL: /// test '$name' \\\\\\$def\n";
347 colorprint($red, @original_output);
348 print "${red}FAIL: \\\\\\ test '$name' ///$def\n";
349 print "${red}FAIL: $name: $bad$def\n";
352 elsif ($warn ne "") {
353 my $yellow = "\e[43;37m";
355 print "${yellow}PASS: /// test '$name' \\\\\\$def\n";
356 colorprint($yellow, @original_output);
357 print "${yellow}PASS: \\\\\\ test '$name' ///$def\n";
358 print "PASS: $name (with warnings)\n";
361 print "PASS: $name\n";
368 my $outputref = shift;
372 my %T = %{$C{"TEST_$name"}};
373 my $runerror = $T{TEST_RUN_OUTPUT} || return "";
377 my $output = join("\n", @$outputref) . "\n";
378 if ($output !~ /$runerror/) {
379 $bad = "(run output does not match TEST_RUN_OUTPUT)";
380 @$outputref = ("FAIL: $name");
382 @$outputref = ("OK: $name"); # pacify later filter
390 my $outputref = shift;
394 for my $line (@$outputref) {
395 if ($line =~ /^BAD: (.*)/) {
398 push @new_output, $line;
402 @$outputref = @new_output;
408 my $outputref = shift;
412 for my $line (@$outputref) {
413 if ($line !~ /^WARN: (.*)/) {
414 push @new_output, $line;
420 @$outputref = @new_output;
426 my $outputref = shift;
429 for my $line (@$outputref) {
430 if ($line !~ /^VERBOSE: (.*)/) {
431 push @new_output, $line;
435 @$outputref = @new_output;
440 my $outputref = shift;
445 for my $line (@$outputref) {
446 if ($line =~ /^Approx: do_origins_Dirty\([RW]\): missed \d bytes$/) {
447 # --track-origins warning (harmless)
450 if ($line =~ /^UNKNOWN __disable_threadsignal is unsupported. This warning will not be repeated.$/) {
451 # signals unsupported (harmless)
454 if ($line =~ /^UNKNOWN __pthread_sigmask is unsupported. This warning will not be repeated.$/) {
455 # signals unsupported (harmless)
458 if ($line !~ /^^\.*==\d+==/) {
459 # not valgrind output
460 push @new_output, $line;
464 my ($errcount) = ($line =~ /==\d+== ERROR SUMMARY: (\d+) errors/);
465 if (defined $errcount && $errcount > 0) {
469 (my $leakcount) = ($line =~ /==\d+==\s+(?:definitely|possibly) lost:\s+([0-9,]+)/);
470 if (defined $leakcount && $leakcount > 0) {
475 @$outputref = @new_output;
478 $bad .= "(valgrind errors)" if ($errors);
479 $bad .= "(valgrind leaks)" if ($leaks);
483 sub filter_guardmalloc
485 my $outputref = shift;
490 for my $line (@$outputref) {
491 if ($line !~ /^GuardMalloc\[[^\]]+\]: /) {
492 # not guardmalloc output
493 push @new_output, $line;
497 # Ignore 4 lines of guardmalloc prologue.
498 # Anything further is a guardmalloc error.
504 @$outputref = @new_output;
507 $bad .= "(guardmalloc errors)" if ($errors);
517 my $ext = $ALL_TESTS{$name};
518 my $file = "$name.$ext";
521 # search file for 'TEST_CONFIG' or '#include "test.h"'
522 # also collect other values:
523 # TEST_CONFIG test conditions
524 # TEST_ENV environment prefix
525 # TEST_CFLAGS compile flags
526 # TEST_BUILD build instructions
527 # TEST_BUILD_OUTPUT expected build stdout/stderr
528 # TEST_RUN_OUTPUT expected run stdout/stderr
529 open(my $in, "< $file") || die;
530 my $contents = join "", <$in>;
532 my $test_h = ($contents =~ /^\s*#\s*(include|import)\s*"test\.h"/m);
533 my $disabled = ($contents =~ /\bTEST_DISABLED\b/m);
534 my $crashes = ($contents =~ /\bTEST_CRASHES\b/m);
535 my ($conditionstring) = ($contents =~ /\bTEST_CONFIG\b(.*)$/m);
536 my ($envstring) = ($contents =~ /\bTEST_ENV\b(.*)$/m);
537 my ($cflags) = ($contents =~ /\bTEST_CFLAGS\b(.*)$/m);
538 my ($buildcmd) = ($contents =~ /TEST_BUILD\n(.*?\n)END[ *\/]*\n/s);
539 my ($builderror) = ($contents =~ /TEST_BUILD_OUTPUT\n(.*?\n)END[ *\/]*\n/s);
540 my ($runerror) = ($contents =~ /TEST_RUN_OUTPUT\n(.*?\n)END[ *\/]*\n/s);
542 return 0 if !$test_h && !$disabled && !$crashes && !defined($conditionstring) && !defined($envstring) && !defined($cflags) && !defined($buildcmd) && !defined($builderror) && !defined($runerror);
545 print "${yellow}SKIP: $name (disabled by TEST_DISABLED)$def\n";
549 # check test conditions
552 my %conditions = readconditions($conditionstring);
553 if (! $conditions{LANGUAGE}) {
554 # implicit language restriction from file extension
555 $conditions{LANGUAGE} = $languages_for_extension{$ext};
557 for my $condkey (keys %conditions) {
558 my @condvalues = @{$conditions{$condkey}};
560 # special case: RUN=0 does not affect build
561 if ($condkey eq "RUN" && @condvalues == 1 && $condvalues[0] == 0) {
566 my $testvalue = $C{$condkey};
567 next if !defined($testvalue);
568 # testvalue is the configuration being run now
569 # condvalues are the allowed values for this test
571 # special case: look up the name of SDK "system"
572 if ($condkey eq "SDK" && $testvalue eq "system") {
573 $testvalue = systemsdkname();
577 for my $condvalue (@condvalues) {
579 # special case: objc and objc++
580 if ($condkey eq "LANGUAGE") {
581 $condvalue = "objective-c" if $condvalue eq "objc";
582 $condvalue = "objective-c++" if $condvalue eq "objc++";
585 $ok = 1 if ($testvalue eq $condvalue);
587 # special case: SDK allows prefixes, and "system" is "macosx"
588 if ($condkey eq "SDK") {
589 $ok = 1 if ($testvalue =~ /^$condvalue/);
590 $ok = 1 if ($testvalue eq "system" && "macosx" =~ /^$condvalue/);
593 # special case: CC and CXX allow substring matches
594 if ($condkey eq "CC" || $condkey eq "CXX") {
595 $ok = 1 if ($testvalue =~ /$condvalue/);
602 my $plural = (@condvalues > 1) ? "one of: " : "";
603 print "SKIP: $name ($condkey=$testvalue, but test requires $plural", join(' ', @condvalues), ")\n";
608 # builderror is multiple REs separated by OR
609 if (defined $builderror) {
610 $builderror =~ s/\nOR\n/\n|/sg;
611 $builderror = "^(" . $builderror . ")\$";
613 # runerror is multiple REs separated by OR
614 if (defined $runerror) {
615 $runerror =~ s/\nOR\n/\n|/sg;
616 $runerror = "^(" . $runerror . ")\$";
619 # save some results for build and run phases
620 $$CREF{"TEST_$name"} = {
621 TEST_BUILD => $buildcmd,
622 TEST_BUILD_OUTPUT => $builderror,
623 TEST_CRASHES => $crashes,
624 TEST_RUN_OUTPUT => $runerror,
625 TEST_CFLAGS => $cflags,
626 TEST_ENV => $envstring,
633 # Builds a simple test
637 my %T = %{$C{"TEST_$name"}};
638 chdir_verbose "$C{DIR}/$name.build";
640 my $ext = $ALL_TESTS{$name};
641 my $file = "$DIR/$name.$ext";
643 if ($T{TEST_CRASHES}) {
644 `echo
'$crashcatch' > crashcatch
.c
`;
645 make("$C{COMPILE_C} -dynamiclib -o libcrashcatch.dylib -x c crashcatch.c");
649 my $cmd = $T{TEST_BUILD} ? eval "return \"$T{TEST_BUILD}\"" : "$C{COMPILE} $T{TEST_CFLAGS} $file -o $name.out";
651 my $output = make($cmd);
654 if (my $builderror = $T{TEST_BUILD_OUTPUT}) {
655 # check for expected output and ignore $?
656 if ($output =~ /$builderror/) {
659 print "${red}FAIL: /// test '$name' \\\\\\$def\n";
660 colorprint $red, $output;
661 print "${red}FAIL: \\\\\\ test '$name' ///$def\n";
662 print "${red}FAIL: $name (build output does not match TEST_BUILD_OUTPUT)$def\n";
666 print "${red}FAIL: /// test '$name' \\\\\\$def\n";
667 colorprint $red, $output;
668 print "${red}FAIL: \\\\\\ test '$name' ///$def\n";
669 print "${red}FAIL: $name (build failed)$def\n";
671 } elsif ($output ne "") {
672 print "${red}FAIL: /// test '$name' \\\\\\$def\n";
673 colorprint $red, $output;
674 print "${red}FAIL: \\\\\\ test '$name' ///$def\n";
675 print "${red}FAIL: $name (unexpected build output)$def\n";
683 foreach my $file (glob("*.out *.dylib *.bundle")) {
684 make("dsymutil $file");
691 # Run a simple test (testname.out, with error checking of stdout and stderr)
695 my %T = %{$C{"TEST_$name"}};
697 if (! $T{TEST_RUN}) {
698 print "PASS: $name (build only)\n";
702 chdir_verbose "$C{DIR}/$name.build";
705 my $env = "$C{ENV} $T{TEST_ENV}";
706 if ($T{TEST_CRASHES}) {
707 $env .= " DYLD_INSERT_LIBRARIES=libcrashcatch.dylib";
712 if ($C{ARCH} =~ /^arm/ && `unamep
-p
` !~ /^arm/) {
715 my $remotedir = "/var/root/test/" . basename($C{DIR}) . "/$name.build";
716 my $remotedyld = " DYLD_LIBRARY_PATH=$remotedir";
717 $remotedyld .= ":/var/root/test/" if ($C{TESTLIB} ne $TESTLIBPATH);
719 # elide host-specific paths
720 $env =~ s/DYLD_LIBRARY_PATH=\S+//;
721 $env =~ s/DYLD_ROOT_PATH=\S+//;
723 my $cmd = "ssh iphone 'cd $remotedir && env $env $remotedyld ./$name.out'";
724 $output = make("$cmd");
729 my $cmd = "env $env ./$name.out";
730 $output = make("sh -c '$cmd 2>&1' 2>&1");
731 # need extra sh level to capture "sh: Illegal instruction" after crash
732 # fixme fail if $? except tests that expect to crash
735 return check_output(\%C, $name, split("\n", $output));
741 my ($cc, $sdk, $sdk_path) = @_;
744 my $key = $cc . ':' . $sdk;
745 my $result = $compiler_memo{$key};
746 return $result if defined $result;
750 } elsif (-e "$sdk_path/$cc") {
751 $result = "$sdk_path/$cc";
752 } elsif ($sdk eq "system" && -e "/usr/bin/$cc") {
753 $result = "/usr/bin/$cc";
754 } elsif ($sdk eq "system") {
755 $result = `xcrun
-find
$cc 2>/dev/null
`;
757 $result = `xcrun
-sdk
$sdk -find
$cc 2>/dev/null
`;
761 $compiler_memo{$key} = $result;
765 sub make_one_config {
766 my $configref = shift;
768 my %C = %{$configref};
771 $C{LANGUAGE} = "objective-c" if $C{LANGUAGE} eq "objc";
772 $C{LANGUAGE} = "objective-c++" if $C{LANGUAGE} eq "objc++";
775 # Try exact match first.
776 # Then try lexically-last prefix match (so "macosx" => "macosx10.7internal").
777 my @sdks = getsdks();
779 print "Installed SDKs: @sdks\n";
781 my $exactsdk = undef;
782 my $prefixsdk = undef;
783 foreach my $sdk (@sdks) {
785 $exactsdk = $sdk if ($sdk eq $SDK);
786 # check for digits to prevent e.g. "iphone" => "iphonesimulator4.2"
787 $prefixsdk = $sdk if ($sdk =~ /^$SDK[0-9]/ && $sdk gt $prefixsdk);
791 } elsif ($prefixsdk) {
792 $C{SDK} = $prefixsdk;
794 die "unknown SDK '$C{SDK}'\nInstalled SDKs: @sdks\n";
797 # set the config name now, after massaging the language and sdk,
798 # but before adding other settings
799 my $configname = config_name(%C);
800 die if ($configname =~ /'/);
801 die if ($configname =~ / /);
802 ($C{NAME} = $configname) =~ s/~/ /g;
803 (my $configdir = $configname) =~ s#/##g;
804 $C{DIR} = "$BUILDDIR/$configdir";
807 if ($C{SDK} ne "system") {
808 ($C{SDK_PATH}) = (`xcodebuild
-version
-sdk
$C{SDK
} Path
` =~ /^\s*(.+?)\s*$/);
811 # Look up test library (possible in root or SDK_PATH)
813 if (-e (glob "$root/*~dst")[0]) {
814 $root = (glob "$root/*~dst")[0];
817 if ($root ne "" && -e "$root$C{SDK_PATH}$TESTLIBPATH") {
818 $C{TESTLIB} = "$root$C{SDK_PATH}$TESTLIBPATH";
819 } elsif (-e "$root$TESTLIBPATH") {
820 $C{TESTLIB} = "$root$TESTLIBPATH";
821 } elsif (-e "$root/$TESTLIBNAME") {
822 $C{TESTLIB} = "$root/$TESTLIBNAME";
824 die "No $TESTLIBNAME in root '$root' for sdk '$C{SDK_PATH}'\n";
828 my @uuids = `/usr/bin
/dwarfdump
-u
'$C{TESTLIB}'`;
829 while (my $uuid = shift @uuids) {
836 my $cxx = cplusplus($C{CC});
841 $C{CC} = find_compiler($cc, $C{SDK}, $C{SDK_PATH});
842 $C{CXX} = find_compiler($cxx, $C{SDK}, $C{SDK_PATH});
844 die "No compiler '$cc' ('$C{CC}') in SDK '$C{SDK}'\n" if !-e $C{CC};
845 die "No compiler '$cxx' ('$C{CXX}') in SDK '$C{SDK}'\n" if !-e $C{CXX};
850 # save-temps so dsymutil works so debug info works
851 my $cflags = "-I$DIR -W -Wall -Wno-deprecated-declarations -Wshorten-64-to-32 -g -save-temps -Os -arch $C{ARCH} ";
854 if ($C{SDK} ne "system") {
855 $cflags .= " -isysroot '$C{SDK_PATH}'";
856 $cflags .= " '-Wl,-syslibroot,$C{SDK_PATH}'";
859 if ($C{SDK} =~ /^iphoneos[0-9]/ && $cflags !~ /-miphoneos-version-min/) {
860 my ($vers) = ($C{SDK} =~ /^iphoneos([0-9]+\.[0-9+])/);
861 $cflags .= " -miphoneos-version-min=$vers";
863 if ($C{SDK} =~ /^iphonesimulator[0-9]/ && $cflags !~ /-D__IPHONE_OS_VERSION_MIN_REQUIRED/) {
864 my ($vers) = ($C{SDK} =~ /^iphonesimulator([0-9]+\.[0-9+])/);
865 $vers = int($vers * 10000); # 4.2 => 42000
866 $cflags .= " -D__IPHONE_OS_VERSION_MIN_REQUIRED=$vers";
868 if ($C{SDK} =~ /^iphonesimulator/) {
869 $objcflags .= " -fobjc-abi-version=2 -fobjc-legacy-dispatch";
873 my $library_path = dirname($C{TESTLIB});
874 $cflags .= " -L$library_path";
875 $cflags .= " -isystem '$root/usr/include'";
876 $cflags .= " -isystem '$root/usr/local/include'";
878 if ($C{SDK_PATH} ne "/") {
879 $cflags .= " -isystem '$root$C{SDK_PATH}/usr/include'";
880 $cflags .= " -isystem '$root$C{SDK_PATH}/usr/local/include'";
884 if ($C{CC} =~ /clang/) {
885 $cflags .= " -Qunused-arguments -fno-caret-diagnostics";
886 $cflags .= " -stdlib=$C{STDLIB} -fno-objc-link-runtime";
892 $objcflags .= " -lobjc";
893 if ($C{MEM} eq "gc") {
894 $objcflags .= " -fobjc-gc";
896 elsif ($C{MEM} eq "arc") {
897 $objcflags .= " -fobjc-arc";
899 elsif ($C{MEM} eq "mrc") {
903 die "unrecognized MEM '$C{MEM}'\n";
906 if (supportslibauto($C{SDK})) {
907 # do this even for non-GC tests
908 $objcflags .= " -lauto";
911 # Populate ENV_PREFIX
913 $C{ENV} .= " VERBOSE=1" if $VERBOSE;
915 my $library_path = dirname($C{TESTLIB});
916 die "no spaces allowed in root" if $library_path =~ /\s+/;
917 $C{ENV} .= " DYLD_LIBRARY_PATH=$library_path" if ($library_path ne "/usr/lib");
919 if ($C{SDK_PATH} ne "/") {
920 die "no spaces allowed in sdk" if $C{SDK_PATH} =~ /\s+/;
921 $C{ENV} .= " DYLD_ROOT_PATH=$C{SDK_PATH}";
923 if ($C{GUARDMALLOC}) {
924 $ENV{GUARDMALLOC} = "1"; # checked by tests and errcheck.pl
925 $C{ENV} .= " DYLD_INSERT_LIBRARIES=/usr/lib/libgmalloc.dylib";
927 if ($C{SDK} =~ /^iphonesimulator[0-9]/) {
928 my ($vers) = ($C{SDK} =~ /^iphonesimulator([0-9]+\.[0-9+])/);
930 " CFFIXED_USER_HOME=$ENV{HOME}/Library/Application\\ Support/iPhone\\ Simulator/$vers" .
931 " IPHONE_SIMULATOR_ROOT=$C{SDK_PATH}" .
932 " IPHONE_SHARED_RESOURCES_DIRECTORY=$ENV{HOME}/Library/Application\\ Support/iPhone\\ Simulator/$vers";
935 # Populate compiler commands
936 $C{COMPILE_C} = "env LANG=C '$C{CC}' $cflags -x c -std=gnu99";
937 $C{COMPILE_CXX} = "env LANG=C '$C{CXX}' $cflags -x c++";
938 $C{COMPILE_M} = "env LANG=C '$C{CC}' $cflags $objcflags -x objective-c -std=gnu99";
939 $C{COMPILE_MM} = "env LANG=C '$C{CXX}' $cflags $objcflags -x objective-c++";
941 $C{COMPILE} = $C{COMPILE_C} if $C{LANGUAGE} eq "c";
942 $C{COMPILE} = $C{COMPILE_CXX} if $C{LANGUAGE} eq "c++";
943 $C{COMPILE} = $C{COMPILE_M} if $C{LANGUAGE} eq "objective-c";
944 $C{COMPILE} = $C{COMPILE_MM} if $C{LANGUAGE} eq "objective-c++";
945 die "unknown language '$C{LANGUAGE}'\n" if !defined $C{COMPILE};
947 ($C{COMPILE_NOMEM} = $C{COMPILE}) =~ s/ -fobjc-(?:gc|arc)\S*//g;
948 ($C{COMPILE_NOLINK} = $C{COMPILE}) =~ s/ '?-(?:Wl,|l)\S*//g;
949 ($C{COMPILE_NOLINK_NOMEM} = $C{COMPILE_NOMEM}) =~ s/ '?-(?:Wl,|l)\S*//g;
952 # Reject some self-inconsistent configurations
953 if ($C{MEM} !~ /^(mrc|arc|gc)$/) {
954 die "unknown MEM=$C{MEM} (expected one of mrc arc gc)\n";
957 if ($C{MEM} eq "gc" && $C{SDK} =~ /^iphone/) {
958 print "note: skipping configuration $C{NAME}\n";
959 print "note: because SDK=$C{SDK} does not support MEM=$C{MEM}\n";
962 if ($C{MEM} eq "arc" && $C{SDK} !~ /^iphone/ && $C{ARCH} eq "i386") {
963 print "note: skipping configuration $C{NAME}\n";
964 print "note: because 32-bit Mac does not support MEM=$C{MEM}\n";
967 if ($C{MEM} eq "arc" && $C{CC} !~ /clang/) {
968 print "note: skipping configuration $C{NAME}\n";
969 print "note: because CC=$C{CC} does not support MEM=$C{MEM}\n";
973 if ($C{STDLIB} ne "libstdc++" && $C{CC} !~ /clang/) {
974 print "note: skipping configuration $C{NAME}\n";
975 print "note: because CC=$C{CC} does not support STDLIB=$C{STDLIB}\n";
983 my ($root, %args) = @_;
985 my @results = ({}); # start with one empty config
987 for my $key (keys %args) {
989 my @values = @{$args{$key}};
990 for my $configref (@results) {
991 my %config = %{$configref};
992 for my $value (@values) {
993 my %newconfig = %config;
994 $newconfig{$key} = $value;
995 push @newresults, \%newconfig;
998 @results = @newresults;
1002 for my $configref(@results) {
1003 if (make_one_config($configref, $root)) {
1004 push @newresults, $configref;
1014 for my $key (sort keys %config) {
1015 $name .= '~' if $name ne "";
1016 $name .= "$key=$config{$key}";
1021 sub run_one_config {
1030 foreach my $test (@tests) {
1032 print "\nGATHER $test\n";
1035 if ($ALL_TESTS{$test}) {
1036 gather_simple(\%C, $test) || next; # not pass, not fail
1037 push @gathertests, $test;
1039 die "No test named '$test'\n";
1045 @builttests = @gathertests;
1046 $testcount = scalar(@gathertests);
1048 my $configdir = $C{DIR};
1049 print $configdir, "\n" if $VERBOSE;
1050 mkdir $configdir || die;
1052 foreach my $test (@gathertests) {
1054 print "\nBUILD $test\n";
1056 mkdir "$configdir/$test.build" || die;
1058 if ($ALL_TESTS{$test}) {
1060 if (!build_simple(\%C, $test)) {
1063 push @builttests, $test;
1066 die "No test named '$test'\n";
1071 if (!$RUN || !scalar(@builttests)) {
1075 if ($C{ARCH} =~ /^arm/ && `unamep
-p
` !~ /^arm/) {
1076 # upload all tests to iOS device
1077 make("RSYNC_PASSWORD=alpine rsync -av $C{DIR} rsync://root\@localhost:10873/root/var/root/test/");
1078 die "Couldn't rsync tests to device\n" if ($?);
1080 # upload library to iOS device
1081 if ($C{TESTLIB} ne $TESTLIBPATH) {
1082 # hack - send thin library because device may use lib=armv7
1083 # even though app=armv6, and we want to set the lib's arch
1084 make("lipo -output /tmp/$TESTLIBNAME -thin $C{ARCH} $C{TESTLIB} || cp $C{TESTLIB} /tmp/$TESTLIBNAME");
1085 die "Couldn't thin $C{TESTLIB} to $C{ARCH}\n" if ($?);
1086 make("RSYNC_PASSWORD=alpine rsync -av /tmp/$TESTLIBNAME rsync://root\@localhost:10873/root/var/root/test/");
1087 die "Couldn't rsync $C{TESTLIB} to device\n" if ($?);
1091 foreach my $test (@builttests) {
1092 print "\nRUN $test\n" if ($VERBOSE);
1094 if ($ALL_TESTS{$test})
1096 if (!run_simple(\%C, $test)) {
1100 die "No test named '$test'\n";
1105 return ($testcount, $failcount);
1110 # Return value if set by "$argname=value" on the command line
1111 # Return $default if not set.
1113 my ($argname, $default) = @_;
1115 foreach my $arg (@ARGV) {
1116 my ($value) = ($arg =~ /^$argname=(.+)$/);
1117 return [split ',', $value] if defined $value;
1123 # Return 1 or 0 if set by "$argname=1" or "$argname=0" on the
1124 # command line. Return $default if not set.
1126 my ($argname, $default) = @_;
1128 my @values = @{getargs($argname, $default)};
1129 return [( map { ($_ eq "0") ? 0 : 1 } @values )];
1133 my ($argname, $default) = @_;
1134 my @values = @{getargs($argname, $default)};
1135 die "Only one value allowed for $argname\n" if @values > 1;
1140 my ($argname, $default) = @_;
1141 my @values = @{getbools($argname, $default)};
1142 die "Only one value allowed for $argname\n" if @values > 1;
1151 my $default_arch = (`/usr/sbin
/sysctl hw
.optional
.x86_64
` eq "hw.optional.x86_64: 1\n") ? "x86_64" : "i386";
1152 $args{ARCH} = getargs("ARCH", 0);
1153 $args{ARCH} = getargs("ARCHS", $default_arch) if !@{$args{ARCH}}[0];
1155 $args{SDK} = getargs("SDK", "system");
1157 $args{MEM} = getargs("MEM", "mrc");
1158 $args{LANGUAGE} = [ map { lc($_) } @{getargs("LANGUAGE", "objective-c")} ];
1159 $args{STDLIB} = getargs("STDLIB", "libstdc++");
1161 $args{CC} = getargs("CC", "clang");
1163 $args{GUARDMALLOC} = getbools("GUARDMALLOC", 0);
1165 $BUILD = getbool("BUILD", 1);
1166 $RUN = getbool("RUN", 1);
1167 $VERBOSE = getbool("VERBOSE", 0);
1169 my $root = getarg("ROOT", "");
1172 my @tests = gettests();
1174 print "note: -----\n";
1175 print "note: testing root '$root'\n";
1177 my @configs = make_configs($root, %args);
1179 print "note: -----\n";
1180 print "note: testing ", scalar(@configs), " configurations:\n";
1181 for my $configref (@configs) {
1182 my $configname = $$configref{NAME};
1183 print "note: configuration $configname\n";
1187 `rm
-rf
'$BUILDDIR'`;
1188 mkdir "$BUILDDIR" || die;
1193 my $testconfigs = @configs;
1194 my $failconfigs = 0;
1197 for my $configref (@configs) {
1198 my $configname = $$configref{NAME};
1199 print "note: -----\n";
1200 print "note: \nnote: $configname\nnote: \n";
1202 (my $t, my $f) = eval { run_one_config($configref, @tests); };
1205 print "${red}FAIL: $configname${def}\n";
1206 print "${red}FAIL: $@${def}\n";
1209 my $color = ($f ? $red : "");
1211 print "${color}note: $configname$def\n";
1212 print "${color}note: $t tests, $f failures$def\n";
1215 $failconfigs++ if ($f);
1219 print "note: -----\n";
1220 my $color = ($failconfigs ? $red : "");
1221 print "${color}note: $testconfigs configurations, $failconfigs with failures$def\n";
1222 print "${color}note: $testcount tests, $failcount failures$def\n";
1224 $failed = ($failconfigs ? 1 : 0);
1226 exit ($failed ? 1 : 0);