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

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: Rebased Created 6 years, 9 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
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)
70 'dependencies_include_paths': paths for use in C++ #include directives
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 IdlInterfaceFileNotFoundError(Exception): 107 class IdlInterfaceFileNotFoundError(Exception):
62 """Raised if the IDL file implementing an interface cannot be found.""" 108 """Raised if the IDL file implementing an interface cannot be found."""
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
101 ... 147 ...
102 148
103 The above indicates that: 149 The above indicates that:
104 Document.idl depends on P.idl, 150 Document.idl depends on P.idl,
105 Event.idl depends on no other IDL files, and 151 Event.idl depends on no other IDL files, and
106 Window.idl depends on Q.idl, R.idl, and S.idl. 152 Window.idl depends on Q.idl, R.idl, and S.idl.
107 153
108 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
109 own line in the dependency file. 155 own line in the dependency file.
110 """ 156 """
111 # FIXME: remove text format once Perl gone (Python uses pickle) 157 # FIXME: remove this file once Perl is gone http://crbug.com/239771
112 dependencies_list = sorted( 158 dependencies_list = sorted(
113 (interface_info['full_path'], sorted(interface_info['dependencies_full_p aths'])) 159 (interface_info['full_path'], sorted(interface_info['dependencies_full_p aths']))
114 for interface_info in interfaces_info.values()) 160 for interface_info in interfaces_info.values())
115 lines = ['%s %s\n' % (idl_file, ' '.join(dependency_files)) 161 lines = ['%s %s\n' % (idl_file, ' '.join(dependency_files))
116 for idl_file, dependency_files in dependencies_list] 162 for idl_file, dependency_files in dependencies_list]
117 write_file(lines, dependencies_filename, only_if_changed) 163 write_file(lines, dependencies_filename, only_if_changed)
118 164
119 165
120 def write_event_names_file(destination_filename, only_if_changed): 166 def write_event_names_file(destination_filename, only_if_changed):
121 # Generate event names for all interfaces that inherit from Event, 167 # Generate event names for all interfaces that inherit from Event,
122 # including Event itself. 168 # including Event itself.
169 # FIXME: factor out. http://crbug.com/341748
123 event_names = set( 170 event_names = set(
124 interface_name 171 interface_name
125 for interface_name, interface_info in interfaces_info.iteritems() 172 for interface_name, interface_info in interfaces_info.iteritems()
126 if (interface_name == 'Event' or 173 if (interface_name == 'Event' or
127 ('ancestors' in interface_info and 174 ('ancestors' in interface_info and
128 interface_info['ancestors'][-1] == 'Event'))) 175 interface_info['ancestors'][-1] == 'Event')))
129 176
130 def extended_attribute_string(name): 177 def extended_attribute_string(name):
131 value = extended_attributes[name] 178 value = extended_attributes[name]
132 if name == 'RuntimeEnabled': 179 if name == 'RuntimeEnabled':
(...skipping 13 matching lines...) Expand all
146 refined_filename = refined_filename.replace(os.sep, posixpath.sep) 193 refined_filename = refined_filename.replace(os.sep, posixpath.sep)
147 extended_attributes_list = [ 194 extended_attributes_list = [
148 extended_attribute_string(name) 195 extended_attribute_string(name)
149 for name in 'Conditional', 'ImplementedAs', 'RuntimeEnabled' 196 for name in 'Conditional', 'ImplementedAs', 'RuntimeEnabled'
150 if name in extended_attributes] 197 if name in extended_attributes]
151 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)))
152 write_file(lines, destination_filename, only_if_changed) 199 write_file(lines, destination_filename, only_if_changed)
153 200
154 201
155 ################################################################################ 202 ################################################################################
156 # Dependency resolution 203 # Computations
157 ################################################################################ 204 ################################################################################
158 205
159 def include_path(idl_filename, implemented_as=None): 206 def include_path(idl_filename, implemented_as=None):
160 """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.
161 208
162 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
163 platform-independent. 210 platform-independent.
164 """ 211 """
165 relative_path_local = os.path.relpath(idl_filename, source_path) 212 relative_path_local = os.path.relpath(idl_filename, source_path)
166 relative_dir_local = os.path.dirname(relative_path_local) 213 relative_dir_local = os.path.dirname(relative_path_local)
167 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)
168 215
169 idl_file_basename, _ = os.path.splitext(os.path.basename(idl_filename)) 216 idl_file_basename, _ = os.path.splitext(os.path.basename(idl_filename))
170 cpp_class_name = implemented_as or idl_file_basename 217 cpp_class_name = implemented_as or idl_file_basename
171 218
172 return posixpath.join(relative_dir_posix, cpp_class_name + '.h') 219 return posixpath.join(relative_dir_posix, cpp_class_name + '.h')
173 220
174 221
175 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):
176 paths_dict = partial_interface_files.setdefault(partial_interface_name, 223 paths_dict = partial_interface_files.setdefault(partial_interface_name,
177 {'full_paths': [], 224 {'full_paths': [],
178 'include_paths': []}) 225 'include_paths': []})
179 paths_dict['full_paths'].append(full_path) 226 paths_dict['full_paths'].append(full_path)
180 if this_include_path: 227 if this_include_path:
181 paths_dict['include_paths'].append(this_include_path) 228 paths_dict['include_paths'].append(this_include_path)
182 229
183 230
184 def generate_dependencies(idl_filename): 231 def compute_individual_info(idl_filename):
185 """Compute dependencies for IDL file, returning True if main (non-partial) i nterface"""
186 full_path = os.path.realpath(idl_filename) 232 full_path = os.path.realpath(idl_filename)
187 idl_file_contents = get_file_contents(full_path) 233 idl_file_contents = get_file_contents(full_path)
188 234
189 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)
190 implemented_as = extended_attributes.get('ImplementedAs') 236 implemented_as = extended_attributes.get('ImplementedAs')
191 # FIXME: remove [NoHeader] once switch to Python 237 # FIXME: remove [NoHeader] once switch to Python
192 this_include_path = (include_path(idl_filename, implemented_as) 238 this_include_path = (include_path(idl_filename, implemented_as)
193 if 'NoHeader' not in extended_attributes else None) 239 if 'NoHeader' not in extended_attributes else None)
194 240
195 # Handle partial interfaces 241 # Handle partial interfaces
(...skipping 15 matching lines...) Expand all
211 # deep dependencies. 257 # deep dependencies.
212 # These cause rebuilds of referrers, due to the dependency, so these 258 # These cause rebuilds of referrers, due to the dependency, so these
213 # should be minimized; currently only targets of [PutForwards]. 259 # should be minimized; currently only targets of [PutForwards].
214 '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),
215 } 261 }
216 if this_include_path: 262 if this_include_path:
217 interfaces_info[interface_name]['include_path'] = this_include_path 263 interfaces_info[interface_name]['include_path'] = this_include_path
218 if implemented_as: 264 if implemented_as:
219 interfaces_info[interface_name]['implemented_as'] = implemented_as 265 interfaces_info[interface_name]['implemented_as'] = implemented_as
220 266
221 # Record extended attributes 267 # Record auxiliary information
222 extended_attributes_by_interface[interface_name] = extended_attributes 268 extended_attributes_by_interface[interface_name] = extended_attributes
223
224 # Record parents
225 parent = get_parent_interface(idl_file_contents) 269 parent = get_parent_interface(idl_file_contents)
226 if parent: 270 if parent:
227 parent_interfaces[interface_name] = parent 271 parent_interfaces[interface_name] = parent
228 272
229 273
230 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."""
231 interface_info = interfaces_info[interface_name] 276 interface_info = interfaces_info[interface_name]
232 interface_extended_attributes = extended_attributes_by_interface[interface_n ame] 277 interface_extended_attributes = extended_attributes_by_interface[interface_n ame]
233 inherited_extended_attributes = dict( 278 inherited_extended_attributes = dict(
234 (key, value) 279 (key, value)
235 for key, value in interface_extended_attributes.iteritems() 280 for key, value in interface_extended_attributes.iteritems()
236 if key in INHERITED_EXTENDED_ATTRIBUTES) 281 if key in INHERITED_EXTENDED_ATTRIBUTES)
237 282
238 def generate_ancestors(interface_name): 283 def generate_ancestors(interface_name):
239 while interface_name in parent_interfaces: 284 while interface_name in parent_interfaces:
240 interface_name = parent_interfaces[interface_name] 285 interface_name = parent_interfaces[interface_name]
241 yield interface_name 286 yield interface_name
242 287
243 ancestors = list(generate_ancestors(interface_name)) 288 ancestors = list(generate_ancestors(interface_name))
244 if not ancestors: 289 if not ancestors:
245 if inherited_extended_attributes: 290 if inherited_extended_attributes:
246 interface_info['inherited_extended_attributes'] = inherited_extended _attributes 291 interface_info['inherited_extended_attributes'] = inherited_extended _attributes
247 return 292 return
248 293
249 interface_info['ancestors'] = ancestors 294 interface_info['ancestors'] = ancestors
250 for ancestor in ancestors: 295 for ancestor in ancestors:
251 # Extended attributes are missing if an ancestor is an interface that 296 # Extended attributes are missing if an ancestor is an interface that
252 # 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
253 # IDL files, or generated support files. 298 # IDL files.
254 ancestor_extended_attributes = extended_attributes_by_interface.get(ance stor, {}) 299 ancestor_extended_attributes = extended_attributes_by_interface.get(ance stor, {})
255 inherited_extended_attributes.update(dict( 300 inherited_extended_attributes.update(dict(
256 (key, value) 301 (key, value)
257 for key, value in ancestor_extended_attributes.iteritems() 302 for key, value in ancestor_extended_attributes.iteritems()
258 if key in INHERITED_EXTENDED_ATTRIBUTES)) 303 if key in INHERITED_EXTENDED_ATTRIBUTES))
259 if inherited_extended_attributes: 304 if inherited_extended_attributes:
260 interface_info['inherited_extended_attributes'] = inherited_extended_att ributes 305 interface_info['inherited_extended_attributes'] = inherited_extended_att ributes
261 306
262 307
263 def parse_idl_files(idl_files): 308 def compute_interfaces_info(idl_files):
264 """Compute information about IDL files. 309 """Compute information about IDL files.
265 310
266 Primary effect is computing info about main interfaces, stored in global 311 Information is stored in global interfaces_info.
267 interfaces_info.
268 """ 312 """
269 # Generate dependencies. 313 # Compute information for individual files
270 for idl_filename in idl_files: 314 for idl_filename in idl_files:
271 generate_dependencies(idl_filename) 315 compute_individual_info(idl_filename)
272 316
317 # Once all individual files handled, can compute inheritance information
273 for interface_name in interfaces_info: 318 for interface_name in interfaces_info:
274 generate_ancestors_and_inherited_extended_attributes(interface_name) 319 compute_inheritance_info(interface_name)
275 320
276 # 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,
277 # and files for other interfaces that this interfaces implements. 322 # and files for other interfaces that this interfaces implements.
278 for interface_name, interface_info in interfaces_info.iteritems(): 323 for interface_name, interface_info in interfaces_info.iteritems():
279 partial_interfaces_full_paths, partial_interfaces_include_paths = ( 324 partial_interfaces_full_paths, partial_interfaces_include_paths = (
280 (partial_interface_files[interface_name]['full_paths'], 325 (partial_interface_files[interface_name]['full_paths'],
281 partial_interface_files[interface_name]['include_paths']) 326 partial_interface_files[interface_name]['include_paths'])
282 if interface_name in partial_interface_files else ([], [])) 327 if interface_name in partial_interface_files else ([], []))
283 328
284 implemented_interfaces = interface_info['implements_interfaces'] 329 implemented_interfaces = interface_info['implements_interfaces']
(...skipping 24 matching lines...) Expand all
309 # 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
310 # command line length limits 355 # command line length limits
311 with open(options.idl_files_list) as idl_files_list: 356 with open(options.idl_files_list) as idl_files_list:
312 idl_files = [line.rstrip('\n') for line in idl_files_list] 357 idl_files = [line.rstrip('\n') for line in idl_files_list]
313 # 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
314 # 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
315 # cannot be included in the file listing static files 360 # cannot be included in the file listing static files
316 idl_files.extend(args) 361 idl_files.extend(args)
317 362
318 only_if_changed = options.write_file_only_if_changed 363 only_if_changed = options.write_file_only_if_changed
319 364 compute_interfaces_info(idl_files)
320 parse_idl_files(idl_files)
321 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)
322 write_dependencies_file(options.interface_dependencies_file, only_if_changed ) 366 write_dependencies_file(options.interface_dependencies_file, only_if_changed )
323 write_event_names_file(options.event_names_file, only_if_changed) 367 write_event_names_file(options.event_names_file, only_if_changed)
324 368
325 369
326 if __name__ == '__main__': 370 if __name__ == '__main__':
327 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