All prototypes should call didBecomePrototype()
[WebKit.git] / Source / WebCore / bindings / scripts / generate-bindings-all.pl
1 #!/usr/bin/env perl
2 #
3 # Copyright (C) 2016 Sony Interactive Entertainment Inc.
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 # 1.  Redistributions of source code must retain the above copyright
9 #     notice, this list of conditions and the following disclaimer.
10 # 2.  Redistributions in binary form must reproduce the above copyright
11 #     notice, this list of conditions and the following disclaimer in the
12 #     documentation and/or other materials provided with the distribution.
13 #
14 # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
15 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 # DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
21 # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
23 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 #
25
26 use strict;
27 use warnings;
28 use FindBin;
29 use lib $FindBin::Bin;
30
31 use File::Basename;
32 use File::Spec;
33 use File::Find;
34 use Getopt::Long;
35
36 my $perl = $^X;
37 my $scriptDir = $FindBin::Bin;
38 my @idlDirectories;
39 my $outputDirectory;
40 my $idlFilesList;
41 my $generator;
42 my @generatorDependency;
43 my $defines;
44 my $preprocessor;
45 my $supplementalDependencyFile;
46 my @ppExtraOutput;
47 my @ppExtraArgs;
48 my $numOfJobs = 1;
49 my $idlAttributesFile;
50 my $showProgress;
51
52 GetOptions('include=s@' => \@idlDirectories,
53            'outputDir=s' => \$outputDirectory,
54            'idlFilesList=s' => \$idlFilesList,
55            'generator=s' => \$generator,
56            'generatorDependency=s@' => \@generatorDependency,
57            'defines=s' => \$defines,
58            'preprocessor=s' => \$preprocessor,
59            'supplementalDependencyFile=s' => \$supplementalDependencyFile,
60            'ppExtraOutput=s@' => \@ppExtraOutput,
61            'ppExtraArgs=s@' => \@ppExtraArgs,
62            'idlAttributesFile=s' => \$idlAttributesFile,
63            'numOfJobs=i' => \$numOfJobs,
64            'showProgress' => \$showProgress);
65
66 $| = 1;
67 my @idlFiles;
68 open(my $fh, '<', $idlFilesList) or die "Cannot open $idlFilesList";
69 @idlFiles = map { CygwinPathIfNeeded(s/\r?\n?$//r) } <$fh>;
70 close($fh) or die;
71
72 my %oldSupplements;
73 my %newSupplements;
74 if ($supplementalDependencyFile) {
75     my @output = ($supplementalDependencyFile, @ppExtraOutput);
76     my @deps = ($idlFilesList, @idlFiles, @generatorDependency);
77     if (needsUpdate(\@output, \@deps)) {
78         readSupplementalDependencyFile($supplementalDependencyFile, \%oldSupplements) if -e $supplementalDependencyFile;
79         my @args = (File::Spec->catfile($scriptDir, 'preprocess-idls.pl'),
80                     '--defines', $defines,
81                     '--idlFilesList', $idlFilesList,
82                     '--supplementalDependencyFile', $supplementalDependencyFile,
83                     @ppExtraArgs);
84         printProgress("Preprocess IDL");
85         executeCommand($perl, @args) == 0 or die;
86     }
87     readSupplementalDependencyFile($supplementalDependencyFile, \%newSupplements);
88 }
89
90 my @args = (File::Spec->catfile($scriptDir, 'generate-bindings.pl'),
91             '--defines', $defines,
92             '--generator', $generator,
93             '--outputDir', $outputDirectory,
94             '--preprocessor', $preprocessor,
95             '--idlAttributesFile', $idlAttributesFile,
96             '--write-dependencies');
97 push @args, map { ('--include', $_) } @idlDirectories;
98 push @args, '--supplementalDependencyFile', $supplementalDependencyFile if $supplementalDependencyFile;
99
100 my %directoryCache;
101 buildDirectoryCache();
102
103 my @idlFilesToUpdate = grep &{sub {
104     if (defined($oldSupplements{$_})
105         && @{$oldSupplements{$_}} ne @{$newSupplements{$_} or []}) {
106         # Re-process the IDL file if its supplemental dependencies were added or removed
107         return 1;
108     }
109     my ($filename, $dirs, $suffix) = fileparse($_, '.idl');
110     my $sourceFile = File::Spec->catfile($outputDirectory, "JS$filename.cpp");
111     my $headerFile = File::Spec->catfile($outputDirectory, "JS$filename.h");
112     my $depFile = File::Spec->catfile($outputDirectory, "JS$filename.dep");
113     my @output = ($sourceFile, $headerFile);
114     my @deps = ($_,
115                 $idlAttributesFile,
116                 @generatorDependency,
117                 @{$newSupplements{$_} or []},
118                 implicitDependencies($depFile));
119     needsUpdate(\@output, \@deps);
120 }}, @idlFiles;
121
122 my $abort = 0;
123 my $totalCount = @idlFilesToUpdate;
124 my $currentCount = 0;
125
126 spawnGenerateBindingsIfNeeded() for (1 .. $numOfJobs);
127 while (waitpid(-1, 0) != -1) {
128     if ($?) {
129         $abort = 1;
130     }
131     spawnGenerateBindingsIfNeeded();
132 }
133 exit $abort;
134
135 sub needsUpdate
136 {
137     my ($objects, $depends) = @_;
138     my $oldestObjectTime;
139     for (@$objects) {
140         return 1 if !-f;
141         my $m = mtime($_);
142         if (!defined $oldestObjectTime || $m < $oldestObjectTime) {
143             $oldestObjectTime = $m;
144         }
145     }
146     for (@$depends) {
147         die "Missing required dependency: $_" if !-f;
148         my $m = mtime($_);
149         if ($oldestObjectTime < $m) {
150             return 1;
151         }
152     }
153     return 0;
154 }
155
156 sub mtime
157 {
158     my ($file) = @_;
159     return (stat $file)[9];
160 }
161
162 sub spawnGenerateBindingsIfNeeded
163 {
164     return if $abort;
165     return unless @idlFilesToUpdate;
166     my $batchCount = 30;
167     # my $batchCount = int(($totalCount - $currentCount) / $numOfJobs) || 1;
168     my @files = splice(@idlFilesToUpdate, 0, $batchCount);
169     for (@files) {
170         $currentCount++;
171         my $basename = basename($_);
172         printProgress("[$currentCount/$totalCount] $basename");
173     }
174     my $pid = spawnCommand($perl, @args, @files);
175     $abort = 1 unless defined $pid;
176 }
177
178 sub buildDirectoryCache
179 {
180     my $wanted = sub {
181         $directoryCache{$_} = $File::Find::name;
182         $File::Find::prune = 1 unless ~/\./;
183     };
184     find($wanted, @idlDirectories);
185 }
186
187 sub implicitDependencies
188 {
189     my ($depFile) = @_;
190     return () unless -f $depFile;
191     open(my $fh, '<', $depFile) or die "Cannot open $depFile";
192     my $firstLine = <$fh>;
193     close($fh) or die;
194     my (undef, $deps) = split(/ : /, $firstLine);
195     my @deps = split(/\s+/, $deps);
196     return map { $directoryCache{$_} or () } @deps;
197 }
198
199 sub executeCommand
200 {
201     if ($^O eq 'MSWin32') {
202         return system(quoteCommand(@_));
203     }
204     return system(@_);
205 }
206
207 sub spawnCommand
208 {
209     my $pid = fork();
210     if ($pid == 0) {
211         @_ = quoteCommand(@_) if ($^O eq 'MSWin32');
212         exec(@_);
213         die "Cannot exec";
214     }
215     return $pid;
216 }
217
218 sub quoteCommand
219 {
220     return map {
221         '"' . s/([\\\"])/\\$1/gr . '"';
222     } @_;
223 }
224
225 sub CygwinPathIfNeeded
226 {
227     my $path = shift;
228     return Cygwin::win_to_posix_path($path) if ($^O eq 'cygwin');
229     return $path;
230 }
231
232 sub readSupplementalDependencyFile
233 {
234     my $filename = shift;
235     my $supplements = shift;
236     open(my $fh, '<', $filename) or die "Cannot open $filename";
237     while (<$fh>) {
238         my ($idlFile, @followingIdlFiles) = split(/\s+/);
239         $supplements->{$idlFile} = [sort @followingIdlFiles];
240     }
241     close($fh) or die;
242 }
243
244 sub printProgress
245 {
246     return unless $showProgress;
247     my $msg = shift;
248     print "$msg\n";
249 }