2 # SPDX-License-Identifier: BSD-3-Clause
3 # Copyright(c) 2010-2015 Intel Corporation
5 from docutils import nodes
6 from distutils.version import LooseVersion
7 from sphinx import __version__ as sphinx_version
8 from sphinx.highlighting import PygmentsBridge
9 from pygments.formatters.latex import LatexFormatter
10 from os import listdir
11 from os import environ
12 from os.path import basename
13 from os.path import dirname
14 from os.path import join as path_join
15 from sys import argv, stderr
20 import sphinx_rtd_theme
22 html_theme = "sphinx_rtd_theme"
24 print('Install the sphinx ReadTheDocs theme for improved html documentation '
25 'layout: https://sphinx-rtd-theme.readthedocs.io/',
29 stop_on_error = ('-W' in argv)
31 project = 'Data Plane Development Kit'
32 html_logo = '../logo/DPDK_logo_vertical_rev_small.png'
33 latex_logo = '../logo/DPDK_logo_horizontal_tag.png'
34 html_add_permalinks = ""
35 html_show_copyright = False
36 highlight_language = 'none'
38 release = environ.setdefault('DPDK_VERSION', "None")
43 # Maximum feature description string length
46 # Figures, tables and code-blocks automatically numbered if they have caption
57 # Latex directives to be included directly in the latex/pdf docs.
58 custom_latex_preamble = r"""
59 \usepackage{textalpha}
60 \RecustomVerbatimEnvironment{Verbatim}{Verbatim}{xleftmargin=5mm}
66 # Configuration for the latex/pdf docs.
68 'papersize': 'a4paper',
71 'classoptions': ',openany,oneside',
72 'babel': '\\usepackage[english]{babel}',
73 # customize Latex formatting
74 'preamble': custom_latex_preamble
78 # Override the default Latex formatter in order to modify the
79 # code/verbatim blocks.
80 class CustomLatexFormatter(LatexFormatter):
81 def __init__(self, **options):
82 super(CustomLatexFormatter, self).__init__(**options)
83 # Use the second smallest font size for code/verbatim blocks.
84 self.verboptions = r'formatcom=\footnotesize'
86 # Replace the default latex formatter.
87 PygmentsBridge.latex_formatter = CustomLatexFormatter
89 # Configuration for man pages
90 man_pages = [("testpmd_app_ug/run_app", "testpmd",
91 "tests for dpdk pmds", "", 1),
92 ("tools/pdump", "dpdk-pdump",
93 "enable packet capture on dpdk ports", "", 1),
94 ("tools/proc_info", "dpdk-procinfo",
95 "access dpdk port stats and memory info", "", 1),
96 ("tools/pmdinfo", "dpdk-pmdinfo",
97 "dump a PMDs hardware support info", "", 1),
98 ("tools/devbind", "dpdk-devbind",
99 "check device status and bind/unbind them from drivers", "", 8)]
102 # ####### :numref: fallback ########
103 # The following hook functions add some simple handling for the :numref:
104 # directive for Sphinx versions prior to 1.3.1. The functions replace the
105 # :numref: reference with a link to the target (for all Sphinx doc types).
106 # It doesn't try to label figures/tables.
107 def numref_role(reftype, rawtext, text, lineno, inliner):
109 Add a Sphinx role to handle numref references. Note, we can't convert
110 the link here because the doctree isn't build and the target information
113 # Add an identifier to distinguish numref from other references.
114 newnode = nodes.reference('',
116 refuri='_local_numref_#%s' % text,
121 def process_numref(app, doctree, from_docname):
123 Process the numref nodes once the doctree has been built and prior to
124 writing the files. The processing involves replacing the numref with a
125 link plus text to indicate if it is a Figure or Table link.
128 # Iterate over the reference nodes in the doctree.
129 for node in doctree.traverse(nodes.reference):
130 target = node.get('refuri', '')
132 # Look for numref nodes.
133 if target.startswith('_local_numref_#'):
134 target = target.replace('_local_numref_#', '')
136 # Get the target label and link information from the Sphinx env.
137 data = app.builder.env.domains['std'].data
138 docname, label, _ = data['labels'].get(target, ('', '', ''))
139 relative_url = app.builder.get_relative_uri(from_docname, docname)
141 # Add a text label to the link.
142 if target.startswith('figure'):
144 elif target.startswith('table'):
149 # New reference node with the updated link information.
150 newnode = nodes.reference('',
152 refuri='%s#%s' % (relative_url, label),
154 node.replace_self(newnode)
157 def generate_overview_table(output_filename, table_id, section, table_name, title):
159 Function to generate the Overview Table from the ini files that define
160 the features for each driver.
162 The default features for the table and their order is defined by the
166 # Default warning string.
167 warning = 'Warning generate_overview_table()'
169 # Get the default features and order from the 'default.ini' file.
170 ini_path = path_join(dirname(output_filename), 'features')
171 config = configparser.ConfigParser()
172 config.optionxform = str
173 config.read(path_join(ini_path, 'default.ini'))
174 default_features = config.items(section)
176 # Create a dict of the valid features to validate the other ini files.
178 max_feature_length = 0
179 for feature in default_features:
181 valid_features[key] = ' '
182 max_feature_length = max(max_feature_length, len(key))
184 # Get a list of driver ini files, excluding 'default.ini'.
185 ini_files = [basename(file) for file in listdir(ini_path)
186 if file.endswith('.ini') and file != 'default.ini']
189 # Build up a list of the table header names from the ini filenames.
191 for ini_filename in ini_files:
192 name = ini_filename[:-4]
193 name = name.replace('_vf', 'vf')
194 pmd_names.append(name)
196 # Pad the table header names.
197 max_header_len = len(max(pmd_names, key=len))
199 for name in pmd_names:
201 pmd, vec = name.split('_')
202 name = '{0:{fill}{align}{width}}vec'.format(pmd,
203 fill='.', align='<', width=max_header_len-3)
205 name = '{0:{fill}{align}{width}}'.format(name,
206 fill=' ', align='<', width=max_header_len)
207 header_names.append(name)
209 # Create a dict of the defined features for each driver from the ini files.
211 for ini_filename in ini_files:
212 config = configparser.ConfigParser()
213 config.optionxform = str
214 config.read(path_join(ini_path, ini_filename))
216 # Initialize the dict with the default.ini value.
217 ini_data[ini_filename] = valid_features.copy()
219 # Check for a valid ini section.
220 if not config.has_section(section):
221 print("{}: File '{}' has no [{}] secton".format(warning,
226 raise Exception('Warning is treated as a failure')
229 # Check for valid features names.
230 for name, value in config.items(section):
231 if name not in valid_features:
232 print("{}: Unknown feature '{}' in '{}'".format(warning,
237 raise Exception('Warning is treated as a failure')
241 # Get the first letter only.
242 ini_data[ini_filename][name] = value[0]
244 # Print out the RST Driver Overview table from the ini file data.
245 outfile = open(output_filename, 'w')
246 num_cols = len(header_names)
248 print_table_css(outfile, table_id)
249 print('.. table:: ' + table_name + '\n', file=outfile)
250 print_table_header(outfile, num_cols, header_names, title)
251 print_table_body(outfile, num_cols, ini_files, ini_data, default_features)
254 def print_table_header(outfile, num_cols, header_names, title):
255 """ Print the RST table header. The header names are vertical. """
256 print_table_divider(outfile, num_cols)
259 for name in header_names:
260 line += ' ' + name[0]
262 print_table_row(outfile, title, line)
264 for i in range(1, len(header_names[0])):
266 for name in header_names:
267 line += ' ' + name[i]
269 print_table_row(outfile, '', line)
271 print_table_divider(outfile, num_cols)
274 def print_table_body(outfile, num_cols, ini_files, ini_data, default_features):
275 """ Print out the body of the table. Each row is a NIC feature. """
277 for feature, _ in default_features:
280 for ini_filename in ini_files:
281 line += ' ' + ini_data[ini_filename][feature]
283 print_table_row(outfile, feature, line)
285 print_table_divider(outfile, num_cols)
288 def print_table_row(outfile, feature, line):
289 """ Print a single row of the table with fixed formatting. """
291 print(' {:<{}}{}'.format(feature, feature_str_len, line), file=outfile)
294 def print_table_divider(outfile, num_cols):
295 """ Print the table divider line. """
297 column_dividers = ['='] * num_cols
298 line += ' '.join(column_dividers)
300 feature = '=' * feature_str_len
302 print_table_row(outfile, feature, line)
305 def print_table_css(outfile, table_id):
319 line-height: inherit;
321 table#idx th, table#idx td {
323 border: solid 1px #ddd;
328 table#idx th, table#idx th p {
330 white-space: pre-wrap;
334 table#idx col:first-child {
337 table#idx th:first-child {
338 vertical-align: bottom;
343 table#idx td, table#idx td p {
346 table#idx td:first-child {
350 table#idx tr:nth-child(2n-1) td {
351 background-color: rgba(210, 210, 210, 0.2);
353 table#idx th:not(:first-child):hover,
354 table#idx td:not(:first-child):hover {
357 table#idx th:not(:first-child):hover::after,
358 table#idx td:not(:first-child):hover::after {
366 background-color: #ffb;
368 table#idx tr:hover td {
369 background-color: #ffb;
373 print(template.replace("idx", "id%d" % (table_id)), file=outfile)
377 table_file = dirname(__file__) + '/nics/overview_table.txt'
378 generate_overview_table(table_file, 1,
380 'Features availability in networking drivers',
382 table_file = dirname(__file__) + '/cryptodevs/overview_feature_table.txt'
383 generate_overview_table(table_file, 1,
385 'Features availability in crypto drivers',
387 table_file = dirname(__file__) + '/cryptodevs/overview_cipher_table.txt'
388 generate_overview_table(table_file, 2,
390 'Cipher algorithms in crypto drivers',
392 table_file = dirname(__file__) + '/cryptodevs/overview_auth_table.txt'
393 generate_overview_table(table_file, 3,
395 'Authentication algorithms in crypto drivers',
396 'Authentication algorithm')
397 table_file = dirname(__file__) + '/cryptodevs/overview_aead_table.txt'
398 generate_overview_table(table_file, 4,
400 'AEAD algorithms in crypto drivers',
402 table_file = dirname(__file__) + '/cryptodevs/overview_asym_table.txt'
403 generate_overview_table(table_file, 5,
405 'Asymmetric algorithms in crypto drivers',
406 'Asymmetric algorithm')
407 table_file = dirname(__file__) + '/compressdevs/overview_feature_table.txt'
408 generate_overview_table(table_file, 1,
410 'Features availability in compression drivers',
412 table_file = dirname(__file__) + '/regexdevs/overview_feature_table.txt'
413 generate_overview_table(table_file, 1,
415 'Features availability in regex drivers',
417 table_file = dirname(__file__) + '/vdpadevs/overview_feature_table.txt'
418 generate_overview_table(table_file, 1,
420 'Features availability in vDPA drivers',
422 table_file = dirname(__file__) + '/bbdevs/overview_feature_table.txt'
423 generate_overview_table(table_file, 1,
425 'Features availability in bbdev drivers',
428 if LooseVersion(sphinx_version) < LooseVersion('1.3.1'):
429 print('Upgrade sphinx to version >= 1.3.1 for '
430 'improved Figure/Table number handling.',
432 # Add a role to handle :numref: references.
433 app.add_role('numref', numref_role)
434 # Process the numref references once the doctree has been created.
435 app.connect('doctree-resolved', process_numref)
438 # New function in sphinx 1.8
439 app.add_css_file('css/custom.css')
441 app.add_stylesheet('css/custom.css')