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"
23 html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
25 print('Install the sphinx ReadTheDocs theme for improved html documentation '
26 'layout: https://sphinx-rtd-theme.readthedocs.io/',
30 stop_on_error = ('-W' in argv)
32 project = 'Data Plane Development Kit'
33 html_logo = '../logo/DPDK_logo_vertical_rev_small.png'
34 latex_logo = '../logo/DPDK_logo_horizontal_tag.png'
35 html_add_permalinks = ""
36 html_show_copyright = False
37 highlight_language = 'none'
39 release = environ.setdefault('DPDK_VERSION', "None")
44 # Maximum feature description string length
47 # Figures, tables and code-blocks automatically numbered if they have caption
58 # Latex directives to be included directly in the latex/pdf docs.
59 custom_latex_preamble = r"""
60 \usepackage{textalpha}
61 \RecustomVerbatimEnvironment{Verbatim}{Verbatim}{xleftmargin=5mm}
67 # Configuration for the latex/pdf docs.
69 'papersize': 'a4paper',
72 'classoptions': ',openany,oneside',
73 'babel': '\\usepackage[english]{babel}',
74 # customize Latex formatting
75 'preamble': custom_latex_preamble
79 # Override the default Latex formatter in order to modify the
80 # code/verbatim blocks.
81 class CustomLatexFormatter(LatexFormatter):
82 def __init__(self, **options):
83 super(CustomLatexFormatter, self).__init__(**options)
84 # Use the second smallest font size for code/verbatim blocks.
85 self.verboptions = r'formatcom=\footnotesize'
87 # Replace the default latex formatter.
88 PygmentsBridge.latex_formatter = CustomLatexFormatter
90 # Configuration for man pages
91 man_pages = [("testpmd_app_ug/run_app", "testpmd",
92 "tests for dpdk pmds", "", 1),
93 ("tools/pdump", "dpdk-pdump",
94 "enable packet capture on dpdk ports", "", 1),
95 ("tools/proc_info", "dpdk-procinfo",
96 "access dpdk port stats and memory info", "", 1),
97 ("tools/pmdinfo", "dpdk-pmdinfo",
98 "dump a PMDs hardware support info", "", 1),
99 ("tools/devbind", "dpdk-devbind",
100 "check device status and bind/unbind them from drivers", "", 8)]
103 # ####### :numref: fallback ########
104 # The following hook functions add some simple handling for the :numref:
105 # directive for Sphinx versions prior to 1.3.1. The functions replace the
106 # :numref: reference with a link to the target (for all Sphinx doc types).
107 # It doesn't try to label figures/tables.
108 def numref_role(reftype, rawtext, text, lineno, inliner):
110 Add a Sphinx role to handle numref references. Note, we can't convert
111 the link here because the doctree isn't build and the target information
114 # Add an identifier to distinguish numref from other references.
115 newnode = nodes.reference('',
117 refuri='_local_numref_#%s' % text,
122 def process_numref(app, doctree, from_docname):
124 Process the numref nodes once the doctree has been built and prior to
125 writing the files. The processing involves replacing the numref with a
126 link plus text to indicate if it is a Figure or Table link.
129 # Iterate over the reference nodes in the doctree.
130 for node in doctree.traverse(nodes.reference):
131 target = node.get('refuri', '')
133 # Look for numref nodes.
134 if target.startswith('_local_numref_#'):
135 target = target.replace('_local_numref_#', '')
137 # Get the target label and link information from the Sphinx env.
138 data = app.builder.env.domains['std'].data
139 docname, label, _ = data['labels'].get(target, ('', '', ''))
140 relative_url = app.builder.get_relative_uri(from_docname, docname)
142 # Add a text label to the link.
143 if target.startswith('figure'):
145 elif target.startswith('table'):
150 # New reference node with the updated link information.
151 newnode = nodes.reference('',
153 refuri='%s#%s' % (relative_url, label),
155 node.replace_self(newnode)
158 def generate_overview_table(output_filename, table_id, section, table_name, title):
160 Function to generate the Overview Table from the ini files that define
161 the features for each driver.
163 The default features for the table and their order is defined by the
167 # Default warning string.
168 warning = 'Warning generate_overview_table()'
170 # Get the default features and order from the 'default.ini' file.
171 ini_path = path_join(dirname(output_filename), 'features')
172 config = configparser.ConfigParser()
173 config.optionxform = str
174 config.read(path_join(ini_path, 'default.ini'))
175 default_features = config.items(section)
177 # Create a dict of the valid features to validate the other ini files.
179 max_feature_length = 0
180 for feature in default_features:
182 valid_features[key] = ' '
183 max_feature_length = max(max_feature_length, len(key))
185 # Get a list of driver ini files, excluding 'default.ini'.
186 ini_files = [basename(file) for file in listdir(ini_path)
187 if file.endswith('.ini') and file != 'default.ini']
190 # Build up a list of the table header names from the ini filenames.
192 for ini_filename in ini_files:
193 name = ini_filename[:-4]
194 name = name.replace('_vf', 'vf')
195 pmd_names.append(name)
197 # Pad the table header names.
198 max_header_len = len(max(pmd_names, key=len))
200 for name in pmd_names:
202 pmd, vec = name.split('_')
203 name = '{0:{fill}{align}{width}}vec'.format(pmd,
204 fill='.', align='<', width=max_header_len-3)
206 name = '{0:{fill}{align}{width}}'.format(name,
207 fill=' ', align='<', width=max_header_len)
208 header_names.append(name)
210 # Create a dict of the defined features for each driver from the ini files.
212 for ini_filename in ini_files:
213 config = configparser.ConfigParser()
214 config.optionxform = str
215 config.read(path_join(ini_path, ini_filename))
217 # Initialize the dict with the default.ini value.
218 ini_data[ini_filename] = valid_features.copy()
220 # Check for a valid ini section.
221 if not config.has_section(section):
222 print("{}: File '{}' has no [{}] secton".format(warning,
227 raise Exception('Warning is treated as a failure')
230 # Check for valid features names.
231 for name, value in config.items(section):
232 if name not in valid_features:
233 print("{}: Unknown feature '{}' in '{}'".format(warning,
238 raise Exception('Warning is treated as a failure')
242 # Get the first letter only.
243 ini_data[ini_filename][name] = value[0]
245 # Print out the RST Driver Overview table from the ini file data.
246 outfile = open(output_filename, 'w')
247 num_cols = len(header_names)
249 print_table_css(outfile, table_id)
250 print('.. table:: ' + table_name + '\n', file=outfile)
251 print_table_header(outfile, num_cols, header_names, title)
252 print_table_body(outfile, num_cols, ini_files, ini_data, default_features)
255 def print_table_header(outfile, num_cols, header_names, title):
256 """ Print the RST table header. The header names are vertical. """
257 print_table_divider(outfile, num_cols)
260 for name in header_names:
261 line += ' ' + name[0]
263 print_table_row(outfile, title, line)
265 for i in range(1, len(header_names[0])):
267 for name in header_names:
268 line += ' ' + name[i]
270 print_table_row(outfile, '', line)
272 print_table_divider(outfile, num_cols)
275 def print_table_body(outfile, num_cols, ini_files, ini_data, default_features):
276 """ Print out the body of the table. Each row is a NIC feature. """
278 for feature, _ in default_features:
281 for ini_filename in ini_files:
282 line += ' ' + ini_data[ini_filename][feature]
284 print_table_row(outfile, feature, line)
286 print_table_divider(outfile, num_cols)
289 def print_table_row(outfile, feature, line):
290 """ Print a single row of the table with fixed formatting. """
292 print(' {:<{}}{}'.format(feature, feature_str_len, line), file=outfile)
295 def print_table_divider(outfile, num_cols):
296 """ Print the table divider line. """
298 column_dividers = ['='] * num_cols
299 line += ' '.join(column_dividers)
301 feature = '=' * feature_str_len
303 print_table_row(outfile, feature, line)
306 def print_table_css(outfile, table_id):
320 line-height: inherit;
322 table#idx th, table#idx td {
324 border: solid 1px #ddd;
329 table#idx th, table#idx th p {
331 white-space: pre-wrap;
335 table#idx col:first-child {
338 table#idx th:first-child {
339 vertical-align: bottom;
344 table#idx td, table#idx td p {
347 table#idx td:first-child {
351 table#idx tr:nth-child(2n-1) td {
352 background-color: rgba(210, 210, 210, 0.2);
354 table#idx th:not(:first-child):hover,
355 table#idx td:not(:first-child):hover {
358 table#idx th:not(:first-child):hover::after,
359 table#idx td:not(:first-child):hover::after {
367 background-color: #ffb;
369 table#idx tr:hover td {
370 background-color: #ffb;
374 print(template.replace("idx", "id%d" % (table_id)), file=outfile)
378 table_file = dirname(__file__) + '/nics/overview_table.txt'
379 generate_overview_table(table_file, 1,
381 'Features availability in networking drivers',
383 table_file = dirname(__file__) + '/cryptodevs/overview_feature_table.txt'
384 generate_overview_table(table_file, 1,
386 'Features availability in crypto drivers',
388 table_file = dirname(__file__) + '/cryptodevs/overview_cipher_table.txt'
389 generate_overview_table(table_file, 2,
391 'Cipher algorithms in crypto drivers',
393 table_file = dirname(__file__) + '/cryptodevs/overview_auth_table.txt'
394 generate_overview_table(table_file, 3,
396 'Authentication algorithms in crypto drivers',
397 'Authentication algorithm')
398 table_file = dirname(__file__) + '/cryptodevs/overview_aead_table.txt'
399 generate_overview_table(table_file, 4,
401 'AEAD algorithms in crypto drivers',
403 table_file = dirname(__file__) + '/cryptodevs/overview_asym_table.txt'
404 generate_overview_table(table_file, 5,
406 'Asymmetric algorithms in crypto drivers',
407 'Asymmetric algorithm')
408 table_file = dirname(__file__) + '/compressdevs/overview_feature_table.txt'
409 generate_overview_table(table_file, 1,
411 'Features availability in compression drivers',
413 table_file = dirname(__file__) + '/regexdevs/overview_feature_table.txt'
414 generate_overview_table(table_file, 1,
416 'Features availability in regex drivers',
418 table_file = dirname(__file__) + '/vdpadevs/overview_feature_table.txt'
419 generate_overview_table(table_file, 1,
421 'Features availability in vDPA drivers',
423 table_file = dirname(__file__) + '/bbdevs/overview_feature_table.txt'
424 generate_overview_table(table_file, 1,
426 'Features availability in bbdev drivers',
429 if LooseVersion(sphinx_version) < LooseVersion('1.3.1'):
430 print('Upgrade sphinx to version >= 1.3.1 for '
431 'improved Figure/Table number handling.',
433 # Add a role to handle :numref: references.
434 app.add_role('numref', numref_role)
435 # Process the numref references once the doctree has been created.
436 app.connect('doctree-resolved', process_numref)
439 # New function in sphinx 1.8
440 app.add_css_file('css/custom.css')
442 app.add_stylesheet('css/custom.css')