3 # Copyright (C) 2013 Google Inc. All rights reserved.
5 # Redistribution and use in source and binary forms, with or without
6 # modification, are permitted provided that the following conditions are
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
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.
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.
31 """Compute global interface information for individual IDL files.
33 Auxiliary module for compute_interfaces_info_overall, which consolidates
34 this individual information, computing info that spans multiple files
35 (dependencies and ancestry).
37 This distinction is so that individual interface info can be computed
38 separately for each component (avoiding duplicated reading of individual
39 files), then consolidated using *only* the info visible to a given component.
41 Design doc: http://www.chromium.org/developers/design-documents/idl-build
44 from collections import defaultdict
50 from utilities import get_file_contents, read_file_to_list, idl_filename_to_interface_name, idl_filename_to_component, write_pickle_file, get_interface_extended_attributes_from_idl, is_callback_interface_from_idl, is_dictionary_from_idl, get_partial_interface_name_from_idl, get_implements_from_idl, get_parent_interface, get_put_forward_interfaces_from_idl
52 module_path = os.path.dirname(__file__)
53 source_path = os.path.normpath(os.path.join(module_path, os.pardir, os.pardir))
55 # Global variables (filled in and exported)
57 partial_interface_files = defaultdict(lambda: {
64 usage = 'Usage: %prog [options] [generated1.idl]...'
65 parser = optparse.OptionParser(usage=usage)
66 parser.add_option('--idl-files-list', help='file listing IDL files')
67 parser.add_option('--interfaces-info-file', help='output pickle file')
68 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')
70 options, args = parser.parse_args()
71 if options.interfaces_info_file is None:
72 parser.error('Must specify an output file using --interfaces-info-file.')
73 if options.idl_files_list is None:
74 parser.error('Must specify a file listing IDL files using --idl-files-list.')
75 if options.write_file_only_if_changed is None:
76 parser.error('Must specify whether file is only written if changed using --write-file-only-if-changed.')
77 options.write_file_only_if_changed = bool(options.write_file_only_if_changed)
81 ################################################################################
83 ################################################################################
85 def relative_dir_posix(idl_filename):
86 """Returns relative path to the directory of idl_file in POSIX format."""
87 relative_path_local = os.path.relpath(idl_filename, source_path)
88 relative_dir_local = os.path.dirname(relative_path_local)
89 return relative_dir_local.replace(os.path.sep, posixpath.sep)
92 def include_path(idl_filename, implemented_as=None):
93 """Returns relative path to header file in POSIX format; used in includes.
95 POSIX format is used for consistency of output, so reference tests are
98 relative_dir = relative_dir_posix(idl_filename)
100 # IDL file basename is used even if only a partial interface file
101 idl_file_basename, _ = os.path.splitext(os.path.basename(idl_filename))
102 cpp_class_name = implemented_as or idl_file_basename
104 return posixpath.join(relative_dir, cpp_class_name + '.h')
107 def add_paths_to_partials_dict(partial_interface_name, full_path, this_include_path=None):
108 paths_dict = partial_interface_files[partial_interface_name]
109 paths_dict['full_paths'].append(full_path)
110 if this_include_path:
111 paths_dict['include_paths'].append(this_include_path)
114 def compute_info_individual(idl_filename):
115 full_path = os.path.realpath(idl_filename)
116 idl_file_contents = get_file_contents(full_path)
118 extended_attributes = get_interface_extended_attributes_from_idl(idl_file_contents)
119 implemented_as = extended_attributes.get('ImplementedAs')
120 relative_dir = relative_dir_posix(idl_filename)
121 this_include_path = None if 'NoImplHeader' in extended_attributes else include_path(idl_filename, implemented_as)
123 # Handle partial interfaces
124 partial_interface_name = get_partial_interface_name_from_idl(idl_file_contents)
125 if partial_interface_name:
126 add_paths_to_partials_dict(partial_interface_name, full_path, this_include_path)
129 # If not a partial interface, the basename is the interface name
130 interface_name = idl_filename_to_interface_name(idl_filename)
132 # 'implements' statements can be included in either the file for the
133 # implement*ing* interface (lhs of 'implements') or implement*ed* interface
134 # (rhs of 'implements'). Store both for now, then merge to implement*ing*
136 left_interfaces, right_interfaces = get_implements_from_idl(idl_file_contents, interface_name)
138 interfaces_info[interface_name] = {
139 'extended_attributes': extended_attributes,
140 'full_path': full_path,
141 'implemented_as': implemented_as,
142 'implemented_by_interfaces': left_interfaces, # private, merged to next
143 'implements_interfaces': right_interfaces,
144 'include_path': this_include_path,
145 'is_callback_interface': is_callback_interface_from_idl(idl_file_contents),
146 'is_dictionary': is_dictionary_from_idl(idl_file_contents),
147 # FIXME: temporary private field, while removing old treatement of
148 # 'implements': http://crbug.com/360435
149 'is_legacy_treat_as_partial_interface': 'LegacyTreatAsPartialInterface' in extended_attributes,
150 'parent': get_parent_interface(idl_file_contents),
151 # Interfaces that are referenced (used as types) and that we introspect
152 # during code generation (beyond interface-level data ([ImplementedAs],
153 # is_callback_interface, ancestors, and inherited extended attributes):
155 # These cause rebuilds of referrers, due to the dependency, so these
156 # should be minimized; currently only targets of [PutForwards].
157 'referenced_interfaces': get_put_forward_interfaces_from_idl(idl_file_contents),
158 'relative_dir': relative_dir,
162 def info_individual():
163 """Returns info packaged as a dict."""
165 'interfaces_info': interfaces_info,
166 # Can't pickle defaultdict, convert to dict
167 'partial_interface_files': dict(partial_interface_files),
171 ################################################################################
174 options, args = parse_options()
176 # Static IDL files are passed in a file (generated at GYP time), due to OS
177 # command line length limits
178 idl_files = read_file_to_list(options.idl_files_list)
179 # Generated IDL files are passed at the command line, since these are in the
180 # build directory, which is determined at build time, not GYP time, so these
181 # cannot be included in the file listing static files
182 idl_files.extend(args)
184 # Compute information for individual files
185 # Information is stored in global variables interfaces_info and
186 # partial_interface_files.
187 for idl_filename in idl_files:
188 compute_info_individual(idl_filename)
190 write_pickle_file(options.interfaces_info_file,
192 options.write_file_only_if_changed)
195 if __name__ == '__main__':