1#!/usr/bin/env python3 2# A tool to parse the output of `llvm-bolt --help-hidden` and update the 3# documentation in CommandLineArgumentReference.md automatically. 4# Run from the directory in which this file is located to update the docs. 5 6import subprocess 7from textwrap import wrap 8 9LINE_LIMIT = 80 10 11 12def wrap_text(text, indent, limit=LINE_LIMIT): 13 wrapped_lines = wrap(text, width=limit - len(indent)) 14 wrapped_text = ("\n" + indent).join(wrapped_lines) 15 return wrapped_text 16 17 18def add_info(sections, section, option, description): 19 indent = " " 20 wrapped_description = "\n".join( 21 [ 22 wrap_text(line, indent) if len(line) > LINE_LIMIT else line 23 for line in description 24 ] 25 ) 26 sections[section].append((option, indent + wrapped_description)) 27 28 29def parse_bolt_options(output): 30 section_headers = [ 31 "Generic options:", 32 "Output options:", 33 "BOLT generic options:", 34 "BOLT optimization options:", 35 "BOLT options in relocation mode:", 36 "BOLT instrumentation options:", 37 "BOLT printing options:", 38 ] 39 40 sections = {key: [] for key in section_headers} 41 current_section, prev_section = None, None 42 option, description = None, [] 43 44 for line in output.split("\n"): 45 cleaned_line = line.strip() 46 47 if cleaned_line.casefold() in map(str.casefold, section_headers): 48 if prev_section is not None: # Save last option from prev section 49 add_info(sections, current_section, option, description) 50 option, description = None, [] 51 52 cleaned_line = cleaned_line.split() 53 # Apply lowercase to all words except the first one 54 cleaned_line = [cleaned_line[0]] + [ 55 word.lower() for word in cleaned_line[1:] 56 ] 57 # Join the words back together into a string 58 cleaned_line = " ".join(cleaned_line) 59 60 current_section = cleaned_line 61 prev_section = current_section 62 continue 63 64 if cleaned_line.startswith("-"): 65 if option and description: 66 # Join description lines, adding an extra newline for 67 # sub-options that start with '=' 68 add_info(sections, current_section, option, description) 69 option, description = None, [] 70 71 parts = cleaned_line.split(" ", 1) 72 if len(parts) > 1: 73 option = parts[0].strip() 74 descr = parts[1].strip() 75 descr = descr[2].upper() + descr[3:] 76 description = [descr] 77 if option.startswith("--print") or option.startswith("--time"): 78 current_section = "BOLT printing options:" 79 elif prev_section is not None: 80 current_section = prev_section 81 continue 82 83 if cleaned_line.startswith("="): 84 parts = cleaned_line.split(maxsplit=1) 85 # Split into two parts: sub-option and description 86 if len(parts) == 2: 87 # Rejoin with a single space 88 cleaned_line = parts[0] + " " + parts[1].rstrip() 89 description.append(cleaned_line) 90 elif cleaned_line: # Multiline description continuation 91 description.append(cleaned_line) 92 93 add_info(sections, current_section, option, description) 94 return sections 95 96 97def generate_markdown(sections): 98 markdown_lines = [ 99 "# BOLT - a post-link optimizer developed to speed up large applications\n", 100 "## SYNOPSIS\n", 101 "`llvm-bolt <executable> [-o outputfile] <executable>.bolt " 102 "[-data=perf.fdata] [options]`\n", 103 "## OPTIONS", 104 ] 105 106 for section, options in sections.items(): 107 markdown_lines.append(f"\n### {section}") 108 if section == "BOLT instrumentation options:": 109 markdown_lines.append( 110 f"\n`llvm-bolt <executable> -instrument" 111 " [-o outputfile] <instrumented-executable>`" 112 ) 113 for option, desc in options: 114 markdown_lines.append(f"\n- `{option}`\n") 115 # Split description into lines to handle sub-options 116 desc_lines = desc.split("\n") 117 for line in desc_lines: 118 if line.startswith("="): 119 # Sub-option: correct formatting with bullet 120 sub_option, sub_desc = line[1:].split(" ", 1) 121 markdown_lines.append(f" - `{sub_option}`: {sub_desc[4:]}") 122 else: 123 # Regular line of description 124 if line[2:].startswith("<"): 125 line = line.replace("<", "").replace(">", "") 126 markdown_lines.append(f"{line}") 127 128 return "\n".join(markdown_lines) 129 130 131def main(): 132 try: 133 help_output = subprocess.run( 134 ["llvm-bolt", "--help-hidden"], capture_output=True, text=True, check=True 135 ).stdout 136 except subprocess.CalledProcessError as e: 137 print("Failed to execute llvm-bolt --help:") 138 print(e) 139 return 140 141 sections = parse_bolt_options(help_output) 142 markdown = generate_markdown(sections) 143 144 with open("CommandLineArgumentReference.md", "w") as md_file: 145 md_file.write(markdown) 146 147 148if __name__ == "__main__": 149 main() 150