a1cc80aada76fcc7bc158aa502d23b500f1be4a9
[WebKit-https.git] / Tools / Scripts / copy-webkitlibraries-to-product-directory
1 #!/usr/bin/perl -w
2
3 # Copyright (C) 2005, 2008, 2010, 2011, 2012, 2013, 2014 Apple Inc. All rights reserved.
4 #
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions
7 # are met:
8 #
9 # 1.  Redistributions of source code must retain the above copyright
10 #     notice, this list of conditions and the following disclaimer. 
11 # 2.  Redistributions in binary form must reproduce the above copyright
12 #     notice, this list of conditions and the following disclaimer in the
13 #     documentation and/or other materials provided with the distribution. 
14 #
15 # THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
16 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 # DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
19 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25
26 use strict;
27 use File::Spec;
28 use FindBin;
29 use Getopt::Long qw(:config pass_through);
30 use lib $FindBin::Bin;
31 use webkitdirs;
32
33 sub buildLLVM($);
34 sub symlinkLLVMLibrariesIfNeeded($$);
35
36 my $showHelp = 0;
37 my $llvm = 0;
38 my $wksi = 0;
39 my $clean = 0;
40 my $llvmIncludePackage = "";
41 my $llvmLibraryPackage = "";
42 my $useFullLibPaths = 0;
43 my $preferSystemLLVMOverDrops = 0;
44 my $llvmSubdirectoryName = "llvm";
45 my $llvmPrefix = willUseIOSDeviceSDK() ? "/usr/local" : "/usr/local/LLVMForJavaScriptCore";
46 my $osxVersion;
47 my $force = 0;
48
49 my $programName = basename($0);
50 my $usage = <<EOF;
51 Usage: $programName [options]
52   --help                        Show this help message
53   --[no-]llvm                   Toggle copying LLVM drops (default: $llvm)
54   --[no-]wksi                   Toggle copying WebKitSystemInterface drops (default: $wksi)
55   --clean                       Clean the libraries (default: $clean)
56   --use-llvm-includes=<path>    Get the LLVM inludes package from <path>
57   --use-llvm-libraries=<path>   Get the LLVM libraries package from <path>
58   --[no-]use-full-lib-paths     Toggle using full library paths
59   --[no-]prefer-system-llvm     Toggle preferring the system LLVM over the binary drops (default: $preferSystemLLVMOverDrops)
60   --llvm-subdirectory=<name>    Set the name of the LLVM subdirectory to search for (default: $llvmSubdirectoryName)
61   --llvm-prefix=<path>          Set the prefix into which LLVM is installed (default: $llvmPrefix)
62   --sdk=<sdk>                   Use a specific Xcode SDK
63   --device                      Use the current iphoneos.internal SDK (iOS only)
64   --simulator                   Use the current iphonesimulator SDK (iOS only)
65   --osx-version=<version>       Set the OS X version to use when deciding what to copy.
66   --[no-]force                  Toggle forcing the copy - i.e. ignoring timestamps (default: $force)
67 EOF
68
69 GetOptions(
70     'help' => \$showHelp,
71     'llvm!' => \$llvm,
72     'wksi!' => \$wksi,
73     'clean' => \$clean,
74     'use-llvm-includes=s' => \$llvmIncludePackage,
75     'use-llvm-libraries=s' => \$llvmLibraryPackage,
76     'use-full-lib-paths!' => \$useFullLibPaths,
77     'prefer-system-llvm!' => \$preferSystemLLVMOverDrops,
78     'llvm-subdirectory=s' => \$llvmSubdirectoryName,
79     'llvm-prefix=s' => \$llvmPrefix,
80     'osx-version=s' => \$osxVersion,
81     'force!' => \$force
82 );
83
84 if ($showHelp) {
85    print STDERR $usage;
86    exit 1;
87 }
88
89 my $productDir = shift @ARGV;
90 if ($productDir) {
91     $productDir = File::Spec->rel2abs($productDir);
92 } else {
93     $productDir = $ENV{BUILT_PRODUCTS_DIR} || productDir();
94 }
95
96 if (!isIOSWebKit() && !$osxVersion &&!isAnyWindows()) {
97     $osxVersion = `sw_vers -productVersion | cut -d. -f-2`;
98     chomp($osxVersion);
99 }
100
101 chdirWebKit();
102
103 sub executeRanlib($)
104 {
105     my ($library) = @_;
106     my @args;
107     push @args, ("-sdk", xcodeSDK()) if xcodeSDK();
108     push @args, "ranlib";
109     push @args, "-no_warning_for_no_symbols" if isIOSWebKit();
110     system("xcrun", @args, $library) == 0 or die;
111 }
112
113 sub unpackIfNecessary
114 {
115     my ($targetDir, $sampleFile, $package, $hasLibraries) = @_;
116     if ($force || !-e $sampleFile || -M $sampleFile > -M $package) {
117         print "Unpacking $package into $targetDir\n";
118         (system("tar -C $targetDir -xmf $package") == 0) or die;
119         if ($hasLibraries) {
120             foreach my $library (`tar -tf $package`) {
121                 chomp $library;
122                 print "   Ranlib $library\n";
123                 executeRanlib($targetDir . "/" . $library);
124             }
125         }
126         return 1;
127     }
128     return 0;
129 }
130
131 sub dittoHeaders
132 {
133     my ($srcHeader, $header) = @_;
134     if ($force || !-e $header || -M $header > -M $srcHeader) {
135         print "Updating $header\n";
136         (system("ditto", $srcHeader, $header) == 0) or die;
137     }
138 }
139
140 if ($clean) {
141     print "Cleaning.\n";    
142     (system("rm", "-rf", File::Spec->catfile($productDir, "usr", "local", "include", "WebKitSystemInterface.h")) == 0) or die;
143     (system("rm", "-rf", "$productDir$llvmPrefix") == 0) or die;
144     unlink glob "$productDir/libWebKitSystemInterface*" or die if glob "$productDir/libWebKitSystemInterface*";
145     unlink glob "$productDir/usr/local/lib/libWebKitSystemInterface*" or die if glob "$productDir/usr/local/lib/libWebKitSystemInterface*";
146     unlink glob "$productDir/libLLVM*" or die if glob "$productDir/libLLVM*";
147     unlink glob "$productDir/libLTO*" or die if glob "$productDir/libLTO*";
148 }
149
150 if ($wksi) {
151     (system("mkdir", "-p", "$productDir/usr/local/include") == 0) or die;
152     
153     my $libraryDir = $useFullLibPaths ? "$productDir/usr/local/lib" : $productDir;
154     (system("mkdir", "-p", $libraryDir) == 0) or die;
155
156     my @librariesToCopy;
157     if (isIOSWebKit()) {
158         push(@librariesToCopy, (
159             "libWebKitSystemInterfaceIOSDevice8.1.a",
160             "libWebKitSystemInterfaceIOSSimulator8.1.a",
161             "libWebKitSystemInterfaceIOSDevice8.2.a",
162             "libWebKitSystemInterfaceIOSSimulator8.2.a",
163             "libWebKitSystemInterfaceIOSDevice8.3.a",
164             "libWebKitSystemInterfaceIOSSimulator8.3.a",
165             "libWebKitSystemInterfaceIOSDevice8.4.a",
166             "libWebKitSystemInterfaceIOSSimulator8.4.a",
167             "libWebKitSystemInterfaceIOSDevice9.0.a",
168             "libWebKitSystemInterfaceIOSSimulator9.0.a",
169             "libWebKitSystemInterfaceIOSDevice9.2.a",
170             "libWebKitSystemInterfaceIOSSimulator9.2.a",
171         ));
172     } else {
173         push(@librariesToCopy, (
174             "libWebKitSystemInterfaceYosemite.a",
175             "libWebKitSystemInterfaceElCapitan.a"
176         ));
177     }
178
179     foreach my $libraryName (@librariesToCopy) {
180         my $sourceLibrary = "WebKitLibraries/" . $libraryName;
181         my $targetLibrary = "$libraryDir/" . $libraryName;
182         if ($force || !-e $targetLibrary || -M $targetLibrary > -M $sourceLibrary) {
183             print "Updating $targetLibrary\n";
184             (system("ditto", $sourceLibrary, $targetLibrary) == 0) or die;
185             executeRanlib($targetLibrary);
186         }
187     }
188     
189     dittoHeaders("WebKitLibraries/WebKitSystemInterface.h", "$productDir/usr/local/include/WebKitSystemInterface.h");
190 }
191
192 if ($llvm) {
193     (system("mkdir", "-p", "$productDir$llvmPrefix/include") == 0) or die;
194
195     my $libraryDir = $useFullLibPaths ? "$productDir$llvmPrefix/lib" : $productDir;
196     # Always create a directory at the full library path, because the JavaScriptCore build emits a warning if it's not there.
197     (system("mkdir", "-p", "$productDir$llvmPrefix/lib") == 0) or die;
198
199     (system("rm", "-f", File::Spec->catfile($productDir, "ExtraIncludesForLocalLLVMBuild")) == 0) or die;
200
201     if ($preferSystemLLVMOverDrops) {
202         print "Using system LLVM.\n";
203         exit 0;
204     }
205
206     my $llvmSourceDirectory = $ENV{LLVM_SOURCE_PATH};
207     $llvmSourceDirectory = File::Spec->catdir(sourceDir(), $llvmSubdirectoryName) unless $llvmSourceDirectory;
208     if (-d $llvmSourceDirectory) {
209         my $llvmBuildFile = File::Spec->catfile($llvmSourceDirectory, "LLVMBuild.txt");
210         if (-f $llvmBuildFile) {
211             print "Using LLVM source from $llvmSourceDirectory.\n";
212             buildLLVM($llvmSourceDirectory);
213             if (symlinkLLVMLibrariesIfNeeded($llvmSourceDirectory, $libraryDir)) {
214                 # LLVM libraries changed; make JavaScriptCore relink against the new LLVM the next time it is built.
215                 (system("touch", "Source/JavaScriptCore/llvm/library/LLVMAnchor.cpp") == 0) or die;
216             }
217             exit 0;
218         }
219         print STDERR "*************************************************************\n";
220         print STDERR "Cannot find file '$llvmBuildFile'.\n";
221         print STDERR "Please ensure that you have a complete LLVM distribution.\n";
222         print STDERR "You can check out LLVM trunk into the WebKit directory by running:\n";
223         print STDERR "svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm\n";
224         print STDERR "*************************************************************\n";
225         exit 1;
226     }
227
228     $llvmIncludePackage = $ENV{LLVM_LIBRARY_PACKAGE} unless $llvmIncludePackage;
229     $llvmIncludePackage = $ENV{LLVM_INCLUDE_PACKAGE} unless $llvmIncludePackage;
230     if (!$llvmLibraryPackage || !$llvmIncludePackage) {
231         if (isIOSWebKit()) {
232             my $majorSDKVersion = iosVersion()->{"major"};
233             $llvmLibraryPackage = "WebKitLibraries/LLVMLibrariesIOS$majorSDKVersion.tar.bz2";
234             $llvmIncludePackage = "WebKitLibraries/LLVMIncludesIOS$majorSDKVersion.tar.bz2";
235         } elsif (isAppleMacWebKit()) {
236             if ($osxVersion eq "10.10") {
237                 $llvmLibraryPackage = "WebKitLibraries/LLVMLibrariesYosemite.tar.bz2";
238                 $llvmIncludePackage = "WebKitLibraries/LLVMIncludesYosemite.tar.bz2";
239             } elsif ($osxVersion eq "10.11") {
240                 $llvmLibraryPackage = "WebKitLibraries/LLVMLibrariesElCapitan.tar.bz2";
241                 $llvmIncludePackage = "WebKitLibraries/LLVMIncludesElCapitan.tar.bz2";
242             }
243         }
244     }
245     if ($llvmLibraryPackage && $llvmIncludePackage) {
246         print "Using LLVM binary drops $llvmLibraryPackage and $llvmIncludePackage.\n";
247         if (unpackIfNecessary($libraryDir, "$libraryDir/libLLVMCore.a", $llvmLibraryPackage, 1)) {
248             # LLVM libraries changed; make JavaScriptCore relink against the new LLVM the next time it is built.
249             (system("touch", "Source/JavaScriptCore/llvm/library/LLVMAnchor.cpp") == 0) or die;
250         }
251         unpackIfNecessary(File::Spec->catdir("$productDir$llvmPrefix", "include"), File::Spec->catfile("$productDir$llvmPrefix", "include", "llvm-c", "Core.h"), $llvmIncludePackage, 0);
252         exit 0;
253     }
254
255     print STDERR "*************************************************************\n";
256     print STDERR "Don't know where to find LLVM!\n";
257     print STDERR "\n";
258     print STDERR "Try defining LLVM_LIBRARY_PACKAGE and LLVM_INCLUDE_PACKAGE or setting the\n";
259     print STDERR "--use-llvm-includes and --use-llvm-libraries options.\n";
260     print STDERR "\n";
261     print STDERR "Alternatively, you can check out llvm trunk into the WebKit directory:\n";
262     print STDERR "svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm\n";
263     print STDERR "*************************************************************\n";
264     exit 1;
265 }
266
267 sub fileContains
268 {
269     my ($filename, $string) = @_;
270     open my $fileHandle, '<', $filename or die;
271     while (<$fileHandle>) {
272         return 1 if /^$string$/;
273     }
274     return 0;
275 }
276
277 sub isContentOfFileEqualToString($$)
278 {
279     my ($filename, $string) = @_;
280     open my $fileHandle, '<', $filename or die;
281     binmode $fileHandle;
282     my $contents = <$fileHandle>;
283     return $contents eq $string;
284 }
285
286 sub buildLLVM($)
287 {
288     my ($llvmSourceDirectory) = @_;
289
290     my $savedWorkingDirectory = getcwd();
291     chomp(my $sdkRootEnvironmentVariable = `xcrun @{[xcodeSDK() ? "--sdk " . xcodeSDK() : ""]} --show-sdk-path`);
292     $sdkRootEnvironmentVariable = "SDKROOT=$sdkRootEnvironmentVariable";
293
294     my $llvmBaseProductDirectory = File::Spec->catdir($llvmSourceDirectory, "wkLLVMBuild");
295     if (!-e File::Spec->catfile($llvmBaseProductDirectory, "Makefile.config")) {
296         system("mkdir", "-p", $llvmBaseProductDirectory);
297         chdir($llvmBaseProductDirectory) or die;
298         my @args = qw(
299             --enable-optimized=yes
300             --enable-backtraces=no
301             --enable-libcpp=yes
302             --enable-zlib=no
303             --enable-terminfo=no
304             --enable-crash-overrides=no
305         );
306         my $targetArchitecture;
307         if (isIOSWebKit()) {
308             $targetArchitecture = "arm64";
309             push @args, "--host=arm-apple-darwin";
310             push @args, "--enable-targets=$targetArchitecture";
311         } else {
312             $targetArchitecture = "x86_64";
313             push @args, "--enable-targets=$targetArchitecture";
314         }
315
316         # Environment variables are explicitly appended after command line options so that
317         # the script configure caches them in file config.status for automatic reconfiguration.
318         if (isIOSWebKit()) {
319             # We must explicitly specify the target architecture to the compiler/preprocessor
320             # since we are cross-compiling LLVM.
321             for my $environmentVariableName (qw(CFLAGS CXXFLAGS CPPFLAGS)) {
322                 push @args, "$environmentVariableName=-arch $targetArchitecture";
323             }
324         }
325         push @args, $sdkRootEnvironmentVariable;
326         (system("../configure", @args) == 0) or die;
327     }
328
329     chdir($llvmBaseProductDirectory) or die;
330     my $savedPath = $ENV{"PATH"};
331
332     my $binariesDirectory = "binariesForLLVMBuild";
333     my $pathEnvironmentVariable = "";
334     if (-e $binariesDirectory) {
335         my $binariesPath = File::Spec->rel2abs($binariesDirectory);
336         $pathEnvironmentVariable = "PATH=" . join(":", $binariesPath, '$PATH');
337     }
338     my $makeCommand = "env -i bash -l -c \"$pathEnvironmentVariable $sdkRootEnvironmentVariable make -j `sysctl -n hw.activecpu`\"";
339     print $makeCommand . "\n";
340     (system($makeCommand) == 0) or die;
341
342     $ENV{"PATH"} = $savedPath;
343     chdir($savedWorkingDirectory);
344 }
345
346 sub symlinkLLVMLibrariesIfNeeded($$)
347 {
348     my ($llvmSourceDirectory, $libraryTargetDirectory) = @_;
349
350     my $llvmMakefileConfig = File::Spec->catfile($llvmSourceDirectory, "wkLLVMBuild", "Makefile.config");
351     my $configurationDirectoryName = "";
352     if (fileContains($llvmMakefileConfig, "ENABLE_OPTIMIZED=1")) {
353         $configurationDirectoryName .= "Release";
354     } else {
355         $configurationDirectoryName .= "Debug";
356     }
357     $configurationDirectoryName .= "+Asserts" unless fileContains($llvmMakefileConfig, "DISABLE_ASSERTIONS=1");
358     my $librarySourceDirectory = File::Spec->catdir($llvmSourceDirectory, "wkLLVMBuild", $configurationDirectoryName, "lib");
359
360     my $shouldUpdateLLVMLibraryToken = 0;
361     print("Symlinking libraries from $librarySourceDirectory to $libraryTargetDirectory\n");
362     opendir(my $dirHandle, $librarySourceDirectory);
363     while (my $filename = readdir($dirHandle)) {
364         next if $filename !~ /\.a$/;
365         next if $filename =~ /libgtest/;
366
367         print "   Symlink $filename\n";
368         my $sourceLibrary = File::Spec->catfile($librarySourceDirectory, $filename);
369         my $targetLibrary = File::Spec->catfile($libraryTargetDirectory, $filename);
370         my $ranlibToken = File::Spec->catfile($libraryTargetDirectory, ".ranlibToken-$filename");
371         unlink($targetLibrary);
372         symlink($sourceLibrary, $targetLibrary);
373         if ($force || !-e $ranlibToken || !isContentOfFileEqualToString($ranlibToken, $sourceLibrary) || -M $ranlibToken > -M $sourceLibrary) {
374             print "   Ranlib $filename\n";
375             executeRanlib($targetLibrary);
376             open(RANLIB_TOKEN, ">", $ranlibToken) or die "Failed to open $ranlibToken: $!";
377             print RANLIB_TOKEN $sourceLibrary;
378             close(RANLIB_TOKEN);
379             $shouldUpdateLLVMLibraryToken = 1;
380         }
381     }
382     closedir($dirHandle);
383
384     my $targetIncludeLLVMDirectory = File::Spec->catdir("$productDir$llvmPrefix", "include", "llvm");
385     my $targetIncludeLLVMCDirectory = File::Spec->catdir("$productDir$llvmPrefix", "include", "llvm-c");
386     (system("rm", "-rf", $targetIncludeLLVMDirectory) == 0) or die;
387     (system("rm", "-rf", $targetIncludeLLVMCDirectory) == 0) or die;
388     symlink(File::Spec->catdir($llvmSourceDirectory, "include", "llvm"), $targetIncludeLLVMDirectory) or die;
389     symlink(File::Spec->catdir($llvmSourceDirectory, "include", "llvm-c"), $targetIncludeLLVMCDirectory) or die;
390     symlink(File::Spec->catdir($llvmSourceDirectory, "wkLLVMBuild", "include"), File::Spec->catfile($productDir, "ExtraIncludesForLocalLLVMBuild")) or die;
391
392     return $shouldUpdateLLVMLibraryToken;
393 }