1 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
5 """Base class for generating wrapper functions for PPAPI methods.
8 from datetime
import datetime
12 from idl_c_proto
import CGen
13 from idl_generator
import Generator
14 from idl_log
import ErrOut
, InfoOut
, WarnOut
15 from idl_option
import GetOption
16 from idl_outfile
import IDLOutFile
21 def ChoosePPFunc(iface
, ppb_func
, ppp_func
):
22 name
= iface
.node
.GetName()
23 if name
.startswith("PPP"):
25 elif name
.startswith("PPB"):
28 raise Exception('Unknown PPKind for ' + name
)
31 class Interface(object):
32 """Tracks information about a particular interface version.
34 - struct_name: the struct type used by the ppapi headers to hold the
35 method pointers (the vtable).
36 - needs_wrapping: True if a method in the interface needs wrapping.
37 - header_file: the name of the header file that defined this interface.
39 def __init__(self
, interface_node
, release
, version
,
40 struct_name
, needs_wrapping
, header_file
):
41 self
.node
= interface_node
42 self
.release
= release
43 self
.version
= version
44 self
.struct_name
= struct_name
45 # We may want finer grained filtering (method level), but it is not
46 # yet clear how to actually do that.
47 self
.needs_wrapping
= needs_wrapping
48 self
.header_file
= header_file
51 class WrapperGen(Generator
):
52 """WrapperGen - An abstract class that generates wrappers for PPAPI methods.
54 This generates a wrapper PPB and PPP GetInterface, which directs users
55 to wrapper PPAPI methods. Wrapper PPAPI methods may perform arbitrary
56 work before invoking the real PPAPI method (supplied by the original
57 GetInterface functions).
59 Subclasses must implement GenerateWrapperForPPBMethod (and PPP).
62 def __init__(self
, wrapper_prefix
, s1
, s2
, s3
):
63 Generator
.__init
__(self
, s1
, s2
, s3
)
64 self
.wrapper_prefix
= wrapper_prefix
65 self
._skip
_opt
= False
66 self
.output_file
= None
69 def SetOutputFile(self
, fname
):
70 self
.output_file
= fname
73 def GenerateRelease(self
, ast
, release
, options
):
74 return self
.GenerateRange(ast
, [release
], options
)
78 def GetHeaderName(name
):
79 """Get the corresponding ppapi .h file from each IDL filename.
81 name
= os
.path
.splitext(name
)[0] + '.h'
82 name
= name
.replace(os
.sep
, '/')
83 return 'ppapi/c/' + name
86 def WriteCopyright(self
, out
):
88 c
= """/* Copyright (c) %s The Chromium Authors. All rights reserved.
89 * Use of this source code is governed by a BSD-style license that can be
90 * found in the LICENSE file.
93 /* NOTE: this is auto-generated from IDL */
97 def GetWrapperMetadataName(self
):
98 return '__%sWrapperInfo' % self
.wrapper_prefix
101 def GenerateHelperFunctions(self
, out
):
102 """Generate helper functions to avoid dependencies on libc.
104 out
.Write("""/* Use local strcmp to avoid dependency on libc. */
105 static int mystrcmp(const char* s1, const char *s2) {
109 if (*s1 != *s2) break;
113 return (int)(*s1) - (int)(*s2);
118 def GenerateFixedFunctions(self
, out
):
119 """Write out the set of constant functions (those that do not depend on
120 the current Pepper IDL).
124 static PPB_GetInterface __real_PPBGetInterface;
125 static PPP_GetInterface_Type __real_PPPGetInterface;
127 void __set_real_%(wrapper_prefix)s_PPBGetInterface(PPB_GetInterface real) {
128 __real_PPBGetInterface = real;
131 void __set_real_%(wrapper_prefix)s_PPPGetInterface(PPP_GetInterface_Type real) {
132 __real_PPPGetInterface = real;
135 /* Map interface string -> wrapper metadata */
136 static struct %(wrapper_struct)s *%(wrapper_prefix)sPPBShimIface(
138 struct %(wrapper_struct)s **next = s_ppb_wrappers;
139 while (*next != NULL) {
140 if (mystrcmp(name, (*next)->iface_macro) == 0) return *next;
146 /* Map interface string -> wrapper metadata */
147 static struct %(wrapper_struct)s *%(wrapper_prefix)sPPPShimIface(
149 struct %(wrapper_struct)s **next = s_ppp_wrappers;
150 while (*next != NULL) {
151 if (mystrcmp(name, (*next)->iface_macro) == 0) return *next;
157 const void *__%(wrapper_prefix)s_PPBGetInterface(const char *name) {
158 struct %(wrapper_struct)s *wrapper = %(wrapper_prefix)sPPBShimIface(name);
159 if (wrapper == NULL) {
160 /* We did not generate a wrapper for this, so return the real interface. */
161 return (*__real_PPBGetInterface)(name);
164 /* Initialize the real_iface if it hasn't been. The wrapper depends on it. */
165 if (wrapper->real_iface == NULL) {
166 const void *iface = (*__real_PPBGetInterface)(name);
167 if (NULL == iface) return NULL;
168 wrapper->real_iface = iface;
171 return wrapper->wrapped_iface;
174 const void *__%(wrapper_prefix)s_PPPGetInterface(const char *name) {
175 struct %(wrapper_struct)s *wrapper = %(wrapper_prefix)sPPPShimIface(name);
176 if (wrapper == NULL) {
177 /* We did not generate a wrapper for this, so return the real interface. */
178 return (*__real_PPPGetInterface)(name);
181 /* Initialize the real_iface if it hasn't been. The wrapper depends on it. */
182 if (wrapper->real_iface == NULL) {
183 const void *iface = (*__real_PPPGetInterface)(name);
184 if (NULL == iface) return NULL;
185 wrapper->real_iface = iface;
188 return wrapper->wrapped_iface;
190 """ % { 'wrapper_struct' : self
.GetWrapperMetadataName(),
191 'wrapper_prefix' : self
.wrapper_prefix
,
195 ############################################################
197 def OwnHeaderFile(self
):
198 """Return the header file that specifies the API of this wrapper.
199 We do not generate the header files. """
200 raise Exception('Child class must implement this')
203 ############################################################
205 def DetermineInterfaces(self
, ast
, releases
):
206 """Get a list of interfaces along with whatever metadata we need.
209 for filenode
in ast
.GetListOf('File'):
210 # If this file has errors, skip it
211 if filenode
in self
.skip_list
:
212 if GetOption('verbose'):
213 InfoOut
.Log('WrapperGen: Skipping %s due to errors\n' %
217 file_name
= self
.GetHeaderName(filenode
.GetName())
218 ifaces
= filenode
.GetListOf('Interface')
220 releases_for_iface
= iface
.GetUniqueReleases(releases
)
221 for release
in releases_for_iface
:
222 version
= iface
.GetVersion(release
)
223 struct_name
= self
.cgen
.GetStructName(iface
, release
,
224 include_version
=True)
225 needs_wrap
= self
.InterfaceVersionNeedsWrapping(iface
, version
)
227 if GetOption('verbose'):
228 InfoOut
.Log('Interface %s ver %s does not need wrapping' %
229 (struct_name
, version
))
230 iface_releases
.append(
231 Interface(iface
, release
, version
,
232 struct_name
, needs_wrap
, file_name
))
233 return iface_releases
236 def GenerateIncludes(self
, iface_releases
, out
):
237 """Generate the list of #include that define the original interfaces.
239 self
.WriteCopyright(out
)
240 # First include own header.
241 out
.Write('#include "%s"\n\n' % self
.OwnHeaderFile())
243 # Get typedefs for PPB_GetInterface.
244 out
.Write('#include "%s"\n' % self
.GetHeaderName('ppb.h'))
246 # Only include headers where *some* interface needs wrapping.
248 for iface
in iface_releases
:
249 if iface
.needs_wrapping
:
250 header_files
.add(iface
.header_file
)
251 for header
in sorted(header_files
):
252 out
.Write('#include "%s"\n' % header
)
256 def WrapperMethodPrefix(self
, iface
, release
):
257 return '%s_%s_%s_' % (self
.wrapper_prefix
, release
, iface
.GetName())
260 def GenerateWrapperForPPBMethod(self
, iface
, member
):
262 func_prefix
= self
.WrapperMethodPrefix(iface
.node
, iface
.release
)
263 sig
= self
.cgen
.GetSignature(member
, iface
.release
, 'store',
265 result
.append('static %s {\n' % sig
)
266 result
.append(' while(1) { /* Not implemented */ } \n')
271 def GenerateWrapperForPPPMethod(self
, iface
, member
):
273 func_prefix
= self
.WrapperMethodPrefix(iface
.node
, iface
.release
)
274 sig
= self
.cgen
.GetSignature(member
, iface
.release
, 'store',
276 result
.append('static %s {\n' % sig
)
277 result
.append(' while(1) { /* Not implemented */ } \n')
282 def GenerateWrapperForMethods(self
, iface_releases
, comments
=True):
283 """Return a string representing the code for each wrapper method
284 (using a string rather than writing to the file directly for testing.)
287 for iface
in iface_releases
:
288 if not iface
.needs_wrapping
:
290 result
.append('/* Not generating wrapper methods for %s */\n\n' %
294 result
.append('/* Begin wrapper methods for %s */\n\n' %
296 generator
= PPKind
.ChoosePPFunc(iface
,
297 self
.GenerateWrapperForPPBMethod
,
298 self
.GenerateWrapperForPPPMethod
)
299 for member
in iface
.node
.GetListOf('Member'):
300 # Skip the method if it's not actually in the release.
301 if not member
.InReleases([iface
.release
]):
303 result
.extend(generator(iface
, member
))
305 result
.append('/* End wrapper methods for %s */\n\n' %
307 return ''.join(result
)
310 def GenerateWrapperInterfaces(self
, iface_releases
, out
):
311 for iface
in iface_releases
:
312 if not iface
.needs_wrapping
:
313 out
.Write('/* Not generating wrapper interface for %s */\n\n' %
317 out
.Write('static const struct %s %s_Wrappers_%s = {\n' % (
318 iface
.struct_name
, self
.wrapper_prefix
, iface
.struct_name
))
320 for member
in iface
.node
.GetListOf('Member'):
321 # Skip the method if it's not actually in the release.
322 if not member
.InReleases([iface
.release
]):
324 prefix
= self
.WrapperMethodPrefix(iface
.node
, iface
.release
)
325 # Casts are necessary for the PPB_* wrappers because we must
326 # cast away "__attribute__((pnaclcall))". The PPP_* wrappers
327 # must match the default calling conventions and so don't have
328 # the attribute, so omitting casts for them provides a little
329 # extra type checking.
330 if iface
.node
.GetName().startswith('PPB_'):
331 cast
= '(%s)' % self
.cgen
.GetSignature(
332 member
, iface
.release
, 'return',
338 methods
.append(' .%s = %s&%s%s' % (member
.GetName(),
342 out
.Write(' ' + ',\n '.join(methods
) + '\n')
346 def GetWrapperInfoName(self
, iface
):
347 return '%s_WrapperInfo_%s' % (self
.wrapper_prefix
, iface
.struct_name
)
350 def GenerateWrapperInfoAndCollection(self
, iface_releases
, out
):
351 for iface
in iface_releases
:
352 iface_macro
= self
.cgen
.GetInterfaceMacro(iface
.node
, iface
.version
)
353 if iface
.needs_wrapping
:
354 wrap_iface
= '(const void *) &%s_Wrappers_%s' % (self
.wrapper_prefix
,
356 out
.Write("""static struct %s %s = {
360 };\n\n""" % (self
.GetWrapperMetadataName(),
361 self
.GetWrapperInfoName(iface
),
365 # Now generate NULL terminated arrays of the above wrapper infos.
366 ppb_wrapper_infos
= []
367 ppp_wrapper_infos
= []
368 for iface
in iface_releases
:
369 if iface
.needs_wrapping
:
370 appender
= PPKind
.ChoosePPFunc(iface
,
371 ppb_wrapper_infos
.append
,
372 ppp_wrapper_infos
.append
)
373 appender(' &%s' % self
.GetWrapperInfoName(iface
))
374 ppb_wrapper_infos
.append(' NULL')
375 ppp_wrapper_infos
.append(' NULL')
377 'static struct %s *s_ppb_wrappers[] = {\n%s\n};\n\n' %
378 (self
.GetWrapperMetadataName(), ',\n'.join(ppb_wrapper_infos
)))
380 'static struct %s *s_ppp_wrappers[] = {\n%s\n};\n\n' %
381 (self
.GetWrapperMetadataName(), ',\n'.join(ppp_wrapper_infos
)))
384 def DeclareWrapperInfos(self
, iface_releases
, out
):
385 """The wrapper methods usually need access to the real_iface, so we must
386 declare these wrapper infos ahead of time (there is a circular dependency).
388 out
.Write('/* BEGIN Declarations for all Wrapper Infos */\n\n')
389 for iface
in iface_releases
:
390 if iface
.needs_wrapping
:
391 out
.Write('static struct %s %s;\n' %
392 (self
.GetWrapperMetadataName(),
393 self
.GetWrapperInfoName(iface
)))
394 out
.Write('/* END Declarations for all Wrapper Infos. */\n\n')
397 def GenerateRange(self
, ast
, releases
, options
):
398 """Generate shim code for a range of releases.
401 # Remember to set the output filename before running this.
402 out_filename
= self
.output_file
403 if out_filename
is None:
404 ErrOut
.Log('Did not set filename for writing out wrapper\n')
407 InfoOut
.Log("Generating %s for %s" % (out_filename
, self
.wrapper_prefix
))
409 out
= IDLOutFile(out_filename
)
411 # Get a list of all the interfaces along with metadata.
412 iface_releases
= self
.DetermineInterfaces(ast
, releases
)
414 # Generate the includes.
415 self
.GenerateIncludes(iface_releases
, out
)
417 # Write out static helper functions (mystrcmp).
418 self
.GenerateHelperFunctions(out
)
420 # Declare list of WrapperInfo before actual wrapper methods, since
421 # they reference each other.
422 self
.DeclareWrapperInfos(iface_releases
, out
)
424 # Generate wrapper functions for each wrapped method in the interfaces.
425 result
= self
.GenerateWrapperForMethods(iface_releases
)
428 # Collect all the wrapper functions into interface structs.
429 self
.GenerateWrapperInterfaces(iface_releases
, out
)
431 # Generate a table of the wrapped interface structs that can be looked up.
432 self
.GenerateWrapperInfoAndCollection(iface_releases
, out
)
434 # Write out the IDL-invariant functions.
435 self
.GenerateFixedFunctions(out
)