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