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

Side by Side Diff: sky/engine/bindings2/scripts/compute_interfaces_info_overall.py

Issue 915293003: Rename sky/engine/bindings2 to sky/engine/bindings (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: more better Created 5 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
OLDNEW
(Empty)
1 #!/usr/bin/python
2 #
3 # Copyright (C) 2013 Google 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 are
7 # met:
8 #
9 # * Redistributions of source code must retain the above copyright
10 # notice, this list of conditions and the following disclaimer.
11 # * Redistributions in binary form must reproduce the above
12 # copyright notice, this list of conditions and the following disclaimer
13 # in the documentation and/or other materials provided with the
14 # distribution.
15 # * Neither the name of Google Inc. nor the names of its
16 # contributors may be used to endorse or promote products derived from
17 # this software without specific prior written permission.
18 #
19 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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.
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 Design doc: http://www.chromium.org/developers/design-documents/idl-build
77 """
78
79 from collections import defaultdict
80 import cPickle as pickle
81 import optparse
82 import sys
83
84 from utilities import read_pickle_files, write_pickle_file
85
86 INHERITED_EXTENDED_ATTRIBUTES = set([
87 'ActiveDOMObject',
88 'DependentLifetime',
89 'NotScriptWrappable',
90 ])
91
92 # Main variable (filled in and exported)
93 interfaces_info = {}
94
95 # Auxiliary variables (not visible to future build steps)
96 partial_interface_files = defaultdict(lambda: {
97 'full_paths': [],
98 'include_paths': [],
99 })
100 parent_interfaces = {}
101 inherited_extended_attributes_by_interface = {} # interface name -> extended at tributes
102
103
104 class IdlInterfaceFileNotFoundError(Exception):
105 """Raised if the IDL file implementing an interface cannot be found."""
106 pass
107
108
109 def parse_options():
110 usage = 'Usage: %prog [InfoIndividual.pickle]... [Info.pickle]'
111 parser = optparse.OptionParser(usage=usage)
112 parser.add_option('--write-file-only-if-changed', type='int', help='if true, do not write an output file if it would be identical to the existing one, which avoids unnecessary rebuilds in ninja')
113
114 options, args = parser.parse_args()
115 if options.write_file_only_if_changed is None:
116 parser.error('Must specify whether file is only written if changed using --write-file-only-if-changed.')
117 options.write_file_only_if_changed = bool(options.write_file_only_if_changed )
118 return options, args
119
120
121 def dict_of_dicts_of_lists_update_or_append(existing, other):
122 """Updates an existing dict of dicts of lists, or appends to lists if key al ready present.
123
124 Needed for merging partial_interface_files across components.
125 """
126 for key, value in other.iteritems():
127 if key not in existing:
128 existing[key] = value
129 continue
130 existing_value = existing[key]
131 for inner_key, inner_value in value.iteritems():
132 existing_value[inner_key].extend(inner_value)
133
134
135 ################################################################################
136 # Computations
137 ################################################################################
138
139 def compute_inheritance_info(interface_name):
140 """Compute inheritance information, namely ancestors and inherited extended attributes."""
141 def generate_ancestors(interface_name):
142 while interface_name in parent_interfaces:
143 interface_name = parent_interfaces[interface_name]
144 yield interface_name
145
146 ancestors = list(generate_ancestors(interface_name))
147 inherited_extended_attributes = inherited_extended_attributes_by_interface[i nterface_name]
148 for ancestor in ancestors:
149 # Ancestors may not be present, notably if an ancestor is a generated
150 # IDL file and we are running this script from run-bindings-tests,
151 # where we don't generate these files.
152 ancestor_extended_attributes = inherited_extended_attributes_by_interfac e.get(ancestor, {})
153 inherited_extended_attributes.update(ancestor_extended_attributes)
154
155 interfaces_info[interface_name].update({
156 'ancestors': ancestors,
157 'inherited_extended_attributes': inherited_extended_attributes,
158 })
159
160
161 def compute_interfaces_info_overall(info_individuals):
162 """Compute information about IDL files.
163
164 Information is stored in global interfaces_info.
165 """
166 for info in info_individuals:
167 # No overlap between interface names, so ok to use dict.update
168 interfaces_info.update(info['interfaces_info'])
169 # Interfaces in one component may have partial interfaces in
170 # another component. This is ok (not a layering violation), since
171 # partial interfaces are used to *extend* interfaces.
172 # We thus need to update or append if already present
173 dict_of_dicts_of_lists_update_or_append(
174 partial_interface_files, info['partial_interface_files'])
175
176 # Record inheritance information individually
177 for interface_name, interface_info in interfaces_info.iteritems():
178 extended_attributes = interface_info['extended_attributes']
179 inherited_extended_attributes_by_interface[interface_name] = dict(
180 (key, value)
181 for key, value in extended_attributes.iteritems()
182 if key in INHERITED_EXTENDED_ATTRIBUTES)
183 parent = interface_info['parent']
184 if parent:
185 parent_interfaces[interface_name] = parent
186
187 # Once all individual files handled, can compute inheritance information
188 # and dependencies
189
190 # Compute inheritance info
191 for interface_name in interfaces_info:
192 compute_inheritance_info(interface_name)
193
194 # Compute dependencies
195 # Move implements info from implement*ed* interface (rhs of 'implements')
196 # to implement*ing* interface (lhs of 'implements').
197 # Note that moving an 'implements' statement between implementing and
198 # implemented files does not change the info (or hence cause a rebuild)!
199 for right_interface_name, interface_info in interfaces_info.iteritems():
200 for left_interface_name in interface_info['implemented_by_interfaces']:
201 interfaces_info[left_interface_name]['implements_interfaces'].append (right_interface_name)
202 del interface_info['implemented_by_interfaces']
203
204 # An IDL file's dependencies are partial interface files that extend it,
205 # and files for other interfaces that this interfaces implements.
206 for interface_name, interface_info in interfaces_info.iteritems():
207 partial_interface_paths = partial_interface_files[interface_name]
208 partial_interfaces_full_paths = partial_interface_paths['full_paths']
209 # Partial interface definitions each need an include, as they are
210 # implemented in separate classes from the main interface.
211 partial_interfaces_include_paths = partial_interface_paths['include_path s']
212
213 implemented_interfaces = interface_info['implements_interfaces']
214 try:
215 implemented_interfaces_info = [
216 interfaces_info[interface]
217 for interface in implemented_interfaces]
218 except KeyError as key_name:
219 raise IdlInterfaceFileNotFoundError('Could not find the IDL file whe re the following implemented interface is defined: %s' % key_name)
220 implemented_interfaces_full_paths = [
221 implemented_interface_info['full_path']
222 for implemented_interface_info in implemented_interfaces_info]
223 # Implemented interfaces don't need includes, as this is handled in
224 # the Blink implementation (they are implemented on |impl| itself,
225 # hence header is included in implementing class).
226 # However, they are needed for legacy implemented interfaces that
227 # are being treated as partial interfaces, until we remove these.
228 # http://crbug.com/360435
229 implemented_interfaces_include_paths = []
230 for implemented_interface_info in implemented_interfaces_info:
231 if (implemented_interface_info['is_legacy_treat_as_partial_interface '] and
232 implemented_interface_info['include_path']):
233 implemented_interfaces_include_paths.append(implemented_interfac e_info['include_path'])
234
235 interface_info.update({
236 'dependencies_full_paths': (partial_interfaces_full_paths +
237 implemented_interfaces_full_paths),
238 'dependencies_include_paths': (partial_interfaces_include_paths +
239 implemented_interfaces_include_paths) ,
240 })
241
242 # Clean up temporary private information
243 for interface_info in interfaces_info.itervalues():
244 del interface_info['extended_attributes']
245 del interface_info['is_legacy_treat_as_partial_interface']
246 del interface_info['parent']
247
248
249 ################################################################################
250
251 def main():
252 options, args = parse_options()
253 # args = Input1, Input2, ..., Output
254 interfaces_info_filename = args.pop()
255 info_individuals = read_pickle_files(args)
256
257 compute_interfaces_info_overall(info_individuals)
258 write_pickle_file(interfaces_info_filename,
259 interfaces_info,
260 options.write_file_only_if_changed)
261
262
263 if __name__ == '__main__':
264 sys.exit(main())
OLDNEW
« no previous file with comments | « sky/engine/bindings2/scripts/compute_interfaces_info_individual.py ('k') | sky/engine/bindings2/scripts/dart_attributes.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698