genRef.py
1 #!/usr/bin/python3 2 # 3 # Copyright (c) 2016-2019 The Khronos Group Inc. 4 # 5 # Licensed under the Apache License, Version 2.0 (the "License"); 6 # you may not use this file except in compliance with the License. 7 # You may obtain a copy of the License at 8 # 9 # http://www.apache.org/licenses/LICENSE-2.0 10 # 11 # Unless required by applicable law or agreed to in writing, software 12 # distributed under the License is distributed on an "AS IS" BASIS, 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 # See the License for the specific language governing permissions and 15 # limitations under the License. 16 17 # genRef.py - create API ref pages from spec source files 18 # 19 # Usage: genRef.py files 20 21 import argparse 22 import io 23 import os 24 import re 25 import sys 26 from collections import OrderedDict 27 from reflib import (findRefs, fixupRefs, loadFile, logDiag, logWarn, 28 printPageInfo, setLogFile) 29 from reg import Registry 30 import vkapi as api 31 from vkconventions import VulkanConventions as APIConventions 32 33 def makeExtensionInclude(name): 34 """Return an include command, given an extension name.""" 35 return 'include::{}/refpage.{}{}[]'.format( 36 conventions.specification_path, 37 name, 38 conventions.file_suffix) 39 40 # Return True if name is an API extension name (ends with an upper-case 41 # author ID). This assumes that author IDs are at least two characters. 42 def isextension(name): 43 return name[-2:].isalpha() and name[-2:].isupper() 44 45 # Print Khronos CC-BY copyright notice on open file fp. If comment is 46 # True, print as an asciidoc comment block, which copyrights the source 47 # file. Otherwise print as an asciidoc include of the copyright in markup, 48 # which copyrights the outputs. Also include some asciidoc boilerplate 49 # needed by all the standalone ref pages. 50 def printCopyrightSourceComments(fp): 51 print('// Copyright (c) 2014-2019 Khronos Group. This work is licensed under a', file=fp) 52 print('// Creative Commons Attribution 4.0 International License; see', file=fp) 53 print('// http://creativecommons.org/licenses/by/4.0/', file=fp) 54 print('', file=fp) 55 56 def printFooter(fp): 57 print('include::footer.txt[]', file=fp) 58 print('', file=fp) 59 60 61 # Add a spec asciidoc macro prefix to an API name, depending on its type 62 # (protos, structs, enums, etc.). If the name is not recognized, use 63 # the generic link macro 'reflink:'. 64 def macroPrefix(name): 65 if name in api.basetypes: 66 return 'basetype:' + name 67 elif name in api.defines: 68 return 'dlink:' + name 69 elif name in api.enums: 70 return 'elink:' + name 71 elif name in api.flags: 72 return 'elink:' + name 73 elif name in api.funcpointers: 74 return 'tlink:' + name 75 elif name in api.handles: 76 return 'slink:' + name 77 elif name in api.protos: 78 return 'flink:' + name 79 elif name in api.structs: 80 return 'slink:' + name 81 elif name == 'TBD': 82 return 'No cross-references are available' 83 else: 84 return 'reflink:' + name 85 86 # Return an asciidoc string with a list of 'See Also' references for the 87 # API entity 'apiName', based on the relationship mapping in the api module. 88 # 'explicitRefs' is a list of additional cross-references. 89 # If no relationships are available, return None. 90 def seeAlsoList(apiName, explicitRefs = None): 91 refs = {} 92 93 # Add all the implicit references to refs 94 if apiName in api.mapDict: 95 for name in sorted(api.mapDict[apiName]): 96 refs[name] = None 97 98 # Add all the explicit references 99 if explicitRefs is not None: 100 if isinstance(explicitRefs, str): 101 explicitRefs = explicitRefs.split() 102 for name in explicitRefs: 103 refs[name] = None 104 105 if not refs: 106 return None 107 return ', '.join(macroPrefix(name) for name in sorted(refs.keys())) + '\n' 108 109 # Remap include directives in a list of lines so they can be extracted to a 110 # different directory. Returns remapped lines. 111 # 112 # lines - text to remap 113 # baseDir - target directory 114 # specDir - source directory 115 def remapIncludes(lines, baseDir, specDir): 116 # This should be compiled only once 117 includePat = re.compile(r'^include::(?P<path>.*)\[\]') 118 119 newLines = [] 120 for line in lines: 121 matches = includePat.search(line) 122 if matches is not None: 123 path = matches.group('path') 124 125 if path[0] != '{': 126 # Relative path to include file from here 127 incPath = specDir + '/' + path 128 # Remap to be relative to baseDir 129 newPath = os.path.relpath(incPath, baseDir) 130 newLine = 'include::' + newPath + '[]\n' 131 logDiag('remapIncludes: remapping', line, '->', newLine) 132 newLines.append(newLine) 133 else: 134 # An asciidoctor variable starts the path. 135 # This must be an absolute path, not needing to be rewritten. 136 newLines.append(line) 137 else: 138 newLines.append(line) 139 return newLines 140 141 142 def refPageShell(pageName, pageDesc, fp, sections=None, tail_content=None, man_section=3): 143 printCopyrightSourceComments(fp) 144 145 print(':data-uri:', 146 ':icons: font', 147 conventions.extra_refpage_headers, 148 '', 149 sep='\n', file=fp) 150 151 s = '{}({})'.format(pageName, man_section) 152 print('= ' + s, 153 '', 154 sep='\n', file=fp) 155 if pageDesc.strip() == '': 156 pageDesc = 'NO SHORT DESCRIPTION PROVIDED' 157 logWarn('refPageHead: no short description provided for', pageName) 158 159 print('== Name', 160 '{} - {}'.format(pageName, pageDesc), 161 '', 162 sep='\n', file=fp) 163 164 if sections: 165 for title, content in sections.items(): 166 print('== {}'.format(title), 167 '', 168 content, 169 '', 170 sep='\n', file=fp) 171 172 if tail_content: 173 print(tail_content, 174 '', 175 sep='\n', file=fp) 176 177 178 # Generate header of a reference page 179 # pageName - string name of the page 180 # pageDesc - string short description of the page 181 # specType - string containing 'spec' field from refpage open block, or None. 182 # Used to determine containing spec name and URL. 183 # specText - string that goes in the "C Specification" section 184 # fieldName - string heading an additional section following specText, if not None 185 # fieldText - string that goes in the additional section 186 # descText - string that goes in the "Description" section 187 # fp - file to write to 188 def refPageHead(pageName, pageDesc, specText, fieldName, fieldText, descText, fp): 189 sections = OrderedDict() 190 191 if specText is not None: 192 sections['C Specification'] = specText 193 194 if fieldName is not None: 195 sections[fieldName] = fieldText 196 197 if descText is None or descText.strip() == '': 198 logWarn('refPageHead: no description provided for', pageName) 199 200 if descText is not None: 201 sections['Description'] = descText 202 203 refPageShell(pageName, pageDesc, fp, sections=sections) 204 205 # specType is None or the 'spec' attribute from the refpage open block, 206 # identifying the specification name and URL this refpage links to. 207 # specAnchor is None or the 'anchor' attribute from the refpage open block, 208 # identifying the anchor in the specification this refpage links to. If 209 # None, the pageName is assumed to be a valid anchor. 210 def refPageTail(pageName, 211 specType = None, 212 specAnchor = None, 213 seeAlso = None, 214 fp = None, 215 auto = False): 216 217 specName = conventions.api_name(specType) 218 specURL = conventions.specURL(specType) 219 if specAnchor is None: 220 specAnchor = pageName 221 222 if seeAlso is None: 223 seeAlso = 'No cross-references are available\n' 224 225 notes = [ 226 'For more information, see the ' + specName + ' Specification at URL', 227 '', 228 '{}#{}'.format(specURL, specAnchor), 229 '', 230 ] 231 232 if auto: 233 notes.extend(( 234 'This page is a generated document.', 235 'Fixes and changes should be made to the generator scripts, ' 236 'not directly.', 237 )) 238 else: 239 notes.extend(( 240 'This page is extracted from the ' + specName + ' Specification. ', 241 'Fixes and changes should be made to the Specification, ' 242 'not directly.', 243 )) 244 245 print('== See Also', 246 '', 247 seeAlso, 248 '', 249 sep='\n', file=fp) 250 251 print('== Document Notes', 252 '', 253 '\n'.join(notes), 254 '', 255 sep='\n', file=fp) 256 257 printFooter(fp) 258 259 # Extract a single reference page into baseDir 260 # baseDir - base directory to emit page into 261 # specDir - directory extracted page source came from 262 # pi - pageInfo for this page relative to file 263 # file - list of strings making up the file, indexed by pi 264 def emitPage(baseDir, specDir, pi, file): 265 pageName = baseDir + '/' + pi.name + '.txt' 266 267 # Add a dictionary entry for this page 268 global genDict 269 genDict[pi.name] = None 270 logDiag('emitPage:', pageName) 271 272 # Short description 273 if pi.desc is None: 274 pi.desc = '(no short description available)' 275 276 # Member/parameter section label and text, if there is one 277 field = None 278 fieldText = None 279 280 if pi.type != 'freeform': 281 # Not sure how this happens yet 282 if pi.include is None: 283 logWarn('emitPage:', pageName, 'INCLUDE is None, no page generated') 284 return 285 286 # Specification text 287 lines = remapIncludes(file[pi.begin:pi.include+1], baseDir, specDir) 288 specText = ''.join(lines) 289 290 if pi.param is not None: 291 if pi.type == 'structs': 292 field = 'Members' 293 elif pi.type in ['protos', 'funcpointers']: 294 field = 'Parameters' 295 else: 296 logWarn('emitPage: unknown field type:', pi.type, 297 'for', pi.name) 298 lines = remapIncludes(file[pi.param:pi.body], baseDir, specDir) 299 fieldText = ''.join(lines) 300 301 # Description text 302 if pi.body != pi.include: 303 lines = remapIncludes(file[pi.body:pi.end+1], baseDir, specDir) 304 descText = ''.join(lines) 305 else: 306 descText = None 307 logWarn('emitPage: INCLUDE == BODY, so description will be empty for', pi.name) 308 if pi.begin != pi.include: 309 logWarn('emitPage: Note: BEGIN != INCLUDE, so the description might be incorrectly located before the API include!') 310 else: 311 specText = None 312 descText = ''.join(file[pi.begin:pi.end+1]) 313 314 specURL = conventions.specURL(pi.spec) 315 316 # Substitute xrefs to point at the main spec 317 specLinksPattern = re.compile(r'<<([^>,]+)[,]?[ \t\n]*([^>,]*)>>') 318 specLinksSubstitute = r'link:{}#\1[\2]'.format(specURL) 319 if specText is not None: 320 specText, _ = specLinksPattern.subn(specLinksSubstitute, specText) 321 if fieldText is not None: 322 fieldText, _ = specLinksPattern.subn(specLinksSubstitute, fieldText) 323 if descText is not None: 324 descText, _ = specLinksPattern.subn(specLinksSubstitute, descText) 325 326 fp = open(pageName, 'w', encoding='utf-8') 327 refPageHead(pi.name, 328 pi.desc, 329 specText, 330 field, fieldText, 331 descText, 332 fp) 333 refPageTail(pageName=pi.name, 334 specType=pi.spec, 335 specAnchor=pi.anchor, 336 seeAlso=seeAlsoList(pi.name, pi.refs), 337 fp=fp, 338 auto=False) 339 fp.close() 340 341 # Autogenerate a single reference page in baseDir 342 # Script only knows how to do this for /enums/ pages, at present 343 # baseDir - base directory to emit page into 344 # pi - pageInfo for this page relative to file 345 # file - list of strings making up the file, indexed by pi 346 def autoGenEnumsPage(baseDir, pi, file): 347 pageName = baseDir + '/' + pi.name + '.txt' 348 fp = open(pageName, 'w', encoding='utf-8') 349 350 # Add a dictionary entry for this page 351 global genDict 352 genDict[pi.name] = None 353 logDiag('autoGenEnumsPage:', pageName) 354 355 # Short description 356 if pi.desc is None: 357 pi.desc = '(no short description available)' 358 359 # Description text. Allow for the case where an enum definition 360 # is not embedded. 361 if not pi.embed: 362 embedRef = '' 363 else: 364 embedRef = ''.join(( 365 ' * The reference page for ', 366 macroPrefix(pi.embed), 367 ', where this interface is defined.\n' )) 368 369 txt = ''.join(( 370 'For more information, see:\n\n', 371 embedRef, 372 ' * The See Also section for other reference pages using this type.\n', 373 ' * The ' + apiName + ' Specification.\n' )) 374 375 refPageHead(pi.name, 376 pi.desc, 377 ''.join(file[pi.begin:pi.include+1]), 378 None, None, 379 txt, 380 fp) 381 refPageTail(pageName=pi.name, 382 specType=pi.spec, 383 specAnchor=pi.anchor, 384 seeAlso=seeAlsoList(pi.name, pi.refs), 385 fp=fp, 386 auto=True) 387 fp.close() 388 389 390 # Pattern to break apart an API *Flags{authorID} name, used in 391 # autoGenFlagsPage. 392 flagNamePat = re.compile(r'(?P<name>\w+)Flags(?P<author>[A-Z]*)') 393 394 395 # Autogenerate a single reference page in baseDir for an API *Flags type 396 # baseDir - base directory to emit page into 397 # flagName - API *Flags name 398 def autoGenFlagsPage(baseDir, flagName): 399 pageName = baseDir + '/' + flagName + '.txt' 400 fp = open(pageName, 'w', encoding='utf-8') 401 402 # Add a dictionary entry for this page 403 global genDict 404 genDict[flagName] = None 405 logDiag('autoGenFlagsPage:', pageName) 406 407 # Short description 408 matches = flagNamePat.search(flagName) 409 if matches is not None: 410 name = matches.group('name') 411 author = matches.group('author') 412 logDiag('autoGenFlagsPage: split name into', name, 'Flags', author) 413 flagBits = name + 'FlagBits' + author 414 desc = 'Bitmask of ' + flagBits 415 else: 416 logWarn('autoGenFlagsPage:', pageName, 'does not end in "Flags{author ID}". Cannot infer FlagBits type.') 417 flagBits = None 418 desc = 'Unknown ' + apiName + ' flags type' 419 420 # Description text 421 if flagBits is not None: 422 txt = ''.join(( 423 'etext:' + flagName, 424 ' is a mask of zero or more elink:' + flagBits + '.\n', 425 'It is used as a member and/or parameter of the structures and commands\n', 426 'in the See Also section below.\n' )) 427 else: 428 txt = ''.join(( 429 'etext:' + flagName, 430 ' is an unknown ' + apiName + ' type, assumed to be a bitmask.\n' )) 431 432 refPageHead(flagName, 433 desc, 434 'include::../api/flags/' + flagName + '.txt[]\n', 435 None, None, 436 txt, 437 fp) 438 refPageTail(pageName=flagName, 439 specType=pi.spec, 440 specAnchor=pi.anchor, 441 seeAlso=seeAlsoList(flagName, None), 442 fp=fp, 443 auto=True) 444 fp.close() 445 446 # Autogenerate a single handle page in baseDir for an API handle type 447 # baseDir - base directory to emit page into 448 # handleName - API handle name 449 # @@ Need to determine creation function & add handles/ include for the 450 # @@ interface in generator.py. 451 def autoGenHandlePage(baseDir, handleName): 452 pageName = baseDir + '/' + handleName + '.txt' 453 fp = open(pageName, 'w', encoding='utf-8') 454 455 # Add a dictionary entry for this page 456 global genDict 457 genDict[handleName] = None 458 logDiag('autoGenHandlePage:', pageName) 459 460 # Short description 461 desc = apiName + ' object handle' 462 463 descText = ''.join(( 464 'sname:' + handleName, 465 ' is an object handle type, referring to an object used\n', 466 'by the ' + apiName + ' implementation. These handles are created or allocated\n', 467 'by the @@ TBD @@ function, and used by other ' + apiName + ' structures\n', 468 'and commands in the See Also section below.\n' )) 469 470 refPageHead(handleName, 471 desc, 472 'include::../api/handles/' + handleName + '.txt[]\n', 473 None, None, 474 descText, 475 fp) 476 refPageTail(pageName=handleName, 477 specType=pi.spec, 478 specAnchor=pi.anchor, 479 seeAlso=seeAlsoList(handleName, None), 480 fp=fp, 481 auto=True) 482 fp.close() 483 484 # Extract reference pages from a spec asciidoc source file 485 # specFile - filename to extract from 486 # baseDir - output directory to generate page in 487 # 488 def genRef(specFile, baseDir): 489 file = loadFile(specFile) 490 if file is None: 491 return 492 493 # Save the path to this file for later use in rewriting relative includes 494 specDir = os.path.dirname(os.path.abspath(specFile)) 495 496 pageMap = findRefs(file, specFile) 497 logDiag(specFile + ': found', len(pageMap.keys()), 'potential pages') 498 499 sys.stderr.flush() 500 501 # Fix up references in pageMap 502 fixupRefs(pageMap, specFile, file) 503 504 # Create each page, if possible 505 506 for name in sorted(pageMap): 507 pi = pageMap[name] 508 509 printPageInfo(pi, file) 510 511 if pi.Warning: 512 logDiag('genRef:', pi.name + ':', pi.Warning) 513 514 if pi.extractPage: 515 emitPage(baseDir, specDir, pi, file) 516 elif pi.type == 'enums': 517 autoGenEnumsPage(baseDir, pi, file) 518 elif pi.type == 'flags': 519 autoGenFlagsPage(baseDir, pi.name) 520 else: 521 # Don't extract this page 522 logWarn('genRef: Cannot extract or autogenerate:', pi.name) 523 524 # Generate baseDir/apispec.txt, the single-page version of the ref pages. 525 # This assumes there's a page for everything in the api module dictionaries. 526 # Extensions (KHR, EXT, etc.) are currently skipped 527 def genSinglePageRef(baseDir): 528 # Accumulate head of page 529 head = io.StringIO() 530 531 printCopyrightSourceComments(head) 532 533 print('= ' + apiName + ' API Reference Pages', 534 ':data-uri:', 535 ':icons: font', 536 ':doctype: book', 537 ':numbered!:', 538 ':max-width: 200', 539 ':data-uri:', 540 ':toc2:', 541 ':toclevels: 2', 542 '', 543 sep='\n', file=head) 544 545 print('include::copyright-ccby.txt[]', file=head) 546 print('', file=head) 547 # Inject the table of contents. Asciidoc really ought to be generating 548 # this for us. 549 550 sections = [ 551 [ api.protos, 'protos', apiName + ' Commands' ], 552 [ api.handles, 'handles', 'Object Handles' ], 553 [ api.structs, 'structs', 'Structures' ], 554 [ api.enums, 'enums', 'Enumerations' ], 555 [ api.flags, 'flags', 'Flags' ], 556 [ api.funcpointers, 'funcpointers', 'Function Pointer Types' ], 557 [ api.basetypes, 'basetypes', apiName + ' Scalar types' ], 558 [ api.defines, 'defines', 'C Macro Definitions' ], 559 [ extensions, 'extensions', apiName + ' Extensions' ] 560 ] 561 562 # Accumulate body of page 563 body = io.StringIO() 564 565 for (apiDict,label,title) in sections: 566 # Add section title/anchor header to body 567 anchor = '[[' + label + ',' + title + ']]' 568 print(anchor, 569 '== ' + title, 570 '', 571 ':leveloffset: 2', 572 '', 573 sep='\n', file=body) 574 575 if label == 'extensions': 576 # preserve order of extensions since we already sorted the way we want. 577 keys = apiDict.keys() 578 else: 579 keys = sorted(apiDict.keys()) 580 581 for refPage in keys: 582 # Don't generate links for aliases, which are included with the 583 # aliased page 584 if refPage not in api.alias: 585 # Add page to body 586 if 'FlagBits' in refPage and conventions.unified_flag_refpages: 587 # OpenXR does not create separate ref pages for FlagBits: 588 # the FlagBits includes go in the Flags refpage. 589 # Previously the Vulkan script would only emit non-empty 590 # Vk*Flags pages, via the logic 591 # if refPage not in api.flags or api.flags[refPage] is not None 592 # emit page 593 # Now, all are emitted. 594 continue 595 else: 596 print('include::' + refPage + '.txt[]', file=body) 597 else: 598 # Alternatively, we could (probably should) link to the 599 # aliased refpage 600 logWarn('(Benign) Not including', refPage, 601 'in single-page reference', 602 'because it is an alias of', api.alias[refPage]) 603 604 print('\n' + ':leveloffset: 0' + '\n', file=body) 605 606 # Write head and body to the output file 607 pageName = baseDir + '/apispec.txt' 608 fp = open(pageName, 'w', encoding='utf-8') 609 610 print(head.getvalue(), file=fp, end='') 611 print(body.getvalue(), file=fp, end='') 612 613 head.close() 614 body.close() 615 fp.close() 616 617 618 def genExtension(baseDir, name, info): 619 # Add a dictionary entry for this page 620 global genDict 621 genDict[name] = None 622 declares = [] 623 elem = info.elem 624 625 ext_type = elem.get('type') 626 627 for required in elem.find('require'): 628 req_name = required.get('name') 629 if not req_name: 630 # This isn't what we're looking for 631 continue 632 if req_name.endswith('_SPEC_VERSION') or req_name.endswith('_EXTENSION_NAME'): 633 # Don't link to spec version or extension name - those ref pages aren't created. 634 continue 635 636 if required.get('extends'): 637 # These are either extensions of enums, 638 # or enum values: neither of which get a ref page. 639 continue 640 641 if req_name not in genDict: 642 logWarn('ERROR: {} (in extension {}) does not have a ref page.'.format(req_name, name)) 643 644 declares.append(req_name) 645 pageName = baseDir + '/' + name + '.txt' 646 logDiag('genExtension:', pageName) 647 648 fp = open(pageName, 'w', encoding='utf-8') 649 650 sections = OrderedDict() 651 sections['Specification'] = 'See link:{html_spec_relative}#%s[ %s] in the main specification for complete information.' % ( 652 name, name) 653 refPageShell(name, 654 "{} extension".format(ext_type), 655 fp, 656 sections=sections, 657 tail_content=makeExtensionInclude(name)) 658 refPageTail(pageName=name, 659 specType=None, 660 specAnchor=name, 661 seeAlso=seeAlsoList(name, declares), 662 fp=fp, 663 auto=True) 664 fp.close() 665 666 667 if __name__ == '__main__': 668 global genDict, extensions, conventions, apiName 669 genDict = {} 670 extensions = OrderedDict() 671 conventions = APIConventions() 672 apiName = conventions.api_name('api') 673 674 parser = argparse.ArgumentParser() 675 676 parser.add_argument('-diag', action='store', dest='diagFile', 677 help='Set the diagnostic file') 678 parser.add_argument('-warn', action='store', dest='warnFile', 679 help='Set the warning file') 680 parser.add_argument('-log', action='store', dest='logFile', 681 help='Set the log file for both diagnostics and warnings') 682 parser.add_argument('-basedir', action='store', dest='baseDir', 683 default='man', 684 help='Set the base directory in which pages are generated') 685 parser.add_argument('-noauto', action='store_true', 686 help='Don\'t generate inferred ref pages automatically') 687 parser.add_argument('files', metavar='filename', nargs='*', 688 help='a filename to extract ref pages from') 689 parser.add_argument('--version', action='version', version='%(prog)s 1.0') 690 parser.add_argument('-extension', action='append', 691 default=[], 692 help='Specify an extension or extensions to add to targets') 693 parser.add_argument('-registry', action='store', 694 default=conventions.registry_path, 695 help='Use specified registry file instead of default') 696 697 results = parser.parse_args() 698 699 setLogFile(True, True, results.logFile) 700 setLogFile(True, False, results.diagFile) 701 setLogFile(False, True, results.warnFile) 702 703 baseDir = results.baseDir 704 705 for file in results.files: 706 genRef(file, baseDir) 707 708 # Now figure out which pages *weren't* generated from the spec. 709 # This relies on the dictionaries of API constructs in the api module. 710 711 if not results.noauto: 712 713 registry = Registry() 714 registry.loadFile(results.registry) 715 716 if conventions.write_refpage_include: 717 # Only extensions with a supported="..." attribute in this set 718 # will be considered for extraction/generation. 719 supported_strings = set((conventions.xml_supported_name_of_api,)) 720 ext_names = set(k for k, v in registry.extdict.items() 721 if v.supported in supported_strings) 722 723 desired_extensions = ext_names.intersection(set(results.extension)) 724 for prefix in conventions.extension_index_prefixes: 725 # Splits up into chunks, sorted within each chunk. 726 filtered_extensions = sorted( 727 [name for name in desired_extensions 728 if name.startswith(prefix) and name not in extensions]) 729 for name in filtered_extensions: 730 extensions[name] = None 731 genExtension(baseDir, name, registry.extdict[name]) 732 733 # autoGenFlagsPage is no longer needed because they are added to 734 # the spec sources now. 735 # for page in api.flags: 736 # if page not in genDict: 737 # autoGenFlagsPage(baseDir, page) 738 739 # autoGenHandlePage is no longer needed because they are added to 740 # the spec sources now. 741 # for page in api.structs: 742 # if typeCategory[page] == 'handle': 743 # autoGenHandlePage(baseDir, page) 744 745 sections = [ 746 ( api.flags, 'Flag Types' ), 747 ( api.enums, 'Enumerated Types' ), 748 ( api.structs, 'Structures' ), 749 ( api.protos, 'Prototypes' ), 750 ( api.funcpointers, 'Function Pointers' ), 751 ( api.basetypes, apiName + ' Scalar Types' ), 752 ( extensions, apiName + ' Extensions'), 753 ] 754 755 # Summarize pages that weren't generated, for good or bad reasons 756 757 for (apiDict,title) in sections: 758 # OpenXR was keeping a 'flagged' state which only printed out a 759 # warning for the first non-generated page, but was otherwise 760 # unused. This doesn't seem helpful. 761 for page in apiDict: 762 if page not in genDict: 763 # Page was not generated - why not? 764 if page in api.alias: 765 logWarn('(Benign, is an alias) Ref page for', title, page, 'is aliased into', api.alias[page]) 766 elif page in api.flags and api.flags[page] is None: 767 logWarn('(Benign, no FlagBits defined) No ref page generated for ', title, 768 page) 769 else: 770 # Could introduce additional logic to detect 771 # external types and not emit them. 772 logWarn('No ref page generated for ', title, page) 773 774 genSinglePageRef(baseDir)