Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(25)

Side by Side Diff: Source/bindings/scripts/generate-bindings.pl

Issue 18190004: Add Python flow to bindings generation, move dummy-generating IDL files over (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Revision 3 (tweak similarity) Created 7 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 #!/usr/bin/perl -w
2 #
3 # Copyright (C) 2005 Apple Computer, Inc.
4 # Copyright (C) 2006 Anders Carlsson <andersca@mac.com>
5 #
6 # This file is part of WebKit
7 #
8 # This library is free software; you can redistribute it and/or
9 # modify it under the terms of the GNU Library General Public
10 # License as published by the Free Software Foundation; either
11 # version 2 of the License, or (at your option) any later version.
12 #
13 # This library is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 # Library General Public License for more details.
17 #
18 # You should have received a copy of the GNU Library General Public License
19 # along with this library; see the file COPYING.LIB. If not, write to
20 # the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 # Boston, MA 02110-1301, USA.
22 #
23
24 # This script is a temporary hack.
25 # Files are generated in the source directory, when they really should go
26 # to the DerivedSources directory.
27 # This should also eventually be a build rule driven off of .idl files
28 # however a build rule only solution is blocked by several radars:
29 # <rdar://problems/4251781&4251785>
30
31 use strict;
32
33 use File::Path;
34 use File::Basename;
35 use Getopt::Long;
36 use Text::ParseWords;
37 use Cwd;
38
39 use IDLParser;
40 use CodeGeneratorV8;
41 use IDLSerializer;
42
43 my @idlDirectories;
44 my $outputDirectory;
45 my $defines;
46 my $filename;
47 my $preprocessor;
48 my $verbose;
49 my $interfaceDependenciesFile;
50 my $additionalIdlFiles;
51 my $idlAttributesFile;
52 my $writeFileOnlyIfChanged;
53
54 GetOptions('include=s@' => \@idlDirectories,
55 'outputDir=s' => \$outputDirectory,
56 'defines=s' => \$defines,
57 'filename=s' => \$filename,
58 'preprocessor=s' => \$preprocessor,
59 'verbose' => \$verbose,
60 'interfaceDependenciesFile=s' => \$interfaceDependenciesFile,
61 'additionalIdlFiles=s' => \$additionalIdlFiles,
62 'idlAttributesFile=s' => \$idlAttributesFile,
63 'write-file-only-if-changed=s' => \$writeFileOnlyIfChanged);
64
65 my $targetIdlFile = $ARGV[0];
66
67 die('Must specify input file.') unless defined($targetIdlFile);
68 die('Must specify output directory.') unless defined($outputDirectory);
69 $defines = "" unless defined($defines);
70
71 $targetIdlFile = Cwd::realpath($targetIdlFile);
72 if ($verbose) {
73 print "$targetIdlFile\n";
74 }
75 my $targetInterfaceName = fileparse(basename($targetIdlFile), ".idl");
76
77 my $idlFound = 0;
78 my @dependencyIdlFiles;
79 if ($interfaceDependenciesFile) {
80 # The format of the interface dependencies file:
81 #
82 # Window.idl P.idl Q.idl R.idl
83 # Document.idl S.idl
84 # Event.idl
85 # ...
86 #
87 # The above indicates that Window.idl depends on P.idl, Q.idl, and R.idl,
88 # Document.idl depends on S.idl, and Event.idl depends on no IDLs.
89 # A dependency IDL file (one that is depended on by another IDL, e.g. P.idl
90 # in the above) does not have its own entry in the dependency file.
91 open FH, "< $interfaceDependenciesFile" or die "Cannot open $interfaceDepend enciesFile\n";
92 while (my $line = <FH>) {
93 my ($idlFile, @followingIdlFiles) = split(/\s+/, $line);
94 if ($idlFile and basename($idlFile) eq basename($targetIdlFile)) {
95 $idlFound = 1;
96 # We sort the dependency IDL files so that the corresponding code is generated
97 # in a consistent order. This is important for the bindings tests.
98 @dependencyIdlFiles = sort @followingIdlFiles;
99 }
100 }
101 close FH;
102
103 # $additionalIdlFiles is list of IDL files which should not be included in
104 # DerivedSources*.cpp (i.e. they are not described in the interface
105 # dependencies file) but should generate .h and .cpp files.
106 if (!$idlFound and $additionalIdlFiles) {
107 my @idlFiles = shellwords($additionalIdlFiles);
108 $idlFound = grep { $_ and basename($_) eq basename($targetIdlFile) } @id lFiles;
109 }
110
111 if (!$idlFound) {
112 # We generate empty .h and .cpp files just to tell build scripts that .h and .cpp files are created.
113 generateEmptyHeaderAndCpp($targetInterfaceName, $outputDirectory);
114 exit 0;
115 }
116 }
117
118 # Parse the target IDL file.
119 my $targetParser = IDLParser->new(!$verbose);
120 my $targetDocument = $targetParser->Parse($targetIdlFile, $defines, $preprocesso r);
121
122 if ($idlAttributesFile) {
123 my $idlAttributes = loadIDLAttributes($idlAttributesFile);
124 checkIDLAttributes($idlAttributes, $targetDocument, basename($targetIdlFile) );
125 }
126
127 foreach my $idlFile (@dependencyIdlFiles) {
128 next if $idlFile eq $targetIdlFile;
129
130 my $interfaceName = fileparse(basename($idlFile), ".idl");
131 my $parser = IDLParser->new(!$verbose);
132 my $document = $parser->Parse($idlFile, $defines, $preprocessor);
133
134 foreach my $interface (@{$document->interfaces}) {
135 if (!$interface->isPartial || $interface->name eq $targetInterfaceName) {
136 my $targetDataNode;
137 foreach my $interface (@{$targetDocument->interfaces}) {
138 if ($interface->name eq $targetInterfaceName) {
139 $targetDataNode = $interface;
140 last;
141 }
142 }
143 die "Not found an interface ${targetInterfaceName} in ${targetInterf aceName}.idl." unless defined $targetDataNode;
144
145 # Support for attributes of partial interfaces.
146 foreach my $attribute (@{$interface->attributes}) {
147 # Record that this attribute is implemented by $interfaceName.
148 $attribute->extendedAttributes->{"ImplementedBy"} = $interfaceNa me if $interface->isPartial;
149
150 # Add interface-wide extended attributes to each attribute.
151 applyInterfaceExtendedAttributes($interface, $attribute->extende dAttributes);
152
153 push(@{$targetDataNode->attributes}, $attribute);
154 }
155
156 # Support for methods of partial interfaces.
157 foreach my $function (@{$interface->functions}) {
158 # Record that this method is implemented by $interfaceName.
159 $function->extendedAttributes->{"ImplementedBy"} = $interfaceNam e if $interface->isPartial;
160
161 # Add interface-wide extended attributes to each method.
162 applyInterfaceExtendedAttributes($interface, $function->extended Attributes);
163
164 push(@{$targetDataNode->functions}, $function);
165 }
166
167 # Support for constants of partial interfaces.
168 foreach my $constant (@{$interface->constants}) {
169 # Record that this constant is implemented by $interfaceName.
170 $constant->extendedAttributes->{"ImplementedBy"} = $interfaceNam e if $interface->isPartial;
171
172 # Add interface-wide extended attributes to each constant.
173 applyInterfaceExtendedAttributes($interface, $constant->extended Attributes);
174
175 push(@{$targetDataNode->constants}, $constant);
176 }
177 } else {
178 die "$idlFile is not a dependency of $targetIdlFile. There maybe a b ug in the dependency computer (compute_dependencies.py).\n";
179 }
180 }
181 }
182
183 # FIXME: This code will be removed once IDLParser.pm and CodeGeneratorV8.pm
184 # are connected via JSON files. See http://crbug.com/242795
185 $targetDocument = deserializeJSON(serializeJSON($targetDocument));
186
187 # Generate desired output for the target IDL file.
188 my @interfaceIdlFiles = ($targetDocument->fileName(), @dependencyIdlFiles);
189 my $codeGenerator = CodeGeneratorV8->new($targetDocument, \@idlDirectories, $pre processor, $defines, $verbose, \@interfaceIdlFiles, $writeFileOnlyIfChanged);
190 my $interfaces = $targetDocument->interfaces;
191 foreach my $interface (@$interfaces) {
192 print "Generating bindings code for IDL interface \"" . $interface->name . " \"...\n" if $verbose;
193 $codeGenerator->GenerateInterface($interface);
194 $codeGenerator->WriteData($interface, $outputDirectory);
195 }
196
197 sub generateEmptyHeaderAndCpp
198 {
199 my ($targetInterfaceName, $outputDirectory) = @_;
200
201 my $headerName = "V8${targetInterfaceName}.h";
202 my $cppName = "V8${targetInterfaceName}.cpp";
203 my $contents = "/*
204 This file is generated just to tell build scripts that $headerName and
205 $cppName are created for ${targetInterfaceName}.idl, and thus
206 prevent the build scripts from trying to generate $headerName and
207 $cppName at every build. This file must not be tried to compile.
208 */
209 ";
210 open FH, "> ${outputDirectory}/${headerName}" or die "Cannot open $headerNam e\n";
211 print FH $contents;
212 close FH;
213
214 open FH, "> ${outputDirectory}/${cppName}" or die "Cannot open $cppName\n";
215 print FH $contents;
216 close FH;
217 }
218
219 sub loadIDLAttributes
220 {
221 my $idlAttributesFile = shift;
222
223 my %idlAttributes;
224 open FH, "<", $idlAttributesFile or die "Couldn't open $idlAttributesFile: $ !";
225 while (my $line = <FH>) {
226 chomp $line;
227 next if $line =~ /^\s*#/;
228 next if $line =~ /^\s*$/;
229
230 if ($line =~ /^\s*([^=\s]*)\s*=?\s*(.*)/) {
231 my $name = $1;
232 $idlAttributes{$name} = {};
233 if ($2) {
234 foreach my $rightValue (split /\|/, $2) {
235 $rightValue =~ s/^\s*|\s*$//g;
236 $rightValue = "VALUE_IS_MISSING" unless $rightValue;
237 $idlAttributes{$name}{$rightValue} = 1;
238 }
239 } else {
240 $idlAttributes{$name}{"VALUE_IS_MISSING"} = 1;
241 }
242 } else {
243 die "The format of " . basename($idlAttributesFile) . " is wrong: li ne $.\n";
244 }
245 }
246 close FH;
247
248 return \%idlAttributes;
249 }
250
251 sub checkIDLAttributes
252 {
253 my $idlAttributes = shift;
254 my $document = shift;
255 my $idlFile = shift;
256
257 foreach my $interface (@{$document->interfaces}) {
258 checkIfIDLAttributesExists($idlAttributes, $interface->extendedAttribute s, $idlFile);
259
260 foreach my $attribute (@{$interface->attributes}) {
261 checkIfIDLAttributesExists($idlAttributes, $attribute->extendedAttri butes, $idlFile);
262 }
263
264 foreach my $function (@{$interface->functions}) {
265 checkIfIDLAttributesExists($idlAttributes, $function->extendedAttrib utes, $idlFile);
266 foreach my $parameter (@{$function->parameters}) {
267 checkIfIDLAttributesExists($idlAttributes, $parameter->extendedA ttributes, $idlFile);
268 }
269 }
270 }
271 }
272
273 sub applyInterfaceExtendedAttributes
274 {
275 my $interface = shift;
276 my $extendedAttributes = shift;
277
278 foreach my $extendedAttributeName (keys %{$interface->extendedAttributes}) {
279 next if $extendedAttributeName eq "ImplementedAs";
280 $extendedAttributes->{$extendedAttributeName} = $interface->extendedAttr ibutes->{$extendedAttributeName};
281 }
282 }
283
284 sub checkIfIDLAttributesExists
285 {
286 my $idlAttributes = shift;
287 my $extendedAttributes = shift;
288 my $idlFile = shift;
289
290 my $error;
291 OUTER: for my $name (keys %$extendedAttributes) {
292 if (!exists $idlAttributes->{$name}) {
293 $error = "Unknown IDL attribute [$name] is found at $idlFile.";
294 last OUTER;
295 }
296 if ($idlAttributes->{$name}{"*"}) {
297 next;
298 }
299 for my $rightValue (split /\s*[|&]\s*/, $extendedAttributes->{$name}) {
300 if (!exists $idlAttributes->{$name}{$rightValue}) {
301 $error = "Unknown IDL attribute [$name=" . $extendedAttributes-> {$name} . "] is found at $idlFile.";
302 last OUTER;
303 }
304 }
305 }
306 if ($error) {
307 die "IDL ATTRIBUTE CHECKER ERROR: $error
308 If you want to add a new IDL attribute, you need to add it to bindings/scripts/I DLAttributes.txt and add explanations to the Blink IDL document (http://chromium .org/blink/webidl).
309 ";
310 }
311 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698