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