OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/python |
| 2 # |
| 3 # Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 4 # Use of this source code is governed by a BSD-style license that can be |
| 5 # found in the LICENSE file. |
| 6 |
| 7 """Base class for generating wrapper functions for PPAPI methods. |
| 8 """ |
| 9 |
| 10 from datetime import datetime |
| 11 import os |
| 12 import sys |
| 13 |
| 14 from idl_ast import IDLAst |
| 15 from idl_c_proto import CGen |
| 16 from idl_generator import Generator |
| 17 from idl_log import ErrOut, InfoOut, WarnOut |
| 18 from idl_option import Option |
| 19 from idl_outfile import IDLOutFile |
| 20 |
| 21 |
| 22 class PPKind(object): |
| 23 @staticmethod |
| 24 def ChoosePPFunc(iface, ppb_func, ppp_func): |
| 25 name = iface.node.GetName() |
| 26 if name.startswith("PPP"): |
| 27 return ppp_func |
| 28 elif name.startswith("PPB"): |
| 29 return ppb_func |
| 30 else: |
| 31 raise Exception('Unknown PPKind for ' + name) |
| 32 |
| 33 |
| 34 class Interface(object): |
| 35 """Tracks information about a particular interface version. |
| 36 |
| 37 - struct_name: the struct type used by the ppapi headers to hold the |
| 38 method pointers (the vtable). |
| 39 - needs_wrapping: True if a method in the interface needs wrapping. |
| 40 - header_file: the name of the header file that defined this interface. |
| 41 """ |
| 42 def __init__(self, interface_node, release, version, |
| 43 struct_name, needs_wrapping, header_file): |
| 44 self.node = interface_node |
| 45 self.release = release |
| 46 self.version = version |
| 47 self.struct_name = struct_name |
| 48 # We may want finer grained filtering (method level), but it is not |
| 49 # yet clear how to actually do that. |
| 50 self.needs_wrapping = needs_wrapping |
| 51 self.header_file = header_file |
| 52 |
| 53 |
| 54 class WrapperGen(Generator): |
| 55 """WrapperGen - An abstract class that generates wrappers for PPAPI methods. |
| 56 |
| 57 This generates a wrapper PPB and PPP GetInterface, which directs users |
| 58 to wrapper PPAPI methods. Wrapper PPAPI methods may perform arbitrary |
| 59 work before invoking the real PPAPI method (supplied by the original |
| 60 GetInterface functions). |
| 61 |
| 62 Subclasses must implement GenerateWrapperForPPBMethod (and PPP). |
| 63 Optionally, subclasses can implement InterfaceNeedsWrapper to |
| 64 filter out interfaces that do not actually need wrappers (those |
| 65 interfaces can jump directly to the original interface functions). |
| 66 """ |
| 67 |
| 68 def __init__(self, wrapper_prefix, s1, s2, s3): |
| 69 Generator.__init__(self, s1, s2, s3) |
| 70 self.wrapper_prefix = wrapper_prefix |
| 71 self._skip_opt = False |
| 72 self.output_file = None |
| 73 self.cgen = CGen() |
| 74 |
| 75 def SetOutputFile(self, fname): |
| 76 self.output_file = fname |
| 77 |
| 78 |
| 79 def GenerateRelease(self, ast, release, options): |
| 80 return self.GenerateRange(ast, [release], options) |
| 81 |
| 82 |
| 83 @staticmethod |
| 84 def GetHeaderName(name): |
| 85 """Get the corresponding ppapi .h file from each IDL filename. |
| 86 """ |
| 87 name = os.path.splitext(name)[0] + '.h' |
| 88 return 'ppapi/c/' + name |
| 89 |
| 90 |
| 91 def WriteCopyrightGeneratedTime(self, out): |
| 92 now = datetime.now() |
| 93 c = """/* Copyright (c) %s The Chromium Authors. All rights reserved. |
| 94 * Use of this source code is governed by a BSD-style license that can be |
| 95 * found in the LICENSE file. |
| 96 */ |
| 97 |
| 98 /* Last generated from IDL: %s. */ |
| 99 """ % (now.year, datetime.ctime(now)) |
| 100 out.Write(c) |
| 101 |
| 102 def GetWrapperMetadataName(self): |
| 103 return '__%sWrapperInfo' % self.wrapper_prefix |
| 104 |
| 105 |
| 106 def GetHeaderGuard(self, header_filename): |
| 107 g = header_filename.upper().replace(os.path.sep, '_').replace('.','_') + '_' |
| 108 return g |
| 109 |
| 110 def GenerateHeaderFile(self, header_filename, out): |
| 111 """Writes out an interface header file for the exported symbols. |
| 112 """ |
| 113 self.WriteCopyrightGeneratedTime(out) |
| 114 include_guard = self.GetHeaderGuard(header_filename) |
| 115 out.Write(""" |
| 116 #ifndef %(include_guard)s |
| 117 #define %(include_guard)s |
| 118 |
| 119 #include "ppapi/c/ppb.h" |
| 120 |
| 121 /* There is not a typedef for PPP_GetInterface_type, but it is currently |
| 122 * the same as PPB_GetInterface. */ |
| 123 typedef PPB_GetInterface PPP_GetInterface_type; |
| 124 |
| 125 void __set_real_%(wrapper_prefix)s_PPBGetInterface(PPB_GetInterface real); |
| 126 void __set_real_%(wrapper_prefix)s_PPPGetInterface(PPP_GetInterface_type real); |
| 127 |
| 128 const void *__%(wrapper_prefix)s_PPBGetInterface(const char *name); |
| 129 const void *__%(wrapper_prefix)s_PPPGetInterface(const char *name); |
| 130 |
| 131 struct %(wrapper_struct)s { |
| 132 const char* iface_macro; |
| 133 const void* wrapped_iface; /* If NULL then it was not wrapped! */ |
| 134 const void* real_iface; |
| 135 }; |
| 136 |
| 137 #endif /* %(include_guard)s */ |
| 138 """ % { |
| 139 'include_guard' : include_guard, |
| 140 'timestamp' : datetime.ctime(datetime.now()), |
| 141 'wrapper_prefix' : self.wrapper_prefix, |
| 142 'wrapper_struct' : self.GetWrapperMetadataName(), |
| 143 }) |
| 144 |
| 145 |
| 146 def GenerateHelperFunctions(self, out): |
| 147 """Generate helper functions to avoid dependencies on libc. |
| 148 """ |
| 149 out.Write("""/* Use local strcmp to avoid dependency on libc. */ |
| 150 static int mystrcmp(const char* s1, const char *s2) { |
| 151 while((*s1 && *s2) && (*s1++ == *s2++)); |
| 152 return *(--s1) - *(--s2); |
| 153 }\n |
| 154 """) |
| 155 |
| 156 |
| 157 def GenerateFixedFunctions(self, out): |
| 158 """Write out the set of constant functions (those that do not depend on |
| 159 the current Pepper IDL). |
| 160 """ |
| 161 out.Write(""" |
| 162 |
| 163 static PPB_GetInterface __real_PPBGetInterface; |
| 164 static PPP_GetInterface_type __real_PPPGetInterface; |
| 165 |
| 166 void __set_real_%(wrapper_prefix)s_PPBGetInterface(PPB_GetInterface real) { |
| 167 __real_PPBGetInterface = real; |
| 168 } |
| 169 |
| 170 void __set_real_%(wrapper_prefix)s_PPPGetInterface(PPP_GetInterface_type real) { |
| 171 __real_PPPGetInterface = real; |
| 172 } |
| 173 |
| 174 /* Map interface string -> wrapper metadata */ |
| 175 static struct %(wrapper_struct)s *%(wrapper_prefix)sPPBShimIface( |
| 176 const char *name) { |
| 177 struct %(wrapper_struct)s **next = s_ppb_wrappers; |
| 178 while (*next != NULL) { |
| 179 if (mystrcmp(name, (*next)->iface_macro) == 0) return *next; |
| 180 ++next; |
| 181 } |
| 182 return NULL; |
| 183 } |
| 184 |
| 185 /* Map interface string -> wrapper metadata */ |
| 186 static struct %(wrapper_struct)s *%(wrapper_prefix)sPPPShimIface( |
| 187 const char *name) { |
| 188 struct %(wrapper_struct)s **next = s_ppp_wrappers; |
| 189 while (*next != NULL) { |
| 190 if (mystrcmp(name, (*next)->iface_macro) == 0) return *next; |
| 191 ++next; |
| 192 } |
| 193 return NULL; |
| 194 } |
| 195 |
| 196 const void *__%(wrapper_prefix)s_PPBGetInterface(const char *name) { |
| 197 struct %(wrapper_struct)s *wrapper = %(wrapper_prefix)sPPBShimIface(name); |
| 198 if (wrapper == NULL) { |
| 199 /* We don't have an IDL for this, for some reason. Take our chances. */ |
| 200 return (*__real_PPBGetInterface)(name); |
| 201 } |
| 202 |
| 203 /* Initialize the real_iface if it hasn't been. The wrapper depends on it. */ |
| 204 if (wrapper->real_iface == NULL) { |
| 205 const void *iface = (*__real_PPBGetInterface)(name); |
| 206 if (NULL == iface) return NULL; |
| 207 wrapper->real_iface = iface; |
| 208 } |
| 209 |
| 210 if (wrapper->wrapped_iface) { |
| 211 return wrapper->wrapped_iface; |
| 212 } else { |
| 213 return wrapper->real_iface; |
| 214 } |
| 215 } |
| 216 |
| 217 const void *__%(wrapper_prefix)s_PPPGetInterface(const char *name) { |
| 218 struct %(wrapper_struct)s *wrapper = %(wrapper_prefix)sPPPShimIface(name); |
| 219 if (wrapper == NULL) { |
| 220 /* We don't have an IDL for this, for some reason. Take our chances. */ |
| 221 return (*__real_PPPGetInterface)(name); |
| 222 } |
| 223 |
| 224 /* Initialize the real_iface if it hasn't been. The wrapper depends on it. */ |
| 225 if (wrapper->real_iface == NULL) { |
| 226 const void *iface = (*__real_PPPGetInterface)(name); |
| 227 if (NULL == iface) return NULL; |
| 228 wrapper->real_iface = iface; |
| 229 } |
| 230 |
| 231 if (wrapper->wrapped_iface) { |
| 232 return wrapper->wrapped_iface; |
| 233 } else { |
| 234 return wrapper->real_iface; |
| 235 } |
| 236 } |
| 237 """ % { 'wrapper_struct' : self.GetWrapperMetadataName(), |
| 238 'wrapper_prefix' : self.wrapper_prefix, |
| 239 } ) |
| 240 |
| 241 |
| 242 ############################################################ |
| 243 |
| 244 def InterfaceNeedsWrapper(self, iface, releases): |
| 245 """Return true if the interface has ANY methods that need wrapping. |
| 246 """ |
| 247 return True |
| 248 |
| 249 |
| 250 ############################################################ |
| 251 |
| 252 def DetermineInterfaces(self, ast, releases): |
| 253 """Get a list of interfaces along with whatever metadata we need. |
| 254 """ |
| 255 iface_releases = [] |
| 256 for filenode in ast.GetListOf('File'): |
| 257 # If this file has errors, skip it |
| 258 if filenode in self.skip_list: |
| 259 InfoOut.Log('WrapperGen: Skipping %s due to errors\n' % |
| 260 filenode.GetName()) |
| 261 continue |
| 262 |
| 263 file_name = self.GetHeaderName(filenode.GetName()) |
| 264 ifaces = filenode.GetListOf('Interface') |
| 265 for iface in ifaces: |
| 266 releases_for_iface = iface.GetUniqueReleases(releases) |
| 267 for release in releases_for_iface: |
| 268 version = iface.GetVersion(release) |
| 269 not_latest = release != releases_for_iface[-1] |
| 270 struct_name = self.cgen.GetStructName(iface, release, |
| 271 include_version=not_latest) |
| 272 needs_wrap = self.InterfaceVersionNeedsWrapping(iface, version) |
| 273 if not needs_wrap: |
| 274 InfoOut.Log('Interface %s ver %s does not need wrapping' % |
| 275 (struct_name, version)) |
| 276 iface_releases.append( |
| 277 Interface(iface, release, version, |
| 278 struct_name, needs_wrap, file_name)) |
| 279 return iface_releases |
| 280 |
| 281 |
| 282 def GenerateIncludes(self, iface_releases, out_header_filename, out): |
| 283 """Generate the list of #include that define the original interfaces. |
| 284 """ |
| 285 self.WriteCopyrightGeneratedTime(out) |
| 286 # First include own header. |
| 287 out.Write('#include "%s"\n\n' % out_header_filename) |
| 288 |
| 289 # Get typedefs for PPB_GetInterface. |
| 290 out.Write('#include "%s"\n' % self.GetHeaderName('ppb.h')) |
| 291 |
| 292 # Get a conservative list of all #includes that are needed, |
| 293 # whether it requires wrapping or not. We currently depend on the macro |
| 294 # string for comparison, even when it is not wrapped, to decide when |
| 295 # to use the original/real interface. |
| 296 header_files = set() |
| 297 for iface in iface_releases: |
| 298 header_files.add(iface.header_file) |
| 299 for header in sorted(header_files): |
| 300 out.Write('#include "%s"\n' % header) |
| 301 out.Write('\n') |
| 302 |
| 303 |
| 304 def WrapperMethodPrefix(self, iface, release): |
| 305 return '%s_%s_%s_' % (self.wrapper_prefix, release, iface.GetName()) |
| 306 |
| 307 |
| 308 def GetReturnArgs(self, ret_type, args_spec): |
| 309 if ret_type != 'void': |
| 310 ret = 'return ' |
| 311 else: |
| 312 ret = '' |
| 313 if args_spec: |
| 314 args = [] |
| 315 for arg in args_spec: |
| 316 args.append(arg[1]) |
| 317 args = ', '.join(args) |
| 318 else: |
| 319 args = '' |
| 320 return (ret, args) |
| 321 |
| 322 |
| 323 def GenerateWrapperForPPBMethod(self, iface, member): |
| 324 result = [] |
| 325 func_prefix = self.WrapperMethodPrefix(iface.node, iface.release) |
| 326 sig = self.cgen.GetSignature(member, iface.release, 'store', |
| 327 func_prefix, False) |
| 328 result.append('static %s {\n' % sig) |
| 329 result.append(' while(1) { /* Not implemented */ } \n') |
| 330 result.append('}\n') |
| 331 return result |
| 332 |
| 333 |
| 334 def GenerateWrapperForPPPMethod(self, iface, member): |
| 335 result = [] |
| 336 func_prefix = self.WrapperMethodPrefix(iface.node, iface.release) |
| 337 sig = self.cgen.GetSignature(member, iface.release, 'store', |
| 338 func_prefix, False) |
| 339 result.append('static %s {\n' % sig) |
| 340 result.append(' while(1) { /* Not implemented */ } \n') |
| 341 result.append('}\n') |
| 342 return result |
| 343 |
| 344 |
| 345 def GenerateWrapperForMethods(self, iface_releases, comments=True): |
| 346 """Return a string representing the code for each wrapper method |
| 347 (using a string rather than writing to the file directly for testing.) |
| 348 """ |
| 349 result = [] |
| 350 for iface in iface_releases: |
| 351 if not iface.needs_wrapping: |
| 352 if comments: |
| 353 result.append('/* Not generating wrapper methods for %s */\n\n' % |
| 354 iface.struct_name) |
| 355 continue |
| 356 if comments: |
| 357 result.append('/* Begin wrapper methods for %s */\n\n' % |
| 358 iface.struct_name) |
| 359 generator = PPKind.ChoosePPFunc(iface, |
| 360 self.GenerateWrapperForPPBMethod, |
| 361 self.GenerateWrapperForPPPMethod) |
| 362 for member in iface.node.GetListOf('Member'): |
| 363 # Skip the method if it's not actually in the release. |
| 364 if not member.InReleases([iface.release]): |
| 365 continue |
| 366 result.extend(generator(iface, member)) |
| 367 if comments: |
| 368 result.append('/* End wrapper methods for %s */\n\n' % |
| 369 iface.struct_name) |
| 370 return ''.join(result) |
| 371 |
| 372 |
| 373 def GenerateWrapperInterfaces(self, iface_releases, out): |
| 374 for iface in iface_releases: |
| 375 if not iface.needs_wrapping: |
| 376 out.Write('/* Not generating wrapper interface for %s */\n\n' % |
| 377 iface.struct_name) |
| 378 continue |
| 379 |
| 380 out.Write('struct %s %s_Wrappers_%s = {\n' % (iface.struct_name, |
| 381 self.wrapper_prefix, |
| 382 iface.struct_name)) |
| 383 methods = [] |
| 384 for member in iface.node.GetListOf('Member'): |
| 385 # Skip the method if it's not actually in the release. |
| 386 if not member.InReleases([iface.release]): |
| 387 continue |
| 388 prefix = self.WrapperMethodPrefix(iface.node, iface.release) |
| 389 cast = self.cgen.GetSignature(member, iface.release, 'return', |
| 390 prefix='', |
| 391 func_as_ptr=True, |
| 392 ptr_prefix='', |
| 393 include_name=False) |
| 394 methods.append(' .%s = (%s)&%s%s' % (member.GetName(), |
| 395 cast, |
| 396 prefix, |
| 397 member.GetName())) |
| 398 out.Write(' ' + ',\n '.join(methods) + '\n') |
| 399 out.Write('};\n\n') |
| 400 |
| 401 |
| 402 def GetWrapperInfoName(self, iface): |
| 403 return '%s_WrapperInfo_%s' % (self.wrapper_prefix, iface.struct_name) |
| 404 |
| 405 |
| 406 def GenerateWrapperInfoAndCollection(self, iface_releases, out): |
| 407 for iface in iface_releases: |
| 408 iface_macro = self.cgen.GetInterfaceMacro(iface.node, iface.version) |
| 409 if iface.needs_wrapping: |
| 410 wrap_iface = '(void *) &%s_Wrappers_%s' % (self.wrapper_prefix, |
| 411 iface.struct_name) |
| 412 else: |
| 413 wrap_iface = 'NULL /* Still need slot for real_iface */' |
| 414 out.Write("""static struct %s %s = { |
| 415 .iface_macro = %s, |
| 416 .wrapped_iface = %s, |
| 417 .real_iface = NULL |
| 418 };\n\n""" % (self.GetWrapperMetadataName(), |
| 419 self.GetWrapperInfoName(iface), |
| 420 iface_macro, |
| 421 wrap_iface)) |
| 422 |
| 423 # Now generate NULL terminated arrays of the above wrapper infos. |
| 424 ppb_wrapper_infos = [] |
| 425 ppp_wrapper_infos = [] |
| 426 for iface in iface_releases: |
| 427 appender = PPKind.ChoosePPFunc(iface, |
| 428 ppb_wrapper_infos.append, |
| 429 ppp_wrapper_infos.append) |
| 430 appender(' &%s' % self.GetWrapperInfoName(iface)) |
| 431 ppb_wrapper_infos.append(' NULL') |
| 432 ppp_wrapper_infos.append(' NULL') |
| 433 out.Write( |
| 434 'static struct %s *s_ppb_wrappers[] = {\n%s\n};\n\n' % |
| 435 (self.GetWrapperMetadataName(), ',\n'.join(ppb_wrapper_infos))) |
| 436 out.Write( |
| 437 'static struct %s *s_ppp_wrappers[] = {\n%s\n};\n\n' % |
| 438 (self.GetWrapperMetadataName(), ',\n'.join(ppp_wrapper_infos))) |
| 439 |
| 440 |
| 441 def DeclareWrapperInfos(self, iface_releases, out): |
| 442 """The wrapper methods usually need access to the real_iface, so we must |
| 443 declare these wrapper infos ahead of time (there is a circular dependency). |
| 444 """ |
| 445 out.Write('/* BEGIN Declarations for all Wrapper Infos */\n\n') |
| 446 for iface in iface_releases: |
| 447 out.Write('static struct %s %s;\n' % |
| 448 (self.GetWrapperMetadataName(), self.GetWrapperInfoName(iface))) |
| 449 out.Write('/* END Declarations for all Wrapper Infos. */\n\n') |
| 450 |
| 451 |
| 452 def GenerateRange(self, ast, releases, options): |
| 453 """Generate shim code for a range of releases. |
| 454 """ |
| 455 |
| 456 # Remember to set the output filename before running this. |
| 457 out_filename = self.output_file |
| 458 if out_filename is None: |
| 459 ErrOut.Log('Did not set filename for writing out wrapper\n') |
| 460 return 1 |
| 461 |
| 462 out_header_filename = os.path.splitext(out_filename)[0] + '.h' |
| 463 InfoOut.Log("Generating %s and %s for %s" % |
| 464 (out_filename, out_header_filename, self.wrapper_prefix)) |
| 465 |
| 466 out_header = IDLOutFile(out_header_filename) |
| 467 self.GenerateHeaderFile(out_header_filename, out_header) |
| 468 out_header.Close() |
| 469 |
| 470 out = IDLOutFile(out_filename) |
| 471 |
| 472 # Get a list of all the interfaces along with metadata. |
| 473 iface_releases = self.DetermineInterfaces(ast, releases) |
| 474 |
| 475 # Generate the includes. |
| 476 self.GenerateIncludes(iface_releases, out_header_filename, out) |
| 477 |
| 478 # Write out static helper functions (mystrcmp). |
| 479 self.GenerateHelperFunctions(out) |
| 480 |
| 481 # Declare list of WrapperInfo before actual wrapper methods, since |
| 482 # they reference each other. |
| 483 self.DeclareWrapperInfos(iface_releases, out) |
| 484 |
| 485 # Generate wrapper functions for each wrapped method in the interfaces. |
| 486 result = self.GenerateWrapperForMethods(iface_releases) |
| 487 out.Write(result) |
| 488 |
| 489 # Collect all the wrapper functions into interface structs. |
| 490 self.GenerateWrapperInterfaces(iface_releases, out) |
| 491 |
| 492 # Generate a table of the wrapped interface structs that can be looked up. |
| 493 self.GenerateWrapperInfoAndCollection(iface_releases, out) |
| 494 |
| 495 # Write out the IDL-invariant functions. |
| 496 self.GenerateFixedFunctions(out) |
| 497 out.Close() |
| 498 return 0 |
OLD | NEW |