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