410f58b2dc4c68789bd08839a1cf3cf1f19bc57f
[WebKit-https.git] / Tools / Scripts / webkitdirs.pm
1 # Copyright (C) 2005, 2006, 2007, 2010 Apple Inc. All rights reserved.
2 # Copyright (C) 2009 Google Inc. All rights reserved.
3 # Copyright (C) 2011 Research In Motion Limited. All rights reserved.
4 #
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions
7 # are met:
8 #
9 # 1.  Redistributions of source code must retain the above copyright
10 #     notice, this list of conditions and the following disclaimer. 
11 # 2.  Redistributions in binary form must reproduce the above copyright
12 #     notice, this list of conditions and the following disclaimer in the
13 #     documentation and/or other materials provided with the distribution. 
14 # 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 #     its contributors may be used to endorse or promote products derived
16 #     from this software without specific prior written permission. 
17 #
18 # THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 # DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 # Module to share code to get to WebKit directories.
30
31 use strict;
32 use warnings;
33 use Config;
34 use FindBin;
35 use File::Basename;
36 use File::Path qw(mkpath rmtree);
37 use File::Spec;
38 use POSIX;
39 use VCSUtils;
40
41 BEGIN {
42    use Exporter   ();
43    our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
44    $VERSION     = 1.00;
45    @ISA         = qw(Exporter);
46    @EXPORT      = qw(&chdirWebKit &baseProductDir &productDir &XcodeOptions &XcodeOptionString &XcodeOptionStringNoConfig &passedConfiguration &setConfiguration &safariPath &checkFrameworks &currentSVNRevision);
47    %EXPORT_TAGS = ( );
48    @EXPORT_OK   = ();
49 }
50
51 our @EXPORT_OK;
52
53 my $architecture;
54 my $numberOfCPUs;
55 my $baseProductDir;
56 my @baseProductDirOption;
57 my $configuration;
58 my $configurationForVisualStudio;
59 my $configurationProductDir;
60 my $sourceDir;
61 my $currentSVNRevision;
62 my $osXVersion;
63 my $generateDsym;
64 my $isQt;
65 my $qmakebin = "qmake"; # Allow override of the qmake binary from $PATH
66 my $isSymbian;
67 my %qtFeatureDefaults;
68 my $isGtk;
69 my $isWinCE;
70 my $isWinCairo;
71 my $isWx;
72 my $isEfl;
73 my @wxArgs;
74 my $isChromium;
75 my $isChromiumAndroid;
76 my $isInspectorFrontend;
77 my $isWK2;
78
79 # Variables for Win32 support
80 my $vcBuildPath;
81 my $windowsSourceDir;
82 my $winVersion;
83 my $willUseVCExpressWhenBuilding = 0;
84
85 # Defined in VCSUtils.
86 sub exitStatus($);
87
88 sub determineSourceDir
89 {
90     return if $sourceDir;
91     $sourceDir = $FindBin::Bin;
92     $sourceDir =~ s|/+$||; # Remove trailing '/' as we would die later
93
94     # walks up path checking each directory to see if it is the main WebKit project dir, 
95     # defined by containing Sources, WebCore, and WebKit
96     until ((-d "$sourceDir/Source" && -d "$sourceDir/Source/WebCore" && -d "$sourceDir/Source/WebKit") || (-d "$sourceDir/Internal" && -d "$sourceDir/OpenSource"))
97     {
98         if ($sourceDir !~ s|/[^/]+$||) {
99             die "Could not find top level webkit directory above source directory using FindBin.\n";
100         }
101     }
102
103     $sourceDir = "$sourceDir/OpenSource" if -d "$sourceDir/OpenSource";
104 }
105
106 sub currentPerlPath()
107 {
108     my $thisPerl = $^X;
109     if ($^O ne 'VMS') {
110         $thisPerl .= $Config{_exe} unless $thisPerl =~ m/$Config{_exe}$/i;
111     }
112     return $thisPerl;
113 }
114
115 sub setQmakeBinaryPath($)
116 {
117     ($qmakebin) = @_;
118 }
119
120 # used for scripts which are stored in a non-standard location
121 sub setSourceDir($)
122 {
123     ($sourceDir) = @_;
124 }
125
126 sub determineBaseProductDir
127 {
128     return if defined $baseProductDir;
129     determineSourceDir();
130
131     $baseProductDir = $ENV{"WEBKITOUTPUTDIR"};
132
133     if (!defined($baseProductDir) and isAppleMacWebKit()) {
134         # Silently remove ~/Library/Preferences/xcodebuild.plist which can
135         # cause build failure. The presence of
136         # ~/Library/Preferences/xcodebuild.plist can prevent xcodebuild from
137         # respecting global settings such as a custom build products directory
138         # (<rdar://problem/5585899>).
139         my $personalPlistFile = $ENV{HOME} . "/Library/Preferences/xcodebuild.plist";
140         if (-e $personalPlistFile) {
141             unlink($personalPlistFile) || die "Could not delete $personalPlistFile: $!";
142         }
143
144         my $xcodebuildVersionOutput = `xcodebuild -version`;
145         my $xcodeVersion = ($xcodebuildVersionOutput =~ /Xcode ([0-9](\.[0-9]+)*)/) ? $1 : "3.0";
146         my $xcodeDefaultsDomain = (eval "v$xcodeVersion" lt v4) ? "com.apple.Xcode" : "com.apple.dt.Xcode";
147         my $xcodeDefaultsPrefix = (eval "v$xcodeVersion" lt v4) ? "PBX" : "IDE";
148
149         open PRODUCT, "defaults read $xcodeDefaultsDomain ${xcodeDefaultsPrefix}ApplicationwideBuildSettings 2> " . File::Spec->devnull() . " |" or die;
150         $baseProductDir = join '', <PRODUCT>;
151         close PRODUCT;
152
153         $baseProductDir = $1 if $baseProductDir =~ /SYMROOT\s*=\s*\"(.*?)\";/s;
154         undef $baseProductDir unless $baseProductDir =~ /^\//;
155     } elsif (isSymbian()) {
156         # Shadow builds are not supported on Symbian
157         $baseProductDir = $sourceDir;
158     } elsif (isChromium()) {
159         if (isLinux() || isChromiumAndroid()) {
160             $baseProductDir = "$sourceDir/out";
161         } elsif (isDarwin()) {
162             $baseProductDir = "$sourceDir/Source/WebKit/chromium/xcodebuild";
163         } elsif (isWindows() || isCygwin()) {
164             # FIXME: set the correct baseProductDir for chromium-win.
165         }
166     }
167
168     if (!defined($baseProductDir)) { # Port-spesific checks failed, use default
169         $baseProductDir = "$sourceDir/WebKitBuild";
170     }
171
172     if (isGit() && isGitBranchBuild()) {
173         my $branch = gitBranch();
174         $baseProductDir = "$baseProductDir/$branch";
175     }
176
177     if (isAppleMacWebKit()) {
178         $baseProductDir =~ s|^\Q$(SRCROOT)/..\E$|$sourceDir|;
179         $baseProductDir =~ s|^\Q$(SRCROOT)/../|$sourceDir/|;
180         $baseProductDir =~ s|^~/|$ENV{HOME}/|;
181         die "Can't handle Xcode product directory with a ~ in it.\n" if $baseProductDir =~ /~/;
182         die "Can't handle Xcode product directory with a variable in it.\n" if $baseProductDir =~ /\$/;
183         @baseProductDirOption = ("SYMROOT=$baseProductDir", "OBJROOT=$baseProductDir");
184     }
185
186     if (isCygwin()) {
187         my $dosBuildPath = `cygpath --windows \"$baseProductDir\"`;
188         chomp $dosBuildPath;
189         $ENV{"WEBKITOUTPUTDIR"} = $dosBuildPath;
190         my $unixBuildPath = `cygpath --unix \"$baseProductDir\"`;
191         chomp $unixBuildPath;
192         $baseProductDir = $unixBuildPath;
193     }
194 }
195
196 sub setBaseProductDir($)
197 {
198     ($baseProductDir) = @_;
199 }
200
201 sub determineConfiguration
202 {
203     return if defined $configuration;
204     determineBaseProductDir();
205     if (open CONFIGURATION, "$baseProductDir/Configuration") {
206         $configuration = <CONFIGURATION>;
207         close CONFIGURATION;
208     }
209     if ($configuration) {
210         chomp $configuration;
211         # compatibility for people who have old Configuration files
212         $configuration = "Release" if $configuration eq "Deployment";
213         $configuration = "Debug" if $configuration eq "Development";
214     } else {
215         $configuration = "Release";
216     }
217
218     if ($configuration && isWinCairo()) {
219         $configuration .= "_Cairo_CFLite";
220     }
221 }
222
223 sub determineArchitecture
224 {
225     return if defined $architecture;
226     # make sure $architecture is defined for non-apple-mac builds
227     $architecture = "";
228     return unless isAppleMacWebKit();
229
230     determineBaseProductDir();
231     if (open ARCHITECTURE, "$baseProductDir/Architecture") {
232         $architecture = <ARCHITECTURE>;
233         close ARCHITECTURE;
234     }
235     if ($architecture) {
236         chomp $architecture;
237     } else {
238         if (isLeopard()) {
239             $architecture = `arch`;
240         } else {
241             my $supports64Bit = `sysctl -n hw.optional.x86_64`;
242             chomp $supports64Bit;
243             $architecture = $supports64Bit ? 'x86_64' : `arch`;
244         }
245         chomp $architecture;
246     }
247 }
248
249 sub determineNumberOfCPUs
250 {
251     return if defined $numberOfCPUs;
252     if (isLinux()) {
253         # First try the nproc utility, if it exists. If we get no
254         # results fall back to just interpretting /proc directly.
255         chomp($numberOfCPUs = `nproc 2> /dev/null`);
256         if ($numberOfCPUs eq "") {
257             $numberOfCPUs = (grep /processor/, `cat /proc/cpuinfo`);
258         }
259     } elsif (isWindows() || isCygwin()) {
260         if (defined($ENV{NUMBER_OF_PROCESSORS})) {
261             $numberOfCPUs = $ENV{NUMBER_OF_PROCESSORS};
262         } else {
263             # Assumes cygwin
264             $numberOfCPUs = `ls /proc/registry/HKEY_LOCAL_MACHINE/HARDWARE/DESCRIPTION/System/CentralProcessor | wc -w`;
265         }
266     } elsif (isDarwin()) {
267         $numberOfCPUs = `sysctl -n hw.ncpu`;
268     }
269 }
270
271 sub jscPath($)
272 {
273     my ($productDir) = @_;
274     my $jscName = "jsc";
275     $jscName .= "_debug"  if configurationForVisualStudio() eq "Debug_All";
276     $jscName .= ".exe" if (isWindows() || isCygwin());
277     return "$productDir/$jscName" if -e "$productDir/$jscName";
278     return "$productDir/JavaScriptCore.framework/Resources/$jscName";
279 }
280
281 sub argumentsForConfiguration()
282 {
283     determineConfiguration();
284     determineArchitecture();
285
286     my @args = ();
287     push(@args, '--debug') if $configuration eq "Debug";
288     push(@args, '--release') if $configuration eq "Release";
289     push(@args, '--32-bit') if $architecture ne "x86_64";
290     push(@args, '--qt') if isQt();
291     push(@args, '--symbian') if isSymbian();
292     push(@args, '--gtk') if isGtk();
293     push(@args, '--efl') if isEfl();
294     push(@args, '--wince') if isWinCE();
295     push(@args, '--wx') if isWx();
296     push(@args, '--chromium') if isChromium() && !isChromiumAndroid();
297     push(@args, '--chromium-android') if isChromiumAndroid();
298     push(@args, '--inspector-frontend') if isInspectorFrontend();
299     return @args;
300 }
301
302 sub determineConfigurationForVisualStudio
303 {
304     return if defined $configurationForVisualStudio;
305     determineConfiguration();
306     # FIXME: We should detect when Debug_All or Production has been chosen.
307     $configurationForVisualStudio = $configuration;
308 }
309
310 sub usesPerConfigurationBuildDirectory
311 {
312     # [Gtk][Efl] We don't have Release/Debug configurations in straight
313     # autotool builds (non build-webkit). In this case and if
314     # WEBKITOUTPUTDIR exist, use that as our configuration dir. This will
315     # allows us to run run-webkit-tests without using build-webkit.
316     #
317     # Symbian builds do not have Release/Debug configurations either.
318     return ($ENV{"WEBKITOUTPUTDIR"} && (isGtk() || isEfl())) || isSymbian() || isAppleWinWebKit();
319 }
320
321 sub determineConfigurationProductDir
322 {
323     return if defined $configurationProductDir;
324     determineBaseProductDir();
325     determineConfiguration();
326     if (isAppleWinWebKit() && !isWx()) {
327         $configurationProductDir = File::Spec->catdir($baseProductDir, configurationForVisualStudio(), "bin");
328     } else {
329         if (usesPerConfigurationBuildDirectory()) {
330             $configurationProductDir = "$baseProductDir";
331         } else {
332             $configurationProductDir = "$baseProductDir/$configuration";
333         }
334     }
335 }
336
337 sub setConfigurationProductDir($)
338 {
339     ($configurationProductDir) = @_;
340 }
341
342 sub determineCurrentSVNRevision
343 {
344     return if defined $currentSVNRevision;
345     determineSourceDir();
346     $currentSVNRevision = svnRevisionForDirectory($sourceDir);
347     return $currentSVNRevision;
348 }
349
350
351 sub chdirWebKit
352 {
353     determineSourceDir();
354     chdir $sourceDir or die;
355 }
356
357 sub baseProductDir
358 {
359     determineBaseProductDir();
360     return $baseProductDir;
361 }
362
363 sub sourceDir
364 {
365     determineSourceDir();
366     return $sourceDir;
367 }
368
369 sub productDir
370 {
371     determineConfigurationProductDir();
372     return $configurationProductDir;
373 }
374
375 sub jscProductDir
376 {
377     my $productDir = productDir();
378     $productDir .= "/JavaScriptCore" if isQt();
379     $productDir .= "/$configuration" if (isQt() && isWindows());
380     $productDir .= "/Programs" if (isGtk() || isEfl());
381
382     return $productDir;
383 }
384
385 sub configuration()
386 {
387     determineConfiguration();
388     return $configuration;
389 }
390
391 sub configurationForVisualStudio()
392 {
393     determineConfigurationForVisualStudio();
394     return $configurationForVisualStudio;
395 }
396
397 sub currentSVNRevision
398 {
399     determineCurrentSVNRevision();
400     return $currentSVNRevision;
401 }
402
403 sub generateDsym()
404 {
405     determineGenerateDsym();
406     return $generateDsym;
407 }
408
409 sub determineGenerateDsym()
410 {
411     return if defined($generateDsym);
412     $generateDsym = checkForArgumentAndRemoveFromARGV("--dsym");
413 }
414
415 sub argumentsForXcode()
416 {
417     my @args = ();
418     push @args, "DEBUG_INFORMATION_FORMAT=dwarf-with-dsym" if generateDsym();
419     return @args;
420 }
421
422 sub XcodeOptions
423 {
424     determineBaseProductDir();
425     determineConfiguration();
426     determineArchitecture();
427     return (@baseProductDirOption, "-configuration", $configuration, "ARCHS=$architecture", argumentsForXcode());
428 }
429
430 sub XcodeOptionString
431 {
432     return join " ", XcodeOptions();
433 }
434
435 sub XcodeOptionStringNoConfig
436 {
437     return join " ", @baseProductDirOption;
438 }
439
440 sub XcodeCoverageSupportOptions()
441 {
442     my @coverageSupportOptions = ();
443     push @coverageSupportOptions, "GCC_GENERATE_TEST_COVERAGE_FILES=YES";
444     push @coverageSupportOptions, "GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES";
445     push @coverageSupportOptions, "EXTRA_LINK= \$(EXTRA_LINK) -ftest-coverage -fprofile-arcs";
446     push @coverageSupportOptions, "OTHER_CFLAGS= \$(OTHER_CFLAGS) -DCOVERAGE -MD";
447     push @coverageSupportOptions, "OTHER_LDFLAGS=\$(OTHER_LDFLAGS) -ftest-coverage -fprofile-arcs -lgcov";
448     return @coverageSupportOptions;
449 }
450
451 my $passedConfiguration;
452 my $searchedForPassedConfiguration;
453 sub determinePassedConfiguration
454 {
455     return if $searchedForPassedConfiguration;
456     $searchedForPassedConfiguration = 1;
457
458     for my $i (0 .. $#ARGV) {
459         my $opt = $ARGV[$i];
460         if ($opt =~ /^--debug$/i || $opt =~ /^--devel/i) {
461             splice(@ARGV, $i, 1);
462             $passedConfiguration = "Debug";
463             $passedConfiguration .= "_Cairo_CFLite" if (isWinCairo() && isCygwin());
464             return;
465         }
466         if ($opt =~ /^--release$/i || $opt =~ /^--deploy/i) {
467             splice(@ARGV, $i, 1);
468             $passedConfiguration = "Release";
469             $passedConfiguration .= "_Cairo_CFLite" if (isWinCairo() && isCygwin());
470             return;
471         }
472         if ($opt =~ /^--profil(e|ing)$/i) {
473             splice(@ARGV, $i, 1);
474             $passedConfiguration = "Profiling";
475             $passedConfiguration .= "_Cairo_CFLite" if (isWinCairo() && isCygwin());
476             return;
477         }
478     }
479     $passedConfiguration = undef;
480 }
481
482 sub passedConfiguration
483 {
484     determinePassedConfiguration();
485     return $passedConfiguration;
486 }
487
488 sub setConfiguration
489 {
490     setArchitecture();
491
492     if (my $config = shift @_) {
493         $configuration = $config;
494         return;
495     }
496
497     determinePassedConfiguration();
498     $configuration = $passedConfiguration if $passedConfiguration;
499 }
500
501
502 my $passedArchitecture;
503 my $searchedForPassedArchitecture;
504 sub determinePassedArchitecture
505 {
506     return if $searchedForPassedArchitecture;
507     $searchedForPassedArchitecture = 1;
508
509     for my $i (0 .. $#ARGV) {
510         my $opt = $ARGV[$i];
511         if ($opt =~ /^--32-bit$/i) {
512             splice(@ARGV, $i, 1);
513             if (isAppleMacWebKit() || isWx()) {
514                 $passedArchitecture = `arch`;
515                 chomp $passedArchitecture;
516             }
517             return;
518         }
519     }
520     $passedArchitecture = undef;
521 }
522
523 sub passedArchitecture
524 {
525     determinePassedArchitecture();
526     return $passedArchitecture;
527 }
528
529 sub architecture()
530 {
531     determineArchitecture();
532     return $architecture;
533 }
534
535 sub numberOfCPUs()
536 {
537     determineNumberOfCPUs();
538     return $numberOfCPUs;
539 }
540
541 sub setArchitecture
542 {
543     if (my $arch = shift @_) {
544         $architecture = $arch;
545         return;
546     }
547
548     determinePassedArchitecture();
549     $architecture = $passedArchitecture if $passedArchitecture;
550 }
551
552
553 sub safariPathFromSafariBundle
554 {
555     my ($safariBundle) = @_;
556
557     return "$safariBundle/Contents/MacOS/Safari" if isAppleMacWebKit();
558     return $safariBundle if isAppleWinWebKit();
559 }
560
561 sub installedSafariPath
562 {
563     my $safariBundle;
564
565     if (isAppleMacWebKit()) {
566         $safariBundle = "/Applications/Safari.app";
567     } elsif (isAppleWinWebKit()) {
568         $safariBundle = `"$configurationProductDir/FindSafari.exe"`;
569         $safariBundle =~ s/[\r\n]+$//;
570         $safariBundle = `cygpath -u '$safariBundle'` if isCygwin();
571         $safariBundle =~ s/[\r\n]+$//;
572         $safariBundle .= "Safari.exe";
573     }
574
575     return safariPathFromSafariBundle($safariBundle);
576 }
577
578 # Locate Safari.
579 sub safariPath
580 {
581     # Use WEBKIT_SAFARI environment variable if present.
582     my $safariBundle = $ENV{WEBKIT_SAFARI};
583     if (!$safariBundle) {
584         determineConfigurationProductDir();
585         # Use Safari.app in product directory if present (good for Safari development team).
586         if (isAppleMacWebKit() && -d "$configurationProductDir/Safari.app") {
587             $safariBundle = "$configurationProductDir/Safari.app";
588         } elsif (isAppleWinWebKit()) {
589             my $path = "$configurationProductDir/Safari.exe";
590             my $debugPath = "$configurationProductDir/Safari_debug.exe";
591
592             if (configurationForVisualStudio() eq "Debug_All" && -x $debugPath) {
593                 $safariBundle = $debugPath;
594             } elsif (-x $path) {
595                 $safariBundle = $path;
596             }
597         }
598         if (!$safariBundle) {
599             return installedSafariPath();
600         }
601     }
602     my $safariPath = safariPathFromSafariBundle($safariBundle);
603     die "Can't find executable at $safariPath.\n" if isAppleMacWebKit() && !-x $safariPath;
604     return $safariPath;
605 }
606
607 sub builtDylibPathForName
608 {
609     my $libraryName = shift;
610     determineConfigurationProductDir();
611     if (isChromium()) {
612         return "$configurationProductDir/$libraryName";
613     }
614     if (isQt()) {
615         $libraryName = "QtWebKit";
616         if (isDarwin() and -d "$configurationProductDir/lib/$libraryName.framework") {
617             return "$configurationProductDir/lib/$libraryName.framework/$libraryName";
618         } elsif (isDarwin() and -d "$configurationProductDir/lib") {
619             return "$configurationProductDir/lib/lib$libraryName.dylib";
620         } elsif (isWindows()) {
621             if (configuration() eq "Debug") {
622                 # On Windows, there is a "d" suffix to the library name. See <http://trac.webkit.org/changeset/53924/>.
623                 $libraryName .= "d";
624             }
625
626             my $mkspec = `$qmakebin -query QMAKE_MKSPECS`;
627             $mkspec =~ s/[\n|\r]$//g;
628             my $qtMajorVersion = retrieveQMakespecVar("$mkspec/qconfig.pri", "QT_MAJOR_VERSION");
629             if (not $qtMajorVersion) {
630                 $qtMajorVersion = "";
631             }
632             return "$configurationProductDir/lib/$libraryName$qtMajorVersion.dll";
633         } else {
634             return "$configurationProductDir/lib/lib$libraryName.so";
635         }
636     }
637     if (isWx()) {
638         return "$configurationProductDir/libwxwebkit.dylib";
639     }
640     if (isGtk()) {
641         # WebKitGTK+ for GTK2, WebKitGTK+ for GTK3, and WebKit2 respectively.
642         my @libraries = ("libwebkitgtk-1.0", "libwebkitgtk-3.0", "libwebkit2gtk-1.0");
643         my $extension = isDarwin() ? ".dylib" : ".so";
644
645         foreach $libraryName (@libraries) {
646             my $libraryPath = "$configurationProductDir/.libs/" . $libraryName . $extension;
647             return $libraryPath if -e $libraryPath;
648         }
649         return "NotFound";
650     }
651     if (isEfl()) {
652         return "$configurationProductDir/$libraryName/../WebKit/libewebkit.so";
653     }
654     if (isWinCE()) {
655         return "$configurationProductDir/$libraryName";
656     }
657     if (isAppleMacWebKit()) {
658         return "$configurationProductDir/$libraryName.framework/Versions/A/$libraryName";
659     }
660     if (isAppleWinWebKit()) {
661         if ($libraryName eq "JavaScriptCore") {
662             return "$baseProductDir/lib/$libraryName.lib";
663         } else {
664             return "$baseProductDir/$libraryName.intermediate/$configuration/$libraryName.intermediate/$libraryName.lib";
665         }
666     }
667
668     die "Unsupported platform, can't determine built library locations.\nTry `build-webkit --help` for more information.\n";
669 }
670
671 # Check to see that all the frameworks are built.
672 sub checkFrameworks # FIXME: This is a poor name since only the Mac calls built WebCore a Framework.
673 {
674     return if isCygwin() || isWindows();
675     my @frameworks = ("JavaScriptCore", "WebCore");
676     push(@frameworks, "WebKit") if isAppleMacWebKit(); # FIXME: This seems wrong, all ports should have a WebKit these days.
677     for my $framework (@frameworks) {
678         my $path = builtDylibPathForName($framework);
679         die "Can't find built framework at \"$path\".\n" unless -e $path;
680     }
681 }
682
683 sub isInspectorFrontend()
684 {
685     determineIsInspectorFrontend();
686     return $isInspectorFrontend;
687 }
688
689 sub determineIsInspectorFrontend()
690 {
691     return if defined($isInspectorFrontend);
692     $isInspectorFrontend = checkForArgumentAndRemoveFromARGV("--inspector-frontend");
693 }
694
695 sub isQt()
696 {
697     determineIsQt();
698     return $isQt;
699 }
700
701 sub getQtVersion()
702 {
703     my $qtVersion = `$qmakebin --version`;
704     $qtVersion =~ s/^(.*)Qt version (\d\.\d)(.*)/$2/s ;
705     return $qtVersion;
706 }
707
708 sub isSymbian()
709 {
710     determineIsSymbian();
711     return $isSymbian;
712 }
713
714 sub qtFeatureDefaults()
715 {
716     determineQtFeatureDefaults();
717     return %qtFeatureDefaults;
718 }
719
720 sub commandExists($)
721 {
722     my $command = shift;
723     my $devnull = File::Spec->devnull();
724     return `$command --version 2> $devnull`;
725 }
726
727 sub determineQtFeatureDefaults()
728 {
729     return if %qtFeatureDefaults;
730     die "ERROR: qmake missing but required to build WebKit.\n" if not commandExists($qmakebin);
731     my $originalCwd = getcwd();
732     chdir File::Spec->catfile(sourceDir(), "Source", "WebCore");
733     my $defaults = `$qmakebin CONFIG+=compute_defaults 2>&1`;
734     chdir $originalCwd;
735
736     while ($defaults =~ m/(\S+?)=(\S+?)/gi) {
737         $qtFeatureDefaults{$1}=$2;
738     }
739 }
740
741 sub checkForArgumentAndRemoveFromARGV
742 {
743     my $argToCheck = shift;
744     return checkForArgumentAndRemoveFromArrayRef($argToCheck, \@ARGV);
745 }
746
747 sub checkForArgumentAndRemoveFromArrayRef
748 {
749     my ($argToCheck, $arrayRef) = @_;
750     my @indicesToRemove;
751     foreach my $index (0 .. $#$arrayRef) {
752         my $opt = $$arrayRef[$index];
753         if ($opt =~ /^$argToCheck$/i ) {
754             push(@indicesToRemove, $index);
755         }
756     }
757     foreach my $index (@indicesToRemove) {
758         splice(@$arrayRef, $index, 1);
759     }
760     return $#indicesToRemove > -1;
761 }
762
763 sub isWK2()
764 {
765     if (defined($isWK2)) {
766         return $isWK2;
767     }
768     if (checkForArgumentAndRemoveFromARGV("-2")) {
769         $isWK2 = 1;
770     } else {
771         $isWK2 = 0;
772     }
773     return $isWK2;
774 }
775
776 sub determineIsQt()
777 {
778     return if defined($isQt);
779
780     # Allow override in case QTDIR is not set.
781     if (checkForArgumentAndRemoveFromARGV("--qt")) {
782         $isQt = 1;
783         return;
784     }
785
786     # The presence of QTDIR only means Qt if --gtk or --wx or --efl are not on the command-line
787     if (isGtk() || isWx() || isEfl()) {
788         $isQt = 0;
789         return;
790     }
791     
792     $isQt = defined($ENV{'QTDIR'});
793 }
794
795 sub determineIsSymbian()
796 {
797     return if defined($isSymbian);
798
799     if (checkForArgumentAndRemoveFromARGV("--symbian")) {
800         $isSymbian = 1;
801         return;
802     }
803 }
804
805 sub determineIsEfl()
806 {
807     return if defined($isEfl);
808     $isEfl = checkForArgumentAndRemoveFromARGV("--efl");
809 }
810
811 sub isEfl()
812 {
813     determineIsEfl();
814     return $isEfl;
815 }
816
817 sub isGtk()
818 {
819     determineIsGtk();
820     return $isGtk;
821 }
822
823 sub determineIsGtk()
824 {
825     return if defined($isGtk);
826     $isGtk = checkForArgumentAndRemoveFromARGV("--gtk");
827 }
828
829 sub isWinCE()
830 {
831     determineIsWinCE();
832     return $isWinCE;
833 }
834
835 sub determineIsWinCE()
836 {
837     return if defined($isWinCE);
838     $isWinCE = checkForArgumentAndRemoveFromARGV("--wince");
839 }
840
841 sub isWx()
842 {
843     determineIsWx();
844     return $isWx;
845 }
846
847 sub determineIsWx()
848 {
849     return if defined($isWx);
850     $isWx = checkForArgumentAndRemoveFromARGV("--wx");
851 }
852
853 sub getWxArgs()
854 {
855     if (!@wxArgs) {
856         @wxArgs = ("");
857         my $rawWxArgs = "";
858         foreach my $opt (@ARGV) {
859             if ($opt =~ /^--wx-args/i ) {
860                 @ARGV = grep(!/^--wx-args/i, @ARGV);
861                 $rawWxArgs = $opt;
862                 $rawWxArgs =~ s/--wx-args=//i;
863             }
864         }
865         @wxArgs = split(/,/, $rawWxArgs);
866     }
867     return @wxArgs;
868 }
869
870 # Determine if this is debian, ubuntu, linspire, or something similar.
871 sub isDebianBased()
872 {
873     return -e "/etc/debian_version";
874 }
875
876 sub isFedoraBased()
877 {
878     return -e "/etc/fedora-release";
879 }
880
881 sub isChromium()
882 {
883     determineIsChromium();
884     determineIsChromiumAndroid();
885     return $isChromium || $isChromiumAndroid;
886 }
887
888 sub determineIsChromium()
889 {
890     return if defined($isChromium);
891     $isChromium = checkForArgumentAndRemoveFromARGV("--chromium");
892 }
893
894 sub isChromiumAndroid()
895 {
896     determineIsChromiumAndroid();
897     return $isChromiumAndroid;
898 }
899
900 sub determineIsChromiumAndroid()
901 {
902     return if defined($isChromiumAndroid);
903     $isChromiumAndroid = checkForArgumentAndRemoveFromARGV("--chromium-android");
904 }
905
906 sub isWinCairo()
907 {
908     determineIsWinCairo();
909     return $isWinCairo;
910 }
911
912 sub determineIsWinCairo()
913 {
914     return if defined($isWinCairo);
915     $isWinCairo = checkForArgumentAndRemoveFromARGV("--wincairo");
916 }
917
918 sub isCygwin()
919 {
920     return ($^O eq "cygwin") || 0;
921 }
922
923 sub isAnyWindows()
924 {
925     return isWindows() || isCygwin() || isMsys();
926 }
927
928 sub determineWinVersion()
929 {
930     return if $winVersion;
931
932     if (!isAnyWindows()) {
933         $winVersion = -1;
934         return;
935     }
936
937     my $versionString = `cmd /c ver`;
938     $versionString =~ /(\d)\.(\d)\.(\d+)/;
939
940     $winVersion = {
941         major => $1,
942         minor => $2,
943         build => $3,
944     };
945 }
946
947 sub winVersion()
948 {
949     determineWinVersion();
950     return $winVersion;
951 }
952
953 sub isWindows7SP0()
954 {
955     return isAnyWindows() && winVersion()->{major} == 6 && winVersion()->{minor} == 1 && winVersion()->{build} == 7600;
956 }
957
958 sub isWindowsVista()
959 {
960     return isAnyWindows() && winVersion()->{major} == 6 && winVersion()->{minor} == 0;
961 }
962
963 sub isWindowsXP()
964 {
965     return isAnyWindows() && winVersion()->{major} == 5 && winVersion()->{minor} == 1;
966 }
967
968 sub isDarwin()
969 {
970     return ($^O eq "darwin") || 0;
971 }
972
973 sub isWindows()
974 {
975     return ($^O eq "MSWin32") || 0;
976 }
977
978 sub isMsys()
979 {
980     return ($^O eq "msys") || 0;
981 }
982
983 sub isLinux()
984 {
985     return ($^O eq "linux") || 0;
986 }
987
988 sub isARM()
989 {
990     return $Config{archname} =~ /^arm-/;
991 }
992
993 sub isAppleWebKit()
994 {
995     return !(isQt() or isGtk() or isWx() or isChromium() or isEfl() or isWinCE());
996 }
997
998 sub isAppleMacWebKit()
999 {
1000     return isAppleWebKit() && isDarwin();
1001 }
1002
1003 sub isAppleWinWebKit()
1004 {
1005     return isAppleWebKit() && (isCygwin() || isWindows());
1006 }
1007
1008 sub isPerianInstalled()
1009 {
1010     if (!isAppleWebKit()) {
1011         return 0;
1012     }
1013
1014     if (-d "/Library/QuickTime/Perian.component") {
1015         return 1;
1016     }
1017
1018     if (-d "$ENV{HOME}/Library/QuickTime/Perian.component") {
1019         return 1;
1020     }
1021
1022     return 0;
1023 }
1024
1025 sub determineOSXVersion()
1026 {
1027     return if $osXVersion;
1028
1029     if (!isDarwin()) {
1030         $osXVersion = -1;
1031         return;
1032     }
1033
1034     my $version = `sw_vers -productVersion`;
1035     my @splitVersion = split(/\./, $version);
1036     @splitVersion >= 2 or die "Invalid version $version";
1037     $osXVersion = {
1038             "major" => $splitVersion[0],
1039             "minor" => $splitVersion[1],
1040             "subminor" => (defined($splitVersion[2]) ? $splitVersion[2] : 0),
1041     };
1042 }
1043
1044 sub osXVersion()
1045 {
1046     determineOSXVersion();
1047     return $osXVersion;
1048 }
1049
1050 sub isLeopard()
1051 {
1052     return isDarwin() && osXVersion()->{"minor"} == 5;
1053 }
1054
1055 sub isSnowLeopard()
1056 {
1057     return isDarwin() && osXVersion()->{"minor"} == 6;
1058 }
1059
1060 sub isLion()
1061 {
1062     return isDarwin() && osXVersion()->{"minor"} == 7;
1063 }
1064
1065 sub isWindowsNT()
1066 {
1067     return $ENV{'OS'} eq 'Windows_NT';
1068 }
1069
1070 sub relativeScriptsDir()
1071 {
1072     my $scriptDir = File::Spec->catpath("", File::Spec->abs2rel($FindBin::Bin, getcwd()), "");
1073     if ($scriptDir eq "") {
1074         $scriptDir = ".";
1075     }
1076     return $scriptDir;
1077 }
1078
1079 sub launcherPath()
1080 {
1081     my $relativeScriptsPath = relativeScriptsDir();
1082     if (isGtk() || isQt() || isWx() || isEfl() || isWinCE()) {
1083         return "$relativeScriptsPath/run-launcher";
1084     } elsif (isAppleWebKit()) {
1085         return "$relativeScriptsPath/run-safari";
1086     }
1087 }
1088
1089 sub launcherName()
1090 {
1091     if (isGtk()) {
1092         return "GtkLauncher";
1093     } elsif (isQt()) {
1094         return "QtTestBrowser";
1095     } elsif (isWx()) {
1096         return "wxBrowser";
1097     } elsif (isAppleWebKit()) {
1098         return "Safari";
1099     } elsif (isEfl()) {
1100         return "EWebLauncher";
1101     } elsif (isWinCE()) {
1102         return "WinCELauncher";
1103     }
1104 }
1105
1106 sub checkRequiredSystemConfig
1107 {
1108     if (isDarwin()) {
1109         chomp(my $productVersion = `sw_vers -productVersion`);
1110         if (eval "v$productVersion" lt v10.4) {
1111             print "*************************************************************\n";
1112             print "Mac OS X Version 10.4.0 or later is required to build WebKit.\n";
1113             print "You have " . $productVersion . ", thus the build will most likely fail.\n";
1114             print "*************************************************************\n";
1115         }
1116         my $xcodebuildVersionOutput = `xcodebuild -version`;
1117         my $devToolsCoreVersion = ($xcodebuildVersionOutput =~ /DevToolsCore-(\d+)/) ? $1 : undef;
1118         my $xcodeVersion = ($xcodebuildVersionOutput =~ /Xcode ([0-9](\.[0-9]+)*)/) ? $1 : undef;
1119         if (!$devToolsCoreVersion && !$xcodeVersion
1120             || $devToolsCoreVersion && $devToolsCoreVersion < 747
1121             || $xcodeVersion && eval "v$xcodeVersion" lt v2.3) {
1122             print "*************************************************************\n";
1123             print "Xcode Version 2.3 or later is required to build WebKit.\n";
1124             print "You have an earlier version of Xcode, thus the build will\n";
1125             print "most likely fail.  The latest Xcode is available from the web:\n";
1126             print "http://developer.apple.com/tools/xcode\n";
1127             print "*************************************************************\n";
1128         }
1129     } elsif (isGtk() or isQt() or isWx() or isEfl()) {
1130         my @cmds = qw(flex bison gperf);
1131         my @missing = ();
1132         foreach my $cmd (@cmds) {
1133             push @missing, $cmd if not commandExists($cmd);
1134         }
1135
1136         if (@missing) {
1137             my $list = join ", ", @missing;
1138             die "ERROR: $list missing but required to build WebKit.\n";
1139         }
1140     }
1141     # Win32 and other platforms may want to check for minimum config
1142 }
1143
1144 sub determineWindowsSourceDir()
1145 {
1146     return if $windowsSourceDir;
1147     $windowsSourceDir = sourceDir();
1148     chomp($windowsSourceDir = `cygpath -w '$windowsSourceDir'`) if isCygwin();
1149 }
1150
1151 sub windowsSourceDir()
1152 {
1153     determineWindowsSourceDir();
1154     return $windowsSourceDir;
1155 }
1156
1157 sub windowsLibrariesDir()
1158 {
1159     return windowsSourceDir() . "\\WebKitLibraries\\win";
1160 }
1161
1162 sub windowsOutputDir()
1163 {
1164     return windowsSourceDir() . "\\WebKitBuild";
1165 }
1166
1167 sub setupAppleWinEnv()
1168 {
1169     return unless isAppleWinWebKit();
1170
1171     if (isWindowsNT()) {
1172         my $restartNeeded = 0;
1173         my %variablesToSet = ();
1174
1175         # Setting the environment variable 'CYGWIN' to 'tty' makes cygwin enable extra support (i.e., termios)
1176         # for UNIX-like ttys in the Windows console
1177         $variablesToSet{CYGWIN} = "tty" unless $ENV{CYGWIN};
1178         
1179         # Those environment variables must be set to be able to build inside Visual Studio.
1180         $variablesToSet{WEBKITLIBRARIESDIR} = windowsLibrariesDir() unless $ENV{WEBKITLIBRARIESDIR};
1181         $variablesToSet{WEBKITOUTPUTDIR} = windowsOutputDir() unless $ENV{WEBKITOUTPUTDIR};
1182
1183         foreach my $variable (keys %variablesToSet) {
1184             print "Setting the Environment Variable '" . $variable . "' to '" . $variablesToSet{$variable} . "'\n\n";
1185             system qw(regtool -s set), '\\HKEY_CURRENT_USER\\Environment\\' . $variable, $variablesToSet{$variable};
1186             $restartNeeded ||= $variable eq "WEBKITLIBRARIESDIR" || $variable eq "WEBKITOUTPUTDIR";
1187         }
1188
1189         if ($restartNeeded) {
1190             print "Please restart your computer before attempting to build inside Visual Studio.\n\n";
1191         }
1192     } else {
1193         if (!$ENV{'WEBKITLIBRARIESDIR'}) {
1194             print "Warning: You must set the 'WebKitLibrariesDir' environment variable\n";
1195             print "         to be able build WebKit from within Visual Studio.\n";
1196             print "         Make sure that 'WebKitLibrariesDir' points to the\n";
1197             print "         'WebKitLibraries/win' directory, not the 'WebKitLibraries/' directory.\n\n";
1198         }
1199         if (!$ENV{'WEBKITOUTPUTDIR'}) {
1200             print "Warning: You must set the 'WebKitOutputDir' environment variable\n";
1201             print "         to be able build WebKit from within Visual Studio.\n\n";
1202         }
1203     }
1204 }
1205
1206 sub setupCygwinEnv()
1207 {
1208     return if !isCygwin() && !isWindows();
1209     return if $vcBuildPath;
1210
1211     my $vsInstallDir;
1212     my $programFilesPath = $ENV{'PROGRAMFILES(X86)'} || $ENV{'PROGRAMFILES'} || "C:\\Program Files";
1213     if ($ENV{'VSINSTALLDIR'}) {
1214         $vsInstallDir = $ENV{'VSINSTALLDIR'};
1215     } else {
1216         $vsInstallDir = File::Spec->catdir($programFilesPath, "Microsoft Visual Studio 8");
1217     }
1218     chomp($vsInstallDir = `cygpath "$vsInstallDir"`) if isCygwin();
1219     $vcBuildPath = File::Spec->catfile($vsInstallDir, qw(Common7 IDE devenv.com));
1220     if (-e $vcBuildPath) {
1221         # Visual Studio is installed; we can use pdevenv to build.
1222         # FIXME: Make pdevenv work with non-Cygwin Perl.
1223         $vcBuildPath = File::Spec->catfile(sourceDir(), qw(Tools Scripts pdevenv)) if isCygwin();
1224     } else {
1225         # Visual Studio not found, try VC++ Express
1226         $vcBuildPath = File::Spec->catfile($vsInstallDir, qw(Common7 IDE VCExpress.exe));
1227         if (! -e $vcBuildPath) {
1228             print "*************************************************************\n";
1229             print "Cannot find '$vcBuildPath'\n";
1230             print "Please execute the file 'vcvars32.bat' from\n";
1231             print "'$programFilesPath\\Microsoft Visual Studio 8\\VC\\bin\\'\n";
1232             print "to setup the necessary environment variables.\n";
1233             print "*************************************************************\n";
1234             die;
1235         }
1236         $willUseVCExpressWhenBuilding = 1;
1237     }
1238
1239     my $qtSDKPath = File::Spec->catdir($programFilesPath, "QuickTime SDK");
1240     if (0 && ! -e $qtSDKPath) {
1241         print "*************************************************************\n";
1242         print "Cannot find '$qtSDKPath'\n";
1243         print "Please download the QuickTime SDK for Windows from\n";
1244         print "http://developer.apple.com/quicktime/download/\n";
1245         print "*************************************************************\n";
1246         die;
1247     }
1248     
1249     unless ($ENV{WEBKITLIBRARIESDIR}) {
1250         $ENV{'WEBKITLIBRARIESDIR'} = File::Spec->catdir($sourceDir, "WebKitLibraries", "win");
1251         chomp($ENV{WEBKITLIBRARIESDIR} = `cygpath -wa '$ENV{WEBKITLIBRARIESDIR}'`) if isCygwin();
1252     }
1253
1254     print "Building results into: ", baseProductDir(), "\n";
1255     print "WEBKITOUTPUTDIR is set to: ", $ENV{"WEBKITOUTPUTDIR"}, "\n";
1256     print "WEBKITLIBRARIESDIR is set to: ", $ENV{"WEBKITLIBRARIESDIR"}, "\n";
1257 }
1258
1259 sub dieIfWindowsPlatformSDKNotInstalled
1260 {
1261     my $registry32Path = "/proc/registry/";
1262     my $registry64Path = "/proc/registry64/";
1263     my $windowsPlatformSDKRegistryEntry = "HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/MicrosoftSDK/InstalledSDKs/D2FF9F89-8AA2-4373-8A31-C838BF4DBBE1";
1264
1265     # FIXME: It would be better to detect whether we are using 32- or 64-bit Windows
1266     # and only check the appropriate entry. But for now we just blindly check both.
1267     return if (-e $registry32Path . $windowsPlatformSDKRegistryEntry) || (-e $registry64Path . $windowsPlatformSDKRegistryEntry);
1268
1269     print "*************************************************************\n";
1270     print "Cannot find registry entry '$windowsPlatformSDKRegistryEntry'.\n";
1271     print "Please download and install the Microsoft Windows Server 2003 R2\n";
1272     print "Platform SDK from <http://www.microsoft.com/downloads/details.aspx?\n";
1273     print "familyid=0baf2b35-c656-4969-ace8-e4c0c0716adb&displaylang=en>.\n\n";
1274     print "Then follow step 2 in the Windows section of the \"Installing Developer\n";
1275     print "Tools\" instructions at <http://www.webkit.org/building/tools.html>.\n";
1276     print "*************************************************************\n";
1277     die;
1278 }
1279
1280 sub copyInspectorFrontendFiles
1281 {
1282     my $productDir = productDir();
1283     my $sourceInspectorPath = sourceDir() . "/Source/WebCore/inspector/front-end/";
1284     my $inspectorResourcesDirPath = $ENV{"WEBKITINSPECTORRESOURCESDIR"};
1285
1286     if (!defined($inspectorResourcesDirPath)) {
1287         $inspectorResourcesDirPath = "";
1288     }
1289
1290     if (isAppleMacWebKit()) {
1291         $inspectorResourcesDirPath = $productDir . "/WebCore.framework/Resources/inspector";
1292     } elsif (isAppleWinWebKit()) {
1293         $inspectorResourcesDirPath = $productDir . "/WebKit.resources/inspector";
1294     } elsif (isQt() || isGtk()) {
1295         my $prefix = $ENV{"WebKitInstallationPrefix"};
1296         $inspectorResourcesDirPath = (defined($prefix) ? $prefix : "/usr/share") . "/webkit-1.0/webinspector";
1297     } elsif (isEfl()) {
1298         my $prefix = $ENV{"WebKitInstallationPrefix"};
1299         $inspectorResourcesDirPath = (defined($prefix) ? $prefix : "/usr/share") . "/ewebkit/webinspector";
1300     }
1301
1302     if (! -d $inspectorResourcesDirPath) {
1303         print "*************************************************************\n";
1304         print "Cannot find '$inspectorResourcesDirPath'.\n" if (defined($inspectorResourcesDirPath));
1305         print "Make sure that you have built WebKit first.\n" if (! -d $productDir || defined($inspectorResourcesDirPath));
1306         print "Optionally, set the environment variable 'WebKitInspectorResourcesDir'\n";
1307         print "to point to the directory that contains the WebKit Inspector front-end\n";
1308         print "files for the built WebCore framework.\n";
1309         print "*************************************************************\n";
1310         die;
1311     }
1312     return system "rsync", "-aut", "--exclude=/.DS_Store", "--exclude=*.re2js", "--exclude=.svn/", !isQt() ? "--exclude=/WebKit.qrc" : "", $sourceInspectorPath, $inspectorResourcesDirPath;
1313 }
1314
1315 sub buildXCodeProject($$@)
1316 {
1317     my ($project, $clean, @extraOptions) = @_;
1318
1319     if ($clean) {
1320         push(@extraOptions, "-alltargets");
1321         push(@extraOptions, "clean");
1322     }
1323
1324     return system "xcodebuild", "-project", "$project.xcodeproj", @extraOptions;
1325 }
1326
1327 sub usingVisualStudioExpress()
1328 {
1329     setupCygwinEnv();
1330     return $willUseVCExpressWhenBuilding;
1331 }
1332
1333 sub buildVisualStudioProject
1334 {
1335     my ($project, $clean) = @_;
1336     setupCygwinEnv();
1337
1338     my $config = configurationForVisualStudio();
1339
1340     dieIfWindowsPlatformSDKNotInstalled() if $willUseVCExpressWhenBuilding;
1341
1342     chomp($project = `cygpath -w "$project"`) if isCygwin();
1343     
1344     my $action = "/build";
1345     if ($clean) {
1346         $action = "/clean";
1347     }
1348
1349     my @command = ($vcBuildPath, $project, $action, $config);
1350
1351     print join(" ", @command), "\n";
1352     return system @command;
1353 }
1354
1355 sub downloadWafIfNeeded
1356 {
1357     # get / update waf if needed
1358     my $waf = "$sourceDir/Tools/waf/waf";
1359     my $wafURL = 'http://wxwebkit.kosoftworks.com/downloads/deps/waf';
1360     if (!-f $waf) {
1361         my $result = system "curl -o $waf $wafURL";
1362         chmod 0755, $waf;
1363     }
1364 }
1365
1366 sub buildWafProject
1367 {
1368     my ($project, $shouldClean, @options) = @_;
1369     
1370     # set the PYTHONPATH for waf
1371     my $pythonPath = $ENV{'PYTHONPATH'};
1372     if (!defined($pythonPath)) {
1373         $pythonPath = '';
1374     }
1375     my $sourceDir = sourceDir();
1376     my $newPythonPath = "$sourceDir/Tools/waf/build:$pythonPath";
1377     if (isCygwin()) {
1378         $newPythonPath = `cygpath --mixed --path $newPythonPath`;
1379     }
1380     $ENV{'PYTHONPATH'} = $newPythonPath;
1381     
1382     print "Building $project\n";
1383
1384     my $wafCommand = "$sourceDir/Tools/waf/waf";
1385     if ($ENV{'WXWEBKIT_WAF'}) {
1386         $wafCommand = $ENV{'WXWEBKIT_WAF'};
1387     }
1388     if (isCygwin()) {
1389         $wafCommand = `cygpath --windows "$wafCommand"`;
1390         chomp($wafCommand);
1391     }
1392     if ($shouldClean) {
1393         return system $wafCommand, "uninstall", "clean", "distclean";
1394     }
1395     
1396     return system $wafCommand, 'configure', 'build', 'install', @options;
1397 }
1398
1399 sub retrieveQMakespecVar
1400 {
1401     my $mkspec = $_[0];
1402     my $varname = $_[1];
1403
1404     my $varvalue = undef;
1405     #print "retrieveMakespecVar " . $mkspec . ", " . $varname . "\n";
1406
1407     local *SPEC;
1408     open SPEC, "<$mkspec" or return $varvalue;
1409     while (<SPEC>) {
1410         if ($_ =~ /\s*include\((.+)\)/) {
1411             # open the included mkspec
1412             my $oldcwd = getcwd();
1413             (my $volume, my $directories, my $file) = File::Spec->splitpath($mkspec);
1414             my $newcwd = "$volume$directories";
1415             chdir $newcwd if $newcwd;
1416             $varvalue = retrieveQMakespecVar($1, $varname);
1417             chdir $oldcwd;
1418         } elsif ($_ =~ /$varname\s*=\s*([^\s]+)/) {
1419             $varvalue = $1;
1420             last;
1421         }
1422     }
1423     close SPEC;
1424     return $varvalue;
1425 }
1426
1427 sub qtMakeCommand($)
1428 {
1429     my ($qmakebin) = @_;
1430     chomp(my $mkspec = `$qmakebin -query QMAKE_MKSPECS`);
1431     $mkspec .= "/default";
1432     my $compiler = retrieveQMakespecVar("$mkspec/qmake.conf", "QMAKE_CC");
1433
1434     #print "default spec: " . $mkspec . "\n";
1435     #print "compiler found: " . $compiler . "\n";
1436
1437     if ($compiler && $compiler eq "cl") {
1438         return "nmake";
1439     }
1440
1441     return "make";
1442 }
1443
1444 sub autotoolsFlag($$)
1445 {
1446     my ($flag, $feature) = @_;
1447     my $prefix = $flag ? "--enable" : "--disable";
1448
1449     return $prefix . '-' . $feature;
1450 }
1451
1452 sub runAutogenForAutotoolsProject($@)
1453 {
1454     my ($dir, $prefix, $sourceDir, $saveArguments, $argumentsFile, @buildArgs) = @_;
1455
1456     print "Calling autogen.sh in " . $dir . "\n\n";
1457     print "Installation prefix directory: $prefix\n" if(defined($prefix));
1458
1459     if ($saveArguments) {
1460         # Write autogen.sh arguments to a file so that we can detect
1461         # when they change and automatically re-run it.
1462         open(AUTOTOOLS_ARGUMENTS, ">$argumentsFile");
1463         print AUTOTOOLS_ARGUMENTS join(" ", @buildArgs);
1464         close(AUTOTOOLS_ARGUMENTS);
1465     }
1466
1467     # Make the path relative since it will appear in all -I compiler flags.
1468     # Long argument lists cause bizarre slowdowns in libtool.
1469     my $relSourceDir = File::Spec->abs2rel($sourceDir) || ".";
1470     if (system("$relSourceDir/autogen.sh", @buildArgs) ne 0) {
1471         die "Calling autogen.sh failed!\n";
1472     }
1473 }
1474
1475 sub autogenArgumentsHaveChanged($@)
1476 {
1477     my ($filename, @currentArguments) = @_;
1478
1479     if (! -e $filename) {
1480         return 1;
1481     }
1482
1483     open(AUTOTOOLS_ARGUMENTS, $filename);
1484     chomp(my $previousArguments = <AUTOTOOLS_ARGUMENTS>);
1485     close(AUTOTOOLS_ARGUMENTS);
1486
1487     my $joinedCurrentArguments = join(" ", @currentArguments);
1488     if ($previousArguments ne $joinedCurrentArguments) {
1489         print "Previous autogen arguments were: $previousArguments\n\n";
1490         print "New autogen arguments are: $joinedCurrentArguments\n";
1491         return 1;
1492     }
1493
1494     return 0;
1495 }
1496
1497 sub buildAutotoolsProject($@)
1498 {
1499     my ($project, $clean, @buildParams) = @_;
1500
1501     my $make = 'make';
1502     my $dir = productDir();
1503     my $config = passedConfiguration() || configuration();
1504     my $prefix;
1505
1506     my @buildArgs = ();
1507     my $makeArgs = $ENV{"WebKitMakeArguments"} || "";
1508     for my $i (0 .. $#buildParams) {
1509         my $opt = $buildParams[$i];
1510         if ($opt =~ /^--makeargs=(.*)/i ) {
1511             $makeArgs = $makeArgs . " " . $1;
1512         } elsif ($opt =~ /^--prefix=(.*)/i ) {
1513             $prefix = $1;
1514         } else {
1515             push @buildArgs, $opt;
1516         }
1517     }
1518
1519     # Automatically determine the number of CPUs for make only
1520     # if make arguments haven't already been specified.
1521     if ($makeArgs eq "") {
1522         $makeArgs = "-j" . numberOfCPUs();
1523     }
1524
1525     # WebKit is the default target, so we don't need to specify anything.
1526     if ($project eq "JavaScriptCore") {
1527         $makeArgs .= " jsc";
1528     }
1529
1530     # This is a temporary work-around to enable building WebKit2 on the bots,
1531     # but ensuring that it does not ship until the API is stable.
1532     if ($project eq "WebKit" and isGtk()) {
1533         push @buildArgs, "--enable-webkit2";
1534     }
1535
1536     $prefix = $ENV{"WebKitInstallationPrefix"} if !defined($prefix);
1537     push @buildArgs, "--prefix=" . $prefix if defined($prefix);
1538
1539     # check if configuration is Debug
1540     if ($config =~ m/debug/i) {
1541         push @buildArgs, "--enable-debug";
1542     } else {
1543         push @buildArgs, "--disable-debug";
1544     }
1545
1546     # Use rm to clean the build directory since distclean may miss files
1547     if ($clean && -d $dir) {
1548         system "rm", "-rf", "$dir";
1549     }
1550
1551     if (! -d $dir) {
1552         File::Path::mkpath($dir) or die "Failed to create build directory " . $dir
1553     }
1554     chdir $dir or die "Failed to cd into " . $dir . "\n";
1555
1556     if ($clean) {
1557         return 0;
1558     }
1559
1560     # If GNUmakefile exists, don't run autogen.sh unless its arguments
1561     # have changed. The makefile should be smart enough to track autotools
1562     # dependencies and re-run autogen.sh when build files change.
1563     my $autogenArgumentsFile = "previous-autogen-arguments.txt";
1564     my $saveAutogenArguments = $project eq "WebKit";
1565     if (!(-e "GNUmakefile")) {
1566         runAutogenForAutotoolsProject($dir, $prefix, $sourceDir, $saveAutogenArguments, $autogenArgumentsFile, @buildArgs);
1567     }
1568
1569     if ($saveAutogenArguments and autogenArgumentsHaveChanged($autogenArgumentsFile, @buildArgs)) {
1570         runAutogenForAutotoolsProject($dir, $prefix, $sourceDir, $saveAutogenArguments, $autogenArgumentsFile, @buildArgs);
1571     }
1572
1573     if (system("$make $makeArgs") ne 0) {
1574         die "\nFailed to build WebKit using '$make'!\n";
1575     }
1576
1577     chdir ".." or die;
1578     return 0;
1579 }
1580
1581 sub generateBuildSystemFromCMakeProject
1582 {
1583     my ($port, $prefixPath, @cmakeArgs) = @_;
1584     my $config = configuration();
1585     my $buildPath = File::Spec->catdir(baseProductDir(), $config);
1586     File::Path::mkpath($buildPath) unless -d $buildPath;
1587     my $originalWorkingDirectory = getcwd();
1588     chdir($buildPath) or die;
1589
1590     my @args;
1591     push @args, "-DPORT=\"$port\"";
1592     push @args, "-DCMAKE_INSTALL_PREFIX=\"$prefixPath\"" if $prefixPath;
1593     if ($config =~ /release/i) {
1594         push @args, "-DCMAKE_BUILD_TYPE=Release";
1595     } elsif ($config =~ /debug/i) {
1596         push @args, "-DCMAKE_BUILD_TYPE=Debug";
1597     }
1598     push @args, @cmakeArgs if @cmakeArgs;
1599     push @args, '"' . File::Spec->catdir(sourceDir(), "Source") . '"';
1600
1601     # We call system("cmake @args") instead of system("cmake", @args) so that @args is
1602     # parsed for shell metacharacters.
1603     my $returnCode = system("cmake @args");
1604
1605     chdir($originalWorkingDirectory);
1606     return $returnCode;
1607 }
1608
1609 sub buildCMakeGeneratedProject($)
1610 {
1611     my ($makeArgs) = @_;
1612     my $config = configuration();
1613     my $buildPath = File::Spec->catdir(baseProductDir(), $config);
1614     if (! -d $buildPath) {
1615         die "Must call generateBuildSystemFromCMakeProject() before building CMake project.";
1616     }
1617     my @args = ("--build", $buildPath, "--config", $config);
1618     push @args, ("--", $makeArgs) if $makeArgs;
1619
1620     # We call system("cmake @args") instead of system("cmake", @args) so that @args is
1621     # parsed for shell metacharacters. In particular, $makeArgs may contain such metacharacters.
1622     return system("cmake @args");
1623 }
1624
1625 sub cleanCMakeGeneratedProject()
1626 {
1627     my $config = configuration();
1628     my $buildPath = File::Spec->catdir(baseProductDir(), $config);
1629     if (-d $buildPath) {
1630         return system("cmake", "--build", $buildPath, "--config", $config, "--target", "clean");
1631     }
1632     return 0;
1633 }
1634
1635 sub buildCMakeProjectOrExit($$$$@)
1636 {
1637     my ($clean, $port, $prefixPath, $makeArgs, @cmakeArgs) = @_;
1638     my $returnCode;
1639     if ($clean) {
1640         $returnCode = exitStatus(cleanCMakeGeneratedProject());
1641         exit($returnCode) if $returnCode;
1642     }
1643     $returnCode = exitStatus(generateBuildSystemFromCMakeProject($port, $prefixPath, @cmakeArgs));
1644     exit($returnCode) if $returnCode;
1645     $returnCode = exitStatus(buildCMakeGeneratedProject($makeArgs));
1646     exit($returnCode) if $returnCode;
1647 }
1648
1649 sub buildQMakeProject($@)
1650 {
1651     my ($project, $clean, @buildParams) = @_;
1652
1653     my @subdirs = ("JavaScriptCore", "WebCore", "WebKit/qt/Api");
1654     if (grep { $_ eq $project } @subdirs) {
1655         @subdirs = ($project);
1656     } else {
1657         $project = 0;
1658     }
1659
1660     my @buildArgs = ("-r");
1661
1662     my $makeargs = "";
1663     my $installHeaders;
1664     my $installLibs;
1665     for my $i (0 .. $#buildParams) {
1666         my $opt = $buildParams[$i];
1667         if ($opt =~ /^--qmake=(.*)/i ) {
1668             $qmakebin = $1;
1669         } elsif ($opt =~ /^--qmakearg=(.*)/i ) {
1670             push @buildArgs, $1;
1671         } elsif ($opt =~ /^--makeargs=(.*)/i ) {
1672             $makeargs = $1;
1673         } elsif ($opt =~ /^--install-headers=(.*)/i ) {
1674             $installHeaders = $1;
1675         } elsif ($opt =~ /^--install-libs=(.*)/i ) {
1676             $installLibs = $1;
1677         } else {
1678             push @buildArgs, $opt;
1679         }
1680     }
1681
1682     my $make = qtMakeCommand($qmakebin);
1683     my $config = configuration();
1684     push @buildArgs, "INSTALL_HEADERS=" . $installHeaders if defined($installHeaders);
1685     push @buildArgs, "INSTALL_LIBS=" . $installLibs if defined($installLibs);
1686     my $dir = File::Spec->canonpath(productDir());
1687
1688     my $originalCwd = getcwd();
1689     chdir File::Spec->catfile(sourceDir(), "Source", "WebCore");
1690     my $defaults = `$qmakebin CONFIG+=compute_defaults 2>&1`;
1691     chdir $originalCwd;
1692
1693     # On Symbian qmake needs to run in the same directory where the pro file is located.
1694     if (isSymbian()) {
1695         $dir = $sourceDir . "/Source";
1696     }
1697
1698     File::Path::mkpath($dir);
1699     chdir $dir or die "Failed to cd into " . $dir . "\n";
1700
1701     my $pathToDefaultsTxt = File::Spec->catfile( $dir, "defaults.txt" );
1702     my $defaultsTxt = "";
1703     if(open DEFAULTS, "$pathToDefaultsTxt"){
1704         while (<DEFAULTS>) {
1705             $defaultsTxt .= $_;
1706         }
1707         close (DEFAULTS);
1708     }
1709     # Automatic clean build isn't supported on Symbian yet, see https://bugs.webkit.org/show_bug.cgi?id=67706 for details.
1710     if (($defaults ne $defaultsTxt) and !isSymbian()){
1711         print "Make clean build because the Defines are changed.\n";
1712         chdir $originalCwd;
1713         File::Path::rmtree($dir);
1714         File::Path::mkpath($dir);
1715         chdir $dir or die "Failed to cd into " . $dir . "\n";
1716         open DEFAULTS, ">$pathToDefaultsTxt";
1717         print DEFAULTS $defaults;
1718         close (DEFAULTS);
1719     }
1720
1721     print "Generating derived sources\n\n";
1722
1723     push @buildArgs, "OUTPUT_DIR=" . $dir;
1724
1725     my @dsQmakeArgs = @buildArgs;
1726     push @dsQmakeArgs, "-r";
1727     push @dsQmakeArgs, sourceDir() . "/Source/DerivedSources.pro";
1728     if ($project) {
1729         push @dsQmakeArgs, "-after SUBDIRS=" . $project. "/DerivedSources.pro";
1730     }
1731     push @dsQmakeArgs, "-o Makefile.DerivedSources";
1732     print "Calling '$qmakebin @dsQmakeArgs' in " . $dir . "\n\n";
1733     my $result = system "$qmakebin @dsQmakeArgs";
1734     if ($result ne 0) {
1735         die "Failed while running $qmakebin to generate derived sources!\n";
1736     }
1737
1738     if ($project ne "JavaScriptCore") {
1739         # FIXME: Iterate over different source directories manually to workaround a problem with qmake+extraTargets+s60
1740         # To avoid overwriting of Makefile.DerivedSources in the root dir use Makefile.DerivedSources.Tools for Tools
1741         if (grep { $_ eq "CONFIG+=webkit2"} @buildArgs) {
1742             push @subdirs, "WebKit2";
1743             if ( -e sourceDir() ."/Tools/DerivedSources.pro" ) {
1744                 @dsQmakeArgs = @buildArgs;
1745                 push @dsQmakeArgs, "-r";
1746                 push @dsQmakeArgs, sourceDir() . "/Tools/DerivedSources.pro";
1747                 push @dsQmakeArgs, "-o Makefile.DerivedSources.Tools";
1748                 print "Calling '$qmakebin @dsQmakeArgs' in " . $dir . "\n\n";
1749                 my $result = system "$qmakebin @dsQmakeArgs";
1750                 if ($result ne 0) {
1751                     die "Failed while running $qmakebin to generate derived sources for Tools!\n";
1752                 }
1753                 push @subdirs, "WebKitTestRunner";
1754             }
1755         }
1756     }
1757
1758     for my $subdir (@subdirs) {
1759         my $dsMakefile = "Makefile.DerivedSources";
1760         print "Calling '$make $makeargs -C $subdir -f $dsMakefile generated_files' in " . $dir . "/$subdir\n\n";
1761         if ($make eq "nmake") {
1762             my $subdirWindows = $subdir;
1763             $subdirWindows =~ s:/:\\:g;
1764             $result = system "pushd $subdirWindows && $make $makeargs -f $dsMakefile generated_files && popd";
1765         } else {
1766             $result = system "$make $makeargs -C $subdir -f $dsMakefile generated_files";
1767         }
1768         if ($result ne 0) {
1769             die "Failed to generate ${subdir}'s derived sources!\n";
1770         }
1771     }
1772
1773     if ($config =~ m/debug/i) {
1774         push @buildArgs, "CONFIG-=release";
1775         push @buildArgs, "CONFIG+=debug";
1776     } else {
1777         my $passedConfig = passedConfiguration() || "";
1778         if (!isDarwin() || $passedConfig =~ m/release/i) {
1779             push @buildArgs, "CONFIG+=release";
1780             push @buildArgs, "CONFIG-=debug";
1781         } else {
1782             push @buildArgs, "CONFIG+=debug";
1783             push @buildArgs, "CONFIG+=debug_and_release";
1784         }
1785     }
1786
1787     if ($project) {
1788         push @buildArgs, "-after SUBDIRS=" . $project . "/" . $project . ".pro ";
1789         if ($project eq "JavaScriptCore") {
1790             push @buildArgs, "-after SUBDIRS+=" . $project . "/jsc.pro ";
1791         }
1792     }
1793     push @buildArgs, sourceDir() . "/Source/WebKit.pro";
1794     print "Calling '$qmakebin @buildArgs' in " . $dir . "\n\n";
1795     print "Installation headers directory: $installHeaders\n" if(defined($installHeaders));
1796     print "Installation libraries directory: $installLibs\n" if(defined($installLibs));
1797
1798     $result = system "$qmakebin @buildArgs";
1799     if ($result ne 0) {
1800        die "Failed to setup build environment using $qmakebin!\n";
1801     }
1802
1803     my $makefile = "";
1804     if (!$project) {
1805         $buildArgs[-1] = sourceDir() . "/Tools/Tools.pro";
1806         $makefile = "Makefile.Tools";
1807
1808         # On Symbian qmake needs to run in the same directory where the pro file is located.
1809         if (isSymbian()) {
1810             $dir = $sourceDir . "/Tools";
1811             chdir $dir or die "Failed to cd into " . $dir . "\n";
1812             $makefile = "bld.inf";
1813         }
1814
1815         print "Calling '$qmakebin @buildArgs -o $makefile' in " . $dir . "\n\n";
1816         $result = system "$qmakebin @buildArgs -o $makefile";
1817         if ($result ne 0) {
1818             die "Failed to setup build environment using $qmakebin!\n";
1819         }
1820     }
1821
1822     if (!$project) {
1823         # Manually create makefiles for the examples so we don't build by default
1824         my $examplesDir = $dir . "/WebKit/qt/examples";
1825         File::Path::mkpath($examplesDir);
1826         $buildArgs[-1] = sourceDir() . "/Source/WebKit/qt/examples/examples.pro";
1827         chdir $examplesDir or die;
1828         print "Calling '$qmakebin @buildArgs' in " . $examplesDir . "\n\n";
1829         $result = system "$qmakebin @buildArgs";
1830         die "Failed to create makefiles for the examples!\n" if $result ne 0;
1831         chdir $dir or die;
1832     }
1833
1834     my $makeTools = "echo";
1835     if (!$project) {
1836         $makeTools = "echo No Makefile for Tools. Skipping make";
1837
1838         if (-e "$dir/$makefile") {
1839             $makeTools = "$make $makeargs -f $makefile";
1840         }
1841     }
1842
1843     if ($clean) {
1844       print "Calling '$make $makeargs distclean' in " . $dir . "\n\n";
1845       $result = system "$make $makeargs distclean";
1846       $result = $result || system "$makeTools distclean";
1847     } elsif (isSymbian()) {
1848       print "\n\nWebKit is now configured for building, but you have to make\n";
1849       print "a choice about the target yourself. To start the build run:\n\n";
1850       print "    make release-armv5|debug-winscw|etc.\n\n";
1851     } else {
1852       print "Calling '$make $makeargs' in " . $dir . "\n\n";
1853       $result = system "$make $makeargs";
1854       $result = $result || system "$makeTools";
1855     }
1856
1857     chdir ".." or die;
1858     return $result;
1859 }
1860
1861 sub buildQMakeQtProject($$@)
1862 {
1863     my ($project, $clean, @buildArgs) = @_;
1864
1865     return buildQMakeProject("", $clean, @buildArgs);
1866 }
1867
1868 sub buildGtkProject
1869 {
1870     my ($project, $clean, @buildArgs) = @_;
1871
1872     if ($project ne "WebKit" and $project ne "JavaScriptCore") {
1873         die "Unsupported project: $project. Supported projects: WebKit, JavaScriptCore\n";
1874     }
1875
1876     return buildAutotoolsProject($project, $clean, @buildArgs);
1877 }
1878
1879 sub buildChromiumMakefile($$@)
1880 {
1881     my ($target, $clean, @options) = @_;
1882     if ($clean) {
1883         return system qw(rm -rf out);
1884     }
1885     my $config = configuration();
1886     my $numCpus = numberOfCPUs();
1887     my $makeArgs;
1888     for (@options) {
1889         $makeArgs = $1 if /^--makeargs=(.*)/i;
1890     }
1891     $makeArgs = "-j$numCpus" if not $makeArgs;
1892     my $command = "make -fMakefile.chromium $makeArgs BUILDTYPE=$config $target";
1893     print "$command\n";
1894     return system $command;
1895 }
1896
1897 sub buildChromiumVisualStudioProject($$)
1898 {
1899     my ($projectPath, $clean) = @_;
1900
1901     my $config = configuration();
1902     my $action = "/build";
1903     $action = "/clean" if $clean;
1904
1905     # Find Visual Studio installation.
1906     my $vsInstallDir;
1907     my $programFilesPath = $ENV{'PROGRAMFILES'} || "C:\\Program Files";
1908     if ($ENV{'VSINSTALLDIR'}) {
1909         $vsInstallDir = $ENV{'VSINSTALLDIR'};
1910     } else {
1911         $vsInstallDir = "$programFilesPath/Microsoft Visual Studio 8";
1912     }
1913     $vsInstallDir = `cygpath "$vsInstallDir"` if isCygwin();
1914     chomp $vsInstallDir;
1915     $vcBuildPath = "$vsInstallDir/Common7/IDE/devenv.com";
1916     if (! -e $vcBuildPath) {
1917         # Visual Studio not found, try VC++ Express
1918         $vcBuildPath = "$vsInstallDir/Common7/IDE/VCExpress.exe";
1919         if (! -e $vcBuildPath) {
1920             print "*************************************************************\n";
1921             print "Cannot find '$vcBuildPath'\n";
1922             print "Please execute the file 'vcvars32.bat' from\n";
1923             print "'$programFilesPath\\Microsoft Visual Studio 8\\VC\\bin\\'\n";
1924             print "to setup the necessary environment variables.\n";
1925             print "*************************************************************\n";
1926             die;
1927         }
1928     }
1929
1930     # Create command line and execute it.
1931     my @command = ($vcBuildPath, $projectPath, $action, $config);
1932     print "Building results into: ", baseProductDir(), "\n";
1933     print join(" ", @command), "\n";
1934     return system @command;
1935 }
1936
1937 sub buildChromium($@)
1938 {
1939     my ($clean, @options) = @_;
1940
1941     # We might need to update DEPS or re-run GYP if things have changed.
1942     if (checkForArgumentAndRemoveFromArrayRef("--update-chromium", \@options)) {
1943         system("perl", "Tools/Scripts/update-webkit-chromium") == 0 or die $!;
1944     }
1945
1946     my $result = 1;
1947     if (isChromiumAndroid()) {
1948         # Building Chromium for Android needs to cross-compile using the
1949         # Toolchains supplied by the Android NDK.
1950         my $ndkBaseDir = sourceDir() . "/Source/WebKit/chromium/third_party/android-ndk-r6";
1951         my $platform = isDarwin() ? "darwin-x86" : "linux-x86";
1952
1953         my $toolchainBase = $ndkBaseDir . "/toolchains/arm-linux-androideabi-4.4.3/prebuilt/" . $platform . "/bin/arm-linux-androideabi-";
1954
1955         $ENV{AR} = $toolchainBase . "ar";
1956         $ENV{CC} = $toolchainBase . "gcc";
1957         $ENV{CXX} = $toolchainBase . "g++";
1958         $ENV{LINK} = $toolchainBase . "gcc";
1959         $ENV{RANLIB} = $toolchainBase . "ranlib";
1960         $ENV{STRIP} = $toolchainBase . "strip";
1961
1962         $result = buildChromiumMakefile("all", $clean);
1963     } elsif (isDarwin()) {
1964         # Mac build - builds the root xcode project.
1965         $result = buildXCodeProject("Source/WebKit/chromium/WebKit", $clean, "-configuration", configuration(), @options);
1966     } elsif (isCygwin() || isWindows()) {
1967         # Windows build - builds the root visual studio solution.
1968         $result = buildChromiumVisualStudioProject("Source/WebKit/chromium/WebKit.sln", $clean);
1969     } elsif (isLinux()) {
1970         # Linux build - build using make.
1971         $result = buildChromiumMakefile("all", $clean, @options);
1972     } else {
1973         print STDERR "This platform is not supported by chromium.\n";
1974     }
1975     return $result;
1976 }
1977
1978 sub appleApplicationSupportPath
1979 {
1980     open INSTALL_DIR, "</proc/registry/HKEY_LOCAL_MACHINE/SOFTWARE/Apple\ Inc./Apple\ Application\ Support/InstallDir";
1981     my $path = <INSTALL_DIR>;
1982     $path =~ s/[\r\n\x00].*//;
1983     close INSTALL_DIR;
1984
1985     my $unixPath = `cygpath -u '$path'`;
1986     chomp $unixPath;
1987     return $unixPath;
1988 }
1989
1990 sub setPathForRunningWebKitApp
1991 {
1992     my ($env) = @_;
1993
1994     if (isAppleWinWebKit()) {
1995         $env->{PATH} = join(':', productDir(), dirname(installedSafariPath()), appleApplicationSupportPath(), $env->{PATH} || "");
1996     } elsif (isQt()) {
1997         my $qtLibs = `$qmakebin -query QT_INSTALL_LIBS`;
1998         $qtLibs =~ s/[\n|\r]$//g;
1999         $env->{PATH} = join(';', $qtLibs, productDir() . "/lib", $env->{PATH} || "");
2000     }
2001 }
2002
2003 sub runSafari
2004 {
2005     my ($debugger) = @_;
2006
2007     if (isAppleMacWebKit()) {
2008         return system "$FindBin::Bin/gdb-safari", argumentsForConfiguration() if $debugger;
2009
2010         my $productDir = productDir();
2011         print "Starting Safari with DYLD_FRAMEWORK_PATH set to point to built WebKit in $productDir.\n";
2012         $ENV{DYLD_FRAMEWORK_PATH} = $productDir;
2013         $ENV{WEBKIT_UNSET_DYLD_FRAMEWORK_PATH} = "YES";
2014         if (architecture()) {
2015             return system "arch", "-" . architecture(), safariPath(), @ARGV;
2016         } else {
2017             return system safariPath(), @ARGV;
2018         }
2019     }
2020
2021     if (isAppleWinWebKit()) {
2022         my $result;
2023         my $productDir = productDir();
2024         if ($debugger) {
2025             setupCygwinEnv();
2026             chomp($ENV{WEBKITNIGHTLY} = `cygpath -wa "$productDir"`);
2027             my $safariPath = safariPath();
2028             chomp($safariPath = `cygpath -wa "$safariPath"`);
2029             $result = system $vcBuildPath, "/debugexe", "\"$safariPath\"", @ARGV;
2030         } else {
2031             $result = system File::Spec->catfile(productDir(), "WebKit.exe"), @ARGV;
2032         }
2033         return $result if $result;
2034     }
2035
2036     return 1;
2037 }
2038
2039 sub runMiniBrowser
2040 {
2041     if (isAppleMacWebKit()) {
2042         my $productDir = productDir();
2043         print "Starting MiniBrowser with DYLD_FRAMEWORK_PATH set to point to $productDir.\n";
2044         $ENV{DYLD_FRAMEWORK_PATH} = $productDir;
2045         $ENV{WEBKIT_UNSET_DYLD_FRAMEWORK_PATH} = "YES";
2046         my $miniBrowserPath = "$productDir/MiniBrowser.app/Contents/MacOS/MiniBrowser";
2047         if (architecture()) {
2048             return system "arch", "-" . architecture(), $miniBrowserPath, @ARGV;
2049         } else {
2050             return system $miniBrowserPath, @ARGV;
2051         }
2052     }
2053
2054     return 1;
2055 }
2056
2057 sub debugMiniBrowser
2058 {
2059     if (isAppleMacWebKit()) {
2060         my $gdbPath = "/usr/bin/gdb";
2061         die "Can't find gdb executable. Is gdb installed?\n" unless -x $gdbPath;
2062
2063         my $productDir = productDir();
2064
2065         $ENV{DYLD_FRAMEWORK_PATH} = $productDir;
2066         $ENV{WEBKIT_UNSET_DYLD_FRAMEWORK_PATH} = 'YES';
2067
2068         my $miniBrowserPath = "$productDir/MiniBrowser.app/Contents/MacOS/MiniBrowser";
2069
2070         print "Starting MiniBrowser under gdb with DYLD_FRAMEWORK_PATH set to point to built WebKit2 in $productDir.\n";
2071         my @architectureFlags = ("-arch", architecture());
2072         exec $gdbPath, @architectureFlags, $miniBrowserPath or die;
2073         return;
2074     }
2075     
2076     return 1;
2077 }
2078
2079 sub runWebKitTestRunner
2080 {
2081     if (isAppleMacWebKit()) {
2082         my $productDir = productDir();
2083         print "Starting WebKitTestRunner with DYLD_FRAMEWORK_PATH set to point to $productDir.\n";
2084         $ENV{DYLD_FRAMEWORK_PATH} = $productDir;
2085         $ENV{WEBKIT_UNSET_DYLD_FRAMEWORK_PATH} = "YES";
2086         my $webKitTestRunnerPath = "$productDir/WebKitTestRunner";
2087         if (architecture()) {
2088             return system "arch", "-" . architecture(), $webKitTestRunnerPath, @ARGV;
2089         } else {
2090             return system $webKitTestRunnerPath, @ARGV;
2091         }
2092     } elsif (isGtk()) {
2093         my $productDir = productDir();
2094         my $injectedBundlePath = "$productDir/Libraries/.libs/libTestRunnerInjectedBundle";
2095         print "Starting WebKitTestRunner with TEST_RUNNER_INJECTED_BUNDLE_FILENAME set to point to $injectedBundlePath.\n";
2096         $ENV{TEST_RUNNER_INJECTED_BUNDLE_FILENAME} = $injectedBundlePath;
2097         my @args = ("$productDir/Programs/WebKitTestRunner", @ARGV);
2098         return system {$args[0] } @args;
2099     }
2100
2101     return 1;
2102 }
2103
2104 sub debugWebKitTestRunner
2105 {
2106     if (isAppleMacWebKit()) {
2107         my $gdbPath = "/usr/bin/gdb";
2108         die "Can't find gdb executable. Is gdb installed?\n" unless -x $gdbPath;
2109
2110         my $productDir = productDir();
2111         $ENV{DYLD_FRAMEWORK_PATH} = $productDir;
2112         $ENV{WEBKIT_UNSET_DYLD_FRAMEWORK_PATH} = 'YES';
2113
2114         my $webKitTestRunnerPath = "$productDir/WebKitTestRunner";
2115
2116         print "Starting WebKitTestRunner under gdb with DYLD_FRAMEWORK_PATH set to point to $productDir.\n";
2117         my @architectureFlags = ("-arch", architecture());
2118         exec $gdbPath, @architectureFlags, $webKitTestRunnerPath or die;
2119         return;
2120     }
2121
2122     return 1;
2123 }
2124
2125 sub runTestWebKitAPI
2126 {
2127     if (isAppleMacWebKit()) {
2128         my $productDir = productDir();
2129         print "Starting TestWebKitAPI with DYLD_FRAMEWORK_PATH set to point to $productDir.\n";
2130         $ENV{DYLD_FRAMEWORK_PATH} = $productDir;
2131         $ENV{WEBKIT_UNSET_DYLD_FRAMEWORK_PATH} = "YES";
2132         my $testWebKitAPIPath = "$productDir/TestWebKitAPI";
2133         if (architecture()) {
2134             return system "arch", "-" . architecture(), $testWebKitAPIPath, @ARGV;
2135         } else {
2136             return system $testWebKitAPIPath, @ARGV;
2137         }
2138     }
2139
2140     return 1;
2141 }
2142
2143 1;