1#!/usr/bin/env python3 2# Copyright 2017 The Dawn Authors 3# 4# Licensed under the Apache License, Version 2.0 (the "License"); 5# you may not use this file except in compliance with the License. 6# You may obtain a copy of the License at 7# 8# http://www.apache.org/licenses/LICENSE-2.0 9# 10# Unless required by applicable law or agreed to in writing, software 11# distributed under the License is distributed on an "AS IS" BASIS, 12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13# See the License for the specific language governing permissions and 14# limitations under the License. 15 16import json, os, sys 17from collections import namedtuple 18 19from generator_lib import Generator, run_generator, FileRender 20 21############################################################ 22# OBJECT MODEL 23############################################################ 24 25 26class Name: 27 def __init__(self, name, native=False): 28 self.native = native 29 self.name = name 30 if native: 31 self.chunks = [name] 32 else: 33 self.chunks = name.split(' ') 34 35 def get(self): 36 return self.name 37 38 def CamelChunk(self, chunk): 39 return chunk[0].upper() + chunk[1:] 40 41 def canonical_case(self): 42 return (' '.join(self.chunks)).lower() 43 44 def concatcase(self): 45 return ''.join(self.chunks) 46 47 def camelCase(self): 48 return self.chunks[0] + ''.join( 49 [self.CamelChunk(chunk) for chunk in self.chunks[1:]]) 50 51 def CamelCase(self): 52 return ''.join([self.CamelChunk(chunk) for chunk in self.chunks]) 53 54 def SNAKE_CASE(self): 55 return '_'.join([chunk.upper() for chunk in self.chunks]) 56 57 def snake_case(self): 58 return '_'.join(self.chunks) 59 60 def js_enum_case(self): 61 result = self.chunks[0].lower() 62 for chunk in self.chunks[1:]: 63 if not result[-1].isdigit(): 64 result += '-' 65 result += chunk.lower() 66 return result 67 68 69def concat_names(*names): 70 return ' '.join([name.canonical_case() for name in names]) 71 72 73class Type: 74 def __init__(self, name, json_data, native=False): 75 self.json_data = json_data 76 self.dict_name = name 77 self.name = Name(name, native=native) 78 self.category = json_data['category'] 79 self.javascript = self.json_data.get('javascript', True) 80 81 82EnumValue = namedtuple('EnumValue', ['name', 'value', 'valid', 'jsrepr']) 83 84 85class EnumType(Type): 86 def __init__(self, name, json_data): 87 Type.__init__(self, name, json_data) 88 89 self.values = [] 90 self.contiguousFromZero = True 91 lastValue = -1 92 for m in self.json_data['values']: 93 value = m['value'] 94 if value != lastValue + 1: 95 self.contiguousFromZero = False 96 lastValue = value 97 self.values.append( 98 EnumValue(Name(m['name']), value, m.get('valid', True), 99 m.get('jsrepr', None))) 100 101 # Assert that all values are unique in enums 102 all_values = set() 103 for value in self.values: 104 if value.value in all_values: 105 raise Exception("Duplicate value {} in enum {}".format( 106 value.value, name)) 107 all_values.add(value.value) 108 109 110BitmaskValue = namedtuple('BitmaskValue', ['name', 'value']) 111 112 113class BitmaskType(Type): 114 def __init__(self, name, json_data): 115 Type.__init__(self, name, json_data) 116 self.values = [ 117 BitmaskValue(Name(m['name']), m['value']) 118 for m in self.json_data['values'] 119 ] 120 self.full_mask = 0 121 for value in self.values: 122 self.full_mask = self.full_mask | value.value 123 124 125class CallbackType(Type): 126 def __init__(self, name, json_data): 127 Type.__init__(self, name, json_data) 128 self.arguments = [] 129 130 131class NativeType(Type): 132 def __init__(self, name, json_data): 133 Type.__init__(self, name, json_data, native=True) 134 135 136# Methods and structures are both "records", so record members correspond to 137# method arguments or structure members. 138class RecordMember: 139 def __init__(self, 140 name, 141 typ, 142 annotation, 143 optional=False, 144 is_return_value=False, 145 default_value=None, 146 skip_serialize=False): 147 self.name = name 148 self.type = typ 149 self.annotation = annotation 150 self.length = None 151 self.optional = optional 152 self.is_return_value = is_return_value 153 self.handle_type = None 154 self.default_value = default_value 155 self.skip_serialize = skip_serialize 156 157 def set_handle_type(self, handle_type): 158 assert self.type.dict_name == "ObjectHandle" 159 self.handle_type = handle_type 160 161 162Method = namedtuple('Method', ['name', 'return_type', 'arguments']) 163 164 165class ObjectType(Type): 166 def __init__(self, name, json_data): 167 Type.__init__(self, name, json_data) 168 self.methods = [] 169 self.built_type = None 170 171 172class Record: 173 def __init__(self, name): 174 self.name = Name(name) 175 self.members = [] 176 self.may_have_dawn_object = False 177 178 def update_metadata(self): 179 def may_have_dawn_object(member): 180 if isinstance(member.type, ObjectType): 181 return True 182 elif isinstance(member.type, StructureType): 183 return member.type.may_have_dawn_object 184 else: 185 return False 186 187 self.may_have_dawn_object = any( 188 may_have_dawn_object(member) for member in self.members) 189 190 # Set may_have_dawn_object to true if the type is chained or 191 # extensible. Chained structs may contain a Dawn object. 192 if isinstance(self, StructureType): 193 self.may_have_dawn_object = (self.may_have_dawn_object 194 or self.chained or self.extensible) 195 196 197class StructureType(Record, Type): 198 def __init__(self, name, json_data): 199 Record.__init__(self, name) 200 Type.__init__(self, name, json_data) 201 self.chained = json_data.get("chained", False) 202 self.extensible = json_data.get("extensible", False) 203 # Chained structs inherit from wgpu::ChainedStruct, which has 204 # nextInChain, so setting both extensible and chained would result in 205 # two nextInChain members. 206 assert not (self.extensible and self.chained) 207 208 209class Command(Record): 210 def __init__(self, name, members=None): 211 Record.__init__(self, name) 212 self.members = members or [] 213 self.derived_object = None 214 self.derived_method = None 215 216 217def linked_record_members(json_data, types): 218 members = [] 219 members_by_name = {} 220 for m in json_data: 221 member = RecordMember(Name(m['name']), 222 types[m['type']], 223 m.get('annotation', 'value'), 224 optional=m.get('optional', False), 225 is_return_value=m.get('is_return_value', False), 226 default_value=m.get('default', None), 227 skip_serialize=m.get('skip_serialize', False)) 228 handle_type = m.get('handle_type') 229 if handle_type: 230 member.set_handle_type(types[handle_type]) 231 members.append(member) 232 members_by_name[member.name.canonical_case()] = member 233 234 for (member, m) in zip(members, json_data): 235 if member.annotation != 'value': 236 if not 'length' in m: 237 if member.type.category != 'object': 238 member.length = "constant" 239 member.constant_length = 1 240 else: 241 assert False 242 elif m['length'] == 'strlen': 243 member.length = 'strlen' 244 else: 245 member.length = members_by_name[m['length']] 246 247 return members 248 249 250############################################################ 251# PARSE 252############################################################ 253 254 255def link_object(obj, types): 256 def make_method(json_data): 257 arguments = linked_record_members(json_data.get('args', []), types) 258 return Method(Name(json_data['name']), 259 types[json_data.get('returns', 'void')], arguments) 260 261 obj.methods = [make_method(m) for m in obj.json_data.get('methods', [])] 262 obj.methods.sort(key=lambda method: method.name.canonical_case()) 263 264 265def link_structure(struct, types): 266 struct.members = linked_record_members(struct.json_data['members'], types) 267 268 269def link_callback(callback, types): 270 callback.arguments = linked_record_members(callback.json_data['args'], 271 types) 272 273 274# Sort structures so that if struct A has struct B as a member, then B is 275# listed before A. 276# 277# This is a form of topological sort where we try to keep the order reasonably 278# similar to the original order (though the sort isn't technically stable). 279# 280# It works by computing for each struct type what is the depth of its DAG of 281# dependents, then resorting based on that depth using Python's stable sort. 282# This makes a toposort because if A depends on B then its depth will be bigger 283# than B's. It is also nice because all nodes with the same depth are kept in 284# the input order. 285def topo_sort_structure(structs): 286 for struct in structs: 287 struct.visited = False 288 struct.subdag_depth = 0 289 290 def compute_depth(struct): 291 if struct.visited: 292 return struct.subdag_depth 293 294 max_dependent_depth = 0 295 for member in struct.members: 296 if member.type.category == 'structure': 297 max_dependent_depth = max(max_dependent_depth, 298 compute_depth(member.type) + 1) 299 300 struct.subdag_depth = max_dependent_depth 301 struct.visited = True 302 return struct.subdag_depth 303 304 for struct in structs: 305 compute_depth(struct) 306 307 result = sorted(structs, key=lambda struct: struct.subdag_depth) 308 309 for struct in structs: 310 del struct.visited 311 del struct.subdag_depth 312 313 return result 314 315 316def parse_json(json): 317 category_to_parser = { 318 'bitmask': BitmaskType, 319 'enum': EnumType, 320 'native': NativeType, 321 'callback': CallbackType, 322 'object': ObjectType, 323 'structure': StructureType, 324 } 325 326 types = {} 327 328 by_category = {} 329 for name in category_to_parser.keys(): 330 by_category[name] = [] 331 332 for (name, json_data) in json.items(): 333 if name[0] == '_': 334 continue 335 category = json_data['category'] 336 parsed = category_to_parser[category](name, json_data) 337 by_category[category].append(parsed) 338 types[name] = parsed 339 340 for obj in by_category['object']: 341 link_object(obj, types) 342 343 for struct in by_category['structure']: 344 link_structure(struct, types) 345 346 for callback in by_category['callback']: 347 link_callback(callback, types) 348 349 for category in by_category.keys(): 350 by_category[category] = sorted( 351 by_category[category], key=lambda typ: typ.name.canonical_case()) 352 353 by_category['structure'] = topo_sort_structure(by_category['structure']) 354 355 for struct in by_category['structure']: 356 struct.update_metadata() 357 358 return {'types': types, 'by_category': by_category} 359 360 361############################################################ 362# WIRE STUFF 363############################################################ 364 365 366# Create wire commands from api methods 367def compute_wire_params(api_params, wire_json): 368 wire_params = api_params.copy() 369 types = wire_params['types'] 370 371 commands = [] 372 return_commands = [] 373 374 wire_json['special items']['client_handwritten_commands'] += wire_json[ 375 'special items']['client_side_commands'] 376 377 # Generate commands from object methods 378 for api_object in wire_params['by_category']['object']: 379 for method in api_object.methods: 380 command_name = concat_names(api_object.name, method.name) 381 command_suffix = Name(command_name).CamelCase() 382 383 # Only object return values or void are supported. 384 # Other methods must be handwritten. 385 is_object = method.return_type.category == 'object' 386 is_void = method.return_type.name.canonical_case() == 'void' 387 if not (is_object or is_void): 388 assert command_suffix in ( 389 wire_json['special items']['client_handwritten_commands']) 390 continue 391 392 if command_suffix in ( 393 wire_json['special items']['client_side_commands']): 394 continue 395 396 # Create object method commands by prepending "self" 397 members = [ 398 RecordMember(Name('self'), types[api_object.dict_name], 399 'value') 400 ] 401 members += method.arguments 402 403 # Client->Server commands that return an object return the 404 # result object handle 405 if method.return_type.category == 'object': 406 result = RecordMember(Name('result'), 407 types['ObjectHandle'], 408 'value', 409 is_return_value=True) 410 result.set_handle_type(method.return_type) 411 members.append(result) 412 413 command = Command(command_name, members) 414 command.derived_object = api_object 415 command.derived_method = method 416 commands.append(command) 417 418 for (name, json_data) in wire_json['commands'].items(): 419 commands.append(Command(name, linked_record_members(json_data, types))) 420 421 for (name, json_data) in wire_json['return commands'].items(): 422 return_commands.append( 423 Command(name, linked_record_members(json_data, types))) 424 425 wire_params['cmd_records'] = { 426 'command': commands, 427 'return command': return_commands 428 } 429 430 for commands in wire_params['cmd_records'].values(): 431 for command in commands: 432 command.update_metadata() 433 commands.sort(key=lambda c: c.name.canonical_case()) 434 435 wire_params.update(wire_json.get('special items', {})) 436 437 return wire_params 438 439 440############################################################# 441# Generator 442############################################################# 443 444 445def as_varName(*names): 446 return names[0].camelCase() + ''.join( 447 [name.CamelCase() for name in names[1:]]) 448 449 450def as_cType(name): 451 if name.native: 452 return name.concatcase() 453 else: 454 return 'WGPU' + name.CamelCase() 455 456 457def as_cTypeDawn(name): 458 if name.native: 459 return name.concatcase() 460 else: 461 return 'Dawn' + name.CamelCase() 462 463 464def as_cTypeEnumSpecialCase(typ): 465 if typ.category == 'bitmask': 466 return as_cType(typ.name) + 'Flags' 467 return as_cType(typ.name) 468 469 470def as_cppType(name): 471 if name.native: 472 return name.concatcase() 473 else: 474 return name.CamelCase() 475 476 477def as_jsEnumValue(value): 478 if value.jsrepr: return value.jsrepr 479 return "'" + value.name.js_enum_case() + "'" 480 481 482def convert_cType_to_cppType(typ, annotation, arg, indent=0): 483 if typ.category == 'native': 484 return arg 485 if annotation == 'value': 486 if typ.category == 'object': 487 return '{}::Acquire({})'.format(as_cppType(typ.name), arg) 488 elif typ.category == 'structure': 489 converted_members = [ 490 convert_cType_to_cppType( 491 member.type, member.annotation, 492 '{}.{}'.format(arg, as_varName(member.name)), indent + 1) 493 for member in typ.members 494 ] 495 496 converted_members = [(' ' * 4) + m for m in converted_members] 497 converted_members = ',\n'.join(converted_members) 498 499 return as_cppType(typ.name) + ' {\n' + converted_members + '\n}' 500 else: 501 return 'static_cast<{}>({})'.format(as_cppType(typ.name), arg) 502 else: 503 return 'reinterpret_cast<{} {}>({})'.format(as_cppType(typ.name), 504 annotation, arg) 505 506 507def decorate(name, typ, arg): 508 if arg.annotation == 'value': 509 return typ + ' ' + name 510 elif arg.annotation == '*': 511 return typ + ' * ' + name 512 elif arg.annotation == 'const*': 513 return typ + ' const * ' + name 514 elif arg.annotation == 'const*const*': 515 return 'const ' + typ + '* const * ' + name 516 else: 517 assert False 518 519 520def annotated(typ, arg): 521 name = as_varName(arg.name) 522 return decorate(name, typ, arg) 523 524 525def as_cEnum(type_name, value_name): 526 assert not type_name.native and not value_name.native 527 return 'WGPU' + type_name.CamelCase() + '_' + value_name.CamelCase() 528 529 530def as_cEnumDawn(type_name, value_name): 531 assert not type_name.native and not value_name.native 532 return ('DAWN' + '_' + type_name.SNAKE_CASE() + '_' + 533 value_name.SNAKE_CASE()) 534 535 536def as_cppEnum(value_name): 537 assert not value_name.native 538 if value_name.concatcase()[0].isdigit(): 539 return "e" + value_name.CamelCase() 540 return value_name.CamelCase() 541 542 543def as_cMethod(type_name, method_name): 544 assert not type_name.native and not method_name.native 545 return 'wgpu' + type_name.CamelCase() + method_name.CamelCase() 546 547 548def as_cMethodDawn(type_name, method_name): 549 assert not type_name.native and not method_name.native 550 return 'dawn' + type_name.CamelCase() + method_name.CamelCase() 551 552 553def as_MethodSuffix(type_name, method_name): 554 assert not type_name.native and not method_name.native 555 return type_name.CamelCase() + method_name.CamelCase() 556 557 558def as_cProc(type_name, method_name): 559 assert not type_name.native and not method_name.native 560 return 'WGPU' + 'Proc' + type_name.CamelCase() + method_name.CamelCase() 561 562 563def as_cProcDawn(type_name, method_name): 564 assert not type_name.native and not method_name.native 565 return 'Dawn' + 'Proc' + type_name.CamelCase() + method_name.CamelCase() 566 567 568def as_frontendType(typ): 569 if typ.category == 'object': 570 return typ.name.CamelCase() + 'Base*' 571 elif typ.category in ['bitmask', 'enum']: 572 return 'wgpu::' + typ.name.CamelCase() 573 elif typ.category == 'structure': 574 return as_cppType(typ.name) 575 else: 576 return as_cType(typ.name) 577 578 579def as_wireType(typ): 580 if typ.category == 'object': 581 return typ.name.CamelCase() + '*' 582 elif typ.category in ['bitmask', 'enum']: 583 return 'WGPU' + typ.name.CamelCase() 584 else: 585 return as_cppType(typ.name) 586 587 588def c_methods(types, typ): 589 return typ.methods + [ 590 Method(Name('reference'), types['void'], []), 591 Method(Name('release'), types['void'], []), 592 ] 593 594 595def get_c_methods_sorted_by_name(api_params): 596 unsorted = [(as_MethodSuffix(typ.name, method.name), typ, method) \ 597 for typ in api_params['by_category']['object'] \ 598 for method in c_methods(api_params['types'], typ) ] 599 return [(typ, method) for (_, typ, method) in sorted(unsorted)] 600 601 602def has_callback_arguments(method): 603 return any(arg.type.category == 'callback' for arg in method.arguments) 604 605 606class MultiGeneratorFromDawnJSON(Generator): 607 def get_description(self): 608 return 'Generates code for various target from Dawn.json.' 609 610 def add_commandline_arguments(self, parser): 611 allowed_targets = [ 612 'dawn_headers', 'dawncpp_headers', 'dawncpp', 'dawn_proc', 613 'mock_webgpu', 'dawn_wire', "dawn_native_utils" 614 ] 615 616 parser.add_argument('--dawn-json', 617 required=True, 618 type=str, 619 help='The DAWN JSON definition to use.') 620 parser.add_argument('--wire-json', 621 default=None, 622 type=str, 623 help='The DAWN WIRE JSON definition to use.') 624 parser.add_argument( 625 '--targets', 626 required=True, 627 type=str, 628 help= 629 'Comma-separated subset of targets to output. Available targets: ' 630 + ', '.join(allowed_targets)) 631 632 def get_file_renders(self, args): 633 with open(args.dawn_json) as f: 634 loaded_json = json.loads(f.read()) 635 api_params = parse_json(loaded_json) 636 637 targets = args.targets.split(',') 638 639 wire_json = None 640 if args.wire_json: 641 with open(args.wire_json) as f: 642 wire_json = json.loads(f.read()) 643 644 base_params = { 645 'Name': lambda name: Name(name), 646 'as_annotated_cType': \ 647 lambda arg: annotated(as_cTypeEnumSpecialCase(arg.type), arg), 648 'as_annotated_cppType': \ 649 lambda arg: annotated(as_cppType(arg.type.name), arg), 650 'as_cEnum': as_cEnum, 651 'as_cEnumDawn': as_cEnumDawn, 652 'as_cppEnum': as_cppEnum, 653 'as_cMethod': as_cMethod, 654 'as_cMethodDawn': as_cMethodDawn, 655 'as_MethodSuffix': as_MethodSuffix, 656 'as_cProc': as_cProc, 657 'as_cProcDawn': as_cProcDawn, 658 'as_cType': as_cType, 659 'as_cTypeDawn': as_cTypeDawn, 660 'as_cppType': as_cppType, 661 'as_jsEnumValue': as_jsEnumValue, 662 'convert_cType_to_cppType': convert_cType_to_cppType, 663 'as_varName': as_varName, 664 'decorate': decorate, 665 'c_methods': lambda typ: c_methods(api_params['types'], typ), 666 'c_methods_sorted_by_name': \ 667 get_c_methods_sorted_by_name(api_params), 668 } 669 670 renders = [] 671 672 if 'dawn_headers' in targets: 673 renders.append( 674 FileRender('webgpu.h', 'src/include/dawn/webgpu.h', 675 [base_params, api_params])) 676 renders.append( 677 FileRender('dawn_proc_table.h', 678 'src/include/dawn/dawn_proc_table.h', 679 [base_params, api_params])) 680 681 if 'dawncpp_headers' in targets: 682 renders.append( 683 FileRender('webgpu_cpp.h', 'src/include/dawn/webgpu_cpp.h', 684 [base_params, api_params])) 685 686 if 'dawn_proc' in targets: 687 renders.append( 688 FileRender('dawn_proc.c', 'src/dawn/dawn_proc.c', 689 [base_params, api_params])) 690 renders.append( 691 FileRender('dawn_thread_dispatch_proc.cpp', 692 'src/dawn/dawn_thread_dispatch_proc.cpp', 693 [base_params, api_params])) 694 695 if 'dawncpp' in targets: 696 renders.append( 697 FileRender('webgpu_cpp.cpp', 'src/dawn/webgpu_cpp.cpp', 698 [base_params, api_params])) 699 700 if 'emscripten_bits' in targets: 701 renders.append( 702 FileRender('webgpu_struct_info.json', 703 'src/dawn/webgpu_struct_info.json', 704 [base_params, api_params])) 705 renders.append( 706 FileRender('library_webgpu_enum_tables.js', 707 'src/dawn/library_webgpu_enum_tables.js', 708 [base_params, api_params])) 709 710 if 'mock_webgpu' in targets: 711 mock_params = [ 712 base_params, api_params, { 713 'has_callback_arguments': has_callback_arguments 714 } 715 ] 716 renders.append( 717 FileRender('mock_webgpu.h', 'src/dawn/mock_webgpu.h', 718 mock_params)) 719 renders.append( 720 FileRender('mock_webgpu.cpp', 'src/dawn/mock_webgpu.cpp', 721 mock_params)) 722 723 if 'dawn_native_utils' in targets: 724 frontend_params = [ 725 base_params, 726 api_params, 727 { 728 # TODO: as_frontendType and co. take a Type, not a Name :( 729 'as_frontendType': lambda typ: as_frontendType(typ), 730 'as_annotated_frontendType': \ 731 lambda arg: annotated(as_frontendType(arg.type), arg), 732 } 733 ] 734 735 renders.append( 736 FileRender('dawn_native/ValidationUtils.h', 737 'src/dawn_native/ValidationUtils_autogen.h', 738 frontend_params)) 739 renders.append( 740 FileRender('dawn_native/ValidationUtils.cpp', 741 'src/dawn_native/ValidationUtils_autogen.cpp', 742 frontend_params)) 743 renders.append( 744 FileRender('dawn_native/wgpu_structs.h', 745 'src/dawn_native/wgpu_structs_autogen.h', 746 frontend_params)) 747 renders.append( 748 FileRender('dawn_native/wgpu_structs.cpp', 749 'src/dawn_native/wgpu_structs_autogen.cpp', 750 frontend_params)) 751 renders.append( 752 FileRender('dawn_native/ProcTable.cpp', 753 'src/dawn_native/ProcTable.cpp', frontend_params)) 754 755 if 'dawn_wire' in targets: 756 additional_params = compute_wire_params(api_params, wire_json) 757 758 wire_params = [ 759 base_params, api_params, { 760 'as_wireType': as_wireType, 761 'as_annotated_wireType': \ 762 lambda arg: annotated(as_wireType(arg.type), arg), 763 }, additional_params 764 ] 765 renders.append( 766 FileRender('dawn_wire/ObjectType.h', 767 'src/dawn_wire/ObjectType_autogen.h', wire_params)) 768 renders.append( 769 FileRender('dawn_wire/WireCmd.h', 770 'src/dawn_wire/WireCmd_autogen.h', wire_params)) 771 renders.append( 772 FileRender('dawn_wire/WireCmd.cpp', 773 'src/dawn_wire/WireCmd_autogen.cpp', wire_params)) 774 renders.append( 775 FileRender('dawn_wire/client/ApiObjects.h', 776 'src/dawn_wire/client/ApiObjects_autogen.h', 777 wire_params)) 778 renders.append( 779 FileRender('dawn_wire/client/ApiProcs.cpp', 780 'src/dawn_wire/client/ApiProcs_autogen.cpp', 781 wire_params)) 782 renders.append( 783 FileRender('dawn_wire/client/ClientBase.h', 784 'src/dawn_wire/client/ClientBase_autogen.h', 785 wire_params)) 786 renders.append( 787 FileRender('dawn_wire/client/ClientHandlers.cpp', 788 'src/dawn_wire/client/ClientHandlers_autogen.cpp', 789 wire_params)) 790 renders.append( 791 FileRender( 792 'dawn_wire/client/ClientPrototypes.inc', 793 'src/dawn_wire/client/ClientPrototypes_autogen.inc', 794 wire_params)) 795 renders.append( 796 FileRender('dawn_wire/server/ServerBase.h', 797 'src/dawn_wire/server/ServerBase_autogen.h', 798 wire_params)) 799 renders.append( 800 FileRender('dawn_wire/server/ServerDoers.cpp', 801 'src/dawn_wire/server/ServerDoers_autogen.cpp', 802 wire_params)) 803 renders.append( 804 FileRender('dawn_wire/server/ServerHandlers.cpp', 805 'src/dawn_wire/server/ServerHandlers_autogen.cpp', 806 wire_params)) 807 renders.append( 808 FileRender( 809 'dawn_wire/server/ServerPrototypes.inc', 810 'src/dawn_wire/server/ServerPrototypes_autogen.inc', 811 wire_params)) 812 813 return renders 814 815 def get_dependencies(self, args): 816 deps = [os.path.abspath(args.dawn_json)] 817 if args.wire_json != None: 818 deps += [os.path.abspath(args.wire_json)] 819 return deps 820 821 822if __name__ == '__main__': 823 sys.exit(run_generator(MultiGeneratorFromDawnJSON())) 824