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