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.
7 from textwrap
import wrap
12 def wrap_text(text
, indent
, limit
=LINE_LIMIT
):
13 wrapped_lines
= wrap(text
, width
=limit
- len(indent
))
14 wrapped_text
= ("\n" + indent
).join(wrapped_lines
)
18 def add_info(sections
, section
, option
, description
):
20 wrapped_description
= "\n".join(
22 wrap_text(line
, indent
) if len(line
) > LINE_LIMIT
else line
23 for line
in description
26 sections
[section
].append((option
, indent
+ wrapped_description
))
29 def parse_bolt_options(output
):
33 "BOLT generic options:",
34 "BOLT optimization options:",
35 "BOLT options in relocation mode:",
36 "BOLT instrumentation options:",
37 "BOLT printing options:",
40 sections
= {key
: [] for key
in section_headers
}
41 current_section
, prev_section
= None, None
42 option
, description
= None, []
44 for line
in output
.split("\n"):
45 cleaned_line
= line
.strip()
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, []
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:]
57 # Join the words back together into a string
58 cleaned_line
= " ".join(cleaned_line
)
60 current_section
= cleaned_line
61 prev_section
= current_section
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, []
71 parts
= cleaned_line
.split(" ", 1)
73 option
= parts
[0].strip()
74 descr
= parts
[1].strip()
75 descr
= descr
[2].upper() + descr
[3:]
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
83 if cleaned_line
.startswith("="):
84 parts
= cleaned_line
.split(maxsplit
=1)
85 # Split into two parts: sub-option and description
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
)
93 add_info(sections
, current_section
, option
, description
)
97 def generate_markdown(sections
):
99 "# BOLT - a post-link optimizer developed to speed up large applications\n",
101 "`llvm-bolt <executable> [-o outputfile] <executable>.bolt "
102 "[-data=perf.fdata] [options]`\n",
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>`"
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:]}")
123 # Regular line of description
124 if line
[2:].startswith("<"):
125 line
= line
.replace("<", "").replace(">", "")
126 markdown_lines
.append(f
"{line}")
128 return "\n".join(markdown_lines
)
133 help_output
= subprocess
.run(
134 ["llvm-bolt", "--help-hidden"], capture_output
=True, text
=True, check
=True
136 except subprocess
.CalledProcessError
as e
:
137 print("Failed to execute llvm-bolt --help:")
141 sections
= parse_bolt_options(help_output
)
142 markdown
= generate_markdown(sections
)
144 with
open("CommandLineArgumentReference.md", "w") as md_file
:
145 md_file
.write(markdown
)
148 if __name__
== "__main__":