Reviewed by Stephanie.
[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 $devenvPath;
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         }
90     } else {
91         $baseProductDir =  $ENV{"WEBKITOUTPUTDIR"};
92         if (isCygwin() && $baseProductDir) {
93             my $unixBuildPath = `cygpath --unix \"$baseProductDir\"`;
94             chomp $unixBuildPath;
95             $baseProductDir = $unixBuildPath;
96         }
97     }
98
99     if ($baseProductDir && isOSX()) {
100         $baseProductDir =~ s|^\Q$(SRCROOT)/..\E$|$sourceDir|;
101         $baseProductDir =~ s|^\Q$(SRCROOT)/../|$sourceDir/|;
102         $baseProductDir =~ s|^~/|$ENV{HOME}/|;
103         die "Can't handle Xcode product directory with a ~ in it.\n" if $baseProductDir =~ /~/;
104         die "Can't handle Xcode product directory with a variable in it.\n" if $baseProductDir =~ /\$/;
105         @baseProductDirOption = ();
106     }
107
108     if (!defined($baseProductDir)) {
109         $baseProductDir = "$sourceDir/WebKitBuild";
110         @baseProductDirOption = ("SYMROOT=$baseProductDir") if (isOSX());
111         if (isCygwin()) {
112             my $dosBuildPath = `cygpath --windows \"$baseProductDir\"`;
113             chomp $dosBuildPath;
114             $ENV{"WEBKITOUTPUTDIR"} = $dosBuildPath;
115         }
116     }
117 }
118
119 sub determineConfiguration
120 {
121     return if defined $configuration;
122     determineBaseProductDir();
123     if (open CONFIGURATION, "$baseProductDir/Configuration") {
124         $configuration = <CONFIGURATION>;
125         close CONFIGURATION;
126     }
127     if ($configuration) {
128         chomp $configuration;
129         # compatibility for people who have old Configuration files
130         $configuration = "Release" if $configuration eq "Deployment";
131         $configuration = "Debug" if $configuration eq "Development";
132     } else {
133         $configuration = "Release";
134     }
135 }
136
137 sub determineConfigurationProductDir
138 {
139     return if defined $configurationProductDir;
140     determineBaseProductDir();
141     if(isCygwin()) {
142         $configurationProductDir = "$baseProductDir/bin";
143     } else {
144         determineConfiguration();
145         $configurationProductDir = "$baseProductDir/$configuration";
146     }
147 }
148
149 sub determineCurrentSVNRevision
150 {
151     return if defined $currentSVNRevision;
152     determineSourceDir();
153     my $svnInfo = `svn info $sourceDir | grep Revision:`;
154     ($currentSVNRevision) = ($svnInfo =~ m/Revision: (\d+).*/g);
155     die "Unable to determine current SVN revision in $sourceDir" unless (defined $currentSVNRevision);
156     return $currentSVNRevision;
157 }
158
159
160 sub chdirWebKit
161 {
162     determineSourceDir();
163     chdir $sourceDir or die;
164 }
165
166 sub baseProductDir
167 {
168     determineBaseProductDir();
169     return $baseProductDir;
170 }
171
172 sub productDir
173 {
174     determineConfigurationProductDir();
175     return $configurationProductDir;
176 }
177
178 sub configuration()
179 {
180     determineConfiguration();
181     return $configuration;
182 }
183
184 sub currentSVNRevision
185 {
186     determineCurrentSVNRevision();
187     return $currentSVNRevision;
188 }
189
190 sub XcodeOptions
191 {
192     determineBaseProductDir();
193     determineConfiguration();
194     return (@baseProductDirOption, "-configuration", $configuration);
195 }
196
197 sub XcodeOptionString
198 {
199     return join " ", XcodeOptions();
200 }
201
202 sub XcodeOptionStringNoConfig
203 {
204     return join " ", @baseProductDirOption;
205 }
206
207 my $passedConfiguration;
208 my $searchedForPassedConfiguration;
209 sub determinePassedConfiguration
210 {
211     return if $searchedForPassedConfiguration;
212     $searchedForPassedConfiguration = 1;
213     for my $i (0 .. $#ARGV) {
214         my $opt = $ARGV[$i];
215         if ($opt =~ /^--debug$/i || $opt =~ /^--devel/i) {
216             splice(@ARGV, $i, 1);
217             $passedConfiguration = "Debug";
218             return;
219         }
220         if ($opt =~ /^--release$/i || $opt =~ /^--deploy/i) {
221             splice(@ARGV, $i, 1);
222             $passedConfiguration = "Release";
223             return;
224         }
225     }
226     $passedConfiguration = undef;
227 }
228
229 sub passedConfiguration
230 {
231     determinePassedConfiguration();
232     return $passedConfiguration;
233 }
234
235 sub setConfiguration
236 {
237     determinePassedConfiguration();
238     $configuration = $passedConfiguration if $passedConfiguration;
239 }
240
241 # Locate Safari.
242 sub safariPath
243 {
244     # Use WEBKIT_SAFARI environment variable if present.
245     my $safariBundle = $ENV{WEBKIT_SAFARI};
246     if (!$safariBundle) {
247         determineConfigurationProductDir();
248         # Use Safari.app in product directory if present (good for Safari development team).
249         if (-d "$configurationProductDir/Safari.app") {
250             $safariBundle = "$configurationProductDir/Safari.app";
251         } else {
252             # Otherwise use Safari.app in Applications directory.
253             $safariBundle = "/Applications/Safari.app";
254         }
255     }
256     my $safariPath = "$safariBundle/Contents/MacOS/Safari";
257     die "Can't find executable at $safariPath.\n" unless -x $safariPath;
258     return $safariPath;
259 }
260
261 sub builtDylibPathForName
262 {
263     my $framework = shift;
264     determineConfigurationProductDir();
265     if (isOSX()) {
266         return "$configurationProductDir/$framework.framework/Versions/A/$framework";
267     }
268     if (isCygwin()) {
269         if ($framework eq "JavaScriptCore") {
270                 return "$baseProductDir/lib/$framework.lib";
271         } else {
272             return "$baseProductDir/$framework.intermediate/$configuration/$framework.intermediate/$framework.lib";
273         }
274     }
275     if (isQt()) {
276         return "$configurationProductDir/$framework";
277     }
278
279     die "Unsupported platform, can't determine built library locations.";
280 }
281
282 # Check to see that all the frameworks are built.
283 sub checkFrameworks
284 {
285     my @frameworks = ("JavaScriptCore", "WebCore");
286     push(@frameworks, "WebKit") if isOSX();
287     for my $framework (@frameworks) {
288         my $path = builtDylibPathForName($framework);
289         die "Can't find built framework at \"$path\".\n" unless -x $path;
290     }
291 }
292
293 sub hasSVGSupport
294 {
295     return 0 if isCygwin();
296
297     my $path = shift;
298
299     if ((isQt()) and ($path =~ /WebCore/)) {
300         $path .= "/../lib/libWebCore-unity.so";
301     }
302
303     open NM, "-|", "nm", $path or die;
304     my $hasSVGSupport = 0;
305     while (<NM>) {
306         $hasSVGSupport = 1 if /SVGElement/;
307     }
308     close NM;
309     return $hasSVGSupport;
310 }
311
312 sub removeLibraryDependingOnSVG
313 {
314     my $frameworkName = shift;
315     my $shouldHaveSVG = shift;
316
317     my $path = builtDylibPathForName($frameworkName);
318     return unless -x $path;
319
320     my $hasSVG = hasSVGSupport($path);
321     system "rm -f $path" if ($shouldHaveSVG xor $hasSVG);
322 }
323
324 sub checkWebCoreSVGSupport
325 {
326     my $required = shift;
327     my $framework = "WebCore";
328     my $path = builtDylibPathForName($framework);
329     my $hasSVG = hasSVGSupport($path);
330     if ($required && !$hasSVG) {
331         die "$framework at \"$path\" does not include SVG Support, please run build-webkit --svg\n";
332     }
333     return $hasSVG;
334 }
335
336 sub isQt()
337 {
338     return ($^O eq "linux") and defined($ENV{'QTDIR'})
339 }
340
341 sub isCygwin()
342 {
343     return ($^O eq "cygwin");
344 }
345
346 sub isOSX()
347 {
348     return ($^O eq "darwin");
349 }
350
351 sub checkRequiredSystemConfig
352 {
353     if (isOSX()) {
354         chomp(my $productVersion = `sw_vers -productVersion`);
355         if ($productVersion lt "10.4") {
356             print "*************************************************************\n";
357             print "Mac OS X Version 10.4.0 or later is required to build WebKit.\n";
358             print "You have " . $productVersion . ", thus the build will most likely fail.\n";
359             print "*************************************************************\n";
360         }
361         my $xcodeVersion = `xcodebuild -version`;
362         if ($xcodeVersion !~ /DevToolsCore-(\d+)/ || $1 < 747) {
363             print "*************************************************************\n";
364             print "Xcode Version 2.3 or later is required to build WebKit.\n";
365             print "You have an earlier version of Xcode, thus the build will\n";
366             print "most likely fail.  The latest Xcode is available from the web:\n";
367             print "http://developer.apple.com/tools/xcode\n";
368             print "*************************************************************\n";
369         }
370     }
371     # Win32 and other platforms may want to check for minimum config
372 }
373
374 sub setupCygwinEnv()
375 {
376     return if !isCygwin();
377     return if $devenvPath;
378
379     my $programFilesPath = `cygpath "$ENV{'PROGRAMFILES'}"`;
380     chomp $programFilesPath;
381     $devenvPath = "$programFilesPath/Microsoft Visual Studio 8/Common7/IDE/devenv.com";
382     $windowsTmpPath = `cygpath -w /tmp`;
383     chomp $windowsTmpPath;
384     print "Building results into: ", baseProductDir(), "\n";
385     print "WEBKITOUTPUTDIR is set to: ", $ENV{"WEBKITOUTPUTDIR"}, "\n";
386 }
387
388 sub buildVisualStudioProject($)
389 {
390     my ($project) = @_;
391     setupCygwinEnv();
392
393     chdir "$project.vcproj" or die "Failed to cd into $project.vcproj\n";
394     my $config = configuration();
395
396     print "$devenvPath $project.sln /build $config";
397     my $result = system $devenvPath, "$project.sln", "/build", $config;
398     chdir ".." or die;
399     return $result;
400 }
401
402 sub buildCMakeProject($$)
403 {
404     my ($project, $colorize) = @_;
405
406     if ($project ne "WebKit") { 
407         die "Qt/Linux builds JavaScriptCore/WebCore/WebKitQt in one shot! Only call it for 'WebKit'.\n";
408     }
409
410     my $config = configuration();
411     my $prefix = $ENV{"WebKitInstallationPrefix"};
412  
413     my @buildArgs = ("-DCMAKE_BUILD_TYPE=$config");
414     push @buildArgs, "-DCMAKE_INSTALL_PREFIX=" . $prefix if(defined($prefix));
415     push @buildArgs, "-DWEBKIT_DO_NOT_USE_COLORFUL_OUTPUT=" . ($colorize ? "OFF" : "ON");
416     push @buildArgs, "../../";
417
418     print "Calling 'cmake @buildArgs' in " . baseProductDir() . "/$config ...\n\n";
419     print "Installation directory: $prefix\n" if(defined($prefix));
420
421     system "mkdir -p " . baseProductDir() . "/$config";
422     chdir baseProductDir() . "/$config" or die "Failed to cd into " . baseProductDir() . "/$config \n";
423
424     my $result = system "cmake", @buildArgs;
425     if($result ne 0) {
426        die "Failed to setup build environment using cmake!\n";
427     }
428
429     $result = system "make";
430     chdir ".." or die;
431     return $result;
432 }
433
434 1;