[GTK] Enable introspection always for developer builds
[WebKit-https.git] / Tools / Scripts / webkitdirs.pm
1 # Copyright (C) 2005, 2006, 2007, 2010, 2011, 2012 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 version;
33 use warnings;
34 use Config;
35 use Digest::MD5 qw(md5_hex);
36 use FindBin;
37 use File::Basename;
38 use File::Path qw(mkpath rmtree);
39 use File::Spec;
40 use File::stat;
41 use POSIX;
42 use VCSUtils;
43
44 BEGIN {
45    use Exporter   ();
46    our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
47    $VERSION     = 1.00;
48    @ISA         = qw(Exporter);
49    @EXPORT      = qw(
50        &XcodeOptionString
51        &XcodeOptionStringNoConfig
52        &XcodeOptions
53        &baseProductDir
54        &chdirWebKit
55        &checkFrameworks
56        &cmakeBasedPortArguments
57        &cmakeBasedPortName
58        &currentSVNRevision
59        &debugSafari
60        &nmPath
61        &passedConfiguration
62        &printHelpAndExitForRunAndDebugWebKitAppIfNeeded
63        &productDir
64        &runMacWebKitApp
65        &safariPath
66        &setConfiguration
67        USE_OPEN_COMMAND
68    );
69    %EXPORT_TAGS = ( );
70    @EXPORT_OK   = ();
71 }
72
73 use constant USE_OPEN_COMMAND => 1; # Used in runMacWebKitApp().
74 use constant INCLUDE_OPTIONS_FOR_DEBUGGING => 1;
75
76 our @EXPORT_OK;
77
78 my $architecture;
79 my $numberOfCPUs;
80 my $baseProductDir;
81 my @baseProductDirOption;
82 my $configuration;
83 my $xcodeSDK;
84 my $configurationForVisualStudio;
85 my $configurationProductDir;
86 my $sourceDir;
87 my $currentSVNRevision;
88 my $debugger;
89 my $nmPath;
90 my $osXVersion;
91 my $generateDsym;
92 my $isQt;
93 my $qmakebin = "qmake"; # Allow override of the qmake binary from $PATH
94 my $isGtk;
95 my $isWinCE;
96 my $isWinCairo;
97 my $isWx;
98 my $isEfl;
99 my @wxArgs;
100 my $isBlackBerry;
101 my $isChromium;
102 my $isChromiumAndroid;
103 my $isChromiumMacMake;
104 my $isChromiumNinja;
105 my $forceChromiumUpdate;
106 my $isInspectorFrontend;
107 my $isWK2;
108 my $shouldTargetWebProcess;
109 my $shouldUseXPCServiceForWebProcess;
110 my $shouldUseGuardMalloc;
111 my $xcodeVersion;
112
113 # Variables for Win32 support
114 my $vcBuildPath;
115 my $windowsSourceDir;
116 my $winVersion;
117 my $willUseVCExpressWhenBuilding = 0;
118
119 # Defined in VCSUtils.
120 sub exitStatus($);
121
122 sub determineSourceDir
123 {
124     return if $sourceDir;
125     $sourceDir = $FindBin::Bin;
126     $sourceDir =~ s|/+$||; # Remove trailing '/' as we would die later
127
128     # walks up path checking each directory to see if it is the main WebKit project dir, 
129     # defined by containing Sources, WebCore, and WebKit
130     until ((-d "$sourceDir/Source" && -d "$sourceDir/Source/WebCore" && -d "$sourceDir/Source/WebKit") || (-d "$sourceDir/Internal" && -d "$sourceDir/OpenSource"))
131     {
132         if ($sourceDir !~ s|/[^/]+$||) {
133             die "Could not find top level webkit directory above source directory using FindBin.\n";
134         }
135     }
136
137     $sourceDir = "$sourceDir/OpenSource" if -d "$sourceDir/OpenSource";
138 }
139
140 sub currentPerlPath()
141 {
142     my $thisPerl = $^X;
143     if ($^O ne 'VMS') {
144         $thisPerl .= $Config{_exe} unless $thisPerl =~ m/$Config{_exe}$/i;
145     }
146     return $thisPerl;
147 }
148
149 sub setQmakeBinaryPath($)
150 {
151     ($qmakebin) = @_;
152 }
153
154 # used for scripts which are stored in a non-standard location
155 sub setSourceDir($)
156 {
157     ($sourceDir) = @_;
158 }
159
160 sub determineXcodeVersion
161 {
162     return if defined $xcodeVersion;
163     my $xcodebuildVersionOutput = `xcodebuild -version`;
164     $xcodeVersion = ($xcodebuildVersionOutput =~ /Xcode ([0-9](\.[0-9]+)*)/) ? $1 : "3.0";
165 }
166
167 sub readXcodeUserDefault($)
168 {
169     my ($unprefixedKey) = @_;
170
171     determineXcodeVersion();
172
173     my $xcodeDefaultsDomain = (eval "v$xcodeVersion" lt v4) ? "com.apple.Xcode" : "com.apple.dt.Xcode";
174     my $xcodeDefaultsPrefix = (eval "v$xcodeVersion" lt v4) ? "PBX" : "IDE";
175     my $devnull = File::Spec->devnull();
176
177     my $value = `defaults read $xcodeDefaultsDomain ${xcodeDefaultsPrefix}${unprefixedKey} 2> ${devnull}`;
178     return if $?;
179
180     chomp $value;
181     return $value;
182 }
183
184 sub determineBaseProductDir
185 {
186     return if defined $baseProductDir;
187     determineSourceDir();
188
189     my $setSharedPrecompsDir;
190     $baseProductDir = $ENV{"WEBKITOUTPUTDIR"}; # FIXME: Switch to WEBKIT_OUTPUTDIR as part of https://bugs.webkit.org/show_bug.cgi?id=109472
191
192     if (!defined($baseProductDir) and isAppleMacWebKit()) {
193         # Silently remove ~/Library/Preferences/xcodebuild.plist which can
194         # cause build failure. The presence of
195         # ~/Library/Preferences/xcodebuild.plist can prevent xcodebuild from
196         # respecting global settings such as a custom build products directory
197         # (<rdar://problem/5585899>).
198         my $personalPlistFile = $ENV{HOME} . "/Library/Preferences/xcodebuild.plist";
199         if (-e $personalPlistFile) {
200             unlink($personalPlistFile) || die "Could not delete $personalPlistFile: $!";
201         }
202
203         determineXcodeVersion();
204
205         if (eval "v$xcodeVersion" ge v4) {
206             my $buildLocationStyle = join '', readXcodeUserDefault("BuildLocationStyle");
207             if ($buildLocationStyle eq "Custom") {
208                 my $buildLocationType = join '', readXcodeUserDefault("CustomBuildLocationType");
209                 # FIXME: Read CustomBuildIntermediatesPath and set OBJROOT accordingly.
210                 $baseProductDir = readXcodeUserDefault("CustomBuildProductsPath") if $buildLocationType eq "Absolute";
211             }
212
213             # DeterminedByTargets corresponds to a setting of "Legacy" in Xcode.
214             # It is the only build location style for which SHARED_PRECOMPS_DIR is not
215             # overridden when building from within Xcode.
216             $setSharedPrecompsDir = 1 if $buildLocationStyle ne "DeterminedByTargets";
217         }
218
219         if (!defined($baseProductDir)) {
220             $baseProductDir = join '', readXcodeUserDefault("ApplicationwideBuildSettings");
221             $baseProductDir = $1 if $baseProductDir =~ /SYMROOT\s*=\s*\"(.*?)\";/s;
222         }
223
224         undef $baseProductDir unless $baseProductDir =~ /^\//;
225     } elsif (isChromium()) {
226         if (isLinux() || isChromiumAndroid() || isChromiumMacMake() || isChromiumNinja()) {
227             $baseProductDir = "$sourceDir/out";
228         } elsif (isDarwin()) {
229             $baseProductDir = "$sourceDir/Source/WebKit/chromium/xcodebuild";
230         } elsif (isWindows() || isCygwin()) {
231             $baseProductDir = "$sourceDir/Source/WebKit/chromium/build";
232         }
233     }
234
235     if (!defined($baseProductDir)) { # Port-specific checks failed, use default
236         $baseProductDir = "$sourceDir/WebKitBuild";
237     }
238
239     if (isBlackBerry()) {
240         my %archInfo = blackberryTargetArchitecture();
241         $baseProductDir = "$baseProductDir/" . $archInfo{"cpuDir"};
242     }
243
244     if (isGit() && isGitBranchBuild() && !isChromium()) {
245         my $branch = gitBranch();
246         $baseProductDir = "$baseProductDir/$branch";
247     }
248
249     if (isAppleMacWebKit()) {
250         $baseProductDir =~ s|^\Q$(SRCROOT)/..\E$|$sourceDir|;
251         $baseProductDir =~ s|^\Q$(SRCROOT)/../|$sourceDir/|;
252         $baseProductDir =~ s|^~/|$ENV{HOME}/|;
253         die "Can't handle Xcode product directory with a ~ in it.\n" if $baseProductDir =~ /~/;
254         die "Can't handle Xcode product directory with a variable in it.\n" if $baseProductDir =~ /\$/;
255         @baseProductDirOption = ("SYMROOT=$baseProductDir", "OBJROOT=$baseProductDir");
256         push(@baseProductDirOption, "SHARED_PRECOMPS_DIR=${baseProductDir}/PrecompiledHeaders") if $setSharedPrecompsDir;
257     }
258
259     if (isCygwin()) {
260         my $dosBuildPath = `cygpath --windows \"$baseProductDir\"`;
261         chomp $dosBuildPath;
262         $ENV{"WEBKITOUTPUTDIR"} = $dosBuildPath;
263         $ENV{"WEBKIT_OUTPUTDIR"} = $dosBuildPath;
264         my $unixBuildPath = `cygpath --unix \"$baseProductDir\"`;
265         chomp $unixBuildPath;
266         $baseProductDir = $unixBuildPath;
267     }
268 }
269
270 sub setBaseProductDir($)
271 {
272     ($baseProductDir) = @_;
273 }
274
275 sub determineConfiguration
276 {
277     return if defined $configuration;
278     determineBaseProductDir();
279     if (open CONFIGURATION, "$baseProductDir/Configuration") {
280         $configuration = <CONFIGURATION>;
281         close CONFIGURATION;
282     }
283     if ($configuration) {
284         chomp $configuration;
285         # compatibility for people who have old Configuration files
286         $configuration = "Release" if $configuration eq "Deployment";
287         $configuration = "Debug" if $configuration eq "Development";
288     } else {
289         $configuration = "Release";
290     }
291
292     if ($configuration && isWinCairo()) {
293         unless ($configuration =~ /_Cairo_CFLite$/) {
294             $configuration .= "_Cairo_CFLite";
295         }
296     }
297 }
298
299 sub determineArchitecture
300 {
301     return if defined $architecture;
302     # make sure $architecture is defined in all cases
303     $architecture = "";
304
305     determineBaseProductDir();
306     determineXcodeSDK();
307
308     if (isGtk()) {
309         determineConfigurationProductDir();
310         my $host_triple = `grep -E '^host = ' $configurationProductDir/GNUmakefile`;
311         if ($host_triple =~ m/^host = ([^-]+)-/) {
312             # We have a configured build tree; use it.
313             $architecture = $1;
314         }
315     } elsif (isAppleMacWebKit()) {
316         if (open ARCHITECTURE, "$baseProductDir/Architecture") {
317             $architecture = <ARCHITECTURE>;
318             close ARCHITECTURE;
319         }
320         if ($architecture) {
321             chomp $architecture;
322         } else {
323             if (not defined $xcodeSDK or $xcodeSDK =~ /^(\/$|macosx)/) {
324                 my $supports64Bit = `sysctl -n hw.optional.x86_64`;
325                 chomp $supports64Bit;
326                 $architecture = 'x86_64' if $supports64Bit;
327             } elsif ($xcodeSDK =~ /^iphonesimulator/) {
328                 $architecture = 'i386';
329             } elsif ($xcodeSDK =~ /^iphoneos/) {
330                 $architecture = 'armv7';
331             }
332         }
333     } elsif (isEfl()) {
334         my $host_processor = "";
335         $host_processor = `cmake --system-information | grep CMAKE_SYSTEM_PROCESSOR`;
336         if ($host_processor =~ m/^CMAKE_SYSTEM_PROCESSOR \"([^"]+)\"/) {
337             # We have a configured build tree; use it.
338             $architecture = $1;
339             $architecture = 'x86_64' if $architecture eq 'amd64';
340         }
341     }
342
343     if (!$architecture && (isGtk() || isAppleMacWebKit() || isEfl())) {
344         # Fall back to output of `arch', if it is present.
345         $architecture = `arch`;
346         chomp $architecture;
347     }
348
349     if (!$architecture && (isGtk() || isAppleMacWebKit() || isEfl())) {
350         # Fall back to output of `uname -m', if it is present.
351         $architecture = `uname -m`;
352         chomp $architecture;
353     }
354 }
355
356 sub determineNumberOfCPUs
357 {
358     return if defined $numberOfCPUs;
359     if (defined($ENV{NUMBER_OF_PROCESSORS})) {
360         $numberOfCPUs = $ENV{NUMBER_OF_PROCESSORS};
361     } elsif (isLinux()) {
362         # First try the nproc utility, if it exists. If we get no
363         # results fall back to just interpretting /proc directly.
364         chomp($numberOfCPUs = `nproc --all 2> /dev/null`);
365         if ($numberOfCPUs eq "") {
366             $numberOfCPUs = (grep /processor/, `cat /proc/cpuinfo`);
367         }
368     } elsif (isWindows() || isCygwin()) {
369         # Assumes cygwin
370         $numberOfCPUs = `ls /proc/registry/HKEY_LOCAL_MACHINE/HARDWARE/DESCRIPTION/System/CentralProcessor | wc -w`;
371     } elsif (isDarwin() || isFreeBSD()) {
372         chomp($numberOfCPUs = `sysctl -n hw.ncpu`);
373     }
374 }
375
376 sub jscPath($)
377 {
378     my ($productDir) = @_;
379     my $jscName = "jsc";
380     $jscName .= "_debug"  if configurationForVisualStudio() eq "Debug_All";
381     $jscName .= ".exe" if (isWindows() || isCygwin());
382     return "$productDir/$jscName" if -e "$productDir/$jscName";
383     return "$productDir/JavaScriptCore.framework/Resources/$jscName";
384 }
385
386 sub argumentsForConfiguration()
387 {
388     determineConfiguration();
389     determineArchitecture();
390
391     my @args = ();
392     push(@args, '--debug') if $configuration eq "Debug";
393     push(@args, '--release') if $configuration eq "Release";
394     push(@args, '--32-bit') if $architecture ne "x86_64";
395     push(@args, '--qt') if isQt();
396     push(@args, '--gtk') if isGtk();
397     push(@args, '--efl') if isEfl();
398     push(@args, '--wincairo') if isWinCairo();
399     push(@args, '--wince') if isWinCE();
400     push(@args, '--wx') if isWx();
401     push(@args, '--blackberry') if isBlackBerry();
402     push(@args, '--chromium') if isChromium() && !isChromiumAndroid();
403     push(@args, '--chromium-android') if isChromiumAndroid();
404     push(@args, '--inspector-frontend') if isInspectorFrontend();
405     return @args;
406 }
407
408 sub determineXcodeSDK
409 {
410     return if defined $xcodeSDK;
411     for (my $i = 0; $i <= $#ARGV; $i++) {
412         my $opt = $ARGV[$i];
413         if ($opt =~ /^--sdk$/i) {
414             splice(@ARGV, $i, 1);
415             $xcodeSDK = splice(@ARGV, $i, 1);
416         } elsif ($opt =~ /^--device$/i) {
417             splice(@ARGV, $i, 1);
418             $xcodeSDK = 'iphoneos.internal';
419         } elsif ($opt =~ /^--sim(ulator)?/i) {
420             splice(@ARGV, $i, 1);
421             $xcodeSDK = 'iphonesimulator';
422         }
423     }
424 }
425
426 sub xcodeSDK
427 {
428     determineXcodeSDK();
429     return $xcodeSDK;
430 }
431
432 sub determineConfigurationForVisualStudio
433 {
434     return if defined $configurationForVisualStudio;
435     determineConfiguration();
436     # FIXME: We should detect when Debug_All or Production has been chosen.
437     $configurationForVisualStudio = $configuration;
438 }
439
440 sub usesPerConfigurationBuildDirectory
441 {
442     # [Gtk] We don't have Release/Debug configurations in straight
443     # autotool builds (non build-webkit). In this case and if
444     # WEBKITOUTPUTDIR exist, use that as our configuration dir. This will
445     # allows us to run run-webkit-tests without using build-webkit.
446     return ($ENV{"WEBKITOUTPUTDIR"} && isGtk()) || isAppleWinWebKit();
447 }
448
449 sub determineConfigurationProductDir
450 {
451     return if defined $configurationProductDir;
452     determineBaseProductDir();
453     determineConfiguration();
454     if (isAppleWinWebKit() && !isWx()) {
455         $configurationProductDir = File::Spec->catdir($baseProductDir, configurationForVisualStudio(), "bin");
456     } else {
457         if (usesPerConfigurationBuildDirectory()) {
458             $configurationProductDir = "$baseProductDir";
459         } else {
460             $configurationProductDir = "$baseProductDir/$configuration";
461         }
462     }
463 }
464
465 sub setConfigurationProductDir($)
466 {
467     ($configurationProductDir) = @_;
468 }
469
470 sub determineCurrentSVNRevision
471 {
472     # We always update the current SVN revision here, and leave the caching
473     # to currentSVNRevision(), so that changes to the SVN revision while the
474     # script is running can be picked up by calling this function again.
475     determineSourceDir();
476     $currentSVNRevision = svnRevisionForDirectory($sourceDir);
477     return $currentSVNRevision;
478 }
479
480
481 sub chdirWebKit
482 {
483     determineSourceDir();
484     chdir $sourceDir or die;
485 }
486
487 sub baseProductDir
488 {
489     determineBaseProductDir();
490     return $baseProductDir;
491 }
492
493 sub sourceDir
494 {
495     determineSourceDir();
496     return $sourceDir;
497 }
498
499 sub productDir
500 {
501     determineConfigurationProductDir();
502     return $configurationProductDir;
503 }
504
505 sub jscProductDir
506 {
507     my $productDir = productDir();
508     $productDir .= "/bin" if (isQt() || isEfl());
509     $productDir .= "/Programs" if isGtk();
510
511     return $productDir;
512 }
513
514 sub configuration()
515 {
516     determineConfiguration();
517     return $configuration;
518 }
519
520 sub configurationForVisualStudio()
521 {
522     determineConfigurationForVisualStudio();
523     return $configurationForVisualStudio;
524 }
525
526 sub currentSVNRevision
527 {
528     determineCurrentSVNRevision() if not defined $currentSVNRevision;
529     return $currentSVNRevision;
530 }
531
532 sub generateDsym()
533 {
534     determineGenerateDsym();
535     return $generateDsym;
536 }
537
538 sub determineGenerateDsym()
539 {
540     return if defined($generateDsym);
541     $generateDsym = checkForArgumentAndRemoveFromARGV("--dsym");
542 }
543
544 sub argumentsForXcode()
545 {
546     my @args = ();
547     push @args, "DEBUG_INFORMATION_FORMAT=dwarf-with-dsym" if generateDsym();
548     return @args;
549 }
550
551 sub XcodeOptions
552 {
553     determineBaseProductDir();
554     determineConfiguration();
555     determineArchitecture();
556     determineXcodeSDK();
557
558     my @sdkOption = ($xcodeSDK ? "SDKROOT=$xcodeSDK" : ());
559     my @architectureOption = ($architecture ? "ARCHS=$architecture" : ());
560
561     return (@baseProductDirOption, "-configuration", $configuration, @architectureOption, @sdkOption, argumentsForXcode());
562 }
563
564 sub XcodeOptionString
565 {
566     return join " ", XcodeOptions();
567 }
568
569 sub XcodeOptionStringNoConfig
570 {
571     return join " ", @baseProductDirOption;
572 }
573
574 sub XcodeCoverageSupportOptions()
575 {
576     my @coverageSupportOptions = ();
577     push @coverageSupportOptions, "GCC_GENERATE_TEST_COVERAGE_FILES=YES";
578     push @coverageSupportOptions, "GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES";
579     push @coverageSupportOptions, "EXTRA_LINK= \$(EXTRA_LINK) -ftest-coverage -fprofile-arcs";
580     push @coverageSupportOptions, "OTHER_CFLAGS= \$(OTHER_CFLAGS) -DCOVERAGE -MD";
581     push @coverageSupportOptions, "OTHER_LDFLAGS=\$(OTHER_LDFLAGS) -ftest-coverage -fprofile-arcs -lgcov";
582     return @coverageSupportOptions;
583 }
584
585 my $passedConfiguration;
586 my $searchedForPassedConfiguration;
587 sub determinePassedConfiguration
588 {
589     return if $searchedForPassedConfiguration;
590     $searchedForPassedConfiguration = 1;
591
592     for my $i (0 .. $#ARGV) {
593         my $opt = $ARGV[$i];
594         if ($opt =~ /^--debug$/i) {
595             splice(@ARGV, $i, 1);
596             $passedConfiguration = "Debug";
597             $passedConfiguration .= "_Cairo_CFLite" if (isWinCairo() && isCygwin());
598             return;
599         }
600         if ($opt =~ /^--release$/i) {
601             splice(@ARGV, $i, 1);
602             $passedConfiguration = "Release";
603             $passedConfiguration .= "_Cairo_CFLite" if (isWinCairo() && isCygwin());
604             return;
605         }
606         if ($opt =~ /^--profil(e|ing)$/i) {
607             splice(@ARGV, $i, 1);
608             $passedConfiguration = "Profiling";
609             $passedConfiguration .= "_Cairo_CFLite" if (isWinCairo() && isCygwin());
610             return;
611         }
612     }
613     $passedConfiguration = undef;
614 }
615
616 sub passedConfiguration
617 {
618     determinePassedConfiguration();
619     return $passedConfiguration;
620 }
621
622 sub setConfiguration
623 {
624     setArchitecture();
625
626     if (my $config = shift @_) {
627         $configuration = $config;
628         return;
629     }
630
631     determinePassedConfiguration();
632     $configuration = $passedConfiguration if $passedConfiguration;
633 }
634
635
636 my $passedArchitecture;
637 my $searchedForPassedArchitecture;
638 sub determinePassedArchitecture
639 {
640     return if $searchedForPassedArchitecture;
641     $searchedForPassedArchitecture = 1;
642
643     for my $i (0 .. $#ARGV) {
644         my $opt = $ARGV[$i];
645         if ($opt =~ /^--32-bit$/i) {
646             splice(@ARGV, $i, 1);
647             if (isAppleMacWebKit() || isWx()) {
648                 $passedArchitecture = `arch`;
649                 chomp $passedArchitecture;
650             }
651             return;
652         }
653     }
654     $passedArchitecture = undef;
655 }
656
657 sub passedArchitecture
658 {
659     determinePassedArchitecture();
660     return $passedArchitecture;
661 }
662
663 sub architecture()
664 {
665     determineArchitecture();
666     return $architecture;
667 }
668
669 sub numberOfCPUs()
670 {
671     determineNumberOfCPUs();
672     return $numberOfCPUs;
673 }
674
675 sub setArchitecture
676 {
677     if (my $arch = shift @_) {
678         $architecture = $arch;
679         return;
680     }
681
682     determinePassedArchitecture();
683     $architecture = $passedArchitecture if $passedArchitecture;
684 }
685
686 sub executableHasEntitlements
687 {
688     my $executablePath = shift;
689     return (`codesign -d --entitlements - $executablePath 2>&1` =~ /<key>/);
690 }
691
692 sub safariPathFromSafariBundle
693 {
694     my ($safariBundle) = @_;
695
696     if (isAppleMacWebKit()) {
697         my $safariPath = "$safariBundle/Contents/MacOS/Safari";
698         my $safariForWebKitDevelopmentPath = "$safariBundle/Contents/MacOS/SafariForWebKitDevelopment";
699         return $safariForWebKitDevelopmentPath if -f $safariForWebKitDevelopmentPath && executableHasEntitlements($safariPath);
700         return $safariPath;
701     }
702     return $safariBundle if isAppleWinWebKit();
703 }
704
705 sub installedSafariPath
706 {
707     my $safariBundle;
708
709     if (isAppleMacWebKit()) {
710         $safariBundle = "/Applications/Safari.app";
711     } elsif (isAppleWinWebKit()) {
712         $safariBundle = readRegistryString("/HKLM/SOFTWARE/Apple Computer, Inc./Safari/InstallDir");
713         $safariBundle =~ s/[\r\n]+$//;
714         $safariBundle = `cygpath -u '$safariBundle'` if isCygwin();
715         $safariBundle =~ s/[\r\n]+$//;
716         $safariBundle .= "Safari.exe";
717     }
718
719     return safariPathFromSafariBundle($safariBundle);
720 }
721
722 # Locate Safari.
723 sub safariPath
724 {
725     # Use WEBKIT_SAFARI environment variable if present.
726     my $safariBundle = $ENV{WEBKIT_SAFARI};
727     if (!$safariBundle) {
728         determineConfigurationProductDir();
729         # Use Safari.app in product directory if present (good for Safari development team).
730         if (isAppleMacWebKit() && -d "$configurationProductDir/Safari.app") {
731             $safariBundle = "$configurationProductDir/Safari.app";
732         } elsif (isAppleWinWebKit()) {
733             my $path = "$configurationProductDir/Safari.exe";
734             my $debugPath = "$configurationProductDir/Safari_debug.exe";
735
736             if (configurationForVisualStudio() eq "Debug_All" && -x $debugPath) {
737                 $safariBundle = $debugPath;
738             } elsif (-x $path) {
739                 $safariBundle = $path;
740             }
741         }
742         if (!$safariBundle) {
743             return installedSafariPath();
744         }
745     }
746     my $safariPath = safariPathFromSafariBundle($safariBundle);
747     die "Can't find executable at $safariPath.\n" if isAppleMacWebKit() && !-x $safariPath;
748     return $safariPath;
749 }
750
751 sub builtDylibPathForName
752 {
753     my $libraryName = shift;
754     determineConfigurationProductDir();
755     if (isChromium()) {
756         return "$configurationProductDir/$libraryName";
757     }
758     if (isBlackBerry()) {
759         my $libraryExtension = $libraryName =~ /^WebKit$/i ? ".so" : ".a";
760         return "$configurationProductDir/$libraryName/lib" . lc($libraryName) . $libraryExtension;
761     }
762     if (isQt()) {
763         my $isSearchingForWebCore = $libraryName =~ "WebCore";
764         if (isDarwin()) {
765             $libraryName = "QtWebKitWidgets";
766         } else {
767             $libraryName = "Qt5WebKitWidgets";
768         }
769         my $result;
770         if (isDarwin() and -d "$configurationProductDir/lib/$libraryName.framework") {
771             $result = "$configurationProductDir/lib/$libraryName.framework/$libraryName";
772         } elsif (isDarwin() and -d "$configurationProductDir/lib") {
773             $result = "$configurationProductDir/lib/lib$libraryName.dylib";
774         } elsif (isWindows()) {
775             if (configuration() eq "Debug") {
776                 # On Windows, there is a "d" suffix to the library name. See <http://trac.webkit.org/changeset/53924/>.
777                 $libraryName .= "d";
778             }
779
780             chomp(my $mkspec = `$qmakebin -query QT_HOST_DATA`);
781             $mkspec .= "/mkspecs";
782             my $qtMajorVersion = retrieveQMakespecVar("$mkspec/qconfig.pri", "QT_MAJOR_VERSION");
783             if (not $qtMajorVersion) {
784                 $qtMajorVersion = "";
785             }
786
787             $result = "$configurationProductDir/lib/$libraryName$qtMajorVersion.dll";
788         } else {
789             $result = "$configurationProductDir/lib/lib$libraryName.so";
790         }
791
792         if ($isSearchingForWebCore) {
793             # With CONFIG+=force_static_libs_as_shared we have a shared library for each subdir.
794             # For feature detection to work it is necessary to return the path of the WebCore library here.
795             my $replacedWithWebCore = $result;
796             $replacedWithWebCore =~ s/$libraryName/WebCore/g;
797             if (-e $replacedWithWebCore) {
798                 return $replacedWithWebCore;
799             }
800         }
801
802         return $result;
803     }
804     if (isWx()) {
805         return "$configurationProductDir/libwxwebkit.dylib";
806     }
807     if (isGtk()) {
808         # WebKitGTK+ for GTK2, WebKitGTK+ for GTK3, and WebKit2 respectively.
809         my @libraries = ("libwebkitgtk-1.0", "libwebkitgtk-3.0", "libwebkit2gtk-3.0");
810         my $extension = isDarwin() ? ".dylib" : ".so";
811
812         foreach $libraryName (@libraries) {
813             my $libraryPath = "$configurationProductDir/.libs/" . $libraryName . $extension;
814             return $libraryPath if -e $libraryPath;
815         }
816         return "NotFound";
817     }
818     if (isEfl()) {
819         if (isWK2()) {
820             return "$configurationProductDir/lib/libewebkit2.so";
821         }
822         return "$configurationProductDir/lib/libewebkit.so";
823     }
824     if (isWinCE()) {
825         return "$configurationProductDir/$libraryName";
826     }
827     if (isAppleMacWebKit()) {
828         return "$configurationProductDir/$libraryName.framework/Versions/A/$libraryName";
829     }
830     if (isAppleWinWebKit()) {
831         if ($libraryName eq "JavaScriptCore") {
832             return "$baseProductDir/lib/$libraryName.lib";
833         } else {
834             return "$baseProductDir/$libraryName.intermediate/$configuration/$libraryName.intermediate/$libraryName.lib";
835         }
836     }
837
838     die "Unsupported platform, can't determine built library locations.\nTry `build-webkit --help` for more information.\n";
839 }
840
841 # Check to see that all the frameworks are built.
842 sub checkFrameworks # FIXME: This is a poor name since only the Mac calls built WebCore a Framework.
843 {
844     return if isCygwin() || isWindows();
845     my @frameworks = ("JavaScriptCore", "WebCore");
846     push(@frameworks, "WebKit") if isAppleMacWebKit(); # FIXME: This seems wrong, all ports should have a WebKit these days.
847     for my $framework (@frameworks) {
848         my $path = builtDylibPathForName($framework);
849         die "Can't find built framework at \"$path\".\n" unless -e $path;
850     }
851 }
852
853 sub isInspectorFrontend()
854 {
855     determineIsInspectorFrontend();
856     return $isInspectorFrontend;
857 }
858
859 sub determineIsInspectorFrontend()
860 {
861     return if defined($isInspectorFrontend);
862     $isInspectorFrontend = checkForArgumentAndRemoveFromARGV("--inspector-frontend");
863 }
864
865 sub isQt()
866 {
867     determineIsQt();
868     return $isQt;
869 }
870
871 sub getQtVersion()
872 {
873     my $qtVersion = `$qmakebin --version`;
874     $qtVersion =~ s/^(.*)Qt version (\d\.\d)(.*)/$2/s ;
875     return $qtVersion;
876 }
877
878 sub qtFeatureDefaults
879 {
880     die "ERROR: qmake missing but required to build WebKit.\n" if not commandExists($qmakebin);
881
882     my $oldQmakeEval = $ENV{QMAKE_CACHE_EVAL};
883     $ENV{QMAKE_CACHE_EVAL} = "CONFIG+=print_defaults";
884
885     my $originalCwd = getcwd();
886     my $qmakepath = File::Spec->catfile(sourceDir(), "Tools", "qmake");
887     chdir $qmakepath or die "Failed to cd into " . $qmakepath . "\n";
888
889     my $file = File::Spec->catfile(sourceDir(), "WebKit.pro");
890
891     my @buildArgs;
892     @buildArgs = (@buildArgs, @{$_[0]}) if (@_);
893
894     my @defaults = `$qmakebin @buildArgs $file 2>&1`;
895
896     my %qtFeatureDefaults;
897     for (@defaults) {
898         if (/DEFINES: /) {
899             while (/(\S+?)=(\S+?)/gi) {
900                 $qtFeatureDefaults{$1}=$2;
901             }
902         } elsif (/Done computing defaults/) {
903             last;
904         } elsif (@_) {
905             print $_;
906         }
907     }
908
909     chdir $originalCwd;
910     $ENV{QMAKE_CACHE_EVAL} = $oldQmakeEval;
911
912     return %qtFeatureDefaults;
913 }
914
915 sub commandExists($)
916 {
917     my $command = shift;
918     my $devnull = File::Spec->devnull();
919     return `$command --version 2> $devnull`;
920 }
921
922 sub checkForArgumentAndRemoveFromARGV
923 {
924     my $argToCheck = shift;
925     return checkForArgumentAndRemoveFromArrayRef($argToCheck, \@ARGV);
926 }
927
928 sub checkForArgumentAndRemoveFromArrayRef
929 {
930     my ($argToCheck, $arrayRef) = @_;
931     my @indicesToRemove;
932     foreach my $index (0 .. $#$arrayRef) {
933         my $opt = $$arrayRef[$index];
934         if ($opt =~ /^$argToCheck$/i ) {
935             push(@indicesToRemove, $index);
936         }
937     }
938     foreach my $index (@indicesToRemove) {
939         splice(@$arrayRef, $index, 1);
940     }
941     return $#indicesToRemove > -1;
942 }
943
944 sub isWK2()
945 {
946     if (defined($isWK2)) {
947         return $isWK2;
948     }
949     if (checkForArgumentAndRemoveFromARGV("-2")) {
950         $isWK2 = 1;
951     } else {
952         $isWK2 = 0;
953     }
954     return $isWK2;
955 }
956
957 sub determineIsQt()
958 {
959     return if defined($isQt);
960
961     # Allow override in case QTDIR is not set.
962     if (checkForArgumentAndRemoveFromARGV("--qt")) {
963         $isQt = 1;
964         return;
965     }
966
967     # The presence of QTDIR only means Qt if --gtk or --wx or --efl or --blackberry or --chromium or --wincairo are not on the command-line
968     if (isGtk() || isWx() || isEfl() || isBlackBerry() || isChromium() || isWinCairo()) {
969         $isQt = 0;
970         return;
971     }
972
973     $isQt = defined($ENV{'QTDIR'});
974 }
975
976 sub isBlackBerry()
977 {
978     determineIsBlackBerry();
979     return $isBlackBerry;
980 }
981
982 sub determineIsBlackBerry()
983 {
984     return if defined($isBlackBerry);
985     $isBlackBerry = checkForArgumentAndRemoveFromARGV("--blackberry");
986 }
987
988 sub blackberryTargetArchitecture()
989 {
990     my $arch = $ENV{"BLACKBERRY_ARCH_TYPE"} ? $ENV{"BLACKBERRY_ARCH_TYPE"} : "arm";
991     my $cpu = $ENV{"BLACKBERRY_ARCH_CPU"} ? $ENV{"BLACKBERRY_ARCH_CPU"} : "";
992     my $cpuDir;
993     my $buSuffix;
994     if (($cpu eq "v7le") || ($cpu eq "a9")) {
995         $cpuDir = $arch . "le-v7";
996         $buSuffix = $arch . "v7";
997     } else {
998         $cpu = $arch;
999         $cpuDir = $arch;
1000         $buSuffix = $arch;
1001     }
1002     return ("arch" => $arch,
1003             "cpu" => $cpu,
1004             "cpuDir" => $cpuDir,
1005             "buSuffix" => $buSuffix);
1006 }
1007
1008 sub blackberryCMakeArguments()
1009 {
1010     my %archInfo = blackberryTargetArchitecture();
1011     my $arch = $archInfo{"arch"};
1012     my $cpu = $archInfo{"cpu"};
1013     my $cpuDir = $archInfo{"cpuDir"};
1014     my $buSuffix = $archInfo{"buSuffix"};
1015
1016     my @cmakeExtraOptions;
1017     if ($cpu eq "a9") {
1018         $cpu = $arch . "v7le";
1019         push @cmakeExtraOptions, '-DTARGETING_PLAYBOOK=1';
1020     }
1021
1022     my $stageDir = $ENV{"STAGE_DIR"};
1023     my $stageLib = File::Spec->catdir($stageDir, $cpuDir, "lib");
1024     my $stageUsrLib = File::Spec->catdir($stageDir, $cpuDir, "usr", "lib");
1025     my $stageInc = File::Spec->catdir($stageDir, "usr", "include");
1026
1027     my $qnxHost = $ENV{"QNX_HOST"};
1028     my $ccCommand;
1029     my $cxxCommand;
1030     if ($ENV{"USE_ICECC"}) {
1031         chomp($ccCommand = `which icecc`);
1032         $cxxCommand = $ccCommand;
1033     } else {
1034         $ccCommand = File::Spec->catfile($qnxHost, "usr", "bin", "qcc");
1035         $cxxCommand = $ccCommand;
1036     }
1037
1038     if ($ENV{"CCWRAP"}) {
1039         $ccCommand = $ENV{"CCWRAP"};
1040         push @cmakeExtraOptions, "-DCMAKE_C_COMPILER_ARG1=qcc";
1041         push @cmakeExtraOptions, "-DCMAKE_CXX_COMPILER_ARG1=qcc";
1042     }
1043
1044     push @cmakeExtraOptions, "-DCMAKE_SKIP_RPATH='ON'" if isDarwin();
1045     push @cmakeExtraOptions, "-DPUBLIC_BUILD=1" if $ENV{"PUBLIC_BUILD"};
1046     push @cmakeExtraOptions, "-DENABLE_GLES2=1" unless $ENV{"DISABLE_GLES2"};
1047
1048     my @includeSystemDirectories;
1049     push @includeSystemDirectories, File::Spec->catdir($stageInc, "grskia", "skia");
1050     push @includeSystemDirectories, File::Spec->catdir($stageInc, "grskia");
1051     push @includeSystemDirectories, File::Spec->catdir($stageInc, "harfbuzz");
1052     push @includeSystemDirectories, File::Spec->catdir($stageInc, "imf");
1053     # We only use jpeg-turbo for device build
1054     push @includeSystemDirectories, File::Spec->catdir($stageInc, "jpeg-turbo") if $arch=~/arm/;
1055     push @includeSystemDirectories, $stageInc;
1056     push @includeSystemDirectories, File::Spec->catdir($stageInc, "browser", "platform");
1057     push @includeSystemDirectories, File::Spec->catdir($stageInc, "browser", "platform", "graphics");
1058     push @includeSystemDirectories, File::Spec->catdir($stageInc, "browser", "qsk");
1059     push @includeSystemDirectories, File::Spec->catdir($stageInc, "ots");
1060
1061     my @cxxFlags;
1062     push @cxxFlags, "-Wl,-rpath-link,$stageLib";
1063     push @cxxFlags, "-Wl,-rpath-link," . File::Spec->catfile($stageUsrLib, "torch-webkit");
1064     push @cxxFlags, "-Wl,-rpath-link,$stageUsrLib";
1065     push @cxxFlags, "-L$stageLib";
1066     push @cxxFlags, "-L$stageUsrLib";
1067
1068     if ($ENV{"PROFILE"}) {
1069         push @cmakeExtraOptions, "-DPROFILING=1";
1070         push @cxxFlags, "-p";
1071     }
1072
1073     my @cmakeArgs;
1074     push @cmakeArgs, '-DCMAKE_SYSTEM_NAME="QNX"';
1075     push @cmakeArgs, "-DCMAKE_SYSTEM_PROCESSOR=\"$cpuDir\"";
1076     push @cmakeArgs, '-DCMAKE_SYSTEM_VERSION="1"';
1077     push @cmakeArgs, "-DCMAKE_C_COMPILER=\"$ccCommand\"";
1078     push @cmakeArgs, "-DCMAKE_CXX_COMPILER=\"$cxxCommand\"";
1079     push @cmakeArgs, "-DCMAKE_C_FLAGS=\"-Vgcc_nto${cpu} -g @cxxFlags\"";
1080     push @cmakeArgs, "-DCMAKE_CXX_FLAGS=\"-Vgcc_nto${cpu}_cpp-ne -g -lang-c++ @cxxFlags\"";
1081
1082     # We cannot use CMAKE_INCLUDE_PATH since this describes the search path for header files in user directories.
1083     # And the QNX system headers are in user directories on the host OS (i.e. they aren't installed in the host OS's
1084     # system header search path). So, we need to inform g++ that these user directories (@includeSystemDirectories)
1085     # are to be taken as the host OS's system header directories when building our port.
1086     #
1087     # Also, we cannot use CMAKE_SYSTEM_INCLUDE_PATH since that will override the entire system header path.
1088     # So, we define the additional system include paths in ADDITIONAL_SYSTEM_INCLUDE_PATH. This list will
1089     # be processed in OptionsBlackBerry.cmake.
1090     push @cmakeArgs, '-DADDITIONAL_SYSTEM_INCLUDE_PATH="' . join(';', @includeSystemDirectories) . '"';
1091
1092     # FIXME: Make this more general purpose such that we can pass a list of directories and files.
1093     push @cmakeArgs, '-DTHIRD_PARTY_ICU_DIR="' . File::Spec->catdir($stageInc, "unicode") . '"';
1094     push @cmakeArgs, '-DTHIRD_PARTY_UNICODE_FILE="' . File::Spec->catfile($stageInc, "unicode.h") . '"';
1095
1096     push @cmakeArgs, "-DCMAKE_LIBRARY_PATH=\"$stageLib;$stageUsrLib\"";
1097     push @cmakeArgs, '-DCMAKE_AR="' . File::Spec->catfile($qnxHost, "usr", "bin", "nto${buSuffix}-ar") . '"';
1098     push @cmakeArgs, '-DCMAKE_RANLIB="' . File::Spec->catfile($qnxHost, "usr", "bin", "nto${buSuffix}-ranlib") . '"';
1099     push @cmakeArgs, '-DCMAKE_LD="'. File::Spec->catfile($qnxHost, "usr", "bin", "nto${buSuffix}-ld") . '"';
1100     push @cmakeArgs, '-DCMAKE_LINKER="' . File::Spec->catfile($qnxHost, "usr", "bin", "nto${buSuffix}-ld") . '"';
1101     push @cmakeArgs, "-DECLIPSE_CDT4_GENERATE_SOURCE_PROJECT=TRUE";
1102     push @cmakeArgs, '-G"Eclipse CDT4 - Unix Makefiles"';
1103     push @cmakeArgs, @cmakeExtraOptions;
1104     return @cmakeArgs;
1105 }
1106
1107 sub determineIsEfl()
1108 {
1109     return if defined($isEfl);
1110     $isEfl = checkForArgumentAndRemoveFromARGV("--efl");
1111 }
1112
1113 sub isEfl()
1114 {
1115     determineIsEfl();
1116     return $isEfl;
1117 }
1118
1119 sub isGtk()
1120 {
1121     determineIsGtk();
1122     return $isGtk;
1123 }
1124
1125 sub determineIsGtk()
1126 {
1127     return if defined($isGtk);
1128     $isGtk = checkForArgumentAndRemoveFromARGV("--gtk");
1129 }
1130
1131 sub isWinCE()
1132 {
1133     determineIsWinCE();
1134     return $isWinCE;
1135 }
1136
1137 sub determineIsWinCE()
1138 {
1139     return if defined($isWinCE);
1140     $isWinCE = checkForArgumentAndRemoveFromARGV("--wince");
1141 }
1142
1143 sub isWx()
1144 {
1145     determineIsWx();
1146     return $isWx;
1147 }
1148
1149 sub determineIsWx()
1150 {
1151     return if defined($isWx);
1152     $isWx = checkForArgumentAndRemoveFromARGV("--wx");
1153 }
1154
1155 sub getWxArgs()
1156 {
1157     if (!@wxArgs) {
1158         @wxArgs = ("");
1159         my $rawWxArgs = "";
1160         foreach my $opt (@ARGV) {
1161             if ($opt =~ /^--wx-args/i ) {
1162                 @ARGV = grep(!/^--wx-args/i, @ARGV);
1163                 $rawWxArgs = $opt;
1164                 $rawWxArgs =~ s/--wx-args=//i;
1165             }
1166         }
1167         @wxArgs = split(/,/, $rawWxArgs);
1168     }
1169     return @wxArgs;
1170 }
1171
1172 # Determine if this is debian, ubuntu, linspire, or something similar.
1173 sub isDebianBased()
1174 {
1175     return -e "/etc/debian_version";
1176 }
1177
1178 sub isFedoraBased()
1179 {
1180     return -e "/etc/fedora-release";
1181 }
1182
1183 sub isChromium()
1184 {
1185     determineIsChromium();
1186     determineIsChromiumAndroid();
1187     return $isChromium || $isChromiumAndroid;
1188 }
1189
1190 sub determineIsChromium()
1191 {
1192     return if defined($isChromium);
1193     $isChromium = checkForArgumentAndRemoveFromARGV("--chromium");
1194     if ($isChromium) {
1195         $forceChromiumUpdate = checkForArgumentAndRemoveFromARGV("--force-update");
1196     }
1197 }
1198
1199 sub isChromiumAndroid()
1200 {
1201     determineIsChromiumAndroid();
1202     return $isChromiumAndroid;
1203 }
1204
1205 sub determineIsChromiumAndroid()
1206 {
1207     return if defined($isChromiumAndroid);
1208     $isChromiumAndroid = checkForArgumentAndRemoveFromARGV("--chromium-android");
1209 }
1210
1211 sub isChromiumMacMake()
1212 {
1213     determineIsChromiumMacMake();
1214     return $isChromiumMacMake;
1215 }
1216
1217 sub determineIsChromiumMacMake()
1218 {
1219     return if defined($isChromiumMacMake);
1220
1221     my $hasUpToDateMakefile = 0;
1222     if (-e 'Makefile.chromium') {
1223         unless (-e 'Source/WebKit/chromium/WebKit.xcodeproj') {
1224             $hasUpToDateMakefile = 1;
1225         } else {
1226             $hasUpToDateMakefile = stat('Makefile.chromium')->mtime > stat('Source/WebKit/chromium/WebKit.xcodeproj')->mtime;
1227         }
1228     }
1229     $isChromiumMacMake = isDarwin() && $hasUpToDateMakefile;
1230 }
1231
1232 sub isChromiumNinja()
1233 {
1234     determineIsChromiumNinja();
1235     return $isChromiumNinja;
1236 }
1237
1238 sub determineIsChromiumNinja()
1239 {
1240     return if defined($isChromiumNinja);
1241
1242     # This function can be called from baseProductDir(), which in turn is
1243     # called by configuration(). So calling configuration() here leads to
1244     # infinite recursion. Gyp writes both Debug and Release at the same time
1245     # by default, so just check the timestamp on the Release build.ninja file.
1246     my $config = "Release";
1247
1248     my $hasUpToDateNinjabuild = 0;
1249     if (-e "out/$config/build.ninja") {
1250         my $statNinja = stat("out/$config/build.ninja")->mtime;
1251
1252         my $statXcode = 0;
1253         if (-e 'Source/WebKit/chromium/WebKit.xcodeproj') {
1254           $statXcode = stat('Source/WebKit/chromium/WebKit.xcodeproj')->mtime;
1255         }
1256
1257         my $statMake = 0;
1258         if (-e 'Makefile.chromium') {
1259           $statMake = stat('Makefile.chromium')->mtime;
1260         }
1261
1262         my $statVisualStudio = 0;
1263         if (-e 'Source/WebKit/chromium/webkit.vcxproj') {
1264           $statVisualStudio = stat('Source/WebKit/chromium/webkit.vcxproj')->mtime;
1265         }
1266
1267         $hasUpToDateNinjabuild = $statNinja > $statXcode && $statNinja > $statMake && $statNinja > $statVisualStudio;
1268     }
1269     $isChromiumNinja = $hasUpToDateNinjabuild;
1270 }
1271
1272 sub forceChromiumUpdate()
1273 {
1274     determineIsChromium();
1275     return $forceChromiumUpdate;
1276 }
1277
1278 sub isWinCairo()
1279 {
1280     determineIsWinCairo();
1281     return $isWinCairo;
1282 }
1283
1284 sub determineIsWinCairo()
1285 {
1286     return if defined($isWinCairo);
1287     $isWinCairo = checkForArgumentAndRemoveFromARGV("--wincairo");
1288 }
1289
1290 sub isCygwin()
1291 {
1292     return ($^O eq "cygwin") || 0;
1293 }
1294
1295 sub isAnyWindows()
1296 {
1297     return isWindows() || isCygwin();
1298 }
1299
1300 sub determineWinVersion()
1301 {
1302     return if $winVersion;
1303
1304     if (!isAnyWindows()) {
1305         $winVersion = -1;
1306         return;
1307     }
1308
1309     my $versionString = `cmd /c ver`;
1310     $versionString =~ /(\d)\.(\d)\.(\d+)/;
1311
1312     $winVersion = {
1313         major => $1,
1314         minor => $2,
1315         build => $3,
1316     };
1317 }
1318
1319 sub winVersion()
1320 {
1321     determineWinVersion();
1322     return $winVersion;
1323 }
1324
1325 sub isWindows7SP0()
1326 {
1327     return isAnyWindows() && winVersion()->{major} == 6 && winVersion()->{minor} == 1 && winVersion()->{build} == 7600;
1328 }
1329
1330 sub isWindowsVista()
1331 {
1332     return isAnyWindows() && winVersion()->{major} == 6 && winVersion()->{minor} == 0;
1333 }
1334
1335 sub isWindowsXP()
1336 {
1337     return isAnyWindows() && winVersion()->{major} == 5 && winVersion()->{minor} == 1;
1338 }
1339
1340 sub isDarwin()
1341 {
1342     return ($^O eq "darwin") || 0;
1343 }
1344
1345 sub isWindows()
1346 {
1347     return ($^O eq "MSWin32") || 0;
1348 }
1349
1350 sub isLinux()
1351 {
1352     return ($^O eq "linux") || 0;
1353 }
1354
1355 sub isFreeBSD()
1356 {
1357     return ($^O eq "freebsd") || 0;
1358 }
1359
1360 sub isARM()
1361 {
1362     return $Config{archname} =~ /^arm[v\-]/;
1363 }
1364
1365 sub isCrossCompilation()
1366 {
1367   my $compiler = "";
1368   $compiler = $ENV{'CC'} if (defined($ENV{'CC'}));
1369   if ($compiler =~ /gcc/) {
1370       my $compiler_options = `$compiler -v 2>&1`;
1371       my @host = $compiler_options =~ m/--host=(.*?)\s/;
1372       my @target = $compiler_options =~ m/--target=(.*?)\s/;
1373
1374       return ($host[0] ne "" && $target[0] ne "" && $host[0] ne $target[0]);
1375   }
1376   return 0;
1377 }
1378
1379 sub isAppleWebKit()
1380 {
1381     return !(isQt() or isGtk() or isWx() or isChromium() or isEfl() or isWinCE() or isBlackBerry());
1382 }
1383
1384 sub isAppleMacWebKit()
1385 {
1386     return isAppleWebKit() && isDarwin();
1387 }
1388
1389 sub isAppleWinWebKit()
1390 {
1391     return isAppleWebKit() && (isCygwin() || isWindows());
1392 }
1393
1394 sub isPerianInstalled()
1395 {
1396     if (!isAppleWebKit()) {
1397         return 0;
1398     }
1399
1400     if (-d "/Library/QuickTime/Perian.component") {
1401         return 1;
1402     }
1403
1404     if (-d "$ENV{HOME}/Library/QuickTime/Perian.component") {
1405         return 1;
1406     }
1407
1408     return 0;
1409 }
1410
1411 sub determineNmPath()
1412 {
1413     return if $nmPath;
1414
1415     if (isAppleMacWebKit()) {
1416         $nmPath = `xcrun -find nm`;
1417         chomp $nmPath;
1418     }
1419     $nmPath = "nm" if !$nmPath;
1420 }
1421
1422 sub nmPath()
1423 {
1424     determineNmPath();
1425     return $nmPath;
1426 }
1427
1428 sub determineOSXVersion()
1429 {
1430     return if $osXVersion;
1431
1432     if (!isDarwin()) {
1433         $osXVersion = -1;
1434         return;
1435     }
1436
1437     my $version = `sw_vers -productVersion`;
1438     my @splitVersion = split(/\./, $version);
1439     @splitVersion >= 2 or die "Invalid version $version";
1440     $osXVersion = {
1441             "major" => $splitVersion[0],
1442             "minor" => $splitVersion[1],
1443             "subminor" => (defined($splitVersion[2]) ? $splitVersion[2] : 0),
1444     };
1445 }
1446
1447 sub osXVersion()
1448 {
1449     determineOSXVersion();
1450     return $osXVersion;
1451 }
1452
1453 sub isSnowLeopard()
1454 {
1455     return isDarwin() && osXVersion()->{"minor"} == 6;
1456 }
1457
1458 sub isLion()
1459 {
1460     return isDarwin() && osXVersion()->{"minor"} == 7;
1461 }
1462
1463 sub isWindowsNT()
1464 {
1465     return $ENV{'OS'} eq 'Windows_NT';
1466 }
1467
1468 sub shouldTargetWebProcess
1469 {
1470     determineShouldTargetWebProcess();
1471     return $shouldTargetWebProcess;
1472 }
1473
1474 sub determineShouldTargetWebProcess
1475 {
1476     return if defined($shouldTargetWebProcess);
1477     $shouldTargetWebProcess = checkForArgumentAndRemoveFromARGV("--target-web-process");
1478 }
1479
1480 sub shouldUseXPCServiceForWebProcess
1481 {
1482     determineShouldUseXPCServiceForWebProcess();
1483     return $shouldUseXPCServiceForWebProcess;
1484 }
1485
1486 sub determineShouldUseXPCServiceForWebProcess
1487 {
1488     return if defined($shouldUseXPCServiceForWebProcess);
1489     $shouldUseXPCServiceForWebProcess = checkForArgumentAndRemoveFromARGV("--use-web-process-xpc-service");
1490 }
1491
1492 sub debugger
1493 {
1494     determineDebugger();
1495     return $debugger;
1496 }
1497
1498 sub determineDebugger
1499 {
1500     return if defined($debugger);
1501
1502     determineXcodeVersion();
1503     if (eval "v$xcodeVersion" ge v4.5) {
1504         $debugger = "lldb";
1505     } else {
1506         $debugger = "gdb";
1507     }
1508
1509     if (checkForArgumentAndRemoveFromARGV("--use-lldb")) {
1510         $debugger = "lldb";
1511     }
1512
1513     if (checkForArgumentAndRemoveFromARGV("--use-gdb")) {
1514         $debugger = "gdb";
1515     }
1516 }
1517
1518 sub appendToEnvironmentVariableList
1519 {
1520     my ($environmentVariableName, $value) = @_;
1521
1522     if (defined($ENV{$environmentVariableName})) {
1523         $ENV{$environmentVariableName} .= ":" . $value;
1524     } else {
1525         $ENV{$environmentVariableName} = $value;
1526     }
1527 }
1528
1529 sub setUpGuardMallocIfNeeded
1530 {
1531     if (!isDarwin()) {
1532         return;
1533     }
1534
1535     if (!defined($shouldUseGuardMalloc)) {
1536         $shouldUseGuardMalloc = checkForArgumentAndRemoveFromARGV("--guard-malloc");
1537     }
1538
1539     if ($shouldUseGuardMalloc) {
1540         appendToEnvironmentVariableList("DYLD_INSERT_LIBRARIES", "/usr/lib/libgmalloc.dylib");
1541     }
1542 }
1543
1544 sub relativeScriptsDir()
1545 {
1546     my $scriptDir = File::Spec->catpath("", File::Spec->abs2rel($FindBin::Bin, getcwd()), "");
1547     if ($scriptDir eq "") {
1548         $scriptDir = ".";
1549     }
1550     return $scriptDir;
1551 }
1552
1553 sub launcherPath()
1554 {
1555     my $relativeScriptsPath = relativeScriptsDir();
1556     if (isGtk() || isQt() || isWx() || isEfl() || isWinCE()) {
1557         return "$relativeScriptsPath/run-launcher";
1558     } elsif (isAppleWebKit()) {
1559         return "$relativeScriptsPath/run-safari";
1560     }
1561 }
1562
1563 sub launcherName()
1564 {
1565     if (isGtk()) {
1566         return "GtkLauncher";
1567     } elsif (isQt()) {
1568         return "QtTestBrowser";
1569     } elsif (isWx()) {
1570         return "wxBrowser";
1571     } elsif (isAppleWebKit()) {
1572         return "Safari";
1573     } elsif (isEfl()) {
1574         return "EWebLauncher/MiniBrowser";
1575     } elsif (isWinCE()) {
1576         return "WinCELauncher";
1577     }
1578 }
1579
1580 sub checkRequiredSystemConfig
1581 {
1582     if (isDarwin()) {
1583         chomp(my $productVersion = `sw_vers -productVersion`);
1584         if (eval "v$productVersion" lt v10.4) {
1585             print "*************************************************************\n";
1586             print "Mac OS X Version 10.4.0 or later is required to build WebKit.\n";
1587             print "You have " . $productVersion . ", thus the build will most likely fail.\n";
1588             print "*************************************************************\n";
1589         }
1590         my $xcodebuildVersionOutput = `xcodebuild -version`;
1591         my $devToolsCoreVersion = ($xcodebuildVersionOutput =~ /DevToolsCore-(\d+)/) ? $1 : undef;
1592         my $xcodeVersion = ($xcodebuildVersionOutput =~ /Xcode ([0-9](\.[0-9]+)*)/) ? $1 : undef;
1593         if (!$devToolsCoreVersion && !$xcodeVersion
1594             || $devToolsCoreVersion && $devToolsCoreVersion < 747
1595             || $xcodeVersion && eval "v$xcodeVersion" lt v2.3) {
1596             print "*************************************************************\n";
1597             print "Xcode Version 2.3 or later is required to build WebKit.\n";
1598             print "You have an earlier version of Xcode, thus the build will\n";
1599             print "most likely fail.  The latest Xcode is available from the web:\n";
1600             print "http://developer.apple.com/tools/xcode\n";
1601             print "*************************************************************\n";
1602         }
1603     } elsif (isGtk() or isQt() or isWx() or isEfl()) {
1604         my @cmds = qw(bison gperf);
1605         if (isQt() and isWindows()) {
1606             push @cmds, "win_flex";
1607         } else {
1608             push @cmds, "flex";
1609         }
1610         my @missing = ();
1611         my $oldPath = $ENV{PATH};
1612         if (isQt() and isWindows()) {
1613             chomp(my $gnuWin32Dir = `$qmakebin -query QT_HOST_DATA`);
1614             $gnuWin32Dir = File::Spec->catfile($gnuWin32Dir, "..", "gnuwin32", "bin");
1615             if (-d "$gnuWin32Dir") {
1616                 $ENV{PATH} = $gnuWin32Dir . ";" . $ENV{PATH};
1617             }
1618         }
1619         foreach my $cmd (@cmds) {
1620             push @missing, $cmd if not commandExists($cmd);
1621         }
1622
1623         if (@missing) {
1624             my $list = join ", ", @missing;
1625             die "ERROR: $list missing but required to build WebKit.\n";
1626         }
1627         if (isQt() and isWindows()) {
1628             $ENV{PATH} = $oldPath;
1629         }
1630     }
1631     # Win32 and other platforms may want to check for minimum config
1632 }
1633
1634 sub determineWindowsSourceDir()
1635 {
1636     return if $windowsSourceDir;
1637     $windowsSourceDir = sourceDir();
1638     chomp($windowsSourceDir = `cygpath -w '$windowsSourceDir'`) if isCygwin();
1639 }
1640
1641 sub windowsSourceDir()
1642 {
1643     determineWindowsSourceDir();
1644     return $windowsSourceDir;
1645 }
1646
1647 sub windowsSourceSourceDir()
1648 {
1649     return windowsSourceDir() . "\\Source";
1650 }
1651
1652 sub windowsLibrariesDir()
1653 {
1654     return windowsSourceDir() . "\\WebKitLibraries\\win";
1655 }
1656
1657 sub windowsOutputDir()
1658 {
1659     return windowsSourceDir() . "\\WebKitBuild";
1660 }
1661
1662 sub setupAppleWinEnv()
1663 {
1664     return unless isAppleWinWebKit();
1665
1666     if (isWindowsNT()) {
1667         my $restartNeeded = 0;
1668         my %variablesToSet = ();
1669
1670         # FIXME: We should remove this explicit version check for cygwin once we stop supporting Cygwin 1.7.9 or older versions. 
1671         # https://bugs.webkit.org/show_bug.cgi?id=85791
1672         my $uname_version = (POSIX::uname())[2];
1673         $uname_version =~ s/\(.*\)//;  # Remove the trailing cygwin version, if any.
1674         if (version->parse($uname_version) < version->parse("1.7.10")) {
1675             # Setting the environment variable 'CYGWIN' to 'tty' makes cygwin enable extra support (i.e., termios)
1676             # for UNIX-like ttys in the Windows console
1677             $variablesToSet{CYGWIN} = "tty" unless $ENV{CYGWIN};
1678         }
1679         
1680         # Those environment variables must be set to be able to build inside Visual Studio.
1681         $variablesToSet{WEBKITLIBRARIESDIR} = windowsLibrariesDir() unless $ENV{WEBKITLIBRARIESDIR};
1682         $variablesToSet{WEBKIT_LIBRARIES} = windowsLibrariesDir() unless $ENV{WEBKIT_LIBRARIES};
1683         $variablesToSet{WEBKITOUTPUTDIR} = windowsOutputDir() unless $ENV{WEBKITOUTPUTDIR};
1684         $variablesToSet{WEBKIT_OUTPUTDIR} = windowsOutputDir() unless $ENV{WEBKIT_OUTPUTDIR};
1685         $variablesToSet{WEBKIT_SOURCE} = windowsSourceSourceDir() unless $ENV{WEBKIT_SOURCE};
1686
1687         foreach my $variable (keys %variablesToSet) {
1688             print "Setting the Environment Variable '" . $variable . "' to '" . $variablesToSet{$variable} . "'\n\n";
1689             system qw(regtool -s set), '\\HKEY_CURRENT_USER\\Environment\\' . $variable, $variablesToSet{$variable};
1690             $restartNeeded ||= $variable eq "WEBKITLIBRARIESDIR" || $variable eq "WEBKITOUTPUTDIR" || $variable eq "WEBKIT_LIBRARIES" || $variable eq "WEBKIT_OUTPUTDIR" || $variable eq "WEBKIT_SOURCE";
1691         }
1692
1693         if ($restartNeeded) {
1694             print "Please restart your computer before attempting to build inside Visual Studio.\n\n";
1695         }
1696     } else {
1697         if (!$ENV{'WEBKITLIBRARIESDIR'}) {
1698             # VS2005 version.  This will be removed as part of https://bugs.webkit.org/show_bug.cgi?id=109472.
1699             print "Warning: You must set the 'WebKitLibrariesDir' environment variable\n";
1700             print "         to be able build WebKit from within Visual Studio 2005.\n";
1701             print "         Make sure that 'WebKitLibrariesDir' points to the\n";
1702             print "         'WebKitLibraries/win' directory, not the 'WebKitLibraries/' directory.\n\n";
1703         }
1704         if (!$ENV{'WEBKIT_LIBRARIES'}) {
1705             # VS2010 (and newer) version. This will replace the VS2005 version as part of
1706             # https://bugs.webkit.org/show_bug.cgi?id=109472. 
1707             print "Warning: You must set the 'WebKit_Libraries' environment variable\n";
1708             print "         to be able build WebKit from within Visual Studio 2010 and newer.\n";
1709             print "         Make sure that 'WebKit_Libraries' points to the\n";
1710             print "         'WebKitLibraries/win' directory, not the 'WebKitLibraries/' directory.\n\n";
1711         }
1712         if (!$ENV{'WEBKITOUTPUTDIR'}) {
1713             # VS2005 version.  This will be removed as part of https://bugs.webkit.org/show_bug.cgi?id=109472.
1714             print "Warning: You must set the 'WebKitOutputDir' environment variable\n";
1715             print "         to be able build WebKit from within Visual Studio 2005.\n\n";
1716         }
1717         if (!$ENV{'WEBKIT_OUTPUTDIR'}) {
1718             # VS2010 (and newer) version. This will replace the VS2005 version as part of
1719             # https://bugs.webkit.org/show_bug.cgi?id=109472. 
1720             print "Warning: You must set the 'WebKit_OutputDir' environment variable\n";
1721             print "         to be able build WebKit from within Visual Studio 2010 and newer.\n\n";
1722         }
1723         if (!$ENV{'WEBKIT_SOURCE'}) {
1724             print "Warning: You must set the 'WebKit_Source' environment variable\n";
1725             print "         to be able build WebKit from within Visual Studio 2010 and newer.\n\n";
1726         }
1727     }
1728 }
1729
1730 sub setupCygwinEnv()
1731 {
1732     return if !isCygwin() && !isWindows();
1733     return if $vcBuildPath;
1734
1735     my $vsInstallDir;
1736     my $programFilesPath = $ENV{'PROGRAMFILES(X86)'} || $ENV{'PROGRAMFILES'} || "C:\\Program Files";
1737     if ($ENV{'VSINSTALLDIR'}) {
1738         $vsInstallDir = $ENV{'VSINSTALLDIR'};
1739     } else {
1740         $vsInstallDir = File::Spec->catdir($programFilesPath, "Microsoft Visual Studio 8");
1741     }
1742     chomp($vsInstallDir = `cygpath "$vsInstallDir"`) if isCygwin();
1743     $vcBuildPath = File::Spec->catfile($vsInstallDir, qw(Common7 IDE devenv.com));
1744     if (-e $vcBuildPath) {
1745         # Visual Studio is installed; we can use pdevenv to build.
1746         # FIXME: Make pdevenv work with non-Cygwin Perl.
1747         $vcBuildPath = File::Spec->catfile(sourceDir(), qw(Tools Scripts pdevenv)) if isCygwin();
1748     } else {
1749         # Visual Studio not found, try VC++ Express
1750         $vcBuildPath = File::Spec->catfile($vsInstallDir, qw(Common7 IDE VCExpress.exe));
1751         if (! -e $vcBuildPath) {
1752             print "*************************************************************\n";
1753             print "Cannot find '$vcBuildPath'\n";
1754             print "Please execute the file 'vcvars32.bat' from\n";
1755             print "'$programFilesPath\\Microsoft Visual Studio 8\\VC\\bin\\'\n";
1756             print "to setup the necessary environment variables.\n";
1757             print "*************************************************************\n";
1758             die;
1759         }
1760         $willUseVCExpressWhenBuilding = 1;
1761     }
1762
1763     my $qtSDKPath = File::Spec->catdir($programFilesPath, "QuickTime SDK");
1764     if (0 && ! -e $qtSDKPath) {
1765         print "*************************************************************\n";
1766         print "Cannot find '$qtSDKPath'\n";
1767         print "Please download the QuickTime SDK for Windows from\n";
1768         print "http://developer.apple.com/quicktime/download/\n";
1769         print "*************************************************************\n";
1770         die;
1771     }
1772     
1773     unless ($ENV{WEBKITLIBRARIESDIR}) {
1774         $ENV{'WEBKITLIBRARIESDIR'} = File::Spec->catdir($sourceDir, "WebKitLibraries", "win");
1775         chomp($ENV{WEBKITLIBRARIESDIR} = `cygpath -wa '$ENV{WEBKITLIBRARIESDIR}'`) if isCygwin();
1776     }
1777     unless ($ENV{WEBKIT_LIBRARIES}) {
1778         $ENV{'WEBKIT_LIBRARIES'} = File::Spec->catdir($sourceDir, "WebKitLibraries", "win");
1779         chomp($ENV{WEBKIT_LIBRARIES} = `cygpath -wa '$ENV{WEBKIT_LIBRARIES}'`) if isCygwin();
1780     }
1781
1782     print "Building results into: ", baseProductDir(), "\n";
1783     print "WEBKITOUTPUTDIR is set to: ", $ENV{"WEBKITOUTPUTDIR"}, "\n";
1784     print "WEBKIT_OUTPUTDIR is set to: ", $ENV{"WEBKIT_OUTPUTDIR"}, "\n";
1785     print "WEBKITLIBRARIESDIR is set to: ", $ENV{"WEBKITLIBRARIESDIR"}, "\n";
1786     print "WEBKIT_LIBRARIES is set to: ", $ENV{"WEBKIT_LIBRARIES"}, "\n";
1787 }
1788
1789 sub dieIfWindowsPlatformSDKNotInstalled
1790 {
1791     my $registry32Path = "/proc/registry/";
1792     my $registry64Path = "/proc/registry64/";
1793     my $windowsPlatformSDKRegistryEntry = "HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/MicrosoftSDK/InstalledSDKs/D2FF9F89-8AA2-4373-8A31-C838BF4DBBE1";
1794
1795     # FIXME: It would be better to detect whether we are using 32- or 64-bit Windows
1796     # and only check the appropriate entry. But for now we just blindly check both.
1797     return if (-e $registry32Path . $windowsPlatformSDKRegistryEntry) || (-e $registry64Path . $windowsPlatformSDKRegistryEntry);
1798
1799     print "*************************************************************\n";
1800     print "Cannot find registry entry '$windowsPlatformSDKRegistryEntry'.\n";
1801     print "Please download and install the Microsoft Windows Server 2003 R2\n";
1802     print "Platform SDK from <http://www.microsoft.com/downloads/details.aspx?\n";
1803     print "familyid=0baf2b35-c656-4969-ace8-e4c0c0716adb&displaylang=en>.\n\n";
1804     print "Then follow step 2 in the Windows section of the \"Installing Developer\n";
1805     print "Tools\" instructions at <http://www.webkit.org/building/tools.html>.\n";
1806     print "*************************************************************\n";
1807     die;
1808 }
1809
1810 sub copyInspectorFrontendFiles
1811 {
1812     my $productDir = productDir();
1813     my $sourceInspectorPath = sourceDir() . "/Source/WebCore/inspector/front-end/";
1814     my $inspectorResourcesDirPath = $ENV{"WEBKITINSPECTORRESOURCESDIR"};
1815
1816     if (!defined($inspectorResourcesDirPath)) {
1817         $inspectorResourcesDirPath = "";
1818     }
1819
1820     if (isAppleMacWebKit()) {
1821         $inspectorResourcesDirPath = $productDir . "/WebCore.framework/Resources/inspector";
1822     } elsif (isAppleWinWebKit()) {
1823         $inspectorResourcesDirPath = $productDir . "/WebKit.resources/inspector";
1824     } elsif (isQt() || isGtk()) {
1825         my $prefix = $ENV{"WebKitInstallationPrefix"};
1826         $inspectorResourcesDirPath = (defined($prefix) ? $prefix : "/usr/share") . "/webkit-1.0/webinspector";
1827     } elsif (isEfl()) {
1828         my $prefix = $ENV{"WebKitInstallationPrefix"};
1829         $inspectorResourcesDirPath = (defined($prefix) ? $prefix : "/usr/share") . "/ewebkit/webinspector";
1830     }
1831
1832     if (! -d $inspectorResourcesDirPath) {
1833         print "*************************************************************\n";
1834         print "Cannot find '$inspectorResourcesDirPath'.\n" if (defined($inspectorResourcesDirPath));
1835         print "Make sure that you have built WebKit first.\n" if (! -d $productDir || defined($inspectorResourcesDirPath));
1836         print "Optionally, set the environment variable 'WebKitInspectorResourcesDir'\n";
1837         print "to point to the directory that contains the WebKit Inspector front-end\n";
1838         print "files for the built WebCore framework.\n";
1839         print "*************************************************************\n";
1840         die;
1841     }
1842
1843     if (isAppleMacWebKit()) {
1844         my $sourceLocalizedStrings = sourceDir() . "/Source/WebCore/English.lproj/localizedStrings.js";
1845         my $destinationLocalizedStrings = $productDir . "/WebCore.framework/Resources/English.lproj/localizedStrings.js";
1846         system "ditto", $sourceLocalizedStrings, $destinationLocalizedStrings;
1847     }
1848
1849     return system "rsync", "-aut", "--exclude=/.DS_Store", "--exclude=*.re2js", "--exclude=.svn/", !isQt() ? "--exclude=/WebKit.qrc" : "", $sourceInspectorPath, $inspectorResourcesDirPath;
1850 }
1851
1852 sub buildXCodeProject($$@)
1853 {
1854     my ($project, $clean, @extraOptions) = @_;
1855
1856     if ($clean) {
1857         push(@extraOptions, "-alltargets");
1858         push(@extraOptions, "clean");
1859     }
1860
1861     return system "xcodebuild", "-project", "$project.xcodeproj", @extraOptions;
1862 }
1863
1864 sub usingVisualStudioExpress()
1865 {
1866     setupCygwinEnv();
1867     return $willUseVCExpressWhenBuilding;
1868 }
1869
1870 sub buildVisualStudioProject
1871 {
1872     my ($project, $clean) = @_;
1873     setupCygwinEnv();
1874
1875     my $config = configurationForVisualStudio();
1876
1877     dieIfWindowsPlatformSDKNotInstalled() if $willUseVCExpressWhenBuilding;
1878
1879     chomp($project = `cygpath -w "$project"`) if isCygwin();
1880     
1881     my $action = "/build";
1882     if ($clean) {
1883         $action = "/clean";
1884     }
1885
1886     my @command = ($vcBuildPath, $project, $action, $config);
1887
1888     print join(" ", @command), "\n";
1889     return system @command;
1890 }
1891
1892 sub downloadWafIfNeeded
1893 {
1894     # get / update waf if needed
1895     my $waf = "$sourceDir/Tools/waf/waf";
1896     my $wafURL = 'http://wxwebkit.kosoftworks.com/downloads/deps/waf';
1897     if (!-f $waf) {
1898         my $result = system "curl -o $waf $wafURL";
1899         chmod 0755, $waf;
1900     }
1901 }
1902
1903 sub buildWafProject
1904 {
1905     my ($project, $shouldClean, @options) = @_;
1906     
1907     # set the PYTHONPATH for waf
1908     my $pythonPath = $ENV{'PYTHONPATH'};
1909     if (!defined($pythonPath)) {
1910         $pythonPath = '';
1911     }
1912     my $sourceDir = sourceDir();
1913     my $newPythonPath = "$sourceDir/Tools/waf/build:$pythonPath";
1914     if (isCygwin()) {
1915         $newPythonPath = `cygpath --mixed --path $newPythonPath`;
1916     }
1917     $ENV{'PYTHONPATH'} = $newPythonPath;
1918     
1919     print "Building $project\n";
1920
1921     my $wafCommand = "$sourceDir/Tools/waf/waf";
1922     if ($ENV{'WXWEBKIT_WAF'}) {
1923         $wafCommand = $ENV{'WXWEBKIT_WAF'};
1924     }
1925     if (isCygwin()) {
1926         $wafCommand = `cygpath --windows "$wafCommand"`;
1927         chomp($wafCommand);
1928     }
1929     if ($shouldClean) {
1930         return system $wafCommand, "uninstall", "clean", "distclean";
1931     }
1932     
1933     return system $wafCommand, 'configure', 'build', 'install', @options;
1934 }
1935
1936 sub retrieveQMakespecVar
1937 {
1938     my $mkspec = $_[0];
1939     my $varname = $_[1];
1940
1941     my $varvalue = undef;
1942     #print "retrieveMakespecVar " . $mkspec . ", " . $varname . "\n";
1943
1944     local *SPEC;
1945     open SPEC, "<$mkspec" or return $varvalue;
1946     while (<SPEC>) {
1947         if ($_ =~ /\s*include\((.+)\)/) {
1948             # open the included mkspec
1949             my $oldcwd = getcwd();
1950             (my $volume, my $directories, my $file) = File::Spec->splitpath($mkspec);
1951             my $newcwd = "$volume$directories";
1952             chdir $newcwd if $newcwd;
1953             $varvalue = retrieveQMakespecVar($1, $varname);
1954             chdir $oldcwd;
1955         } elsif ($_ =~ /$varname\s*=\s*([^\s]+)/) {
1956             $varvalue = $1;
1957             last;
1958         }
1959     }
1960     close SPEC;
1961     return $varvalue;
1962 }
1963
1964 sub qtMakeCommand($)
1965 {
1966     my ($qmakebin) = @_;
1967     chomp(my $hostDataPath = `$qmakebin -query QT_HOST_DATA`);
1968     my $mkspecPath = $hostDataPath . "/mkspecs/default/qmake.conf";
1969     if (! -e $mkspecPath) {
1970         chomp(my $mkspec= `$qmakebin -query QMAKE_XSPEC`);
1971         $mkspecPath = $hostDataPath . "/mkspecs/" . $mkspec . "/qmake.conf";
1972     }
1973     my $compiler = retrieveQMakespecVar($mkspecPath, "QMAKE_CC");
1974
1975     #print "default spec: " . $mkspec . "\n";
1976     #print "compiler found: " . $compiler . "\n";
1977
1978     if ($compiler && $compiler eq "cl") {
1979         return "nmake";
1980     }
1981
1982     return "make";
1983 }
1984
1985 sub autotoolsFlag($$)
1986 {
1987     my ($flag, $feature) = @_;
1988     my $prefix = $flag ? "--enable" : "--disable";
1989
1990     return $prefix . '-' . $feature;
1991 }
1992
1993 sub runAutogenForAutotoolsProjectIfNecessary($@)
1994 {
1995     my ($dir, $prefix, $sourceDir, $project, $joinedOverridableFeatures, @buildArgs) = @_;
1996
1997     # Always enable introspection when building WebKitGTK+.
1998     unshift(@buildArgs, "--enable-introspection");
1999
2000     my $joinedBuildArgs = join(" ", @buildArgs);
2001
2002     if (-e "GNUmakefile") {
2003         # Just assume that build-jsc will never be used to reconfigure JSC. Later
2004         # we can go back and make this more complicated if the demand is there.
2005         if ($project ne "WebKit") {
2006             return;
2007         }
2008
2009         # Run autogen.sh again if either the features overrided by build-webkit or build arguments have changed.
2010         if (!mustReRunAutogen($sourceDir, "WebKitFeatureOverrides.txt", $joinedOverridableFeatures)
2011             && !mustReRunAutogen($sourceDir, "previous-autogen-arguments.txt", $joinedBuildArgs)) {
2012             return;
2013         }
2014     }
2015
2016     print "Calling autogen.sh in " . $dir . "\n\n";
2017     print "Installation prefix directory: $prefix\n" if(defined($prefix));
2018
2019     # Only for WebKit, write the autogen.sh arguments to a file so that we can detect
2020     # when they change and automatically re-run it.
2021     if ($project eq 'WebKit') {
2022         open(OVERRIDABLE_FEATURES, ">WebKitFeatureOverrides.txt");
2023         print OVERRIDABLE_FEATURES $joinedOverridableFeatures;
2024         close(OVERRIDABLE_FEATURES);
2025
2026         open(AUTOTOOLS_ARGUMENTS, ">previous-autogen-arguments.txt");
2027         print AUTOTOOLS_ARGUMENTS $joinedBuildArgs;
2028         close(AUTOTOOLS_ARGUMENTS);
2029     }
2030
2031     # Make the path relative since it will appear in all -I compiler flags.
2032     # Long argument lists cause bizarre slowdowns in libtool.
2033     my $relSourceDir = File::Spec->abs2rel($sourceDir) || ".";
2034
2035     # Compiler options to keep floating point values consistent
2036     # between 32-bit and 64-bit architectures. The options are also
2037     # used on Chromium build.
2038     determineArchitecture();
2039     if ($architecture ne "x86_64" && !isARM()) {
2040         $ENV{'CXXFLAGS'} = "-march=pentium4 -msse2 -mfpmath=sse " . ($ENV{'CXXFLAGS'} || "");
2041     }
2042
2043     # Prefix the command with jhbuild run.
2044     unshift(@buildArgs, "$relSourceDir/autogen.sh");
2045     unshift(@buildArgs, jhbuildWrapperPrefixIfNeeded());
2046     if (system(@buildArgs) ne 0) {
2047         die "Calling autogen.sh failed!\n";
2048     }
2049 }
2050
2051 sub getJhbuildPath()
2052 {
2053     return join('/', baseProductDir(), "Dependencies");
2054 }
2055
2056 sub mustReRunAutogen($@)
2057 {
2058     my ($sourceDir, $filename, $currentContents) = @_;
2059
2060     if (! -e $filename) {
2061         return 1;
2062     }
2063
2064     open(CONTENTS_FILE, $filename);
2065     chomp(my $previousContents = <CONTENTS_FILE>);
2066     close(CONTENTS_FILE);
2067
2068     # We only care about the WebKit2 argument when we are building WebKit itself.
2069     # build-jsc never passes --enable-webkit2, so if we didn't do this, autogen.sh
2070     # would run for every single build on the bots, since it runs both build-webkit
2071     # and build-jsc.
2072     if ($previousContents ne $currentContents) {
2073         print "Contents for file $filename have changed.\n";
2074         print "Previous contents were: $previousContents\n\n";
2075         print "New contents are: $currentContents\n";
2076         return 1;
2077     }
2078
2079     return 0;
2080 }
2081
2082 sub buildAutotoolsProject($@)
2083 {
2084     my ($project, $clean, $prefix, $makeArgs, $noWebKit1, $noWebKit2, @features) = @_;
2085
2086     my $make = 'make';
2087     my $dir = productDir();
2088     my $config = passedConfiguration() || configuration();
2089
2090     # Use rm to clean the build directory since distclean may miss files
2091     if ($clean && -d $dir) {
2092         system "rm", "-rf", "$dir";
2093     }
2094
2095     if (! -d $dir) {
2096         File::Path::mkpath($dir) or die "Failed to create build directory " . $dir
2097     }
2098     chdir $dir or die "Failed to cd into " . $dir . "\n";
2099
2100     if ($clean) {
2101         return 0;
2102     }
2103
2104     my @buildArgs = @ARGV;
2105     if ($noWebKit1) {
2106         unshift(@buildArgs, "--disable-webkit1");
2107     }
2108     if ($noWebKit2) {
2109         unshift(@buildArgs, "--disable-webkit2");
2110     }
2111
2112     # Configurable features listed here should be kept in sync with the
2113     # features for which there exists a configuration option in configure.ac.
2114     my %configurableFeatures = (
2115         "gamepad" => 1,
2116         "geolocation" => 1,
2117         "svg" => 1,
2118         "svg-fonts" => 1,
2119         "video" => 1,
2120         "webgl" => 1,
2121         "web-audio" => 1,
2122     );
2123
2124     # These features are ones which build-webkit cannot control, typically because
2125     # they can only be active when we have the proper dependencies.
2126     my %unsetFeatures = (
2127         "accelerated-2d-canvas" => 1,
2128     );
2129
2130     my @overridableFeatures = ();
2131     foreach (@features) {
2132         if ($configurableFeatures{$_->{option}}) {
2133             push @buildArgs, autotoolsFlag(${$_->{value}}, $_->{option});;
2134         } elsif (!$unsetFeatures{$_->{option}}) {
2135             push @overridableFeatures, $_->{define} . "=" . (${$_->{value}} ? "1" : "0");
2136         }
2137     }
2138
2139     $makeArgs = $makeArgs || "";
2140     $makeArgs = $makeArgs . " " . $ENV{"WebKitMakeArguments"} if $ENV{"WebKitMakeArguments"};
2141
2142     # Automatically determine the number of CPUs for make only
2143     # if make arguments haven't already been specified.
2144     if ($makeArgs eq "") {
2145         $makeArgs = "-j" . numberOfCPUs();
2146     }
2147
2148     # WebKit is the default target, so we don't need to specify anything.
2149     if ($project eq "JavaScriptCore") {
2150         $makeArgs .= " jsc";
2151     } elsif ($project eq "WTF") {
2152         $makeArgs .= " libWTF.la";
2153     }
2154
2155     $prefix = $ENV{"WebKitInstallationPrefix"} if !defined($prefix);
2156     push @buildArgs, "--prefix=" . $prefix if defined($prefix);
2157
2158     # Check if configuration is Debug.
2159     my $debug = $config =~ m/debug/i;
2160     if ($debug) {
2161         push @buildArgs, "--enable-debug";
2162     } else {
2163         push @buildArgs, "--disable-debug";
2164     }
2165
2166     if (checkForArgumentAndRemoveFromArrayRef("--update-gtk", \@buildArgs)) {
2167         # Force autogen to run, to catch the possibly updated libraries.
2168         system("rm -f previous-autogen-arguments.txt");
2169
2170         system("perl", "$sourceDir/Tools/Scripts/update-webkitgtk-libs") == 0 or die $!;
2171     }
2172
2173     # If GNUmakefile exists, don't run autogen.sh unless its arguments
2174     # have changed. The makefile should be smart enough to track autotools
2175     # dependencies and re-run autogen.sh when build files change.
2176     my $joinedOverridableFeatures = join(" ", @overridableFeatures);
2177     runAutogenForAutotoolsProjectIfNecessary($dir, $prefix, $sourceDir, $project, $joinedOverridableFeatures, @buildArgs);
2178
2179     my $runWithJhbuild = join(" ", jhbuildWrapperPrefixIfNeeded());
2180     if (system("$runWithJhbuild $make $makeArgs") ne 0) {
2181         die "\nFailed to build WebKit using '$make'!\n";
2182     }
2183
2184     chdir ".." or die;
2185
2186     if ($project eq 'WebKit' && !isCrossCompilation() && !($noWebKit1 && $noWebKit2)) {
2187         my @docGenerationOptions = ("$sourceDir/Tools/gtk/generate-gtkdoc", "--skip-html");
2188         push(@docGenerationOptions, productDir());
2189
2190         unshift(@docGenerationOptions, jhbuildWrapperPrefixIfNeeded());
2191
2192         if (system(@docGenerationOptions)) {
2193             die "\n gtkdoc did not build without warnings\n";
2194         }
2195     }
2196
2197     return 0;
2198 }
2199
2200 sub jhbuildWrapperPrefixIfNeeded()
2201 {
2202     if (-e getJhbuildPath()) {
2203         my @prefix = (File::Spec->catfile(sourceDir(), "Tools", "jhbuild", "jhbuild-wrapper"));
2204         if (isEfl()) {
2205             push(@prefix, "--efl");
2206         } elsif (isGtk()) {
2207             push(@prefix, "--gtk");
2208         }
2209         push(@prefix, "run");
2210
2211         return @prefix;
2212     }
2213
2214     return ();
2215 }
2216
2217 sub removeCMakeCache()
2218 {
2219     my $cacheFilePath = File::Spec->catdir(baseProductDir(), configuration(), "CMakeCache.txt");
2220     unlink($cacheFilePath) if -e $cacheFilePath;
2221 }
2222
2223 sub generateBuildSystemFromCMakeProject
2224 {
2225     my ($port, $prefixPath, @cmakeArgs, $additionalCMakeArgs) = @_;
2226     my $config = configuration();
2227     my $buildPath = File::Spec->catdir(baseProductDir(), $config);
2228     File::Path::mkpath($buildPath) unless -d $buildPath;
2229     my $originalWorkingDirectory = getcwd();
2230     chdir($buildPath) or die;
2231
2232     my @args;
2233     push @args, "-DPORT=\"$port\"";
2234     push @args, "-DCMAKE_INSTALL_PREFIX=\"$prefixPath\"" if $prefixPath;
2235     push @args, "-DSHARED_CORE=ON" if isEfl() && $ENV{"ENABLE_DRT"};
2236     if ($config =~ /release/i) {
2237         push @args, "-DCMAKE_BUILD_TYPE=Release";
2238     } elsif ($config =~ /debug/i) {
2239         push @args, "-DCMAKE_BUILD_TYPE=Debug";
2240     }
2241     # Don't warn variables which aren't used by cmake ports.
2242     push @args, "--no-warn-unused-cli";
2243     push @args, @cmakeArgs if @cmakeArgs;
2244     push @args, $additionalCMakeArgs if $additionalCMakeArgs;
2245
2246     push @args, '"' . sourceDir() . '"';
2247
2248     # Compiler options to keep floating point values consistent
2249     # between 32-bit and 64-bit architectures.
2250     determineArchitecture();
2251     if ($architecture ne "x86_64" && !isARM()) {
2252         $ENV{'CXXFLAGS'} = "-march=pentium4 -msse2 -mfpmath=sse " . ($ENV{'CXXFLAGS'} || "");
2253     }
2254
2255     # We call system("cmake @args") instead of system("cmake", @args) so that @args is
2256     # parsed for shell metacharacters.
2257     my $wrapper = join(" ", jhbuildWrapperPrefixIfNeeded()) . " ";
2258     my $returnCode = system($wrapper . "cmake @args");
2259
2260     chdir($originalWorkingDirectory);
2261     return $returnCode;
2262 }
2263
2264 sub buildCMakeGeneratedProject($)
2265 {
2266     my ($makeArgs) = @_;
2267     my $config = configuration();
2268     my $buildPath = File::Spec->catdir(baseProductDir(), $config);
2269     if (! -d $buildPath) {
2270         die "Must call generateBuildSystemFromCMakeProject() before building CMake project.";
2271     }
2272     my @args = ("--build", $buildPath, "--config", $config);
2273     push @args, ("--", $makeArgs) if $makeArgs;
2274
2275     # We call system("cmake @args") instead of system("cmake", @args) so that @args is
2276     # parsed for shell metacharacters. In particular, $makeArgs may contain such metacharacters.
2277     my $wrapper = join(" ", jhbuildWrapperPrefixIfNeeded()) . " ";
2278     return system($wrapper . "cmake @args");
2279 }
2280
2281 sub cleanCMakeGeneratedProject()
2282 {
2283     my $config = configuration();
2284     my $buildPath = File::Spec->catdir(baseProductDir(), $config);
2285     if (-d $buildPath) {
2286         return system("cmake", "--build", $buildPath, "--config", $config, "--target", "clean");
2287     }
2288     return 0;
2289 }
2290
2291 sub buildCMakeProjectOrExit($$$$@)
2292 {
2293     my ($clean, $port, $prefixPath, $makeArgs, @cmakeArgs) = @_;
2294     my $returnCode;
2295
2296     exit(exitStatus(cleanCMakeGeneratedProject())) if $clean;
2297
2298     if (isEfl() && checkForArgumentAndRemoveFromARGV("--update-efl")) {
2299         system("perl", "$sourceDir/Tools/Scripts/update-webkitefl-libs") == 0 or die $!;
2300     }
2301
2302
2303     $returnCode = exitStatus(generateBuildSystemFromCMakeProject($port, $prefixPath, @cmakeArgs));
2304     exit($returnCode) if $returnCode;
2305     if (isBlackBerry()) {
2306         return 0 if (defined($ENV{"GENERATE_CMAKE_PROJECT_ONLY"}) eq '1');
2307     }
2308     $returnCode = exitStatus(buildCMakeGeneratedProject($makeArgs));
2309     exit($returnCode) if $returnCode;
2310     return 0;
2311 }
2312
2313 sub cmakeBasedPortArguments()
2314 {
2315     return blackberryCMakeArguments() if isBlackBerry();
2316     return ('-G "Visual Studio 8 2005 STANDARDSDK_500 (ARMV4I)"') if isWinCE();
2317     return ();
2318 }
2319
2320 sub cmakeBasedPortName()
2321 {
2322     return "BlackBerry" if isBlackBerry();
2323     return "Efl" if isEfl();
2324     return "WinCE" if isWinCE();
2325     return "";
2326 }
2327
2328 sub promptUser
2329 {
2330     my ($prompt, $default) = @_;
2331     my $defaultValue = $default ? "[$default]" : "";
2332     print "$prompt $defaultValue: ";
2333     chomp(my $input = <STDIN>);
2334     return $input ? $input : $default;
2335 }
2336
2337 sub buildQMakeProjects
2338 {
2339     my ($projects, $clean, @buildParams) = @_;
2340
2341     my @buildArgs = ();
2342     my $qconfigs = "";
2343
2344     my $make = qtMakeCommand($qmakebin);
2345     my $makeargs = "";
2346     my $command;
2347     my $installHeaders;
2348     my $installLibs;
2349     for my $i (0 .. $#buildParams) {
2350         my $opt = $buildParams[$i];
2351         if ($opt =~ /^--qmake=(.*)/i ) {
2352             $qmakebin = $1;
2353         } elsif ($opt =~ /^--qmakearg=(.*)/i ) {
2354             push @buildArgs, $1;
2355         } elsif ($opt =~ /^--makeargs=(.*)/i ) {
2356             $makeargs = $1;
2357         } elsif ($opt =~ /^--install-headers=(.*)/i ) {
2358             $installHeaders = $1;
2359         } elsif ($opt =~ /^--install-libs=(.*)/i ) {
2360             $installLibs = $1;
2361         } else {
2362             push @buildArgs, $opt;
2363         }
2364     }
2365
2366     # Automatically determine the number of CPUs for make only if this make argument haven't already been specified.
2367     if ($make eq "make" && $makeargs !~ /-j\s*\d+/i && (!defined $ENV{"MAKEFLAGS"} || ($ENV{"MAKEFLAGS"} !~ /-j\s*\d+/i ))) {
2368         $makeargs .= " -j" . numberOfCPUs();
2369     }
2370
2371     $make = "$make $makeargs";
2372     $make =~ s/\s+$//;
2373
2374     my $originalCwd = getcwd();
2375     my $dir = File::Spec->canonpath(productDir());
2376     File::Path::mkpath($dir);
2377     chdir $dir or die "Failed to cd into " . $dir . "\n";
2378
2379     if ($clean) {
2380         $command = "$make distclean";
2381         print "\nCalling '$command' in " . $dir . "\n\n";
2382         return system $command;
2383     }
2384
2385     my $qmakepath = File::Spec->catfile(sourceDir(), "Tools", "qmake");
2386     my $qmakecommand = $qmakebin;
2387
2388     my $config = configuration();
2389     push @buildArgs, "INSTALL_HEADERS=" . $installHeaders if defined($installHeaders);
2390     push @buildArgs, "INSTALL_LIBS=" . $installLibs if defined($installLibs);
2391
2392     my $passedConfig = passedConfiguration() || "";
2393     if ($passedConfig =~ m/debug/i) {
2394         push @buildArgs, "CONFIG-=release";
2395         push @buildArgs, "CONFIG+=debug";
2396     } elsif ($passedConfig =~ m/release/i) {
2397         push @buildArgs, "CONFIG+=release";
2398         push @buildArgs, "CONFIG-=debug";
2399     } elsif ($passedConfig) {
2400         die "Build type $passedConfig is not supported with --qt.\n";
2401     }
2402
2403     # Using build-webkit to build assumes you want a developer-build
2404     push @buildArgs, "CONFIG-=production_build";
2405
2406     my $svnRevision = currentSVNRevision();
2407     my $previousSvnRevision = "unknown";
2408
2409     my $buildHint = "";
2410
2411     my $pathToBuiltRevisions = File::Spec->catfile($dir, ".builtRevisions.cache");
2412     if (-e $pathToBuiltRevisions && open(BUILTREVISIONS, $pathToBuiltRevisions)) {
2413         while (<BUILTREVISIONS>) {
2414             if ($_ =~ m/^SVN_REVISION\s=\s(\d+)$/) {
2415                 $previousSvnRevision = $1;
2416             }
2417         }
2418         close(BUILTREVISIONS);
2419     }
2420
2421     my $result = 0;
2422
2423     # Run qmake, regadless of having a makefile or not, so that qmake can
2424     # detect changes to the configuration.
2425
2426     push @buildArgs, "-after OVERRIDE_SUBDIRS=\"@{$projects}\"" if @{$projects};
2427     unshift @buildArgs, File::Spec->catfile(sourceDir(), "WebKit.pro");
2428     $command = "$qmakecommand @buildArgs";
2429     print "Calling '$command' in " . $dir . "\n\n";
2430     print "Installation headers directory: $installHeaders\n" if(defined($installHeaders));
2431     print "Installation libraries directory: $installLibs\n" if(defined($installLibs));
2432
2433     my $configChanged = 0;
2434     open(QMAKE, "$command 2>&1 |") || die "Could not execute qmake";
2435     while (<QMAKE>) {
2436         $configChanged = 1 if $_ =~ m/The configuration was changed since the last build/;
2437         print $_;
2438     }
2439
2440     close(QMAKE);
2441     $result = $?;
2442
2443     if ($result ne 0) {
2444        die "\nFailed to set up build environment using $qmakebin!\n";
2445     }
2446
2447     my $maybeNeedsCleanBuild = 0;
2448     my $needsIncrementalBuild = 0;
2449
2450     # Full incremental build (run qmake) needed on buildbots and EWS bots always.
2451     if (grep(/CONFIG\+=buildbot/,@buildParams)) {
2452         $needsIncrementalBuild = 1;
2453     }
2454
2455     if ($svnRevision ne $previousSvnRevision) {
2456         print "Last built revision was " . $previousSvnRevision .
2457             ", now at revision $svnRevision. Full incremental build needed.\n";
2458         $needsIncrementalBuild = 1;
2459
2460         my @fileList = listOfChangedFilesBetweenRevisions(sourceDir(), $previousSvnRevision, $svnRevision);
2461
2462         foreach (@fileList) {
2463             if (m/\.pr[oif]$/ or
2464                 m/\.qmake.conf$/ or
2465                 m/^Tools\/qmake\//
2466                ) {
2467                 print "Change to $_ detected, clean build may be needed.\n";
2468                 $maybeNeedsCleanBuild = 1;
2469                 last;
2470             }
2471         }
2472     }
2473
2474     if ($configChanged) {
2475         print "Calling '$make wipeclean' in " . $dir . "\n\n";
2476         $result = system "$make wipeclean";
2477     }
2478
2479     $command = "$make";
2480     if ($needsIncrementalBuild) {
2481         $command .= " incremental";
2482     }
2483
2484     print "\nCalling '$command' in " . $dir . "\n\n";
2485     $result = system $command;
2486
2487     chdir ".." or die;
2488
2489     if ($result eq 0) {
2490         # Now that the build completed successfully we can save the SVN revision
2491         open(BUILTREVISIONS, ">>$pathToBuiltRevisions");
2492         print BUILTREVISIONS "SVN_REVISION = $svnRevision\n";
2493         close(BUILTREVISIONS);
2494     } elsif (!$command =~ /incremental/ && exitStatus($result)) {
2495         my $exitCode = exitStatus($result);
2496         my $failMessage = <<EOF;
2497
2498 ===== BUILD FAILED ======
2499
2500 The build failed with exit code $exitCode. This may have been because you
2501
2502   - added an #include to a source/header
2503   - added a Q_OBJECT macro to a class
2504   - added a new resource to a qrc file
2505
2506 as dependencies are not automatically re-computed for local developer builds.
2507 You may try computing dependencies manually by running 'make qmake_all' in:
2508
2509   $dir
2510
2511 or passing --makeargs="qmake_all" to build-webkit.
2512
2513 =========================
2514
2515 EOF
2516         print "$failMessage";
2517     } elsif ($maybeNeedsCleanBuild) {
2518         print "\nIncremental build failed, clean build needed. \n";
2519         print "Calling '$make wipeclean' in " . $dir . "\n\n";
2520         chdir $dir or die;
2521         system "$make wipeclean";
2522
2523         print "\nCalling '$make' in " . $dir . "\n\n";
2524         $result = system $make;
2525     }
2526
2527     return $result;
2528 }
2529
2530 sub buildGtkProject
2531 {
2532     my ($project, $clean, $prefix, $makeArgs, $noWebKit1, $noWebKit2, @features) = @_;
2533
2534     if ($project ne "WebKit" and $project ne "JavaScriptCore" and $project ne "WTF") {
2535         die "Unsupported project: $project. Supported projects: WebKit, JavaScriptCore, WTF\n";
2536     }
2537
2538     return buildAutotoolsProject($project, $clean, $prefix, $makeArgs, $noWebKit1, $noWebKit2, @features);
2539 }
2540
2541 sub buildChromiumMakefile($$@)
2542 {
2543     my ($target, $clean, @options) = @_;
2544     if ($clean) {
2545         return system qw(rm -rf out);
2546     }
2547     my $config = configuration();
2548     my $numCpus = numberOfCPUs();
2549     my $makeArgs;
2550     for (@options) {
2551         $makeArgs = $1 if /^--makeargs=(.*)/i;
2552     }
2553     $makeArgs = "-j$numCpus" if not $makeArgs;
2554     my $command .= "make -fMakefile.chromium $makeArgs BUILDTYPE=$config $target";
2555
2556     print "$command\n";
2557     return system $command;
2558 }
2559
2560 sub buildChromiumNinja($$@)
2561 {
2562     # rm -rf out requires rerunning gyp, so don't support --clean for now.
2563     my ($target, @options) = @_;
2564     my $config = configuration();
2565     my $makeArgs = "";
2566     for (@options) {
2567         $makeArgs = $1 if /^--makeargs=(.*)/i;
2568     }
2569     my $command = "";
2570
2571     # Find ninja.
2572     my $ninjaPath;
2573     if (commandExists('ninja')) {
2574         $ninjaPath = 'ninja';
2575     } elsif (-e 'Source/WebKit/chromium/depot_tools/ninja') {
2576         $ninjaPath = 'Source/WebKit/chromium/depot_tools/ninja';
2577     } else {
2578         die "ninja not found. Install chromium's depot_tools by running update-webkit first\n";
2579     }
2580
2581     $command .= "$ninjaPath -C out/$config $target $makeArgs";
2582
2583     print "$command\n";
2584     return system $command;
2585 }
2586
2587 sub buildChromiumVisualStudioProject($$)
2588 {
2589     my ($projectPath, $clean) = @_;
2590
2591     my $config = configuration();
2592     my $action = "/build";
2593     $action = "/clean" if $clean;
2594
2595     # Find Visual Studio installation.
2596     my $vsInstallDir;
2597     my $programFilesPath = $ENV{'PROGRAMFILES'} || "C:\\Program Files";
2598     if ($ENV{'VSINSTALLDIR'}) {
2599         $vsInstallDir = $ENV{'VSINSTALLDIR'};
2600     } else {
2601         $vsInstallDir = "$programFilesPath/Microsoft Visual Studio 8";
2602     }
2603     $vsInstallDir =~ s,\\,/,g;
2604     $vsInstallDir = `cygpath "$vsInstallDir"` if isCygwin();
2605     chomp $vsInstallDir;
2606     $vcBuildPath = "$vsInstallDir/Common7/IDE/devenv.com";
2607     if (! -e $vcBuildPath) {
2608         # Visual Studio not found, try VC++ Express
2609         $vcBuildPath = "$vsInstallDir/Common7/IDE/VCExpress.exe";
2610         if (! -e $vcBuildPath) {
2611             print "*************************************************************\n";
2612             print "Cannot find '$vcBuildPath'\n";
2613             print "Please execute the file 'vcvars32.bat' from\n";
2614             print "'$programFilesPath\\Microsoft Visual Studio 8\\VC\\bin\\'\n";
2615             print "to setup the necessary environment variables.\n";
2616             print "*************************************************************\n";
2617             die;
2618         }
2619     }
2620
2621     # Create command line and execute it.
2622     my @command = ($vcBuildPath, $projectPath, $action, $config);
2623     print "Building results into: ", baseProductDir(), "\n";
2624     print join(" ", @command), "\n";
2625     return system @command;
2626 }
2627
2628 sub buildChromium($@)
2629 {
2630     my ($clean, @options) = @_;
2631
2632     # We might need to update DEPS or re-run GYP if things have changed.
2633     if (checkForArgumentAndRemoveFromArrayRef("--update-chromium", \@options)) {
2634         my @updateCommand = ("perl", "Tools/Scripts/update-webkit-chromium", "--force");
2635         push @updateCommand, "--chromium-android" if isChromiumAndroid();
2636         system(@updateCommand) == 0 or die $!;
2637     }
2638
2639     my $result = 1;
2640     if (isDarwin() && !isChromiumAndroid() && !isChromiumMacMake() && !isChromiumNinja()) {
2641         # Mac build - builds the root xcode project.
2642         $result = buildXCodeProject("Source/WebKit/chromium/All", $clean, "-configuration", configuration(), @options);
2643     } elsif ((isCygwin() || isWindows()) && !isChromiumNinja()) {
2644         # Windows build - builds the root visual studio solution.
2645         $result = buildChromiumVisualStudioProject("Source/WebKit/chromium/All.sln", $clean);
2646     } elsif (isChromiumNinja()) {
2647         $result = buildChromiumNinja("all", $clean, @options);
2648     } elsif (isLinux() || isChromiumAndroid() || isChromiumMacMake()) {
2649         # Linux build - build using make.
2650         $result = buildChromiumMakefile("all", $clean, @options);
2651     } else {
2652         print STDERR "This platform is not supported by chromium.\n";
2653     }
2654     return $result;
2655 }
2656
2657 sub appleApplicationSupportPath
2658 {
2659     open INSTALL_DIR, "</proc/registry/HKEY_LOCAL_MACHINE/SOFTWARE/Apple\ Inc./Apple\ Application\ Support/InstallDir";
2660     my $path = <INSTALL_DIR>;
2661     $path =~ s/[\r\n\x00].*//;
2662     close INSTALL_DIR;
2663
2664     my $unixPath = `cygpath -u '$path'`;
2665     chomp $unixPath;
2666     return $unixPath;
2667 }
2668
2669 sub setPathForRunningWebKitApp
2670 {
2671     my ($env) = @_;
2672
2673     if (isAppleWinWebKit()) {
2674         $env->{PATH} = join(':', productDir(), dirname(installedSafariPath()), appleApplicationSupportPath(), $env->{PATH} || "");
2675     } elsif (isQt()) {
2676         my $qtLibs = `$qmakebin -query QT_INSTALL_LIBS`;
2677         $qtLibs =~ s/[\n|\r]$//g;
2678         $env->{PATH} = join(';', $qtLibs, productDir() . "/lib", $env->{PATH} || "");
2679     }
2680 }
2681
2682 sub printHelpAndExitForRunAndDebugWebKitAppIfNeeded
2683 {
2684     return unless checkForArgumentAndRemoveFromARGV("--help");
2685
2686     my ($includeOptionsForDebugging) = @_;
2687
2688     print STDERR <<EOF;
2689 Usage: @{[basename($0)]} [options] [args ...]
2690   --help                            Show this help message
2691   --no-saved-state                  Launch the application without state restoration (OS X 10.7 and later)
2692   --guard-malloc                    Enable Guard Malloc (OS X only)
2693   --use-web-process-xpc-service     Launch the Web Process as an XPC Service (OS X only)
2694 EOF
2695
2696     if ($includeOptionsForDebugging) {
2697         print STDERR <<EOF;
2698   --target-web-process              Debug the web process
2699   --use-gdb                         Use GDB (this is the default when using Xcode 4.4 or earlier)
2700   --use-lldb                        Use LLDB (this is the default when using Xcode 4.5 or later)
2701 EOF
2702     }
2703
2704     exit(1);
2705 }
2706
2707 sub argumentsForRunAndDebugMacWebKitApp()
2708 {
2709     my @args = ();
2710     push @args, ("-ApplePersistenceIgnoreState", "YES") if !isSnowLeopard() && checkForArgumentAndRemoveFromArrayRef("--no-saved-state", \@args);
2711     push @args, ("-WebKit2UseXPCServiceForWebProcess", "YES") if shouldUseXPCServiceForWebProcess();
2712     unshift @args, @ARGV;
2713
2714     return @args;
2715 }
2716
2717 sub runMacWebKitApp($;$)
2718 {
2719     my ($appPath, $useOpenCommand) = @_;
2720     my $productDir = productDir();
2721     print "Starting @{[basename($appPath)]} with DYLD_FRAMEWORK_PATH set to point to built WebKit in $productDir.\n";
2722     $ENV{DYLD_FRAMEWORK_PATH} = $productDir;
2723     $ENV{WEBKIT_UNSET_DYLD_FRAMEWORK_PATH} = "YES";
2724
2725     setUpGuardMallocIfNeeded();
2726
2727     if (defined($useOpenCommand) && $useOpenCommand == USE_OPEN_COMMAND) {
2728         return system("open", "-W", "-a", $appPath, "--args", argumentsForRunAndDebugMacWebKitApp());
2729     }
2730     if (architecture()) {
2731         return system "arch", "-" . architecture(), $appPath, argumentsForRunAndDebugMacWebKitApp();
2732     }
2733     return system { $appPath } $appPath, argumentsForRunAndDebugMacWebKitApp();
2734 }
2735
2736 sub execMacWebKitAppForDebugging($)
2737 {
2738     my ($appPath) = @_;
2739     my $architectureSwitch;
2740     my $argumentsSeparator;
2741
2742     if (debugger() eq "lldb") {
2743         $architectureSwitch = "--arch";
2744         $argumentsSeparator = "--";
2745     } elsif (debugger() eq "gdb") {
2746         $architectureSwitch = "-arch";
2747         $argumentsSeparator = "--args";
2748     } else {
2749         die "Unknown debugger $debugger.\n";
2750     }
2751
2752     my $debuggerPath = `xcrun -find $debugger`;
2753     chomp $debuggerPath;
2754     die "Can't find the $debugger executable.\n" unless -x $debuggerPath;
2755
2756     my $productDir = productDir();
2757     $ENV{DYLD_FRAMEWORK_PATH} = $productDir;
2758     $ENV{WEBKIT_UNSET_DYLD_FRAMEWORK_PATH} = "YES";
2759
2760     setUpGuardMallocIfNeeded();
2761
2762     my @architectureFlags = ($architectureSwitch, architecture());
2763     if (!shouldTargetWebProcess()) {
2764         print "Starting @{[basename($appPath)]} under $debugger with DYLD_FRAMEWORK_PATH set to point to built WebKit in $productDir.\n";
2765         exec { $debuggerPath } $debuggerPath, @architectureFlags, $argumentsSeparator, $appPath, argumentsForRunAndDebugMacWebKitApp() or die;
2766     } else {
2767         if (shouldUseXPCServiceForWebProcess()) {
2768             die "Targetting the Web Process is not compatible with using an XPC Service for the Web Process at this time.";
2769         }
2770         
2771         my $webProcessShimPath = File::Spec->catfile($productDir, "SecItemShim.dylib");
2772         my $webProcessPath = File::Spec->catdir($productDir, "WebProcess.app");
2773         my $webKit2ExecutablePath = File::Spec->catfile($productDir, "WebKit2.framework", "WebKit2");
2774
2775         appendToEnvironmentVariableList("DYLD_INSERT_LIBRARIES", $webProcessShimPath);
2776
2777         print "Starting WebProcess under $debugger with DYLD_FRAMEWORK_PATH set to point to built WebKit in $productDir.\n";
2778         exec { $debuggerPath } $debuggerPath, @architectureFlags, $argumentsSeparator, $webProcessPath, $webKit2ExecutablePath, "-type", "webprocess", "-client-executable", $appPath or die;
2779     }
2780 }
2781
2782 sub debugSafari
2783 {
2784     if (isAppleMacWebKit()) {
2785         checkFrameworks();
2786         execMacWebKitAppForDebugging(safariPath());
2787     }
2788
2789     if (isAppleWinWebKit()) {
2790         setupCygwinEnv();
2791         my $productDir = productDir();
2792         chomp($ENV{WEBKITNIGHTLY} = `cygpath -wa "$productDir"`);
2793         my $safariPath = safariPath();
2794         chomp($safariPath = `cygpath -wa "$safariPath"`);
2795         return system { $vcBuildPath } $vcBuildPath, "/debugexe", "\"$safariPath\"", @ARGV;
2796     }
2797
2798     return 1; # Unsupported platform; can't debug Safari on this platform.
2799 }
2800
2801 sub runSafari
2802 {
2803
2804     if (isAppleMacWebKit()) {
2805         return runMacWebKitApp(safariPath());
2806     }
2807
2808     if (isAppleWinWebKit()) {
2809         my $result;
2810         my $productDir = productDir();
2811         my $webKitLauncherPath = File::Spec->catfile(productDir(), "WebKit.exe");
2812         return system { $webKitLauncherPath } $webKitLauncherPath, @ARGV;
2813     }
2814
2815     return 1; # Unsupported platform; can't run Safari on this platform.
2816 }
2817
2818 sub runMiniBrowser
2819 {
2820     if (isAppleMacWebKit()) {
2821         return runMacWebKitApp(File::Spec->catfile(productDir(), "MiniBrowser.app", "Contents", "MacOS", "MiniBrowser"));
2822     }
2823
2824     return 1;
2825 }
2826
2827 sub debugMiniBrowser
2828 {
2829     if (isAppleMacWebKit()) {
2830         execMacWebKitAppForDebugging(File::Spec->catfile(productDir(), "MiniBrowser.app", "Contents", "MacOS", "MiniBrowser"));
2831     }
2832     
2833     return 1;
2834 }
2835
2836 sub runWebKitTestRunner
2837 {
2838     if (isAppleMacWebKit()) {
2839         return runMacWebKitApp(File::Spec->catfile(productDir(), "WebKitTestRunner"));
2840     } elsif (isGtk()) {
2841         my $productDir = productDir();
2842         my $injectedBundlePath = "$productDir/Libraries/.libs/libTestRunnerInjectedBundle";
2843         print "Starting WebKitTestRunner with TEST_RUNNER_INJECTED_BUNDLE_FILENAME set to point to $injectedBundlePath.\n";
2844         $ENV{TEST_RUNNER_INJECTED_BUNDLE_FILENAME} = $injectedBundlePath;
2845         my @args = ("$productDir/Programs/WebKitTestRunner", @ARGV);
2846         return system {$args[0] } @args;
2847     }
2848
2849     return 1;
2850 }
2851
2852 sub debugWebKitTestRunner
2853 {
2854     if (isAppleMacWebKit()) {
2855         execMacWebKitAppForDebugging(File::Spec->catfile(productDir(), "WebKitTestRunner"));
2856     }
2857
2858     return 1;
2859 }
2860
2861 sub runTestWebKitAPI
2862 {
2863     if (isAppleMacWebKit()) {
2864         return runMacWebKitApp(File::Spec->catfile(productDir(), "TestWebKitAPI"));
2865     }
2866
2867     return 1;
2868 }
2869
2870 sub readRegistryString
2871 {
2872     my ($valueName) = @_;
2873     chomp(my $string = `regtool --wow32 get "$valueName"`);
2874     return $string;
2875 }
2876
2877 sub writeRegistryString
2878 {
2879     my ($valueName, $string) = @_;
2880
2881     my $error = system "regtool", "--wow32", "set", "-s", $valueName, $string;
2882
2883     # On Windows Vista/7 with UAC enabled, regtool will fail to modify the registry, but will still
2884     # return a successful exit code. So we double-check here that the value we tried to write to the
2885     # registry was really written.
2886     return !$error && readRegistryString($valueName) eq $string;
2887 }
2888
2889 1;