1 # Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions
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.
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.
27 # Module to share code to get to WebKit directories.
38 our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
41 @EXPORT = qw(&chdirWebKit &baseProductDir &productDir &XcodeOptions &XcodeOptionString &XcodeOptionStringNoConfig &passedConfiguration &setConfiguration &safariPath &checkFrameworks ¤tSVNRevision);
49 my @baseProductDirOption;
51 my $configurationForVisualStudio;
52 my $configurationProductDir;
54 my $currentSVNRevision;
60 # Variables for Win32 support
64 sub determineSourceDir
67 $sourceDir = $FindBin::Bin;
69 # walks up path checking each directory to see if it is the main WebKit project dir,
70 # defined by containing JavaScriptCore, WebCore, and WebKit
71 until ((-d "$sourceDir/JavaScriptCore" && -d "$sourceDir/WebCore" && -d "$sourceDir/WebKit") || (-d "$sourceDir/Internal" && -d "$sourceDir/OpenSource"))
73 if ($sourceDir !~ s|/[^/]+$||) {
74 die "Could not find top level webkit directory above source directory using FindBin.\n";
78 $sourceDir = "$sourceDir/OpenSource" if -d "$sourceDir/OpenSource";
81 # used for scripts which are stored in a non-standard location
87 sub determineBaseProductDir
89 return if defined $baseProductDir;
92 open PRODUCT, "defaults read com.apple.Xcode PBXApplicationwideBuildSettings 2> /dev/null |" or die;
93 $baseProductDir = join '', <PRODUCT>;
96 $baseProductDir = $1 if $baseProductDir =~ /SYMROOT\s*=\s*\"(.*?)\";/s;
97 undef $baseProductDir unless $baseProductDir =~ /^\//;
99 if (!defined($baseProductDir)) {
100 open PRODUCT, "defaults read com.apple.Xcode PBXProductDirectory 2> /dev/null |" or die;
101 $baseProductDir = <PRODUCT>;
103 if ($baseProductDir) {
104 chomp $baseProductDir;
105 undef $baseProductDir unless $baseProductDir =~ /^\//;
109 $baseProductDir = $ENV{"WEBKITOUTPUTDIR"};
110 if (isCygwin() && $baseProductDir) {
111 my $unixBuildPath = `cygpath --unix \"$baseProductDir\"`;
112 chomp $unixBuildPath;
113 $baseProductDir = $unixBuildPath;
117 if ($baseProductDir && isOSX()) {
118 $baseProductDir =~ s|^\Q$(SRCROOT)/..\E$|$sourceDir|;
119 $baseProductDir =~ s|^\Q$(SRCROOT)/../|$sourceDir/|;
120 $baseProductDir =~ s|^~/|$ENV{HOME}/|;
121 die "Can't handle Xcode product directory with a ~ in it.\n" if $baseProductDir =~ /~/;
122 die "Can't handle Xcode product directory with a variable in it.\n" if $baseProductDir =~ /\$/;
123 @baseProductDirOption = ();
126 if (!defined($baseProductDir)) {
127 $baseProductDir = "$sourceDir/WebKitBuild";
129 if (isGit() && isGitBranchBuild()) {
130 my $branch = gitBranch();
131 $baseProductDir = "$baseProductDir/$branch";
134 @baseProductDirOption = ("SYMROOT=$baseProductDir", "OBJROOT=$baseProductDir") if (isOSX());
136 my $dosBuildPath = `cygpath --windows \"$baseProductDir\"`;
138 $ENV{"WEBKITOUTPUTDIR"} = $dosBuildPath;
143 sub setBaseProductDir($)
145 ($baseProductDir) = @_;
148 sub determineConfiguration
150 return if defined $configuration;
151 determineBaseProductDir();
152 if (open CONFIGURATION, "$baseProductDir/Configuration") {
153 $configuration = <CONFIGURATION>;
156 if ($configuration) {
157 chomp $configuration;
158 # compatibility for people who have old Configuration files
159 $configuration = "Release" if $configuration eq "Deployment";
160 $configuration = "Debug" if $configuration eq "Development";
162 $configuration = "Release";
166 sub determineConfigurationForVisualStudio
168 return if defined $configurationForVisualStudio;
169 determineConfiguration();
170 $configurationForVisualStudio = $configuration;
171 return unless $configuration eq "Debug";
173 chomp(my $dir = `cygpath -ua '$ENV{WEBKITLIBRARIESDIR}'`);
174 $configurationForVisualStudio = "Debug_Internal" if -f "$dir/bin/CoreFoundation_debug.dll";
177 sub determineConfigurationProductDir
179 return if defined $configurationProductDir;
180 determineBaseProductDir();
181 if(isCygwin() && !isWx()) {
182 $configurationProductDir = "$baseProductDir/bin";
184 determineConfiguration();
185 $configurationProductDir = "$baseProductDir/$configuration";
189 sub setConfigurationProductDir($)
191 ($configurationProductDir) = @_;
194 sub determineCurrentSVNRevision
196 return if defined $currentSVNRevision;
197 determineSourceDir();
198 my $svnInfo = `LC_ALL=C svn info $sourceDir | grep Revision:`;
199 ($currentSVNRevision) = ($svnInfo =~ m/Revision: (\d+).*/g);
200 die "Unable to determine current SVN revision in $sourceDir" unless (defined $currentSVNRevision);
201 return $currentSVNRevision;
207 determineSourceDir();
208 chdir $sourceDir or die;
213 determineBaseProductDir();
214 return $baseProductDir;
219 determineSourceDir();
225 determineConfigurationProductDir();
226 return $configurationProductDir;
231 determineConfiguration();
232 return $configuration;
235 sub configurationForVisualStudio()
237 determineConfigurationForVisualStudio();
238 return $configurationForVisualStudio;
241 sub currentSVNRevision
243 determineCurrentSVNRevision();
244 return $currentSVNRevision;
249 determineBaseProductDir();
250 determineConfiguration();
251 return (@baseProductDirOption, "-configuration", $configuration);
254 sub XcodeOptionString
256 return join " ", XcodeOptions();
259 sub XcodeOptionStringNoConfig
261 return join " ", @baseProductDirOption;
264 my $passedConfiguration;
265 my $searchedForPassedConfiguration;
266 sub determinePassedConfiguration
268 return if $searchedForPassedConfiguration;
269 $searchedForPassedConfiguration = 1;
270 for my $i (0 .. $#ARGV) {
272 if ($opt =~ /^--debug$/i || $opt =~ /^--devel/i) {
273 splice(@ARGV, $i, 1);
274 $passedConfiguration = "Debug";
277 if ($opt =~ /^--release$/i || $opt =~ /^--deploy/i) {
278 splice(@ARGV, $i, 1);
279 $passedConfiguration = "Release";
283 $passedConfiguration = undef;
286 sub passedConfiguration
288 determinePassedConfiguration();
289 return $passedConfiguration;
294 if (my $config = shift @_) {
295 $configuration = $config;
299 determinePassedConfiguration();
300 $configuration = $passedConfiguration if $passedConfiguration;
303 sub safariPathFromSafariBundle
305 my ($safariBundle) = @_;
307 return "$safariBundle/Contents/MacOS/Safari" if isOSX();
308 return $safariBundle if isCygwin();
311 sub installedSafariPath
316 $safariBundle = "/Applications/Safari.app";
317 } elsif (isCygwin()) {
318 my $findSafariName = "FindSafari";
319 $findSafariName .= "_debug" if $configuration ne "Release";
320 $findSafariName .= ".exe";
322 $safariBundle = `"$configurationProductDir/$findSafariName"`;
323 $safariBundle =~ s/[\r\n]+$//;
324 $safariBundle = `cygpath -u '$safariBundle'`;
325 $safariBundle =~ s/[\r\n]+$//;
326 $safariBundle .= "Safari.exe";
329 return safariPathFromSafariBundle($safariBundle);
335 # Use WEBKIT_SAFARI environment variable if present.
336 my $safariBundle = $ENV{WEBKIT_SAFARI};
337 if (!$safariBundle) {
338 determineConfigurationProductDir();
339 # Use Safari.app in product directory if present (good for Safari development team).
340 if (isOSX() && -d "$configurationProductDir/Safari.app") {
341 $safariBundle = "$configurationProductDir/Safari.app";
342 } elsif (isCygwin() && -x "$configurationProductDir/bin/Safari.exe") {
343 $safariBundle = "$configurationProductDir/bin/Safari.exe";
345 return installedSafariPath();
348 my $safariPath = safariPathFromSafariBundle($safariBundle);
349 die "Can't find executable at $safariPath.\n" if isOSX() && !-x $safariPath;
353 sub builtDylibPathForName
355 my $framework = shift;
356 determineConfigurationProductDir();
357 if (isQt() or isGtk()) {
358 return "$configurationProductDir/$framework";
361 return "$configurationProductDir/$framework.framework/Versions/A/$framework";
364 if ($framework eq "JavaScriptCore") {
365 return "$baseProductDir/lib/$framework.lib";
367 return "$baseProductDir/$framework.intermediate/$configuration/$framework.intermediate/$framework.lib";
371 die "Unsupported platform, can't determine built library locations.";
374 # Check to see that all the frameworks are built.
377 return if isCygwin();
378 my @frameworks = ("JavaScriptCore", "WebCore");
379 push(@frameworks, "WebKit") if isOSX();
380 for my $framework (@frameworks) {
381 my $path = builtDylibPathForName($framework);
382 die "Can't find built framework at \"$path\".\n" unless -x $path;
388 return 0 if isCygwin();
396 if (isGtk() and $path =~ /WebCore/) {
397 $path .= "/../lib/libWebKitGtk.so" if !$ENV{WEBKITAUTOTOOLS};
398 $path .= "/../.libs/libWebKitGtk.so" if $ENV{WEBKITAUTOTOOLS};
401 my $hasSVGSupport = 0;
403 open NM, "-|", "nm", $path or die;
405 $hasSVGSupport = 1 if /SVGElement/;
409 return $hasSVGSupport;
412 sub removeLibraryDependingOnSVG
414 my $frameworkName = shift;
415 my $shouldHaveSVG = shift;
417 my $path = builtDylibPathForName($frameworkName);
418 return unless -x $path;
420 my $hasSVG = hasSVGSupport($path);
421 system "rm -f $path" if ($shouldHaveSVG xor $hasSVG);
424 sub checkWebCoreSVGSupport
426 my $required = shift;
427 my $framework = "WebCore";
428 my $path = builtDylibPathForName($framework);
429 my $hasSVG = hasSVGSupport($path);
430 if ($required && !$hasSVG) {
431 die "$framework at \"$path\" does not include SVG Support, please run build-webkit --svg\n";
444 my $argToCheck = shift;
445 foreach my $opt (@ARGV) {
446 if ($opt =~ /^$argToCheck/i ) {
447 @ARGV = grep(!/^$argToCheck/i, @ARGV);
456 return if defined($isQt);
458 # Allow override in case QTDIR is not set.
459 if (checkArgv("--qt")) {
464 # The presence of QTDIR only means Qt if --gtk is not on the command-line
470 $isQt = defined($ENV{'QTDIR'});
481 return if defined($isGtk);
483 if (checkArgv("--gtk")) {
498 return if defined($isWx);
500 if (checkArgv("--wx")) {
507 # Determine if this is debian, ubuntu, linspire, or something similar.
510 return -e "/etc/debian_version";
515 return ($^O eq "cygwin");
520 return ($^O eq "darwin");
525 return isDarwin() unless (isQt() or isGtk() or isWx());
529 sub determineOSXVersion()
531 return if $osXVersion;
538 my $version = `sw_vers -productVersion`;
539 my @splitVersion = split(/\./, $version);
540 @splitVersion >= 2 or die "Invalid version $version";
542 "major" => $splitVersion[0],
543 "minor" => $splitVersion[1],
544 "subminor" => (defined($splitVersion[2]) ? $splitVersion[2] : 0),
550 determineOSXVersion();
556 return isOSX() && osXVersion()->{"minor"} == 4;
561 return isOSX() && osXVersion()->{"minor"} == 5;
564 sub relativeScriptsDir()
566 my $scriptDir = File::Spec->catpath("", File::Spec->abs2rel(dirname($0), getcwd()), "");
567 if ($scriptDir eq "") {
575 my $relativeScriptsPath = relativeScriptsDir();
576 if (isGtk() || isQt()) {
577 return "$relativeScriptsPath/run-launcher";
578 } elsif (isOSX() || isCygwin()) {
579 return "$relativeScriptsPath/run-safari";
586 return "GtkLauncher";
589 } elsif (isOSX() || isCygwin()) {
594 sub checkRequiredSystemConfig
597 chomp(my $productVersion = `sw_vers -productVersion`);
598 if ($productVersion lt "10.4") {
599 print "*************************************************************\n";
600 print "Mac OS X Version 10.4.0 or later is required to build WebKit.\n";
601 print "You have " . $productVersion . ", thus the build will most likely fail.\n";
602 print "*************************************************************\n";
604 my $xcodeVersion = `xcodebuild -version`;
605 if ($xcodeVersion !~ /DevToolsCore-(\d+)/ || $1 < 747) {
606 print "*************************************************************\n";
607 print "Xcode Version 2.3 or later is required to build WebKit.\n";
608 print "You have an earlier version of Xcode, thus the build will\n";
609 print "most likely fail. The latest Xcode is available from the web:\n";
610 print "http://developer.apple.com/tools/xcode\n";
611 print "*************************************************************\n";
613 } elsif (isGtk() or isQt() or isWx()) {
614 my @cmds = qw(flex bison gperf);
616 foreach my $cmd (@cmds) {
617 if (not `$cmd --version`) {
622 my $list = join ", ", @missing;
623 die "ERROR: $list missing but required to build WebKit.\n";
626 # Win32 and other platforms may want to check for minimum config
631 return if !isCygwin();
632 return if $vcBuildPath;
634 my $programFilesPath = `cygpath "$ENV{'PROGRAMFILES'}"`;
635 chomp $programFilesPath;
636 $vcBuildPath = "$programFilesPath/Microsoft Visual Studio 8/Common7/IDE/devenv.com";
637 if (! -e $vcBuildPath) {
638 # VC++ not found, try VC++ Express
640 if ($ENV{'VSINSTALLDIR'}) {
641 $vsInstallDir = $ENV{'VSINSTALLDIR'};
643 $programFilesPath = $ENV{'PROGRAMFILES'} || "C:\\Program Files";
644 $vsInstallDir = "$programFilesPath/Microsoft Visual Studio 8";
646 $vsInstallDir = `cygpath "$vsInstallDir"`;
648 $vcBuildPath = "$vsInstallDir/Common7/IDE/VCExpress.exe";
649 if (! -e $vcBuildPath) {
650 print "*************************************************************\n";
651 print "Cannot find '$vcBuildPath'\n";
652 print "Please execute the file 'vcvars32.bat' from\n";
653 print "'$programFilesPath\\Microsoft Visual Studio 8\\VC\\bin\\'\n";
654 print "to setup the necessary environment variables.\n";
655 print "*************************************************************\n";
660 my $qtSDKPath = "$programFilesPath/QuickTime SDK";
661 if (0 && ! -e $qtSDKPath) {
662 print "*************************************************************\n";
663 print "Cannot find '$qtSDKPath'\n";
664 print "Please download the QuickTime SDK for Windows from\n";
665 print "http://developer.apple.com/quicktime/download/\n";
666 print "*************************************************************\n";
670 chomp($ENV{'WEBKITLIBRARIESDIR'} = `cygpath -wa "$sourceDir/WebKitLibraries/win"`) unless $ENV{'WEBKITLIBRARIESDIR'};
672 $windowsTmpPath = `cygpath -w /tmp`;
673 chomp $windowsTmpPath;
674 print "Building results into: ", baseProductDir(), "\n";
675 print "WEBKITOUTPUTDIR is set to: ", $ENV{"WEBKITOUTPUTDIR"}, "\n";
676 print "WEBKITLIBRARIESDIR is set to: ", $ENV{"WEBKITLIBRARIESDIR"}, "\n";
679 sub buildVisualStudioProject
681 my ($project, $clean) = @_;
684 my $config = configurationForVisualStudio();
686 chomp(my $winProjectPath = `cygpath -w "$project"`);
688 my $command = "/build";
693 print "$vcBuildPath $winProjectPath /build $config\n";
694 return system $vcBuildPath, $winProjectPath, $command, $config;
700 chomp(my $mkspec = `$qmakebin -query QMAKE_MKSPECS`);
701 $mkspec .= "/default";
704 open SPEC, "<$mkspec/qmake.conf" or return "make";
706 if ($_ =~ /QMAKE_CC\s*=\s*([^\s]+)/) {
712 #print "default spec: " . $mkspec . "\n";
713 #print "compiler found: " . $compiler . "\n";
715 if ($compiler eq "cl") {
722 sub autotoolsFlag($$)
724 my ($flag, $feature) = @_;
725 my $prefix = $flag ? "--enable" : "--disable";
727 return $prefix . '-' . $feature;
730 sub buildAutotoolsProject($@)
732 my ($clean, @buildArgs) = @_;
735 my $dir = productDir();
736 my $config = passedConfiguration() || configuration();
737 my $prefix = $ENV{"WebKitInstallationPrefix"};
739 # check if configuration is Debug
740 if ($config =~ m/debug/i) {
741 push @buildArgs, "--enable-debug";
743 push @buildArgs, "--disable-debug";
747 system "mkdir", "-p", "$dir";
749 die "Failed to create build directory " . $dir;
753 chdir $dir or die "Failed to cd into " . $dir . "\n";
757 $result = system $make, "distclean";
761 print "Calling configure in " . $dir . "\n\n";
762 print "Installation directory: $prefix\n" if(defined($prefix));
764 $result = system "$sourceDir/autogen.sh", @buildArgs;
766 die "Failed to setup build environment using 'autotools'!\n";
769 $result = system $make;
771 die "\nFailed to build WebKit using '$make'!\n";
778 sub buildQMakeProject($@)
780 my ($clean, @buildArgs) = @_;
782 push @buildArgs, "-r";
784 my $qmakebin = "qmake"; # Allow override of the qmake binary from $PATH
785 for my $i (0 .. $#ARGV) {
787 if ($opt =~ /^--qmake=(.*)/i ) {
789 } elsif ($opt =~ /^--qmakearg=(.*)/i ) {
794 my $make = qtMakeCommand($qmakebin);
795 my $config = configuration();
796 my $prefix = $ENV{"WebKitInstallationPrefix"};
798 push @buildArgs, "OUTPUT_DIR=" . baseProductDir() . "/$config";
799 push @buildArgs, sourceDir() . "/WebKit.pro";
800 if ($config =~ m/debug/i) {
801 push @buildArgs, "CONFIG-=release";
802 push @buildArgs, "CONFIG+=debug";
804 push @buildArgs, "CONFIG+=release";
805 push @buildArgs, "CONFIG-=debug";
808 my $dir = baseProductDir();
810 system "mkdir", "-p", "$dir";
812 die "Failed to create product directory " . $dir;
815 $dir = $dir . "/$config";
817 system "mkdir", "-p", "$dir";
819 die "Failed to create build directory " . $dir;
823 chdir $dir or die "Failed to cd into " . $dir . "\n";
825 print "Calling '$qmakebin @buildArgs' in " . $dir . "\n\n";
826 print "Installation directory: $prefix\n" if(defined($prefix));
828 my $result = system $qmakebin, @buildArgs;
830 die "Failed to setup build environment using $qmakebin!\n";
834 $result = system "$make distclean";
836 $result = system "$make";
843 sub buildQMakeQtProject($$)
845 my ($project, $clean) = @_;
847 my @buildArgs = ("CONFIG+=qt-port");
848 return buildQMakeProject($clean, @buildArgs);
851 sub buildGtkProject($$@)
853 my ($project, $clean, @buildArgs) = @_;
855 if ($project ne "WebKit") {
856 die "The Gtk port builds JavaScriptCore, WebCore and WebKit in one shot! Only call it for 'WebKit'.\n";
859 if ($ENV{WEBKITAUTOTOOLS}) {
860 return buildAutotoolsProject($clean, @buildArgs);
862 my @buildArgs = {"CONFIG+=gtk-port"};
863 push @buildArgs, "CONFIG-=qt";
864 return buildQMakeProject($clean, @buildArgs);
868 sub setPathForRunningWebKitApp
872 return unless isCygwin();
874 $env->{PATH} = join(':', productDir(), dirname(installedSafariPath()), $env->{PATH} || "");
879 my ($returnvalue) = @_;
880 if ($^O eq "MSWin32") {
881 return $returnvalue >> 8;
883 return WEXITSTATUS($returnvalue);
891 return system "$FindBin::Bin/gdb-safari", @ARGV if $debugger;
893 my $productDir = productDir();
894 print "Starting Safari with DYLD_FRAMEWORK_PATH set to point to built WebKit in $productDir.\n";
895 $ENV{DYLD_FRAMEWORK_PATH} = $productDir;
896 $ENV{WEBKIT_UNSET_DYLD_FRAMEWORK_PATH} = "YES";
897 return system safariPath(), @ARGV;
901 my $script = "run-webkit-nightly.cmd";
902 my $result = system "cp", "$FindBin::Bin/$script", productDir();
903 return $result if $result;
908 my $debuggerFlag = $debugger ? "/debugger" : "";
909 $result = system "cmd", "/c", "call $script $debuggerFlag";
922 return system "$FindBin::Bin/gdb-drosera", @ARGV if $debugger;
924 my $productDir = productDir();
925 print "Starting Drosera with DYLD_FRAMEWORK_PATH set to point to built WebKit in $productDir.\n";
926 $ENV{DYLD_FRAMEWORK_PATH} = $productDir;
927 $ENV{WEBKIT_UNSET_DYLD_FRAMEWORK_PATH} = "YES";
929 my $droseraPath = "$productDir/Drosera.app/Contents/MacOS/Drosera";
930 return system $droseraPath, @ARGV;
934 print "Running Drosera\n";
935 my $script = "run-drosera-nightly.cmd";
936 my $prodDir = productDir();
937 my $result = system "cp", "$FindBin::Bin/$script", $prodDir;
938 return $result if $result;
943 my $debuggerFlag = $debugger ? "/debugger" : "";
944 $result = system "cmd", "/c", "call $script $debuggerFlag";