1765ce869SElvina Yakubova#!/usr/bin/env python3 2765ce869SElvina Yakubova# A tool to parse the output of `llvm-bolt --help-hidden` and update the 3765ce869SElvina Yakubova# documentation in CommandLineArgumentReference.md automatically. 4765ce869SElvina Yakubova# Run from the directory in which this file is located to update the docs. 5765ce869SElvina Yakubova 6765ce869SElvina Yakubovaimport subprocess 7765ce869SElvina Yakubovafrom textwrap import wrap 8765ce869SElvina Yakubova 9765ce869SElvina YakubovaLINE_LIMIT = 80 10765ce869SElvina Yakubova 11765ce869SElvina Yakubova 12765ce869SElvina Yakubovadef wrap_text(text, indent, limit=LINE_LIMIT): 13765ce869SElvina Yakubova wrapped_lines = wrap(text, width=limit - len(indent)) 14765ce869SElvina Yakubova wrapped_text = ("\n" + indent).join(wrapped_lines) 15765ce869SElvina Yakubova return wrapped_text 16765ce869SElvina Yakubova 17765ce869SElvina Yakubova 18765ce869SElvina Yakubovadef add_info(sections, section, option, description): 19765ce869SElvina Yakubova indent = " " 20765ce869SElvina Yakubova wrapped_description = "\n".join( 21765ce869SElvina Yakubova [ 22765ce869SElvina Yakubova wrap_text(line, indent) if len(line) > LINE_LIMIT else line 23765ce869SElvina Yakubova for line in description 24765ce869SElvina Yakubova ] 25765ce869SElvina Yakubova ) 26765ce869SElvina Yakubova sections[section].append((option, indent + wrapped_description)) 27765ce869SElvina Yakubova 28765ce869SElvina Yakubova 29765ce869SElvina Yakubovadef parse_bolt_options(output): 30765ce869SElvina Yakubova section_headers = [ 31765ce869SElvina Yakubova "Generic options:", 32765ce869SElvina Yakubova "Output options:", 33765ce869SElvina Yakubova "BOLT generic options:", 34765ce869SElvina Yakubova "BOLT optimization options:", 35765ce869SElvina Yakubova "BOLT options in relocation mode:", 36765ce869SElvina Yakubova "BOLT instrumentation options:", 37765ce869SElvina Yakubova "BOLT printing options:", 38765ce869SElvina Yakubova ] 39765ce869SElvina Yakubova 40765ce869SElvina Yakubova sections = {key: [] for key in section_headers} 41765ce869SElvina Yakubova current_section, prev_section = None, None 42765ce869SElvina Yakubova option, description = None, [] 43765ce869SElvina Yakubova 44765ce869SElvina Yakubova for line in output.split("\n"): 45765ce869SElvina Yakubova cleaned_line = line.strip() 46765ce869SElvina Yakubova 47765ce869SElvina Yakubova if cleaned_line.casefold() in map(str.casefold, section_headers): 48*8bc02bf5SEisuke Kawashima if prev_section is not None: # Save last option from prev section 49765ce869SElvina Yakubova add_info(sections, current_section, option, description) 50765ce869SElvina Yakubova option, description = None, [] 51765ce869SElvina Yakubova 52765ce869SElvina Yakubova cleaned_line = cleaned_line.split() 53765ce869SElvina Yakubova # Apply lowercase to all words except the first one 54765ce869SElvina Yakubova cleaned_line = [cleaned_line[0]] + [ 55765ce869SElvina Yakubova word.lower() for word in cleaned_line[1:] 56765ce869SElvina Yakubova ] 57765ce869SElvina Yakubova # Join the words back together into a string 58765ce869SElvina Yakubova cleaned_line = " ".join(cleaned_line) 59765ce869SElvina Yakubova 60765ce869SElvina Yakubova current_section = cleaned_line 61765ce869SElvina Yakubova prev_section = current_section 62765ce869SElvina Yakubova continue 63765ce869SElvina Yakubova 64765ce869SElvina Yakubova if cleaned_line.startswith("-"): 65765ce869SElvina Yakubova if option and description: 66765ce869SElvina Yakubova # Join description lines, adding an extra newline for 67765ce869SElvina Yakubova # sub-options that start with '=' 68765ce869SElvina Yakubova add_info(sections, current_section, option, description) 69765ce869SElvina Yakubova option, description = None, [] 70765ce869SElvina Yakubova 71765ce869SElvina Yakubova parts = cleaned_line.split(" ", 1) 72765ce869SElvina Yakubova if len(parts) > 1: 73765ce869SElvina Yakubova option = parts[0].strip() 74765ce869SElvina Yakubova descr = parts[1].strip() 75765ce869SElvina Yakubova descr = descr[2].upper() + descr[3:] 76765ce869SElvina Yakubova description = [descr] 77765ce869SElvina Yakubova if option.startswith("--print") or option.startswith("--time"): 78765ce869SElvina Yakubova current_section = "BOLT printing options:" 79*8bc02bf5SEisuke Kawashima elif prev_section is not None: 80765ce869SElvina Yakubova current_section = prev_section 81765ce869SElvina Yakubova continue 82765ce869SElvina Yakubova 83765ce869SElvina Yakubova if cleaned_line.startswith("="): 84765ce869SElvina Yakubova parts = cleaned_line.split(maxsplit=1) 85765ce869SElvina Yakubova # Split into two parts: sub-option and description 86765ce869SElvina Yakubova if len(parts) == 2: 87765ce869SElvina Yakubova # Rejoin with a single space 88765ce869SElvina Yakubova cleaned_line = parts[0] + " " + parts[1].rstrip() 89765ce869SElvina Yakubova description.append(cleaned_line) 90765ce869SElvina Yakubova elif cleaned_line: # Multiline description continuation 91765ce869SElvina Yakubova description.append(cleaned_line) 92765ce869SElvina Yakubova 93765ce869SElvina Yakubova add_info(sections, current_section, option, description) 94765ce869SElvina Yakubova return sections 95765ce869SElvina Yakubova 96765ce869SElvina Yakubova 97765ce869SElvina Yakubovadef generate_markdown(sections): 98765ce869SElvina Yakubova markdown_lines = [ 99765ce869SElvina Yakubova "# BOLT - a post-link optimizer developed to speed up large applications\n", 100765ce869SElvina Yakubova "## SYNOPSIS\n", 101765ce869SElvina Yakubova "`llvm-bolt <executable> [-o outputfile] <executable>.bolt " 102765ce869SElvina Yakubova "[-data=perf.fdata] [options]`\n", 103765ce869SElvina Yakubova "## OPTIONS", 104765ce869SElvina Yakubova ] 105765ce869SElvina Yakubova 106765ce869SElvina Yakubova for section, options in sections.items(): 107765ce869SElvina Yakubova markdown_lines.append(f"\n### {section}") 108765ce869SElvina Yakubova if section == "BOLT instrumentation options:": 109765ce869SElvina Yakubova markdown_lines.append( 110765ce869SElvina Yakubova f"\n`llvm-bolt <executable> -instrument" 111765ce869SElvina Yakubova " [-o outputfile] <instrumented-executable>`" 112765ce869SElvina Yakubova ) 113765ce869SElvina Yakubova for option, desc in options: 114765ce869SElvina Yakubova markdown_lines.append(f"\n- `{option}`\n") 115765ce869SElvina Yakubova # Split description into lines to handle sub-options 116765ce869SElvina Yakubova desc_lines = desc.split("\n") 117765ce869SElvina Yakubova for line in desc_lines: 118765ce869SElvina Yakubova if line.startswith("="): 119765ce869SElvina Yakubova # Sub-option: correct formatting with bullet 120765ce869SElvina Yakubova sub_option, sub_desc = line[1:].split(" ", 1) 121765ce869SElvina Yakubova markdown_lines.append(f" - `{sub_option}`: {sub_desc[4:]}") 122765ce869SElvina Yakubova else: 123765ce869SElvina Yakubova # Regular line of description 124765ce869SElvina Yakubova if line[2:].startswith("<"): 125765ce869SElvina Yakubova line = line.replace("<", "").replace(">", "") 126765ce869SElvina Yakubova markdown_lines.append(f"{line}") 127765ce869SElvina Yakubova 128765ce869SElvina Yakubova return "\n".join(markdown_lines) 129765ce869SElvina Yakubova 130765ce869SElvina Yakubova 131765ce869SElvina Yakubovadef main(): 132765ce869SElvina Yakubova try: 133765ce869SElvina Yakubova help_output = subprocess.run( 134765ce869SElvina Yakubova ["llvm-bolt", "--help-hidden"], capture_output=True, text=True, check=True 135765ce869SElvina Yakubova ).stdout 136765ce869SElvina Yakubova except subprocess.CalledProcessError as e: 137765ce869SElvina Yakubova print("Failed to execute llvm-bolt --help:") 138765ce869SElvina Yakubova print(e) 139765ce869SElvina Yakubova return 140765ce869SElvina Yakubova 141765ce869SElvina Yakubova sections = parse_bolt_options(help_output) 142765ce869SElvina Yakubova markdown = generate_markdown(sections) 143765ce869SElvina Yakubova 144765ce869SElvina Yakubova with open("CommandLineArgumentReference.md", "w") as md_file: 145765ce869SElvina Yakubova md_file.write(markdown) 146765ce869SElvina Yakubova 147765ce869SElvina Yakubova 148765ce869SElvina Yakubovaif __name__ == "__main__": 149765ce869SElvina Yakubova main() 150