088fca5d499e6a7e1a0e8ba7ac528125d8c31a06
[WebKit-https.git] / WebKitTools / Scripts / webkitdirs.pm
1 # Copyright (C) 2005, 2006 Apple Computer, 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
29 use strict;
30 use warnings;
31 use FindBin;
32
33 BEGIN {
34    use Exporter   ();
35    our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
36    $VERSION     = 1.00;
37    @ISA         = qw(Exporter);
38    @EXPORT      = qw(&chdirWebKit &baseProductDir &productDir &XcodeOptions &XcodeOptionString &XcodeOptionStringNoConfig &passedConfiguration &setConfiguration &safariPath &checkFrameworks &currentSVNRevision);
39    %EXPORT_TAGS = ( );
40    @EXPORT_OK   = ();
41 }
42
43 our @EXPORT_OK;
44
45 my $baseProductDir;
46 my @baseProductDirOption;
47 my $configuration;
48 my $configurationProductDir;
49 my $sourceDir;
50 my $currentSVNRevision;
51
52 # Variables for Win32 support
53 my $vcBuildPath;
54 my $windowsTmpPath;
55
56 sub determineSourceDir
57 {
58     return if $sourceDir;
59     $sourceDir = $FindBin::Bin;
60     
61     # walks up path checking each directory to see if it is the main WebKit project dir, 
62     # defined by containing JavaScriptCore, WebCore, and WebKit
63     until ((-d "$sourceDir/JavaScriptCore" && -d "$sourceDir/WebCore" && -d "$sourceDir/WebKit") || (-d "$sourceDir/Internal" && -d "$sourceDir/OpenSource"))
64     {
65         if ($sourceDir !~ s|/[^/]+$||) {
66             die "Could not find top level webkit directory above source directory using FindBin.\n";
67         }
68     }
69
70     $sourceDir = "$sourceDir/OpenSource" if -d "$sourceDir/OpenSource";
71 }
72
73 # used for scripts which are stored in a non-standard location
74 sub setSourceDir($)
75 {
76     ($sourceDir) = @_;
77 }
78
79 sub determineBaseProductDir
80 {
81     return if defined $baseProductDir;
82     determineSourceDir();
83     if (isOSX()) {
84         open PRODUCT, "defaults read com.apple.Xcode PBXProductDirectory 2> /dev/null |" or die;
85         $baseProductDir = <PRODUCT>;
86         close PRODUCT;
87         if ($baseProductDir) {
88             chomp $baseProductDir;
89             undef $baseProductDir unless $baseProductDir =~ /^\//;
90         }
91     } else {
92         $baseProductDir = $ENV{"WEBKITOUTPUTDIR"};
93         if (isCygwin() && $baseProductDir) {
94             my $unixBuildPath = `cygpath --unix \"$baseProductDir\"`;
95             chomp $unixBuildPath;
96             $baseProductDir = $unixBuildPath;
97         }
98     }
99
100     if ($baseProductDir && isOSX()) {
101         $baseProductDir =~ s|^\Q$(SRCROOT)/..\E$|$sourceDir|;
102         $baseProductDir =~ s|^\Q$(SRCROOT)/../|$sourceDir/|;
103         $baseProductDir =~ s|^~/|$ENV{HOME}/|;
104         die "Can't handle Xcode product directory with a ~ in it.\n" if $baseProductDir =~ /~/;
105         die "Can't handle Xcode product directory with a variable in it.\n" if $baseProductDir =~ /\$/;
106         @baseProductDirOption = ();
107     }
108
109     if (!defined($baseProductDir)) {
110         $baseProductDir = "$sourceDir/WebKitBuild";
111         @baseProductDirOption = ("SYMROOT=$baseProductDir") if (isOSX());
112         if (isCygwin()) {
113             my $dosBuildPath = `cygpath --windows \"$baseProductDir\"`;
114             chomp $dosBuildPath;
115             $ENV{"WEBKITOUTPUTDIR"} = $dosBuildPath;
116         }
117     }
118 }
119
120 sub determineConfiguration
121 {
122     return if defined $configuration;
123     determineBaseProductDir();
124     if (open CONFIGURATION, "$baseProductDir/Configuration") {
125         $configuration = <CONFIGURATION>;
126         close CONFIGURATION;
127     }
128     if ($configuration) {
129         chomp $configuration;
130         # compatibility for people who have old Configuration files
131         $configuration = "Release" if $configuration eq "Deployment";
132         $configuration = "Debug" if $configuration eq "Development";
133     } else {
134         $configuration = "Release";
135     }
136 }
137
138 sub determineConfigurationProductDir
139 {
140     return if defined $configurationProductDir;
141     determineBaseProductDir();
142     if(isCygwin()) {
143         $configurationProductDir = "$baseProductDir/bin";
144     } else {
145         determineConfiguration();
146         $configurationProductDir = "$baseProductDir/$configuration";
147     }
148 }
149
150 sub determineCurrentSVNRevision
151 {
152     return if defined $currentSVNRevision;
153     determineSourceDir();
154     my $svnInfo = `svn info $sourceDir | grep Revision:`;
155     ($currentSVNRevision) = ($svnInfo =~ m/Revision: (\d+).*/g);
156     die "Unable to determine current SVN revision in $sourceDir" unless (defined $currentSVNRevision);
157     return $currentSVNRevision;
158 }
159
160
161 sub chdirWebKit
162 {
163     determineSourceDir();
164     chdir $sourceDir or die;
165 }
166
167 sub baseProductDir
168 {
169     determineBaseProductDir();
170     return $baseProductDir;
171 }
172
173 sub sourceDir
174 {
175     determineSourceDir();
176     return $sourceDir;
177 }
178
179 sub productDir
180 {
181     determineConfigurationProductDir();
182     return $configurationProductDir;
183 }
184
185 sub configuration()
186 {
187     determineConfiguration();
188     return $configuration;
189 }
190
191 sub currentSVNRevision
192 {
193     determineCurrentSVNRevision();
194     return $currentSVNRevision;
195 }
196
197 sub XcodeOptions
198 {
199     determineBaseProductDir();
200     determineConfiguration();
201     return (@baseProductDirOption, "-configuration", $configuration);
202 }
203
204 sub XcodeOptionString
205 {
206     return join " ", XcodeOptions();
207 }
208
209 sub XcodeOptionStringNoConfig
210 {
211     return join " ", @baseProductDirOption;
212 }
213
214 my $passedConfiguration;
215 my $searchedForPassedConfiguration;
216 sub determinePassedConfiguration
217 {
218     return if $searchedForPassedConfiguration;
219     $searchedForPassedConfiguration = 1;
220     for my $i (0 .. $#ARGV) {
221         my $opt = $ARGV[$i];
222         if ($opt =~ /^--debug$/i || $opt =~ /^--devel/i) {
223             splice(@ARGV, $i, 1);
224             $passedConfiguration = "Debug";
225             return;
226         }
227         if ($opt =~ /^--release$/i || $opt =~ /^--deploy/i) {
228             splice(@ARGV, $i, 1);
229             $passedConfiguration = "Release";
230             return;
231         }
232     }
233     $passedConfiguration = undef;
234 }
235
236 sub passedConfiguration
237 {
238     determinePassedConfiguration();
239     return $passedConfiguration;
240 }
241
242 sub setConfiguration
243 {
244     if (my $config = shift @_) {
245         $configuration = $config;
246         return;
247     }
248
249     determinePassedConfiguration();
250     $configuration = $passedConfiguration if $passedConfiguration;
251 }
252
253 # Locate Safari.
254 sub safariPath
255 {
256     # Use WEBKIT_SAFARI environment variable if present.
257     my $safariBundle = $ENV{WEBKIT_SAFARI};
258     if (!$safariBundle) {
259         determineConfigurationProductDir();
260         # Use Safari.app in product directory if present (good for Safari development team).
261         if (-d "$configurationProductDir/Safari.app") {
262             $safariBundle = "$configurationProductDir/Safari.app";
263         } else {
264             # Otherwise use Safari.app in Applications directory.
265             $safariBundle = "/Applications/Safari.app";
266         }
267     }
268     my $safariPath = "$safariBundle/Contents/MacOS/Safari";
269     die "Can't find executable at $safariPath.\n" unless -x $safariPath;
270     return $safariPath;
271 }
272
273 sub builtDylibPathForName
274 {
275     my $framework = shift;
276     determineConfigurationProductDir();
277     if (isQt() or isGdk()) {
278         return "$configurationProductDir/$framework";
279     }
280     if (isOSX()) {
281         return "$configurationProductDir/$framework.framework/Versions/A/$framework";
282     }
283     if (isCygwin()) {
284         if ($framework eq "JavaScriptCore") {
285                 return "$baseProductDir/lib/$framework.lib";
286         } else {
287             return "$baseProductDir/$framework.intermediate/$configuration/$framework.intermediate/$framework.lib";
288         }
289     }
290
291     die "Unsupported platform, can't determine built library locations.";
292 }
293
294 # Check to see that all the frameworks are built.
295 sub checkFrameworks
296 {
297     my @frameworks = ("JavaScriptCore", "WebCore");
298     push(@frameworks, "WebKit") if isOSX();
299     for my $framework (@frameworks) {
300         my $path = builtDylibPathForName($framework);
301         die "Can't find built framework at \"$path\".\n" unless -x $path;
302     }
303 }
304
305 sub hasSVGSupport
306 {
307     return 0 if isCygwin();
308
309     my $path = shift;
310
311     if (isQt() and $path =~ /WebCore/) {
312         $path .= "/../lib/libWebKitQt.so";
313     }
314
315     if (isGdk() and $path =~ /WebCore/) {
316         $path .= "/../lib/libWebKitGdk.so";
317     }
318
319     open NM, "-|", "nm", $path or die;
320     my $hasSVGSupport = 0;
321     while (<NM>) {
322         $hasSVGSupport = 1 if /SVGElement/;
323     }
324     close NM;
325     return $hasSVGSupport;
326 }
327
328 sub removeLibraryDependingOnSVG
329 {
330     my $frameworkName = shift;
331     my $shouldHaveSVG = shift;
332
333     my $path = builtDylibPathForName($frameworkName);
334     return unless -x $path;
335
336     my $hasSVG = hasSVGSupport($path);
337     system "rm -f $path" if ($shouldHaveSVG xor $hasSVG);
338 }
339
340 sub checkWebCoreSVGSupport
341 {
342     my $required = shift;
343     my $framework = "WebCore";
344     my $path = builtDylibPathForName($framework);
345     my $hasSVG = hasSVGSupport($path);
346     if ($required && !$hasSVG) {
347         die "$framework at \"$path\" does not include SVG Support, please run build-webkit --svg\n";
348     }
349     return $hasSVG;
350 }
351
352 sub isQt()
353 {
354     return defined($ENV{'QTDIR'})
355 }
356
357 sub isGdk()
358 {
359     for my $i (0 .. $#ARGV) {
360         my $opt = $ARGV[$i];
361         if ($opt =~ /^--gdk$/i ) {
362             return 1;
363         }
364     }
365     return 0;
366 }
367
368 sub isCygwin()
369 {
370     return ($^O eq "cygwin");
371 }
372
373 sub isOSX()
374 {
375     return ($^O eq "darwin");
376 }
377
378 sub checkRequiredSystemConfig
379 {
380     if (isOSX()) {
381         chomp(my $productVersion = `sw_vers -productVersion`);
382         if ($productVersion lt "10.4") {
383             print "*************************************************************\n";
384             print "Mac OS X Version 10.4.0 or later is required to build WebKit.\n";
385             print "You have " . $productVersion . ", thus the build will most likely fail.\n";
386             print "*************************************************************\n";
387         }
388         my $xcodeVersion = `xcodebuild -version`;
389         if ($xcodeVersion !~ /DevToolsCore-(\d+)/ || $1 < 747) {
390             print "*************************************************************\n";
391             print "Xcode Version 2.3 or later is required to build WebKit.\n";
392             print "You have an earlier version of Xcode, thus the build will\n";
393             print "most likely fail.  The latest Xcode is available from the web:\n";
394             print "http://developer.apple.com/tools/xcode\n";
395             print "*************************************************************\n";
396         }
397     }
398     # Win32 and other platforms may want to check for minimum config
399 }
400
401 sub setupCygwinEnv()
402 {
403     return if !isCygwin();
404     return if $vcBuildPath;
405
406     my $programFilesPath = `cygpath "$ENV{'PROGRAMFILES'}"`;
407     chomp $programFilesPath;
408     $vcBuildPath = "$programFilesPath/Microsoft Visual Studio 8/Common7/IDE/devenv.com";
409     if (! -e $vcBuildPath) {
410         # VC++ not found, try VC++ Express
411         my $vsInstallDir;
412         if ($ENV{'VSINSTALLDIR'}) {
413             $vsInstallDir = $ENV{'VSINSTALLDIR'};
414         } else {
415             $programFilesPath = $ENV{'PROGRAMFILES'} || "C:\\Program Files";
416             $vsInstallDir = "$programFilesPath/Microsoft Visual Studio 8";
417         }
418         $vsInstallDir = `cygpath "$vsInstallDir"`;
419         chomp $vsInstallDir;
420         $vcBuildPath = "$vsInstallDir/Common7/IDE/VCExpress.exe";
421         if (! -e $vcBuildPath) {
422             print "*************************************************************\n";
423             print "Cannot find '$vcBuildPath'\n";
424             print "Please execute the file 'vcvars32.bat' from\n";
425             print "'$programFilesPath\\Microsoft Visual Studio 8\\VC\\bin\\'\n";
426             print "to setup the necessary environment variables.\n";
427             print "*************************************************************\n";
428             die;
429         }
430     }
431
432     $windowsTmpPath = `cygpath -w /tmp`;
433     chomp $windowsTmpPath;
434     print "Building results into: ", baseProductDir(), "\n";
435     print "WEBKITOUTPUTDIR is set to: ", $ENV{"WEBKITOUTPUTDIR"}, "\n";
436 }
437
438 sub buildVisualStudioProject($)
439 {
440     my ($project) = @_;
441     setupCygwinEnv();
442
443     chdir "$project.vcproj" or die "Failed to cd into $project.vcproj\n";
444     my $config = configuration();
445
446     print "$vcBuildPath $project.sln /build $config";
447     my $result = system $vcBuildPath, "$project.sln", "/build", $config;
448     chdir ".." or die;
449     return $result;
450 }
451
452 sub buildQMakeProject($$)
453 {
454     my ($project, $colorize) = @_;
455
456     if ($project ne "WebKit") {
457         die "Qt/Linux builds JavaScriptCore/WebCore/WebKitQt in one shot! Only call it for 'WebKit'.\n";
458     }
459
460     my $config = configuration();
461     my $prefix = $ENV{"WebKitInstallationPrefix"};
462
463     my @buildArgs = ("-r");
464     push @buildArgs, "OUTPUT_DIR=" . baseProductDir() . "/$config";
465     push @buildArgs, "CONFIG+=qt-port";
466     push @buildArgs, sourceDir() . "/WebKit.pro";
467
468     print "Calling 'qmake @buildArgs' in " . baseProductDir() . "/$config ...\n\n";
469     print "Installation directory: $prefix\n" if(defined($prefix));
470
471     system "mkdir -p " . baseProductDir() . "/$config";
472     chdir baseProductDir() . "/$config" or die "Failed to cd into " . baseProductDir() . "/$config \n";
473
474     my $result = system "qmake", @buildArgs;
475     if($result ne 0) {
476        die "Failed to setup build environment using qmake!\n";
477     }
478
479     my $clean = $ENV{"WEBKIT_FULLBUILD"};
480
481     if(defined $clean) {
482       system "make clean";
483     }
484
485     $result = system "make";
486     chdir ".." or die;
487     return $result;
488 }
489
490 sub buildQMakeGdkProject($$)
491 {
492     my ($project, $colorize) = @_;
493
494     if ($project ne "WebKit") {
495         die "The Gdk portbuilds JavaScriptCore/WebCore/WebKitQt in one shot! Only call it for 'WebKit'.\n";
496     }
497
498     my $config = configuration();
499     my $prefix = $ENV{"WebKitInstallationPrefix"};
500
501     my @buildArgs = ("-r");
502     push @buildArgs, "OUTPUT_DIR=" . baseProductDir() . "/$config";
503     push @buildArgs, "CONFIG-=qt";
504     push @buildArgs, "CONFIG+=gdk-port";
505     push @buildArgs, sourceDir() . "/WebKit.pro";
506
507     print "Calling 'qmake @buildArgs' in " . baseProductDir() . "/$config ...\n\n";
508     print "Installation directory: $prefix\n" if(defined($prefix));
509
510     system "mkdir -p " . baseProductDir() . "/$config";
511     chdir baseProductDir() . "/$config" or die "Failed to cd into " . baseProductDir() . "/$config \n";
512
513     my $result = system "qmake-qt4", @buildArgs;
514     $result =  system "qmake", @buildArgs if ($result ne 0);
515     if ($result ne 0) {
516        die "Failed to setup build environment using qmake!\n";
517     }
518
519     my $clean = $ENV{"WEBKIT_FULLBUILD"};
520
521     if (defined $clean) {
522       system "make clean";
523     }
524
525     $result = system "make";
526     chdir ".." or die;
527     return $result;
528 }
529
530 1;