28"""Generate Blink C++ bindings (.h and .cpp files) for use by Dart:HTML.
30If run itself, caches Jinja templates (and creates dummy file for build,
31since cache filenames are unpredictable and opaque).
33This module is *not* concurrency-safe without care: bytecode caching creates
34a race condition on cache *write* (crashes if one process tries to read a
35partially-written cache). However, if you pre-cache the templates (by running
36the module itself), then you can parallelize compiling individual files, since
37cache *reading* is safe.
39Input: An object of class IdlDefinitions, containing an IDL interface X
40Output: DartX.h and DartX.cpp
42Design doc: http://www.chromium.org/developers/design-documents/idl-compiler
58module_path, module_filename = os.path.split(os.path.realpath(__file__))
59third_party_dir = os.path.normpath(
60 os.path.join(module_path, os.pardir, os.pardir, os.pardir, os.pardir,
62templates_dir = os.path.normpath(os.path.join(module_path,
'templates'))
65module_pyname = os.path.splitext(module_filename)[0] +
'.py'
70sys.path.insert(1, third_party_dir)
73dart_script_path = os.path.dirname(os.path.abspath(__file__))
74script_path = os.path.join(
75 os.path.dirname(os.path.dirname(dart_script_path)),
'scripts')
76sys.path.extend([script_path])
81from idl_types
import IdlType
82from utilities
import write_pickle_file
83from v8_globals
import includes
84from dart_utilities
import DartUtilities
87INTERFACES_WITHOUT_RESOLVERS = frozenset([
88 'TypeConversions',
'GCObservation',
'InternalProfilers',
89 'InternalRuntimeFlags',
'InternalSettings',
'InternalSettingsGenerated',
90 'Internals',
'LayerRect',
'LayerRectList',
'MallocStatistics',
97 def __init__(self, interfaces_info, cache_dir):
98 interfaces_info = interfaces_info
or {}
103 idl_types.set_ancestors(
104 dict((interface_name, interface_info[
'ancestors'])
105 for interface_name, interface_info
in interfaces_info.items()
106 if interface_info[
'ancestors']))
107 IdlType.set_callback_interfaces(
109 for interface_name, interface_info
in interfaces_info.items()
110 if interface_info[
'is_callback_interface']))
111 IdlType.set_implemented_as_interfaces(
112 dict((interface_name, interface_info[
'implemented_as'])
113 for interface_name, interface_info
in interfaces_info.items()
114 if interface_info[
'implemented_as']))
115 IdlType.set_garbage_collected_types(
117 for interface_name, interface_info
in interfaces_info.items()
118 if 'GarbageCollected' in
119 interface_info[
'inherited_extended_attributes']))
123 """Returns .h/.cpp code as (header_text, cpp_text)."""
125 interface = definitions.interfaces[interface_name]
127 raise Exception(
'%s not in IDL definitions' % interface_name)
130 interfaces.update(definitions.interfaces)
133 IdlType.set_callback_functions(definitions.callback_functions.keys())
134 IdlType.set_enums((enum.name, enum.values)
135 for enum
in definitions.enumerations.values())
138 if interface.is_callback:
139 header_template_filename =
'callback_interface_h.template'
140 cpp_template_filename =
'callback_interface_cpp.template'
141 generate_contents = dart_callback_interface.generate_callback_interface
143 header_template_filename =
'interface_h.template'
144 cpp_template_filename =
'interface_cpp.template'
145 generate_contents = dart_interface.generate_interface
146 header_template = self.
jinja_env.get_template(header_template_filename)
147 cpp_template = self.
jinja_env.get_template(cpp_template_filename)
150 template_contents = generate_contents(interface)
151 template_contents[
'code_generator'] = module_pyname
155 template_contents[
'header_includes'].add(interface_info[
'include_path'])
156 template_contents[
'header_includes'] = sorted(
157 template_contents[
'header_includes'])
158 includes.update(interface_info.get(
'dependencies_include_paths', []))
164 includes.discard(
'core/dom/GlobalEventHandlers.h')
165 includes.discard(
'core/frame/DOMWindowEventHandlers.h')
167 template_contents[
'cpp_includes'] = sorted(includes)
169 idl_world = {
'interface':
None,
'callback':
None}
172 if os.path.isfile(idl_pickle_filename):
173 with open(idl_pickle_filename)
as idl_pickle_file:
174 idl_global_data = pickle.load(idl_pickle_file)
175 idl_pickle_file.close()
176 idl_world[
'interface'] = idl_global_data[
'interface']
177 idl_world[
'callback'] = idl_global_data[
'callback']
179 if 'interface_name' in template_contents:
182 template_contents[
'interface_name'],
184 template_contents[
'parent_interface'],
185 'is_active_dom_object':
186 template_contents[
'is_active_dom_object'],
188 template_contents[
'is_event_target'],
190 template_contents[
'interface_name']
not in
191 INTERFACES_WITHOUT_RESOLVERS,
193 template_contents[
'is_node'],
194 'conditional_string':
195 template_contents[
'conditional_string'],
197 idl_world[
'interface'] = interface_global
199 callback_global = {
'name': template_contents[
'cpp_class']}
200 idl_world[
'callback'] = callback_global
202 write_pickle_file(idl_pickle_filename, idl_world, only_if_changed)
205 header_text = header_template.render(template_contents)
206 cpp_text = cpp_template.render(template_contents)
207 return header_text, cpp_text
211 header_template_filename =
'global_h.template'
212 cpp_template_filename =
'global_cpp.template'
216 global_pickle_filename = os.path.join(output_directory,
'global.pickle')
217 if os.path.isfile(global_pickle_filename):
218 os.remove(global_pickle_filename)
221 world = {
'interfaces': [],
'callbacks': []}
224 listing = os.listdir(output_directory)
225 for filename
in listing:
226 if filename.endswith(
'_globals.pickle'):
227 idl_filename = os.path.join(output_directory, filename)
228 with open(idl_filename)
as idl_pickle_file:
229 idl_world = pickle.load(idl_pickle_file)
230 if 'interface' in idl_world:
232 if idl_world[
'interface']:
233 world[
'interfaces'].
append(idl_world[
'interface'])
234 if 'callbacks' in idl_world:
236 if idl_world[
'callbacks']:
237 world[
'callbacks'].
append(idl_world[
'callback'])
238 idl_pickle_file.close()
240 world[
'interfaces'] = sorted(world[
'interfaces'],
241 key=
lambda x: x[
'name'])
242 world[
'callbacks'] = sorted(world[
'callbacks'], key=
lambda x: x[
'name'])
244 template_contents = world
245 template_contents[
'code_generator'] = module_pyname
247 header_template = self.
jinja_env.get_template(header_template_filename)
248 header_text = header_template.render(template_contents)
250 cpp_template = self.
jinja_env.get_template(cpp_template_filename)
251 cpp_text = cpp_template.render(template_contents)
252 return header_text, cpp_text
256 jinja_env = jinja2.Environment(
257 loader=jinja2.FileSystemLoader(templates_dir),
260 bytecode_cache=jinja2.FileSystemBytecodeCache(cache_dir),
261 keep_trailing_newline=
True,
264 jinja_env.filters.update({
265 'blink_capitalize': DartUtilities.capitalize,
266 'conditional': conditional_if_endif,
267 'runtime_enabled': runtime_enabled_if,
275 if not conditional_string:
277 return (
'#if %s\n' % conditional_string + code +
278 '#endif // %s\n' % conditional_string)
283 if not runtime_enabled_function_name:
286 indent = re.match(
' *', code).group(0)
287 return (
'%sif (%s())\n' % (indent, runtime_enabled_function_name) +
298 dummy_filename = argv[2]
299 except IndexError
as err:
300 print(
'Usage: %s OUTPUT_DIR DUMMY_FILENAME' % argv[0])
305 template_filenames = [
306 filename
for filename
in os.listdir(templates_dir)
308 if filename.endswith((
'.cpp',
'.h',
'.template'))
310 for template_filename
in template_filenames:
311 jinja_env.get_template(template_filename)
316 with open(dummy_filename,
'w')
as dummy_file:
320if __name__ ==
'__main__':
321 sys.exit(
main(sys.argv))
__init__(self, interfaces_info, cache_dir)
generate_code(self, definitions, interface_name, idl_pickle_filename, only_if_changed)
generate_globals(self, output_directory)
static void append(char **dst, size_t *count, const char *src, size_t n)
initialize_jinja_env(cache_dir)
runtime_enabled_if(code, runtime_enabled_function_name)
conditional_if_endif(code, conditional_string)