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

Side by Side Diff: Source/bindings/scripts/compute_interfaces_info.py

Issue 174953005: Clean up compute_interfaces_info.py and generate_global_constructors.py (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 6 years, 10 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
1 #!/usr/bin/python 1 #!/usr/bin/python
2 # 2 #
3 # Copyright (C) 2013 Google Inc. All rights reserved. 3 # Copyright (C) 2013 Google Inc. All rights reserved.
4 # 4 #
5 # Redistribution and use in source and binary forms, with or without 5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions are 6 # modification, are permitted provided that the following conditions are
7 # met: 7 # met:
8 # 8 #
9 # * Redistributions of source code must retain the above copyright 9 # * Redistributions of source code must retain the above copyright
10 # notice, this list of conditions and the following disclaimer. 10 # notice, this list of conditions and the following disclaimer.
(...skipping 10 matching lines...) Expand all
21 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 30
31 """Compute global interface information, including public information, dependenc ies, and inheritance.
32
33 Computed data is stored in a global variable, |interfaces_info|, and written as
34 output (concretely, exported as a pickle). This is then used by the IDL compiler
35 itself, so it does not need to compute global information itself, and so that
36 inter-IDL dependencies are clear, since they are all computed here.
37
38 The |interfaces_info| pickle is a *global* dependency: any changes cause a full
39 rebuild. This is to avoid having to compute which public data is visible by
40 which IDL files on a file-by-file basis, which is very complex for little
41 benefit.
42 |interfaces_info| should thus only contain data about an interface that
43 contains paths or is needed by *other* interfaces, e.g., path data (to abstract
44 the compiler from OS-specific file paths) or public data (to avoid having to
45 read other interfaces unnecessarily).
46 It should *not* contain full information about an interface (e.g., all
47 extended attributes), as this would cause unnecessary rebuilds.
48
49 |interfaces_info| is a dict, keyed by |interface_name|.
50
51 Current keys are:
52 * dependencies:
53 'implements_interfaces': targets of 'implements' statements
54 'referenced_interfaces': reference interfaces that are introspected
55 (currently just targets of [PutForwards])
56
57 * inheritance:
58 'ancestors': all ancestor interfaces
59 'inherited_extended_attributes': inherited extended attributes
haraken 2014/02/21 13:37:07 BTW, did you support [WillBeGarbageCollected]?
Nils Barth (inactive) 2014/02/21 13:51:57 Yup, it's just down under INHERITED_EXTENDED_ATTRI
haraken 2014/02/21 13:53:20 Thanks!
60 (all controlling memory management)
61
62 * public:
63 'is_callback_interface': bool, callback interface or not
64 'implemented_as': value of [ImplementedAs=...] on interface (C++ class name)
65
66 * paths:
67 'full_path': path to the IDL file, so can lookup an IDL by interface name
68 'include_path': path for use in C++ #include directives
69 'dependencies_full_paths': paths to dependencies (for merging into main)
haraken 2014/02/21 13:37:07 full_paths_of_dependencies ?
Nils Barth (inactive) 2014/02/21 13:51:57 It feels more natural as '..._paths' than 'paths_o
haraken 2014/02/21 13:53:20 Makes sense.
70 'dependencies_include_paths': paths for use in C++ #include directives
haraken 2014/02/21 13:37:07 include_paths_of_dependencies ?
71
72 Note that all of these are stable information, unlikely to change without
73 moving or deleting files (hence requiring a full rebuild anyway) or significant
74 code changes (for inherited extended attributes).
75
76 FIXME: also generates EventNames.in; factor out. http://crbug.com/341748
77 FIXME: also generates InterfaceDependencies.txt for Perl. http://crbug.com/2397 71
78
79 Design doc: http://www.chromium.org/developers/design-documents/idl-build
80 """
81
31 import optparse 82 import optparse
32 import os 83 import os
33 import posixpath 84 import posixpath
85 import sys
34 86
35 from utilities import get_file_contents, write_file, write_pickle_file, get_inte rface_extended_attributes_from_idl, is_callback_interface_from_idl, get_partial_ interface_name_from_idl, get_implemented_interfaces_from_idl, get_parent_interfa ce, get_put_forward_interfaces_from_idl 87 from utilities import get_file_contents, write_file, write_pickle_file, get_inte rface_extended_attributes_from_idl, is_callback_interface_from_idl, get_partial_ interface_name_from_idl, get_implemented_interfaces_from_idl, get_parent_interfa ce, get_put_forward_interfaces_from_idl
36 88
37 module_path = os.path.dirname(__file__) 89 module_path = os.path.dirname(__file__)
38 source_path = os.path.normpath(os.path.join(module_path, os.pardir, os.pardir)) 90 source_path = os.path.normpath(os.path.join(module_path, os.pardir, os.pardir))
39 91
40 INHERITED_EXTENDED_ATTRIBUTES = set([ 92 INHERITED_EXTENDED_ATTRIBUTES = set([
41 'ActiveDOMObject', 93 'ActiveDOMObject',
42 'DependentLifetime', 94 'DependentLifetime',
43 'WillBeGarbageCollected', 95 'WillBeGarbageCollected',
44 ]) 96 ])
45 97
46 98 # Main variable (filled in and exported)
47 # interfaces_info is *exported* (in a pickle), and should only contain data
48 # about an interface that contains paths or is needed by *other* interfaces,
49 # i.e., file layout data (to abstract the compiler from file paths) or
50 # public data (to avoid having to read other interfaces unnecessarily).
51 # It should *not* contain full information about an interface (e.g., all
52 # extended attributes), as this would cause unnecessary rebuilds.
53 interfaces_info = {} 99 interfaces_info = {}
54 100
55 # Auxiliary variables (not visible to future build steps) 101 # Auxiliary variables (not visible to future build steps)
56 partial_interface_files = {} 102 partial_interface_files = {}
57 parent_interfaces = {} 103 parent_interfaces = {}
58 extended_attributes_by_interface = {} # interface name -> extended attributes 104 extended_attributes_by_interface = {} # interface name -> extended attributes
59 105
60 106
61 class IdlBadFilenameError(Exception):
62 """Raised if an IDL filename disagrees with the interface name in the file." ""
63 pass
64
65
66 class IdlInterfaceFileNotFoundError(Exception): 107 class IdlInterfaceFileNotFoundError(Exception):
67 """Raised if the IDL file implementing an interface cannot be found.""" 108 """Raised if the IDL file implementing an interface cannot be found."""
68 pass 109 pass
69 110
70 111
71 def parse_options(): 112 def parse_options():
72 usage = 'Usage: %prog [options] [generated1.idl]...' 113 usage = 'Usage: %prog [options] [generated1.idl]...'
73 parser = optparse.OptionParser(usage=usage) 114 parser = optparse.OptionParser(usage=usage)
74 parser.add_option('--event-names-file', help='output file') 115 parser.add_option('--event-names-file', help='output file')
75 parser.add_option('--idl-files-list', help='file listing IDL files') 116 parser.add_option('--idl-files-list', help='file listing IDL files')
(...skipping 30 matching lines...) Expand all
106 ... 147 ...
107 148
108 The above indicates that: 149 The above indicates that:
109 Document.idl depends on P.idl, 150 Document.idl depends on P.idl,
110 Event.idl depends on no other IDL files, and 151 Event.idl depends on no other IDL files, and
111 Window.idl depends on Q.idl, R.idl, and S.idl. 152 Window.idl depends on Q.idl, R.idl, and S.idl.
112 153
113 An IDL that is a dependency of another IDL (e.g. P.idl) does not have its 154 An IDL that is a dependency of another IDL (e.g. P.idl) does not have its
114 own line in the dependency file. 155 own line in the dependency file.
115 """ 156 """
116 # FIXME: remove text format once Perl gone (Python uses pickle) 157 # FIXME: remove this file once Perl is gone http://crbug.com/239771
117 dependencies_list = sorted( 158 dependencies_list = sorted(
118 (interface_info['full_path'], sorted(interface_info['dependencies_full_p aths'])) 159 (interface_info['full_path'], sorted(interface_info['dependencies_full_p aths']))
119 for interface_info in interfaces_info.values()) 160 for interface_info in interfaces_info.values())
120 lines = ['%s %s\n' % (idl_file, ' '.join(dependency_files)) 161 lines = ['%s %s\n' % (idl_file, ' '.join(dependency_files))
121 for idl_file, dependency_files in dependencies_list] 162 for idl_file, dependency_files in dependencies_list]
122 write_file(lines, dependencies_filename, only_if_changed) 163 write_file(lines, dependencies_filename, only_if_changed)
123 164
124 165
125 def write_event_names_file(destination_filename, only_if_changed): 166 def write_event_names_file(destination_filename, only_if_changed):
126 # Generate event names for all interfaces that inherit from Event, 167 # Generate event names for all interfaces that inherit from Event,
127 # including Event itself. 168 # including Event itself.
169 # FIXME: factor out. http://crbug.com/341748
128 event_names = set( 170 event_names = set(
129 interface_name 171 interface_name
130 for interface_name, interface_info in interfaces_info.iteritems() 172 for interface_name, interface_info in interfaces_info.iteritems()
131 if (interface_name == 'Event' or 173 if (interface_name == 'Event' or
132 ('ancestors' in interface_info and 174 ('ancestors' in interface_info and
133 interface_info['ancestors'][-1] == 'Event'))) 175 interface_info['ancestors'][-1] == 'Event')))
134 176
135 def extended_attribute_string(name): 177 def extended_attribute_string(name):
136 value = extended_attributes[name] 178 value = extended_attributes[name]
137 if name == 'RuntimeEnabled': 179 if name == 'RuntimeEnabled':
(...skipping 13 matching lines...) Expand all
151 refined_filename = refined_filename.replace(os.sep, posixpath.sep) 193 refined_filename = refined_filename.replace(os.sep, posixpath.sep)
152 extended_attributes_list = [ 194 extended_attributes_list = [
153 extended_attribute_string(name) 195 extended_attribute_string(name)
154 for name in 'Conditional', 'ImplementedAs', 'RuntimeEnabled' 196 for name in 'Conditional', 'ImplementedAs', 'RuntimeEnabled'
155 if name in extended_attributes] 197 if name in extended_attributes]
156 lines.append('%s %s\n' % (refined_filename, ', '.join(extended_attribute s_list))) 198 lines.append('%s %s\n' % (refined_filename, ', '.join(extended_attribute s_list)))
157 write_file(lines, destination_filename, only_if_changed) 199 write_file(lines, destination_filename, only_if_changed)
158 200
159 201
160 ################################################################################ 202 ################################################################################
161 # Dependency resolution 203 # Computations
162 ################################################################################ 204 ################################################################################
163 205
164 def include_path(idl_filename, implemented_as=None): 206 def include_path(idl_filename, implemented_as=None):
165 """Returns relative path to header file in POSIX format; used in includes. 207 """Returns relative path to header file in POSIX format; used in includes.
166 208
167 POSIX format is used for consistency of output, so reference tests are 209 POSIX format is used for consistency of output, so reference tests are
168 platform-independent. 210 platform-independent.
169 """ 211 """
170 relative_path_local = os.path.relpath(idl_filename, source_path) 212 relative_path_local = os.path.relpath(idl_filename, source_path)
171 relative_dir_local = os.path.dirname(relative_path_local) 213 relative_dir_local = os.path.dirname(relative_path_local)
172 relative_dir_posix = relative_dir_local.replace(os.path.sep, posixpath.sep) 214 relative_dir_posix = relative_dir_local.replace(os.path.sep, posixpath.sep)
173 215
174 idl_file_basename, _ = os.path.splitext(os.path.basename(idl_filename)) 216 idl_file_basename, _ = os.path.splitext(os.path.basename(idl_filename))
175 cpp_class_name = implemented_as or idl_file_basename 217 cpp_class_name = implemented_as or idl_file_basename
176 218
177 return posixpath.join(relative_dir_posix, cpp_class_name + '.h') 219 return posixpath.join(relative_dir_posix, cpp_class_name + '.h')
178 220
179 221
180 def add_paths_to_partials_dict(partial_interface_name, full_path, this_include_p ath=None): 222 def add_paths_to_partials_dict(partial_interface_name, full_path, this_include_p ath=None):
181 paths_dict = partial_interface_files.setdefault(partial_interface_name, 223 paths_dict = partial_interface_files.setdefault(partial_interface_name,
182 {'full_paths': [], 224 {'full_paths': [],
183 'include_paths': []}) 225 'include_paths': []})
184 paths_dict['full_paths'].append(full_path) 226 paths_dict['full_paths'].append(full_path)
185 if this_include_path: 227 if this_include_path:
186 paths_dict['include_paths'].append(this_include_path) 228 paths_dict['include_paths'].append(this_include_path)
187 229
188 230
189 def generate_dependencies(idl_filename): 231 def compute_individual_info(idl_filename):
190 """Compute dependencies for IDL file, returning True if main (non-partial) i nterface"""
191 full_path = os.path.realpath(idl_filename) 232 full_path = os.path.realpath(idl_filename)
192 idl_file_contents = get_file_contents(full_path) 233 idl_file_contents = get_file_contents(full_path)
193 234
194 extended_attributes = get_interface_extended_attributes_from_idl(idl_file_co ntents) 235 extended_attributes = get_interface_extended_attributes_from_idl(idl_file_co ntents)
195 implemented_as = extended_attributes.get('ImplementedAs') 236 implemented_as = extended_attributes.get('ImplementedAs')
196 # FIXME: remove [NoHeader] once switch to Python 237 # FIXME: remove [NoHeader] once switch to Python
197 this_include_path = (include_path(idl_filename, implemented_as) 238 this_include_path = (include_path(idl_filename, implemented_as)
198 if 'NoHeader' not in extended_attributes else None) 239 if 'NoHeader' not in extended_attributes else None)
199 240
200 # Handle partial interfaces 241 # Handle partial interfaces
(...skipping 15 matching lines...) Expand all
216 # deep dependencies. 257 # deep dependencies.
217 # These cause rebuilds of referrers, due to the dependency, so these 258 # These cause rebuilds of referrers, due to the dependency, so these
218 # should be minimized; currently only targets of [PutForwards]. 259 # should be minimized; currently only targets of [PutForwards].
219 'referenced_interfaces': get_put_forward_interfaces_from_idl(idl_file_co ntents), 260 'referenced_interfaces': get_put_forward_interfaces_from_idl(idl_file_co ntents),
220 } 261 }
221 if this_include_path: 262 if this_include_path:
222 interfaces_info[interface_name]['include_path'] = this_include_path 263 interfaces_info[interface_name]['include_path'] = this_include_path
223 if implemented_as: 264 if implemented_as:
224 interfaces_info[interface_name]['implemented_as'] = implemented_as 265 interfaces_info[interface_name]['implemented_as'] = implemented_as
225 266
226 # Record extended attributes 267 # Record auxiliary information
227 extended_attributes_by_interface[interface_name] = extended_attributes 268 extended_attributes_by_interface[interface_name] = extended_attributes
228
229 # Record parents
230 parent = get_parent_interface(idl_file_contents) 269 parent = get_parent_interface(idl_file_contents)
231 if parent: 270 if parent:
232 parent_interfaces[interface_name] = parent 271 parent_interfaces[interface_name] = parent
233 272
234 273
235 def generate_ancestors_and_inherited_extended_attributes(interface_name): 274 def compute_inheritance_info(interface_name):
275 """Computes inheritance information, namely ancestors and inherited extended attributes."""
236 interface_info = interfaces_info[interface_name] 276 interface_info = interfaces_info[interface_name]
237 interface_extended_attributes = extended_attributes_by_interface[interface_n ame] 277 interface_extended_attributes = extended_attributes_by_interface[interface_n ame]
238 inherited_extended_attributes = dict( 278 inherited_extended_attributes = dict(
239 (key, value) 279 (key, value)
240 for key, value in interface_extended_attributes.iteritems() 280 for key, value in interface_extended_attributes.iteritems()
241 if key in INHERITED_EXTENDED_ATTRIBUTES) 281 if key in INHERITED_EXTENDED_ATTRIBUTES)
242 282
243 def generate_ancestors(interface_name): 283 def generate_ancestors(interface_name):
244 while interface_name in parent_interfaces: 284 while interface_name in parent_interfaces:
245 interface_name = parent_interfaces[interface_name] 285 interface_name = parent_interfaces[interface_name]
246 yield interface_name 286 yield interface_name
247 287
248 ancestors = list(generate_ancestors(interface_name)) 288 ancestors = list(generate_ancestors(interface_name))
249 if not ancestors: 289 if not ancestors:
250 if inherited_extended_attributes: 290 if inherited_extended_attributes:
251 interface_info['inherited_extended_attributes'] = inherited_extended _attributes 291 interface_info['inherited_extended_attributes'] = inherited_extended _attributes
252 return 292 return
253 293
254 interface_info['ancestors'] = ancestors 294 interface_info['ancestors'] = ancestors
255 for ancestor in ancestors: 295 for ancestor in ancestors:
256 # Extended attributes are missing if an ancestor is an interface that 296 # Extended attributes are missing if an ancestor is an interface that
257 # we're not processing, notably real IDL files if only processing test 297 # we're not processing, namely real IDL files if only processing test
258 # IDL files, or generated support files. 298 # IDL files.
259 ancestor_extended_attributes = extended_attributes_by_interface.get(ance stor, {}) 299 ancestor_extended_attributes = extended_attributes_by_interface.get(ance stor, {})
260 inherited_extended_attributes.update(dict( 300 inherited_extended_attributes.update(dict(
261 (key, value) 301 (key, value)
262 for key, value in ancestor_extended_attributes.iteritems() 302 for key, value in ancestor_extended_attributes.iteritems()
263 if key in INHERITED_EXTENDED_ATTRIBUTES)) 303 if key in INHERITED_EXTENDED_ATTRIBUTES))
264 if inherited_extended_attributes: 304 if inherited_extended_attributes:
265 interface_info['inherited_extended_attributes'] = inherited_extended_att ributes 305 interface_info['inherited_extended_attributes'] = inherited_extended_att ributes
266 306
267 307
268 def parse_idl_files(idl_files): 308 def compute_interfaces_info(idl_files):
269 """Compute information about IDL files. 309 """Compute information about IDL files.
270 310
271 Primary effect is computing info about main interfaces, stored in global 311 Information is stored in global interfaces_info.
272 interfaces_info.
273 """ 312 """
274 # Generate dependencies. 313 # Compute information for individual files
275 for idl_filename in idl_files: 314 for idl_filename in idl_files:
276 generate_dependencies(idl_filename) 315 compute_individual_info(idl_filename)
277 316
317 # Once all individual files handled, can compute inheritance information
278 for interface_name in interfaces_info: 318 for interface_name in interfaces_info:
279 generate_ancestors_and_inherited_extended_attributes(interface_name) 319 compute_inheritance_info(interface_name)
280 320
281 # An IDL file's dependencies are partial interface files that extend it, 321 # An IDL file's dependencies are partial interface files that extend it,
282 # and files for other interfaces that this interfaces implements. 322 # and files for other interfaces that this interfaces implements.
283 for interface_name, interface_info in interfaces_info.iteritems(): 323 for interface_name, interface_info in interfaces_info.iteritems():
284 partial_interfaces_full_paths, partial_interfaces_include_paths = ( 324 partial_interfaces_full_paths, partial_interfaces_include_paths = (
285 (partial_interface_files[interface_name]['full_paths'], 325 (partial_interface_files[interface_name]['full_paths'],
286 partial_interface_files[interface_name]['include_paths']) 326 partial_interface_files[interface_name]['include_paths'])
287 if interface_name in partial_interface_files else ([], [])) 327 if interface_name in partial_interface_files else ([], []))
288 328
289 implemented_interfaces = interface_info['implements_interfaces'] 329 implemented_interfaces = interface_info['implements_interfaces']
(...skipping 24 matching lines...) Expand all
314 # Static IDL files are passed in a file (generated at GYP time), due to OS 354 # Static IDL files are passed in a file (generated at GYP time), due to OS
315 # command line length limits 355 # command line length limits
316 with open(options.idl_files_list) as idl_files_list: 356 with open(options.idl_files_list) as idl_files_list:
317 idl_files = [line.rstrip('\n') for line in idl_files_list] 357 idl_files = [line.rstrip('\n') for line in idl_files_list]
318 # Generated IDL files are passed at the command line, since these are in the 358 # Generated IDL files are passed at the command line, since these are in the
319 # build directory, which is determined at build time, not GYP time, so these 359 # build directory, which is determined at build time, not GYP time, so these
320 # cannot be included in the file listing static files 360 # cannot be included in the file listing static files
321 idl_files.extend(args) 361 idl_files.extend(args)
322 362
323 only_if_changed = options.write_file_only_if_changed 363 only_if_changed = options.write_file_only_if_changed
324 364 compute_interfaces_info(idl_files)
325 parse_idl_files(idl_files)
326 write_pickle_file(options.interfaces_info_file, interfaces_info, only_if_cha nged) 365 write_pickle_file(options.interfaces_info_file, interfaces_info, only_if_cha nged)
327 write_dependencies_file(options.interface_dependencies_file, only_if_changed ) 366 write_dependencies_file(options.interface_dependencies_file, only_if_changed )
328 write_event_names_file(options.event_names_file, only_if_changed) 367 write_event_names_file(options.event_names_file, only_if_changed)
329 368
330 369
331 if __name__ == '__main__': 370 if __name__ == '__main__':
332 main() 371 sys.exit(main())
OLDNEW
« no previous file with comments | « Source/bindings/generated_bindings.gyp ('k') | Source/bindings/scripts/generate_global_constructors.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698