1COPYRIGHT=u""" 2/* Copyright © 2015-2021 Intel Corporation 3 * Copyright © 2021 Collabora, Ltd. 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining a 6 * copy of this software and associated documentation files (the "Software"), 7 * to deal in the Software without restriction, including without limitation 8 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 9 * and/or sell copies of the Software, and to permit persons to whom the 10 * Software is furnished to do so, subject to the following conditions: 11 * 12 * The above copyright notice and this permission notice (including the next 13 * paragraph) shall be included in all copies or substantial portions of the 14 * Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 22 * IN THE SOFTWARE. 23 */ 24""" 25 26import argparse 27import os 28import re 29from collections import namedtuple 30import xml.etree.ElementTree as et 31 32from mako.template import Template 33 34# Mesa-local imports must be declared in meson variable 35# '{file_without_suffix}_depend_files'. 36from vk_entrypoints import EntrypointParam, get_entrypoints_from_xml 37from vk_extensions import filter_api, get_all_required 38 39# These have hand-typed implementations in vk_cmd_enqueue.c 40MANUAL_COMMANDS = [ 41 # This script doesn't know how to copy arrays in structs in arrays 42 'CmdPushDescriptorSetKHR', 43 44 # The size of the elements is specified in a stride param 45 'CmdDrawMultiEXT', 46 'CmdDrawMultiIndexedEXT', 47 48 # The VkPipelineLayout object could be released before the command is 49 # executed 50 'CmdBindDescriptorSets', 51] 52 53NO_ENQUEUE_COMMANDS = [ 54 # pData's size cannot be calculated from the xml 55 'CmdPushDescriptorSetWithTemplateKHR', 56 57 # These don't return void 58 'CmdSetPerformanceMarkerINTEL', 59 'CmdSetPerformanceStreamMarkerINTEL', 60 'CmdSetPerformanceOverrideINTEL', 61] 62 63TEMPLATE_H = Template(COPYRIGHT + """\ 64/* This file generated from ${filename}, don't edit directly. */ 65 66#pragma once 67 68#include "util/list.h" 69 70#define VK_PROTOTYPES 71#include <vulkan/vulkan_core.h> 72#ifdef VK_ENABLE_BETA_EXTENSIONS 73#include <vulkan/vulkan_beta.h> 74#endif 75 76#ifdef __cplusplus 77extern "C" { 78#endif 79 80struct vk_device_dispatch_table; 81 82struct vk_cmd_queue { 83 const VkAllocationCallbacks *alloc; 84 struct list_head cmds; 85}; 86 87enum vk_cmd_type { 88% for c in commands: 89% if c.guard is not None: 90#ifdef ${c.guard} 91% endif 92 ${to_enum_name(c.name)}, 93% if c.guard is not None: 94#endif // ${c.guard} 95% endif 96% endfor 97}; 98 99extern const char *vk_cmd_queue_type_names[]; 100extern size_t vk_cmd_queue_type_sizes[]; 101 102% for c in commands: 103% if len(c.params) <= 1: # Avoid "error C2016: C requires that a struct or union have at least one member" 104<% continue %> 105% endif 106% if c.guard is not None: 107#ifdef ${c.guard} 108% endif 109struct ${to_struct_name(c.name)} { 110% for p in c.params[1:]: 111 ${to_field_decl(p.decl)}; 112% endfor 113}; 114% if c.guard is not None: 115#endif // ${c.guard} 116% endif 117% endfor 118 119struct vk_cmd_queue_entry; 120 121/* this ordering must match vk_cmd_queue_entry */ 122struct vk_cmd_queue_entry_base { 123 struct list_head cmd_link; 124 enum vk_cmd_type type; 125 void *driver_data; 126 void (*driver_free_cb)(struct vk_cmd_queue *queue, 127 struct vk_cmd_queue_entry *cmd); 128}; 129 130/* this ordering must match vk_cmd_queue_entry_base */ 131struct vk_cmd_queue_entry { 132 struct list_head cmd_link; 133 enum vk_cmd_type type; 134 void *driver_data; 135 void (*driver_free_cb)(struct vk_cmd_queue *queue, 136 struct vk_cmd_queue_entry *cmd); 137 union { 138% for c in commands: 139% if len(c.params) <= 1: 140<% continue %> 141% endif 142% if c.guard is not None: 143#ifdef ${c.guard} 144% endif 145 struct ${to_struct_name(c.name)} ${to_struct_field_name(c.name)}; 146% if c.guard is not None: 147#endif // ${c.guard} 148% endif 149% endfor 150 } u; 151}; 152 153% for c in commands: 154% if c.name in manual_commands or c.name in no_enqueue_commands: 155<% continue %> 156% endif 157% if c.guard is not None: 158#ifdef ${c.guard} 159% endif 160 VkResult vk_enqueue_${to_underscore(c.name)}(struct vk_cmd_queue *queue 161% for p in c.params[1:]: 162 , ${p.decl} 163% endfor 164 ); 165% if c.guard is not None: 166#endif // ${c.guard} 167% endif 168 169% endfor 170 171void vk_free_queue(struct vk_cmd_queue *queue); 172 173static inline void 174vk_cmd_queue_init(struct vk_cmd_queue *queue, VkAllocationCallbacks *alloc) 175{ 176 queue->alloc = alloc; 177 list_inithead(&queue->cmds); 178} 179 180static inline void 181vk_cmd_queue_reset(struct vk_cmd_queue *queue) 182{ 183 vk_free_queue(queue); 184 list_inithead(&queue->cmds); 185} 186 187static inline void 188vk_cmd_queue_finish(struct vk_cmd_queue *queue) 189{ 190 vk_free_queue(queue); 191 list_inithead(&queue->cmds); 192} 193 194void vk_cmd_queue_execute(struct vk_cmd_queue *queue, 195 VkCommandBuffer commandBuffer, 196 const struct vk_device_dispatch_table *disp); 197 198#ifdef __cplusplus 199} 200#endif 201""", output_encoding='utf-8') 202 203TEMPLATE_C = Template(COPYRIGHT + """ 204/* This file generated from ${filename}, don't edit directly. */ 205 206#include "${header}" 207 208#define VK_PROTOTYPES 209#include <vulkan/vulkan_core.h> 210#ifdef VK_ENABLE_BETA_EXTENSIONS 211#include <vulkan/vulkan_beta.h> 212#endif 213 214#include "vk_alloc.h" 215#include "vk_cmd_enqueue_entrypoints.h" 216#include "vk_command_buffer.h" 217#include "vk_dispatch_table.h" 218#include "vk_device.h" 219 220const char *vk_cmd_queue_type_names[] = { 221% for c in commands: 222% if c.guard is not None: 223#ifdef ${c.guard} 224% endif 225 "${to_enum_name(c.name)}", 226% if c.guard is not None: 227#endif // ${c.guard} 228% endif 229% endfor 230}; 231 232size_t vk_cmd_queue_type_sizes[] = { 233% for c in commands: 234% if c.guard is not None: 235#ifdef ${c.guard} 236% endif 237% if len(c.params) > 1: 238 sizeof(struct ${to_struct_name(c.name)}) + 239% endif 240 sizeof(struct vk_cmd_queue_entry_base), 241% if c.guard is not None: 242#endif // ${c.guard} 243% endif 244% endfor 245}; 246 247% for c in commands: 248% if c.guard is not None: 249#ifdef ${c.guard} 250% endif 251static void 252vk_free_${to_underscore(c.name)}(struct vk_cmd_queue *queue, 253${' ' * len('vk_free_' + to_underscore(c.name) + '(')}\\ 254struct vk_cmd_queue_entry *cmd) 255{ 256 if (cmd->driver_free_cb) 257 cmd->driver_free_cb(queue, cmd); 258 else 259 vk_free(queue->alloc, cmd->driver_data); 260% for p in c.params[1:]: 261% if p.len: 262 vk_free(queue->alloc, (${remove_suffix(p.decl.replace("const", ""), p.name)})cmd->u.${to_struct_field_name(c.name)}.${to_field_name(p.name)}); 263% elif '*' in p.decl: 264 ${get_struct_free(c, p, types)} 265% endif 266% endfor 267 vk_free(queue->alloc, cmd); 268} 269 270% if c.name not in manual_commands and c.name not in no_enqueue_commands: 271VkResult vk_enqueue_${to_underscore(c.name)}(struct vk_cmd_queue *queue 272% for p in c.params[1:]: 273, ${p.decl} 274% endfor 275) 276{ 277 struct vk_cmd_queue_entry *cmd = vk_zalloc(queue->alloc, vk_cmd_queue_type_sizes[${to_enum_name(c.name)}], 8, 278 VK_SYSTEM_ALLOCATION_SCOPE_OBJECT); 279 if (!cmd) return VK_ERROR_OUT_OF_HOST_MEMORY; 280 281 cmd->type = ${to_enum_name(c.name)}; 282 \ 283 <% need_error_handling = False %> 284% for p in c.params[1:]: 285% if p.len: 286 if (${p.name}) { 287 ${get_array_copy(c, p)} 288 }\ 289 <% need_error_handling = True %> 290% elif '[' in p.decl: 291 memcpy(cmd->u.${to_struct_field_name(c.name)}.${to_field_name(p.name)}, ${p.name}, 292 sizeof(*${p.name}) * ${get_array_len(p)}); 293% elif p.type == "void": 294 cmd->u.${to_struct_field_name(c.name)}.${to_field_name(p.name)} = (${remove_suffix(p.decl.replace("const", ""), p.name)}) ${p.name}; 295% elif '*' in p.decl: 296 ${get_struct_copy("cmd->u.%s.%s" % (to_struct_field_name(c.name), to_field_name(p.name)), p.name, p.type, 'sizeof(%s)' % p.type, types)}\ 297 <% need_error_handling = True %> 298% else: 299 cmd->u.${to_struct_field_name(c.name)}.${to_field_name(p.name)} = ${p.name}; 300% endif 301% endfor 302 303 list_addtail(&cmd->cmd_link, &queue->cmds); 304 return VK_SUCCESS; 305 306% if need_error_handling: 307err: 308 if (cmd) 309 vk_free_${to_underscore(c.name)}(queue, cmd); 310 return VK_ERROR_OUT_OF_HOST_MEMORY; 311% endif 312} 313% endif 314% if c.guard is not None: 315#endif // ${c.guard} 316% endif 317 318% endfor 319 320void 321vk_free_queue(struct vk_cmd_queue *queue) 322{ 323 struct vk_cmd_queue_entry *tmp, *cmd; 324 LIST_FOR_EACH_ENTRY_SAFE(cmd, tmp, &queue->cmds, cmd_link) { 325 switch(cmd->type) { 326% for c in commands: 327% if c.guard is not None: 328#ifdef ${c.guard} 329% endif 330 case ${to_enum_name(c.name)}: 331 vk_free_${to_underscore(c.name)}(queue, cmd); 332 break; 333% if c.guard is not None: 334#endif // ${c.guard} 335% endif 336% endfor 337 } 338 } 339} 340 341void 342vk_cmd_queue_execute(struct vk_cmd_queue *queue, 343 VkCommandBuffer commandBuffer, 344 const struct vk_device_dispatch_table *disp) 345{ 346 list_for_each_entry(struct vk_cmd_queue_entry, cmd, &queue->cmds, cmd_link) { 347 switch (cmd->type) { 348% for c in commands: 349% if c.guard is not None: 350#ifdef ${c.guard} 351% endif 352 case ${to_enum_name(c.name)}: 353 disp->${c.name}(commandBuffer 354% for p in c.params[1:]: 355 , cmd->u.${to_struct_field_name(c.name)}.${to_field_name(p.name)}\\ 356% endfor 357 ); 358 break; 359% if c.guard is not None: 360#endif // ${c.guard} 361% endif 362% endfor 363 default: unreachable("Unsupported command"); 364 } 365 } 366} 367 368% for c in commands: 369% if c.name in no_enqueue_commands: 370/* TODO: Generate vk_cmd_enqueue_${c.name}() */ 371<% continue %> 372% endif 373 374% if c.guard is not None: 375#ifdef ${c.guard} 376% endif 377<% assert c.return_type == 'void' %> 378 379% if c.name in manual_commands: 380/* vk_cmd_enqueue_${c.name}() is hand-typed in vk_cmd_enqueue.c */ 381% else: 382VKAPI_ATTR void VKAPI_CALL 383vk_cmd_enqueue_${c.name}(${c.decl_params()}) 384{ 385 VK_FROM_HANDLE(vk_command_buffer, cmd_buffer, commandBuffer); 386 387 if (vk_command_buffer_has_error(cmd_buffer)) 388 return; 389% if len(c.params) == 1: 390 VkResult result = vk_enqueue_${to_underscore(c.name)}(&cmd_buffer->cmd_queue); 391% else: 392 VkResult result = vk_enqueue_${to_underscore(c.name)}(&cmd_buffer->cmd_queue, 393 ${c.call_params(1)}); 394% endif 395 if (unlikely(result != VK_SUCCESS)) 396 vk_command_buffer_set_error(cmd_buffer, result); 397} 398% endif 399 400VKAPI_ATTR void VKAPI_CALL 401vk_cmd_enqueue_unless_primary_${c.name}(${c.decl_params()}) 402{ 403 VK_FROM_HANDLE(vk_command_buffer, cmd_buffer, commandBuffer); 404 405 if (cmd_buffer->level == VK_COMMAND_BUFFER_LEVEL_PRIMARY) { 406 const struct vk_device_dispatch_table *disp = 407 cmd_buffer->base.device->command_dispatch_table; 408 409 disp->${c.name}(${c.call_params()}); 410 } else { 411 vk_cmd_enqueue_${c.name}(${c.call_params()}); 412 } 413} 414% if c.guard is not None: 415#endif // ${c.guard} 416% endif 417% endfor 418""", output_encoding='utf-8') 419 420def remove_prefix(text, prefix): 421 if text.startswith(prefix): 422 return text[len(prefix):] 423 return text 424 425def remove_suffix(text, suffix): 426 if text.endswith(suffix): 427 return text[:-len(suffix)] 428 return text 429 430def to_underscore(name): 431 return remove_prefix(re.sub('([A-Z]+)', r'_\1', name).lower(), '_') 432 433def to_struct_field_name(name): 434 return to_underscore(name).replace('cmd_', '') 435 436def to_field_name(name): 437 return remove_prefix(to_underscore(name).replace('cmd_', ''), 'p_') 438 439def to_field_decl(decl): 440 if 'const*' in decl: 441 decl = decl.replace('const*', '*') 442 else: 443 decl = decl.replace('const ', '') 444 [decl, name] = decl.rsplit(' ', 1) 445 return decl + ' ' + to_field_name(name) 446 447def to_enum_name(name): 448 return "VK_%s" % to_underscore(name).upper() 449 450def to_struct_name(name): 451 return "vk_%s" % to_underscore(name) 452 453def get_array_len(param): 454 return param.decl[param.decl.find("[") + 1:param.decl.find("]")] 455 456def get_array_copy(command, param): 457 field_name = "cmd->u.%s.%s" % (to_struct_field_name(command.name), to_field_name(param.name)) 458 if param.type == "void": 459 field_size = "1" 460 else: 461 field_size = "sizeof(*%s)" % field_name 462 allocation = "%s = vk_zalloc(queue->alloc, %s * (%s), 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);\n if (%s == NULL) goto err;\n" % (field_name, field_size, param.len, field_name) 463 const_cast = remove_suffix(param.decl.replace("const", ""), param.name) 464 copy = "memcpy((%s)%s, %s, %s * (%s));" % (const_cast, field_name, param.name, field_size, param.len) 465 return "%s\n %s" % (allocation, copy) 466 467def get_array_member_copy(struct, src_name, member): 468 field_name = "%s->%s" % (struct, member.name) 469 if member.len == "struct-ptr": 470 field_size = "sizeof(*%s)" % (field_name) 471 else: 472 field_size = "sizeof(*%s) * %s->%s" % (field_name, struct, member.len) 473 allocation = "%s = vk_zalloc(queue->alloc, %s, 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);\n if (%s == NULL) goto err;\n" % (field_name, field_size, field_name) 474 const_cast = remove_suffix(member.decl.replace("const", ""), member.name) 475 copy = "memcpy((%s)%s, %s->%s, %s);" % (const_cast, field_name, src_name, member.name, field_size) 476 return "if (%s->%s) {\n %s\n %s\n}\n" % (src_name, member.name, allocation, copy) 477 478def get_pnext_member_copy(struct, src_type, member, types, level): 479 if not types[src_type].extended_by: 480 return "" 481 field_name = "%s->%s" % (struct, member.name) 482 pnext_decl = "const VkBaseInStructure *pnext = %s;" % field_name 483 case_stmts = "" 484 for type in types[src_type].extended_by: 485 guard_pre_stmt = "" 486 guard_post_stmt = "" 487 if type.guard is not None: 488 guard_pre_stmt = "#ifdef %s" % type.guard 489 guard_post_stmt = "#endif" 490 case_stmts += """ 491%s 492 case %s: 493 %s 494 break; 495%s 496 """ % (guard_pre_stmt, type.enum, get_struct_copy(field_name, "pnext", type.name, "sizeof(%s)" % type.name, types, level), guard_post_stmt) 497 return """ 498 %s 499 if (pnext) { 500 switch ((int32_t)pnext->sType) { 501 %s 502 } 503 } 504 """ % (pnext_decl, case_stmts) 505 506def get_struct_copy(dst, src_name, src_type, size, types, level=0): 507 global tmp_dst_idx 508 global tmp_src_idx 509 510 allocation = "%s = vk_zalloc(queue->alloc, %s, 8, VK_SYSTEM_ALLOCATION_SCOPE_OBJECT);\n if (%s == NULL) goto err;\n" % (dst, size, dst) 511 copy = "memcpy((void*)%s, %s, %s);" % (dst, src_name, size) 512 513 level += 1 514 tmp_dst = "%s *tmp_dst%d = (void *) %s; (void) tmp_dst%d;" % (src_type, level, dst, level) 515 tmp_src = "%s *tmp_src%d = (void *) %s; (void) tmp_src%d;" % (src_type, level, src_name, level) 516 517 member_copies = "" 518 if src_type in types: 519 for member in types[src_type].members: 520 if member.len and member.len != 'null-terminated': 521 member_copies += get_array_member_copy("tmp_dst%d" % level, "tmp_src%d" % level, member) 522 elif member.name == 'pNext': 523 member_copies += get_pnext_member_copy("tmp_dst%d" % level, src_type, member, types, level) 524 525 null_assignment = "%s = NULL;" % dst 526 if_stmt = "if (%s) {" % src_name 527 return "%s\n %s\n %s\n %s\n %s \n %s } else {\n %s\n }" % (if_stmt, allocation, copy, tmp_dst, tmp_src, member_copies, null_assignment) 528 529def get_struct_free(command, param, types): 530 field_name = "cmd->u.%s.%s" % (to_struct_field_name(command.name), to_field_name(param.name)) 531 const_cast = remove_suffix(param.decl.replace("const", ""), param.name) 532 struct_free = "vk_free(queue->alloc, (%s)%s);" % (const_cast, field_name) 533 member_frees = "" 534 if (param.type in types): 535 for member in types[param.type].members: 536 if member.len and member.len != 'null-terminated': 537 member_name = "cmd->u.%s.%s->%s" % (to_struct_field_name(command.name), to_field_name(param.name), member.name) 538 const_cast = remove_suffix(member.decl.replace("const", ""), member.name) 539 member_frees += "vk_free(queue->alloc, (%s)%s);\n" % (const_cast, member_name) 540 return "%s %s\n" % (member_frees, struct_free) 541 542EntrypointType = namedtuple('EntrypointType', 'name enum members extended_by guard') 543 544def get_types_defines(doc): 545 """Maps types to extension defines.""" 546 types_to_defines = {} 547 548 platform_define = {} 549 for platform in doc.findall('./platforms/platform'): 550 name = platform.attrib['name'] 551 define = platform.attrib['protect'] 552 platform_define[name] = define 553 554 for extension in doc.findall('./extensions/extension[@platform]'): 555 platform = extension.attrib['platform'] 556 define = platform_define[platform] 557 558 for types in extension.findall('./require/type'): 559 fullname = types.attrib['name'] 560 types_to_defines[fullname] = define 561 562 return types_to_defines 563 564def get_types(doc, beta, api, types_to_defines): 565 """Extract the types from the registry.""" 566 types = {} 567 568 required = get_all_required(doc, 'type', api, beta) 569 570 for _type in doc.findall('./types/type'): 571 if _type.attrib.get('category') != 'struct': 572 continue 573 if not filter_api(_type, api): 574 continue 575 if _type.attrib['name'] not in required: 576 continue 577 578 members = [] 579 type_enum = None 580 for p in _type.findall('./member'): 581 if not filter_api(p, api): 582 continue 583 584 mem_type = p.find('./type').text 585 mem_name = p.find('./name').text 586 mem_decl = ''.join(p.itertext()) 587 mem_len = p.attrib.get('altlen', p.attrib.get('len', None)) 588 if mem_len is None and '*' in mem_decl and mem_name != 'pNext': 589 mem_len = "struct-ptr" 590 591 member = EntrypointParam(type=mem_type, 592 name=mem_name, 593 decl=mem_decl, 594 len=mem_len) 595 members.append(member) 596 597 if mem_name == 'sType': 598 type_enum = p.attrib.get('values') 599 types[_type.attrib['name']] = EntrypointType(name=_type.attrib['name'], enum=type_enum, members=members, extended_by=[], guard=types_to_defines.get(_type.attrib['name'])) 600 601 for _type in doc.findall('./types/type'): 602 if _type.attrib.get('category') != 'struct': 603 continue 604 if not filter_api(_type, api): 605 continue 606 if _type.attrib['name'] not in required: 607 continue 608 if _type.attrib.get('structextends') is None: 609 continue 610 for extended in _type.attrib.get('structextends').split(','): 611 if extended not in required: 612 continue 613 types[extended].extended_by.append(types[_type.attrib['name']]) 614 615 return types 616 617def get_types_from_xml(xml_files, beta, api='vulkan'): 618 types = {} 619 620 for filename in xml_files: 621 doc = et.parse(filename) 622 types.update(get_types(doc, beta, api, get_types_defines(doc))) 623 624 return types 625 626def main(): 627 parser = argparse.ArgumentParser() 628 parser.add_argument('--out-c', required=True, help='Output C file.') 629 parser.add_argument('--out-h', required=True, help='Output H file.') 630 parser.add_argument('--beta', required=True, help='Enable beta extensions.') 631 parser.add_argument('--xml', 632 help='Vulkan API XML file.', 633 required=True, action='append', dest='xml_files') 634 args = parser.parse_args() 635 636 commands = [] 637 for e in get_entrypoints_from_xml(args.xml_files, args.beta): 638 if e.name.startswith('Cmd') and \ 639 not e.alias: 640 commands.append(e) 641 642 types = get_types_from_xml(args.xml_files, args.beta) 643 644 assert os.path.dirname(args.out_c) == os.path.dirname(args.out_h) 645 646 environment = { 647 'header': os.path.basename(args.out_h), 648 'commands': commands, 649 'filename': os.path.basename(__file__), 650 'to_underscore': to_underscore, 651 'get_array_len': get_array_len, 652 'to_struct_field_name': to_struct_field_name, 653 'to_field_name': to_field_name, 654 'to_field_decl': to_field_decl, 655 'to_enum_name': to_enum_name, 656 'to_struct_name': to_struct_name, 657 'get_array_copy': get_array_copy, 658 'get_struct_copy': get_struct_copy, 659 'get_struct_free': get_struct_free, 660 'types': types, 661 'manual_commands': MANUAL_COMMANDS, 662 'no_enqueue_commands': NO_ENQUEUE_COMMANDS, 663 'remove_suffix': remove_suffix, 664 } 665 666 try: 667 with open(args.out_h, 'wb') as f: 668 guard = os.path.basename(args.out_h).replace('.', '_').upper() 669 f.write(TEMPLATE_H.render(guard=guard, **environment)) 670 with open(args.out_c, 'wb') as f: 671 f.write(TEMPLATE_C.render(**environment)) 672 except Exception: 673 # In the event there's an error, this imports some helpers from mako 674 # to print a useful stack trace and prints it, then exits with 675 # status 1, if python is run with debug; otherwise it just raises 676 # the exception 677 import sys 678 from mako import exceptions 679 print(exceptions.text_error_template().render(), file=sys.stderr) 680 sys.exit(1) 681 682if __name__ == '__main__': 683 main() 684