#!/usr/bin/env python3 # A tool to parse the output of `llvm-bolt --help-hidden` and update the # documentation in CommandLineArgumentReference.md automatically. # Run from the directory in which this file is located to update the docs. import subprocess from textwrap import wrap LINE_LIMIT = 80 def wrap_text(text, indent, limit=LINE_LIMIT): wrapped_lines = wrap(text, width=limit - len(indent)) wrapped_text = ("\n" + indent).join(wrapped_lines) return wrapped_text def add_info(sections, section, option, description): indent = " " wrapped_description = "\n".join( [ wrap_text(line, indent) if len(line) > LINE_LIMIT else line for line in description ] ) sections[section].append((option, indent + wrapped_description)) def parse_bolt_options(output): section_headers = [ "Generic options:", "Output options:", "BOLT generic options:", "BOLT optimization options:", "BOLT options in relocation mode:", "BOLT instrumentation options:", "BOLT printing options:", ] sections = {key: [] for key in section_headers} current_section, prev_section = None, None option, description = None, [] for line in output.split("\n"): cleaned_line = line.strip() if cleaned_line.casefold() in map(str.casefold, section_headers): if prev_section is not None: # Save last option from prev section add_info(sections, current_section, option, description) option, description = None, [] cleaned_line = cleaned_line.split() # Apply lowercase to all words except the first one cleaned_line = [cleaned_line[0]] + [ word.lower() for word in cleaned_line[1:] ] # Join the words back together into a string cleaned_line = " ".join(cleaned_line) current_section = cleaned_line prev_section = current_section continue if cleaned_line.startswith("-"): if option and description: # Join description lines, adding an extra newline for # sub-options that start with '=' add_info(sections, current_section, option, description) option, description = None, [] parts = cleaned_line.split(" ", 1) if len(parts) > 1: option = parts[0].strip() descr = parts[1].strip() descr = descr[2].upper() + descr[3:] description = [descr] if option.startswith("--print") or option.startswith("--time"): current_section = "BOLT printing options:" elif prev_section is not None: current_section = prev_section continue if cleaned_line.startswith("="): parts = cleaned_line.split(maxsplit=1) # Split into two parts: sub-option and description if len(parts) == 2: # Rejoin with a single space cleaned_line = parts[0] + " " + parts[1].rstrip() description.append(cleaned_line) elif cleaned_line: # Multiline description continuation description.append(cleaned_line) add_info(sections, current_section, option, description) return sections def generate_markdown(sections): markdown_lines = [ "# BOLT - a post-link optimizer developed to speed up large applications\n", "## SYNOPSIS\n", "`llvm-bolt [-o outputfile] .bolt " "[-data=perf.fdata] [options]`\n", "## OPTIONS", ] for section, options in sections.items(): markdown_lines.append(f"\n### {section}") if section == "BOLT instrumentation options:": markdown_lines.append( f"\n`llvm-bolt -instrument" " [-o outputfile] `" ) for option, desc in options: markdown_lines.append(f"\n- `{option}`\n") # Split description into lines to handle sub-options desc_lines = desc.split("\n") for line in desc_lines: if line.startswith("="): # Sub-option: correct formatting with bullet sub_option, sub_desc = line[1:].split(" ", 1) markdown_lines.append(f" - `{sub_option}`: {sub_desc[4:]}") else: # Regular line of description if line[2:].startswith("<"): line = line.replace("<", "").replace(">", "") markdown_lines.append(f"{line}") return "\n".join(markdown_lines) def main(): try: help_output = subprocess.run( ["llvm-bolt", "--help-hidden"], capture_output=True, text=True, check=True ).stdout except subprocess.CalledProcessError as e: print("Failed to execute llvm-bolt --help:") print(e) return sections = parse_bolt_options(help_output) markdown = generate_markdown(sections) with open("CommandLineArgumentReference.md", "w") as md_file: md_file.write(markdown) if __name__ == "__main__": main()