Remove the --64-bit argument from scripts in favor of them detecting when 64-bit...
[WebKit-https.git] / WebKitTools / Scripts / webkitdirs.pm
1 # Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.
2 #
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions
5 # are met:
6 #
7 # 1.  Redistributions of source code must retain the above copyright
8 #     notice, this list of conditions and the following disclaimer. 
9 # 2.  Redistributions in binary form must reproduce the above copyright
10 #     notice, this list of conditions and the following disclaimer in the
11 #     documentation and/or other materials provided with the distribution. 
12 # 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
13 #     its contributors may be used to endorse or promote products derived
14 #     from this software without specific prior written permission. 
15 #
16 # THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
17 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 # DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
20 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26
27 # Module to share code to get to WebKit directories.
28
29 use strict;
30 use warnings;
31 use FindBin;
32 use File::Basename;
33 use POSIX;
34 use VCSUtils;
35
36 BEGIN {
37    use Exporter   ();
38    our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
39    $VERSION     = 1.00;
40    @ISA         = qw(Exporter);
41    @EXPORT      = qw(&chdirWebKit &baseProductDir &productDir &XcodeOptions &XcodeOptionString &XcodeOptionStringNoConfig &passedConfiguration &setConfiguration &safariPath &checkFrameworks &currentSVNRevision);
42    %EXPORT_TAGS = ( );
43    @EXPORT_OK   = ();
44 }
45
46 our @EXPORT_OK;
47
48 my $architecture;
49 my $baseProductDir;
50 my @baseProductDirOption;
51 my $configuration;
52 my $configurationForVisualStudio;
53 my $configurationProductDir;
54 my $sourceDir;
55 my $currentSVNRevision;
56 my $osXVersion;
57 my $isQt;
58 my $isGtk;
59 my $isWx;
60 my @wxArgs;
61 my $isChromium;
62
63 # Variables for Win32 support
64 my $vcBuildPath;
65 my $windowsTmpPath;
66
67 sub determineSourceDir
68 {
69     return if $sourceDir;
70     $sourceDir = $FindBin::Bin;
71     $sourceDir =~ s|/+$||; # Remove trailing '/' as we would die later
72
73     # walks up path checking each directory to see if it is the main WebKit project dir, 
74     # defined by containing JavaScriptCore, WebCore, and WebKit
75     until ((-d "$sourceDir/JavaScriptCore" && -d "$sourceDir/WebCore" && -d "$sourceDir/WebKit") || (-d "$sourceDir/Internal" && -d "$sourceDir/OpenSource"))
76     {
77         if ($sourceDir !~ s|/[^/]+$||) {
78             die "Could not find top level webkit directory above source directory using FindBin.\n";
79         }
80     }
81
82     $sourceDir = "$sourceDir/OpenSource" if -d "$sourceDir/OpenSource";
83 }
84
85 # used for scripts which are stored in a non-standard location
86 sub setSourceDir($)
87 {
88     ($sourceDir) = @_;
89 }
90
91 sub determineBaseProductDir
92 {
93     return if defined $baseProductDir;
94     determineSourceDir();
95     if (isAppleMacWebKit()) {
96         open PRODUCT, "defaults read com.apple.Xcode PBXApplicationwideBuildSettings 2> /dev/null |" or die;
97         $baseProductDir = join '', <PRODUCT>;
98         close PRODUCT;
99
100         $baseProductDir = $1 if $baseProductDir =~ /SYMROOT\s*=\s*\"(.*?)\";/s;
101         undef $baseProductDir unless $baseProductDir =~ /^\//;
102
103         if (!defined($baseProductDir)) {
104             open PRODUCT, "defaults read com.apple.Xcode PBXProductDirectory 2> /dev/null |" or die;
105             $baseProductDir = <PRODUCT>;
106             close PRODUCT;
107             if ($baseProductDir) {
108                 chomp $baseProductDir;
109                 undef $baseProductDir unless $baseProductDir =~ /^\//;
110             }
111         }
112     } else {
113         $baseProductDir = $ENV{"WEBKITOUTPUTDIR"};
114         if (isAppleWinWebKit() && $baseProductDir) {
115             my $unixBuildPath = `cygpath --unix \"$baseProductDir\"`;
116             chomp $unixBuildPath;
117             $baseProductDir = $unixBuildPath;
118         }
119     }
120
121     if ($baseProductDir && isAppleMacWebKit()) {
122         $baseProductDir =~ s|^\Q$(SRCROOT)/..\E$|$sourceDir|;
123         $baseProductDir =~ s|^\Q$(SRCROOT)/../|$sourceDir/|;
124         $baseProductDir =~ s|^~/|$ENV{HOME}/|;
125         die "Can't handle Xcode product directory with a ~ in it.\n" if $baseProductDir =~ /~/;
126         die "Can't handle Xcode product directory with a variable in it.\n" if $baseProductDir =~ /\$/;
127         @baseProductDirOption = ();
128     }
129
130     if (!defined($baseProductDir)) {
131         $baseProductDir = "$sourceDir/WebKitBuild";
132
133         if (isGit() && isGitBranchBuild()) {
134             my $branch = gitBranch();
135             $baseProductDir = "$baseProductDir/$branch";
136         }
137
138         @baseProductDirOption = ("SYMROOT=$baseProductDir", "OBJROOT=$baseProductDir") if (isAppleMacWebKit());
139         if (isCygwin()) {
140             my $dosBuildPath = `cygpath --windows \"$baseProductDir\"`;
141             chomp $dosBuildPath;
142             $ENV{"WEBKITOUTPUTDIR"} = $dosBuildPath;
143         }
144     }
145 }
146
147 sub setBaseProductDir($)
148 {
149     ($baseProductDir) = @_;
150 }
151
152 sub determineConfiguration
153 {
154     return if defined $configuration;
155     determineBaseProductDir();
156     if (open CONFIGURATION, "$baseProductDir/Configuration") {
157         $configuration = <CONFIGURATION>;
158         close CONFIGURATION;
159     }
160     if ($configuration) {
161         chomp $configuration;
162         # compatibility for people who have old Configuration files
163         $configuration = "Release" if $configuration eq "Deployment";
164         $configuration = "Debug" if $configuration eq "Development";
165     } else {
166         $configuration = "Release";
167     }
168 }
169
170 sub determineArchitecture
171 {
172     return if defined $architecture;
173     return unless isAppleMacWebKit();
174
175     determineBaseProductDir();
176     if (open ARCHITECTURE, "$baseProductDir/Architecture") {
177         $architecture = <ARCHITECTURE>;
178         close ARCHITECTURE;
179     }
180     if ($architecture) {
181         chomp $architecture;
182     } else {
183         if (isTiger() or isLeopard()) {
184             $architecture = `arch`;
185         } else {
186             my $supports64Bit = `sysctl -n hw.optional.x86_64`;
187             chomp $supports64Bit;
188             $architecture = $supports64Bit ? 'x86_64' : `arch`;
189         }
190         chomp $architecture;
191     }
192 }
193
194 sub argumentsForConfiguration()
195 {
196     determineConfiguration();
197     determineArchitecture();
198
199     my @args = ();
200     push(@args, '--debug') if $configuration eq "Debug";
201     push(@args, '--release') if $configuration eq "Release";
202     push(@args, '--32-bit') if $architecture ne "x86_64";
203     push(@args, '--qt') if isQt();
204     push(@args, '--gtk') if isGtk();
205     push(@args, '--wx') if isWx();
206     push(@args, '--chromium') if isChromium();
207     return @args;
208 }
209
210 sub determineConfigurationForVisualStudio
211 {
212     return if defined $configurationForVisualStudio;
213     determineConfiguration();
214     $configurationForVisualStudio = $configuration;
215     return unless $configuration eq "Debug";
216     setupCygwinEnv();
217     chomp(my $dir = `cygpath -ua '$ENV{WEBKITLIBRARIESDIR}'`);
218     $configurationForVisualStudio = "Debug_Internal" if -f "$dir/bin/CoreFoundation_debug.dll";
219 }
220
221 sub determineConfigurationProductDir
222 {
223     return if defined $configurationProductDir;
224     determineBaseProductDir();
225     determineConfiguration();
226     if (isAppleWinWebKit() && !isWx()) {
227         $configurationProductDir = "$baseProductDir/bin";
228     } else {
229         $configurationProductDir = "$baseProductDir/$configuration";
230     }
231 }
232
233 sub setConfigurationProductDir($)
234 {
235     ($configurationProductDir) = @_;
236 }
237
238 sub determineCurrentSVNRevision
239 {
240     return if defined $currentSVNRevision;
241     determineSourceDir();
242     $currentSVNRevision = svnRevisionForDirectory($sourceDir);
243     return $currentSVNRevision;
244 }
245
246
247 sub chdirWebKit
248 {
249     determineSourceDir();
250     chdir $sourceDir or die;
251 }
252
253 sub baseProductDir
254 {
255     determineBaseProductDir();
256     return $baseProductDir;
257 }
258
259 sub sourceDir
260 {
261     determineSourceDir();
262     return $sourceDir;
263 }
264
265 sub productDir
266 {
267     determineConfigurationProductDir();
268     return $configurationProductDir;
269 }
270
271 sub configuration()
272 {
273     determineConfiguration();
274     return $configuration;
275 }
276
277 sub configurationForVisualStudio()
278 {
279     determineConfigurationForVisualStudio();
280     return $configurationForVisualStudio;
281 }
282
283 sub currentSVNRevision
284 {
285     determineCurrentSVNRevision();
286     return $currentSVNRevision;
287 }
288
289 sub XcodeOptions
290 {
291     determineBaseProductDir();
292     determineConfiguration();
293     determineArchitecture();
294     return (@baseProductDirOption, "-configuration", $configuration, "ARCHS=$architecture");
295 }
296
297 sub XcodeOptionString
298 {
299     return join " ", XcodeOptions();
300 }
301
302 sub XcodeOptionStringNoConfig
303 {
304     return join " ", @baseProductDirOption;
305 }
306
307 sub XcodeCoverageSupportOptions()
308 {
309     my @coverageSupportOptions = ();
310     push @coverageSupportOptions, "GCC_GENERATE_TEST_COVERAGE_FILES=YES";
311     push @coverageSupportOptions, "GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES";
312     push @coverageSupportOptions, "EXTRA_LINK= -ftest-coverage -fprofile-arcs";
313     push @coverageSupportOptions, "OTHER_CFLAGS= -MD";
314     push @coverageSupportOptions, "OTHER_LDFLAGS=\$(OTHER_LDFLAGS) -ftest-coverage -fprofile-arcs -framework AppKit";
315     return @coverageSupportOptions;
316 }
317
318 my $passedConfiguration;
319 my $searchedForPassedConfiguration;
320 sub determinePassedConfiguration
321 {
322     return if $searchedForPassedConfiguration;
323     $searchedForPassedConfiguration = 1;
324
325     my $isWinCairo = checkForArgumentAndRemoveFromARGV("--cairo-win32");
326
327     for my $i (0 .. $#ARGV) {
328         my $opt = $ARGV[$i];
329         if ($opt =~ /^--debug$/i || $opt =~ /^--devel/i) {
330             splice(@ARGV, $i, 1);
331             $passedConfiguration = "Debug";
332             $passedConfiguration .= "_Cairo" if ($isWinCairo && isCygwin());
333             return;
334         }
335         if ($opt =~ /^--release$/i || $opt =~ /^--deploy/i) {
336             splice(@ARGV, $i, 1);
337             $passedConfiguration = "Release";
338             $passedConfiguration .= "_Cairo" if ($isWinCairo && isCygwin());
339             return;
340         }
341         if ($opt =~ /^--profil(e|ing)$/i) {
342             splice(@ARGV, $i, 1);
343             $passedConfiguration = "Profiling";
344             $passedConfiguration .= "_Cairo" if ($isWinCairo && isCygwin());
345             return;
346         }
347     }
348     $passedConfiguration = undef;
349 }
350
351 sub passedConfiguration
352 {
353     determinePassedConfiguration();
354     return $passedConfiguration;
355 }
356
357 sub setConfiguration
358 {
359     setArchitecture();
360
361     if (my $config = shift @_) {
362         $configuration = $config;
363         return;
364     }
365
366     determinePassedConfiguration();
367     $configuration = $passedConfiguration if $passedConfiguration;
368 }
369
370
371 my $passedArchitecture;
372 my $searchedForPassedArchitecture;
373 sub determinePassedArchitecture
374 {
375     return if $searchedForPassedArchitecture;
376     $searchedForPassedArchitecture = 1;
377
378     return unless isAppleMacWebKit();
379
380     for my $i (0 .. $#ARGV) {
381         my $opt = $ARGV[$i];
382         if ($opt =~ /^--32-bit$/i) {
383             splice(@ARGV, $i, 1);
384             $passedArchitecture = `arch`;
385             chomp $passedArchitecture;
386             return;
387         }
388     }
389     $passedArchitecture = undef;
390 }
391
392 sub passedArchitecture
393 {
394     determinePassedArchitecture();
395     return $passedArchitecture;
396 }
397
398 sub architecture()
399 {
400     determineArchitecture();
401     return $architecture;
402 }
403
404 sub setArchitecture
405 {
406     if (my $arch = shift @_) {
407         $architecture = $arch;
408         return;
409     }
410
411     determinePassedArchitecture();
412     $architecture = $passedArchitecture if $passedArchitecture;
413 }
414
415
416 sub safariPathFromSafariBundle
417 {
418     my ($safariBundle) = @_;
419
420     return "$safariBundle/Contents/MacOS/Safari" if isAppleMacWebKit();
421     return $safariBundle if isAppleWinWebKit();
422 }
423
424 sub installedSafariPath
425 {
426     my $safariBundle;
427
428     if (isAppleMacWebKit()) {
429         $safariBundle = "/Applications/Safari.app";
430     } elsif (isAppleWinWebKit()) {
431         $safariBundle = `"$configurationProductDir/FindSafari.exe"`;
432         $safariBundle =~ s/[\r\n]+$//;
433         $safariBundle = `cygpath -u '$safariBundle'`;
434         $safariBundle =~ s/[\r\n]+$//;
435         $safariBundle .= "Safari.exe";
436     }
437
438     return safariPathFromSafariBundle($safariBundle);
439 }
440
441 # Locate Safari.
442 sub safariPath
443 {
444     # Use WEBKIT_SAFARI environment variable if present.
445     my $safariBundle = $ENV{WEBKIT_SAFARI};
446     if (!$safariBundle) {
447         determineConfigurationProductDir();
448         # Use Safari.app in product directory if present (good for Safari development team).
449         if (isAppleMacWebKit() && -d "$configurationProductDir/Safari.app") {
450             $safariBundle = "$configurationProductDir/Safari.app";
451         } elsif (isAppleWinWebKit() && -x "$configurationProductDir/bin/Safari.exe") {
452             $safariBundle = "$configurationProductDir/bin/Safari.exe";
453         } else {
454             return installedSafariPath();
455         }
456     }
457     my $safariPath = safariPathFromSafariBundle($safariBundle);
458     die "Can't find executable at $safariPath.\n" if isAppleMacWebKit() && !-x $safariPath;
459     return $safariPath;
460 }
461
462 sub builtDylibPathForName
463 {
464     my $libraryName = shift;
465     determineConfigurationProductDir();
466     if (isQt() or isChromium()) {
467         return "$configurationProductDir/$libraryName";
468     }
469     if (isGtk()) {
470         return "$configurationProductDir/$libraryName/../.libs/libwebkit-1.0.so";
471     }
472     if (isAppleMacWebKit()) {
473         return "$configurationProductDir/$libraryName.framework/Versions/A/$libraryName";
474     }
475     if (isAppleWinWebKit()) {
476         if ($libraryName eq "JavaScriptCore") {
477             return "$baseProductDir/lib/$libraryName.lib";
478         } else {
479             return "$baseProductDir/$libraryName.intermediate/$configuration/$libraryName.intermediate/$libraryName.lib";
480         }
481     }
482
483     die "Unsupported platform, can't determine built library locations.";
484 }
485
486 # Check to see that all the frameworks are built.
487 sub checkFrameworks
488 {
489     return if isCygwin();
490     my @frameworks = ("JavaScriptCore", "WebCore");
491     push(@frameworks, "WebKit") if isAppleMacWebKit();
492     for my $framework (@frameworks) {
493         my $path = builtDylibPathForName($framework);
494         die "Can't find built framework at \"$path\".\n" unless -x $path;
495     }
496 }
497
498 sub hasSVGSupport
499 {
500     return 0 if isCygwin();
501
502     my $path = shift;
503
504     if (isQt()) {
505         return 1;
506     }
507
508     my $hasSVGSupport = 0;
509     if (-e $path) {
510         open NM, "-|", "nm", $path or die;
511         while (<NM>) {
512             $hasSVGSupport = 1 if /SVGElement/;
513         }
514         close NM;
515     }
516     return $hasSVGSupport;
517 }
518
519 sub removeLibraryDependingOnSVG
520 {
521     my $frameworkName = shift;
522     my $shouldHaveSVG = shift;
523
524     my $path = builtDylibPathForName($frameworkName);
525     return unless -x $path;
526
527     my $hasSVG = hasSVGSupport($path);
528     system "rm -f $path" if ($shouldHaveSVG xor $hasSVG);
529 }
530
531 sub checkWebCoreSVGSupport
532 {
533     my $required = shift;
534     my $framework = "WebCore";
535     my $path = builtDylibPathForName($framework);
536     my $hasSVG = hasSVGSupport($path);
537     if ($required && !$hasSVG) {
538         die "$framework at \"$path\" does not include SVG Support, please run build-webkit --svg\n";
539     }
540     return $hasSVG;
541 }
542
543 sub hasAcceleratedCompositingSupport
544 {
545     return 0 if isCygwin() || isQt();
546
547     my $path = shift;
548
549     my $useAcceleratedCompositing = 0;
550     if (-e $path) {
551         open NM, "-|", "nm", $path or die;
552         while (<NM>) {
553             $useAcceleratedCompositing = 1 if /GraphicsLayer/;
554         }
555         close NM;
556     }
557     return $useAcceleratedCompositing;
558 }
559
560 sub checkWebCoreAcceleratedCompositingSupport
561 {
562     my $required = shift;
563     my $framework = "WebCore";
564     my $path = builtDylibPathForName($framework);
565     my $hasAcceleratedCompositing = hasAcceleratedCompositingSupport($path);
566     if ($required && !$hasAcceleratedCompositing) {
567         die "$framework at \"$path\" does not use accelerated compositing\n";
568     }
569     return $hasAcceleratedCompositing;
570 }
571
572 sub has3DTransformsSupport
573 {
574     return 0 if isCygwin() || isQt();
575
576     my $path = shift;
577
578     my $has3DTransformsSupport = 0;
579     if (-e $path) {
580         open NM, "-|", "nm", $path or die;
581         while (<NM>) {
582             $has3DTransformsSupport = 1 if /WebCoreHas3DTransforms/;
583         }
584         close NM;
585     }
586     return $has3DTransformsSupport;
587 }
588
589 sub checkWebCore3DTransformsSupport
590 {
591     my $required = shift;
592     my $framework = "WebCore";
593     my $path = builtDylibPathForName($framework);
594     my $has3DTransforms = has3DTransformsSupport($path);
595     if ($required && !$has3DTransforms) {
596         die "$framework at \"$path\" does not include 3D Transforms Support, please run build-webkit --3d-transforms\n";
597     }
598     return $has3DTransforms;
599 }
600
601 sub hasWMLSupport
602 {
603     return 0 if isCygwin();
604
605     my $path = shift;
606
607     if (isQt()) {
608         # FIXME: Check built library for WML support, just like Gtk does it below.
609         return 0;
610     }
611
612     my $hasWMLSupport = 0;
613     if (-e $path) {
614         open NM, "-|", "nm", $path or die;
615         while (<NM>) {
616             $hasWMLSupport = 1 if /WMLElement/;
617         }
618         close NM;
619     }
620     return $hasWMLSupport;
621 }
622
623 sub removeLibraryDependingOnWML
624 {
625     my $frameworkName = shift;
626     my $shouldHaveWML = shift;
627
628     my $path = builtDylibPathForName($frameworkName);
629     return unless -x $path;
630
631     my $hasWML = hasWMLSupport($path);
632     system "rm -f $path" if ($shouldHaveWML xor $hasWML);
633 }
634
635 sub checkWebCoreWMLSupport
636 {
637     my $required = shift;
638     my $framework = "WebCore";
639     my $path = builtDylibPathForName($framework);
640     my $hasWML = hasWMLSupport($path);
641     if ($required && !$hasWML) {
642         die "$framework at \"$path\" does not include WML Support, please run build-webkit --wml\n";
643     }
644     return $hasWML;
645 }
646
647 sub isQt()
648 {
649     determineIsQt();
650     return $isQt;
651 }
652
653 sub checkForArgumentAndRemoveFromARGV
654 {
655     my $argToCheck = shift;
656     foreach my $opt (@ARGV) {
657         if ($opt =~ /^$argToCheck$/i ) {
658             @ARGV = grep(!/^$argToCheck$/i, @ARGV);
659             return 1;
660         }
661     }
662     return 0;
663 }
664
665 sub determineIsQt()
666 {
667     return if defined($isQt);
668
669     # Allow override in case QTDIR is not set.
670     if (checkForArgumentAndRemoveFromARGV("--qt")) {
671         $isQt = 1;
672         return;
673     }
674
675     # The presence of QTDIR only means Qt if --gtk is not on the command-line
676     if (isGtk()) {
677         $isQt = 0;
678         return;
679     }
680     
681     $isQt = defined($ENV{'QTDIR'});
682 }
683
684 sub isGtk()
685 {
686     determineIsGtk();
687     return $isGtk;
688 }
689
690 sub determineIsGtk()
691 {
692     return if defined($isGtk);
693     $isGtk = checkForArgumentAndRemoveFromARGV("--gtk");
694 }
695
696 sub isWx()
697 {
698     determineIsWx();
699     return $isWx;
700 }
701
702 sub determineIsWx()
703 {
704     return if defined($isWx);
705     $isWx = checkForArgumentAndRemoveFromARGV("--wx");
706 }
707
708 sub getWxArgs()
709 {
710     if (!@wxArgs) {
711         @wxArgs = ("");
712         my $rawWxArgs = "";
713         foreach my $opt (@ARGV) {
714             if ($opt =~ /^--wx-args/i ) {
715                 @ARGV = grep(!/^--wx-args/i, @ARGV);
716                 $rawWxArgs = $opt;
717                 $rawWxArgs =~ s/--wx-args=//i;
718             }
719         }
720         @wxArgs = split(/,/, $rawWxArgs);
721     }
722     return @wxArgs;
723 }
724
725 # Determine if this is debian, ubuntu, linspire, or something similar.
726 sub isDebianBased()
727 {
728     return -e "/etc/debian_version";
729 }
730
731 sub isChromium()
732 {
733     determineIsChromium();
734     return $isChromium;
735 }
736
737 sub determineIsChromium()
738 {
739     return if defined($isChromium);
740     $isChromium = checkForArgumentAndRemoveFromARGV("--chromium");
741 }
742
743 sub isCygwin()
744 {
745     return ($^O eq "cygwin") || 0;
746 }
747
748 sub isDarwin()
749 {
750     return ($^O eq "darwin") || 0;
751 }
752
753 sub isAppleWebKit()
754 {
755     return !(isQt() or isGtk() or isWx() or isChromium());
756 }
757
758 sub isAppleMacWebKit()
759 {
760     return isAppleWebKit() && isDarwin();
761 }
762
763 sub isAppleWinWebKit()
764 {
765     return isAppleWebKit() && isCygwin();
766 }
767
768 sub isPerianInstalled()
769 {
770     if (!isAppleWebKit()) {
771         return 0;
772     }
773
774     if (-d "/Library/QuickTime/Perian.component") {
775         return 1;
776     }
777
778     if (-d "$ENV{HOME}/Library/QuickTime/Perian.component") {
779         return 1;
780     }
781
782     return 0;
783 }
784
785 sub determineOSXVersion()
786 {
787     return if $osXVersion;
788
789     if (!isDarwin()) {
790         $osXVersion = -1;
791         return;
792     }
793
794     my $version = `sw_vers -productVersion`;
795     my @splitVersion = split(/\./, $version);
796     @splitVersion >= 2 or die "Invalid version $version";
797     $osXVersion = {
798             "major" => $splitVersion[0],
799             "minor" => $splitVersion[1],
800             "subminor" => (defined($splitVersion[2]) ? $splitVersion[2] : 0),
801     };
802 }
803
804 sub osXVersion()
805 {
806     determineOSXVersion();
807     return $osXVersion;
808 }
809
810 sub isTiger()
811 {
812     return isDarwin() && osXVersion()->{"minor"} == 4;
813 }
814
815 sub isLeopard()
816 {
817     return isDarwin() && osXVersion()->{"minor"} == 5;
818 }
819
820 sub isSnowLeopard()
821 {
822     return isDarwin() && osXVersion()->{"minor"} == 6;
823 }
824
825 sub relativeScriptsDir()
826 {
827     my $scriptDir = File::Spec->catpath("", File::Spec->abs2rel(dirname($0), getcwd()), "");
828     if ($scriptDir eq "") {
829         $scriptDir = ".";
830     }
831     return $scriptDir;
832 }
833
834 sub launcherPath()
835 {
836     my $relativeScriptsPath = relativeScriptsDir();
837     if (isGtk() || isQt()) {
838         return "$relativeScriptsPath/run-launcher";
839     } elsif (isAppleWebKit()) {
840         return "$relativeScriptsPath/run-safari";
841     }
842 }
843
844 sub launcherName()
845 {
846     if (isGtk()) {
847         return "GtkLauncher";
848     } elsif (isQt()) {
849         return "QtLauncher";
850     } elsif (isAppleWebKit()) {
851         return "Safari";
852     }
853 }
854
855 sub checkRequiredSystemConfig
856 {
857     if (isDarwin()) {
858         chomp(my $productVersion = `sw_vers -productVersion`);
859         if ($productVersion lt "10.4") {
860             print "*************************************************************\n";
861             print "Mac OS X Version 10.4.0 or later is required to build WebKit.\n";
862             print "You have " . $productVersion . ", thus the build will most likely fail.\n";
863             print "*************************************************************\n";
864         }
865         my $xcodeVersion = `xcodebuild -version`;
866         if ($xcodeVersion !~ /DevToolsCore-(\d+)/ || $1 < 747) {
867             print "*************************************************************\n";
868             print "Xcode Version 2.3 or later is required to build WebKit.\n";
869             print "You have an earlier version of Xcode, thus the build will\n";
870             print "most likely fail.  The latest Xcode is available from the web:\n";
871             print "http://developer.apple.com/tools/xcode\n";
872             print "*************************************************************\n";
873         }
874     } elsif (isGtk() or isQt() or isWx()) {
875         my @cmds = qw(flex bison gperf);
876         my @missing = ();
877         foreach my $cmd (@cmds) {
878             if (not `$cmd --version`) {
879                 push @missing, $cmd;
880             }
881         }
882         if (@missing) {
883             my $list = join ", ", @missing;
884             die "ERROR: $list missing but required to build WebKit.\n";
885         }
886     }
887     # Win32 and other platforms may want to check for minimum config
888 }
889
890 sub setupCygwinEnv()
891 {
892     return if !isCygwin();
893     return if $vcBuildPath;
894
895     my $programFilesPath = `cygpath "$ENV{'PROGRAMFILES'}"`;
896     chomp $programFilesPath;
897     $vcBuildPath = "$programFilesPath/Microsoft Visual Studio 8/Common7/IDE/devenv.com";
898     if (! -e $vcBuildPath) {
899         # VC++ not found, try VC++ Express
900         my $vsInstallDir;
901         if ($ENV{'VSINSTALLDIR'}) {
902             $vsInstallDir = $ENV{'VSINSTALLDIR'};
903         } else {
904             $programFilesPath = $ENV{'PROGRAMFILES'} || "C:\\Program Files";
905             $vsInstallDir = "$programFilesPath/Microsoft Visual Studio 8";
906         }
907         $vsInstallDir = `cygpath "$vsInstallDir"`;
908         chomp $vsInstallDir;
909         $vcBuildPath = "$vsInstallDir/Common7/IDE/VCExpress.exe";
910         if (! -e $vcBuildPath) {
911             print "*************************************************************\n";
912             print "Cannot find '$vcBuildPath'\n";
913             print "Please execute the file 'vcvars32.bat' from\n";
914             print "'$programFilesPath\\Microsoft Visual Studio 8\\VC\\bin\\'\n";
915             print "to setup the necessary environment variables.\n";
916             print "*************************************************************\n";
917             die;
918         }
919     }
920
921     my $qtSDKPath = "$programFilesPath/QuickTime SDK";
922     if (0 && ! -e $qtSDKPath) {
923         print "*************************************************************\n";
924         print "Cannot find '$qtSDKPath'\n";
925         print "Please download the QuickTime SDK for Windows from\n";
926         print "http://developer.apple.com/quicktime/download/\n";
927         print "*************************************************************\n";
928         die;
929     }
930     
931     chomp($ENV{'WEBKITLIBRARIESDIR'} = `cygpath -wa "$sourceDir/WebKitLibraries/win"`) unless $ENV{'WEBKITLIBRARIESDIR'};
932
933     $windowsTmpPath = `cygpath -w /tmp`;
934     chomp $windowsTmpPath;
935     print "Building results into: ", baseProductDir(), "\n";
936     print "WEBKITOUTPUTDIR is set to: ", $ENV{"WEBKITOUTPUTDIR"}, "\n";
937     print "WEBKITLIBRARIESDIR is set to: ", $ENV{"WEBKITLIBRARIESDIR"}, "\n";
938 }
939
940 sub buildXCodeProject($$@)
941 {
942     my ($project, $clean, @extraOptions) = @_;
943
944     if ($clean) {
945         push(@extraOptions, "-alltargets");
946         push(@extraOptions, "clean");
947     }
948
949     return system "xcodebuild", "-project", "$project.xcodeproj", @extraOptions;
950 }
951
952 sub buildVisualStudioProject
953 {
954     my ($project, $clean) = @_;
955     setupCygwinEnv();
956
957     my $config = configurationForVisualStudio();
958
959     chomp(my $winProjectPath = `cygpath -w "$project"`);
960     
961     my $command = "/build";
962     if ($clean) {
963         $command = "/clean";
964     }
965
966     print "$vcBuildPath $winProjectPath /build $config\n";
967     return system $vcBuildPath, $winProjectPath, $command, $config;
968 }
969
970 sub buildSconsProject
971 {
972     my ($project, $shouldClean) = @_;
973     print "Building from $project/$project.scons\n";
974
975     my $sconsCommand = "scons";
976     if (isCygwin()) {
977         # HACK: Launch scons with Win32 python instead of CYGWIN python
978         # Scons + MSVC only works under Win32 python
979         # http://scons.tigris.org/issues/show_bug.cgi?id=2266
980         $sconsCommand = "cmd /c 'C:\\Python26\\Scripts\\scons'";
981     }
982     if ($shouldClean) {
983         return system $sconsCommand, "--clean";
984     }
985     return system $sconsCommand;
986 }
987
988 sub retrieveQMakespecVar
989 {
990     my $mkspec = $_[0];
991     my $varname = $_[1];
992
993     my $compiler = "unknown";
994     #print "retrieveMakespecVar " . $mkspec . ", " . $varname . "\n";
995
996     local *SPEC;
997     open SPEC, "<$mkspec" or return "make";
998     while (<SPEC>) {
999         if ($_ =~ /\s*include\((.+)\)/) {
1000             # open the included mkspec
1001             my $oldcwd = getcwd();
1002             (my $volume, my $directories, my $file) = File::Spec->splitpath($mkspec);
1003             chdir "$volume$directories";
1004             $compiler = retrieveQMakespecVar($1, $varname);
1005             chdir $oldcwd;
1006         } elsif ($_ =~ /$varname\s*=\s*([^\s]+)/) {
1007             $compiler = $1;
1008             last;
1009         }
1010     }
1011     close SPEC;
1012     return $compiler;
1013 }
1014
1015 sub qtMakeCommand($)
1016 {
1017     my ($qmakebin) = @_;
1018     chomp(my $mkspec = `$qmakebin -query QMAKE_MKSPECS`);
1019     $mkspec .= "/default";
1020     my $compiler = retrieveQMakespecVar("$mkspec/qmake.conf", "QMAKE_CC");
1021
1022     #print "default spec: " . $mkspec . "\n";
1023     #print "compiler found: " . $compiler . "\n";
1024
1025     if ($compiler eq "cl") {
1026         return "nmake";
1027     }
1028
1029     return "make";
1030 }
1031
1032 sub autotoolsFlag($$)
1033 {
1034     my ($flag, $feature) = @_;
1035     my $prefix = $flag ? "--enable" : "--disable";
1036
1037     return $prefix . '-' . $feature;
1038 }
1039
1040 sub buildAutotoolsProject($@)
1041 {
1042     my ($clean, @buildArgs) = @_;
1043
1044     my $make = 'make';
1045     my $dir = productDir();
1046     my $config = passedConfiguration() || configuration();
1047     my $prefix = $ENV{"WebKitInstallationPrefix"};
1048
1049     push @buildArgs, "--prefix=" . $prefix if defined($prefix);
1050
1051     # check if configuration is Debug
1052     if ($config =~ m/debug/i) {
1053         push @buildArgs, "--enable-debug";
1054     } else {
1055         push @buildArgs, "--disable-debug";
1056     }
1057
1058     # Use rm to clean the build directory since distclean may miss files
1059     if ($clean && -d $dir) {
1060         system "rm", "-rf", "$dir";
1061     }
1062
1063     if (! -d $dir) {
1064         system "mkdir", "-p", "$dir";
1065         if (! -d $dir) {
1066             die "Failed to create build directory " . $dir;
1067         }
1068     }
1069
1070     chdir $dir or die "Failed to cd into " . $dir . "\n";
1071
1072     my $result;
1073     if ($clean) {
1074         #$result = system $make, "distclean";
1075         return 0;
1076     }
1077
1078     print "Calling configure in " . $dir . "\n\n";
1079     print "Installation directory: $prefix\n" if(defined($prefix));
1080
1081     # Make the path relative since it will appear in all -I compiler flags.
1082     # Long argument lists cause bizarre slowdowns in libtool.
1083     my $relSourceDir = File::Spec->abs2rel($sourceDir);
1084     $relSourceDir = "." if !$relSourceDir;
1085
1086     $result = system "$relSourceDir/autogen.sh", @buildArgs;
1087     if ($result ne 0) {
1088         die "Failed to setup build environment using 'autotools'!\n";
1089     }
1090
1091     my $makeArgs = $ENV{"WebKitMakeArguments"} || "";
1092
1093     $result = system "$make $makeArgs";
1094     if ($result ne 0) {
1095         die "\nFailed to build WebKit using '$make'!\n";
1096     }
1097
1098     chdir ".." or die;
1099     return $result;
1100 }
1101
1102 sub buildQMakeProject($@)
1103 {
1104     my ($clean, @buildParams) = @_;
1105
1106     my @buildArgs = ("-r");
1107
1108     push @buildArgs, "DEFINES+=QT_SHARED";
1109
1110     my $qmakebin = "qmake"; # Allow override of the qmake binary from $PATH
1111     my $makeargs = "";
1112     for my $i (0 .. $#buildParams) {
1113         my $opt = $buildParams[$i];
1114         if ($opt =~ /^--qmake=(.*)/i ) {
1115             $qmakebin = $1;
1116         } elsif ($opt =~ /^--qmakearg=(.*)/i ) {
1117             push @buildArgs, $1;
1118         } elsif ($opt =~ /^--makeargs=(.*)/i ) {
1119             $makeargs = $1;
1120         } else {
1121             push @buildArgs, $opt;
1122         }
1123     }
1124
1125     my $make = qtMakeCommand($qmakebin);
1126     my $config = configuration();
1127     my $prefix = $ENV{"WebKitInstallationPrefix"};
1128
1129     push @buildArgs, "OUTPUT_DIR=" . baseProductDir() . "/$config";
1130     push @buildArgs, sourceDir() . "/WebKit.pro";
1131     if ($config =~ m/debug/i) {
1132         push @buildArgs, "CONFIG-=release";
1133         push @buildArgs, "CONFIG+=debug";
1134     } else {
1135         push @buildArgs, "CONFIG+=release";
1136         push @buildArgs, "CONFIG-=debug";
1137     }
1138
1139     my $dir = baseProductDir();
1140     if (! -d $dir) {
1141         system "mkdir", "-p", "$dir";
1142         if (! -d $dir) {
1143             die "Failed to create product directory " . $dir;
1144         }
1145     }
1146     $dir = $dir . "/$config";
1147     if (! -d $dir) {
1148         system "mkdir", "-p", "$dir";
1149         if (! -d $dir) {
1150             die "Failed to create build directory " . $dir;
1151         }
1152     }
1153
1154     chdir $dir or die "Failed to cd into " . $dir . "\n";
1155
1156     print "Calling '$qmakebin @buildArgs' in " . $dir . "\n\n";
1157     print "Installation directory: $prefix\n" if(defined($prefix));
1158
1159     my $result = system $qmakebin, @buildArgs;
1160     if ($result ne 0) {
1161        die "Failed to setup build environment using $qmakebin!\n";
1162     }
1163
1164     if ($clean) {
1165       $result = system "$make $makeargs distclean";
1166     } else {
1167       $result = system "$make $makeargs";
1168     }
1169
1170     chdir ".." or die;
1171     return $result;
1172 }
1173
1174 sub buildQMakeQtProject($$@)
1175 {
1176     my ($project, $clean, @buildArgs) = @_;
1177
1178     push @buildArgs, "CONFIG+=qt-port";
1179
1180     return buildQMakeProject($clean, @buildArgs);
1181 }
1182
1183 sub buildGtkProject($$@)
1184 {
1185     my ($project, $clean, @buildArgs) = @_;
1186
1187     if ($project ne "WebKit") {
1188         die "The Gtk port builds JavaScriptCore, WebCore and WebKit in one shot! Only call it for 'WebKit'.\n";
1189     }
1190
1191     return buildAutotoolsProject($clean, @buildArgs);
1192 }
1193
1194 sub setPathForRunningWebKitApp
1195 {
1196     my ($env) = @_;
1197
1198     return unless isAppleWinWebKit();
1199
1200     $env->{PATH} = join(':', productDir(), dirname(installedSafariPath()), $env->{PATH} || "");
1201 }
1202
1203 sub exitStatus($)
1204 {
1205     my ($returnvalue) = @_;
1206     if ($^O eq "MSWin32") {
1207         return $returnvalue >> 8;
1208     }
1209     return WEXITSTATUS($returnvalue);
1210 }
1211
1212 sub runSafari
1213 {
1214     my ($debugger) = @_;
1215
1216     if (isAppleMacWebKit()) {
1217         return system "$FindBin::Bin/gdb-safari", @ARGV if $debugger;
1218
1219         my $productDir = productDir();
1220         print "Starting Safari with DYLD_FRAMEWORK_PATH set to point to built WebKit in $productDir.\n";
1221         $ENV{DYLD_FRAMEWORK_PATH} = $productDir;
1222         $ENV{WEBKIT_UNSET_DYLD_FRAMEWORK_PATH} = "YES";
1223         if (architecture()) {
1224             return system "arch", "-" . architecture(), safariPath(), @ARGV;
1225         } else {
1226             return system safariPath(), @ARGV;
1227         }
1228     }
1229
1230     if (isAppleWinWebKit()) {
1231         my $script = "run-webkit-nightly.cmd";
1232         my $result = system "cp", "$FindBin::Bin/$script", productDir();
1233         return $result if $result;
1234
1235         my $cwd = getcwd();
1236         chdir productDir();
1237
1238         my $debuggerFlag = $debugger ? "/debugger" : "";
1239         $result = system "cmd", "/c", "call $script $debuggerFlag";
1240         chdir $cwd;
1241         return $result;
1242     }
1243
1244     return 1;
1245 }
1246
1247 1;