xref: /dpdk/doc/guides/conf.py (revision 8484d74bd656bc0e951a3ed4e0816ee0fea5e593)
1#!/usr/bin/env python3
2# SPDX-License-Identifier: BSD-3-Clause
3# Copyright(c) 2010-2015 Intel Corporation
4
5from docutils import nodes
6from packaging.version import Version
7from sphinx import __version__ as sphinx_version
8from os import listdir
9from os import environ
10from os.path import basename
11from os.path import dirname
12from os.path import join as path_join
13from sys import argv, stderr, path
14
15import configparser
16
17try:
18    import sphinx_rtd_theme
19    html_theme = "sphinx_rtd_theme"
20except ImportError:
21    print('Install the sphinx ReadTheDocs theme for improved html documentation '
22          'layout: https://sphinx-rtd-theme.readthedocs.io/',
23          file=stderr)
24    html_theme = "default"
25
26stop_on_error = ('-W' in argv)
27
28project = 'Data Plane Development Kit'
29html_logo = '../logo/DPDK_logo_vertical_rev_small.png'
30if Version(sphinx_version) >= Version('3.5'):
31    html_permalinks = False
32else:
33    html_add_permalinks = ""
34html_show_copyright = False
35highlight_language = 'none'
36
37release = environ.setdefault('DPDK_VERSION', "None")
38version = release
39
40master_doc = 'index'
41
42# Maximum feature description string length
43feature_str_len = 30
44
45# Figures, tables and code-blocks automatically numbered if they have caption
46numfig = True
47
48# Configuration for man pages
49man_pages = [("testpmd_app_ug/run_app", "testpmd",
50              "tests for dpdk pmds", "", 1),
51             ("tools/pdump", "dpdk-pdump",
52              "enable packet capture on dpdk ports", "", 1),
53             ("tools/proc_info", "dpdk-procinfo",
54              "access dpdk port stats and memory info", "", 1),
55             ("tools/pmdinfo", "dpdk-pmdinfo",
56              "dump a PMDs hardware support info", "", 1),
57             ("tools/devbind", "dpdk-devbind",
58              "check device status and bind/unbind them from drivers", "", 8)]
59
60# DTS API docs additional configuration
61if environ.get('DTS_DOC_BUILD'):
62    extensions = ['sphinx.ext.napoleon', 'sphinx.ext.autodoc', 'sphinx.ext.intersphinx']
63    # Napoleon enables the Google format of Python doscstrings.
64    napoleon_numpy_docstring = False
65    napoleon_attr_annotations = True
66    napoleon_preprocess_types = True
67
68    # Autodoc pulls documentation from code.
69    autodoc_default_options = {
70        'members': True,
71        'member-order': 'bysource',
72        'show-inheritance': True,
73    }
74    autodoc_class_signature = 'separated'
75    autodoc_typehints = 'both'
76    autodoc_typehints_format = 'short'
77    autodoc_typehints_description_target = 'documented'
78
79    # Intersphinx allows linking to external projects, such as Python docs.
80    intersphinx_mapping = {'python': ('https://docs.python.org/3', None)}
81
82    # DTS docstring options.
83    add_module_names = False
84    toc_object_entries = True
85    toc_object_entries_show_parents = 'hide'
86    # DTS Sidebar config.
87    if html_theme == "sphinx_rtd_theme":
88        html_theme_options = {
89            'collapse_navigation': False,
90            'navigation_depth': -1,  # unlimited depth
91        }
92
93    # Add path to DTS sources so that Sphinx can find them.
94    dpdk_root = dirname(dirname(dirname(__file__)))
95    path.append(path_join(dpdk_root, 'dts'))
96
97    # Get missing DTS dependencies. Add path to buildtools to find the get_missing_imports function.
98    path.append(path_join(dpdk_root, 'buildtools'))
99    import importlib
100    # Ignore missing imports from DTS dependencies, allowing us to build the docs without them.
101    # There's almost no difference between docs built with and without dependencies.
102    # The qualified names of imported objects are fully expanded with dependencies, such as:
103    # fabric.Connection (without) vs. fabric.connection.Connection (with)
104    autodoc_mock_imports = importlib.import_module('check-dts-requirements').get_missing_imports()
105
106
107# ####### :numref: fallback ########
108# The following hook functions add some simple handling for the :numref:
109# directive for Sphinx versions prior to 1.3.1. The functions replace the
110# :numref: reference with a link to the target (for all Sphinx doc types).
111# It doesn't try to label figures/tables.
112def numref_role(reftype, rawtext, text, lineno, inliner):
113    """
114    Add a Sphinx role to handle numref references. Note, we can't convert
115    the link here because the doctree isn't build and the target information
116    isn't available.
117    """
118    # Add an identifier to distinguish numref from other references.
119    newnode = nodes.reference('',
120                              '',
121                              refuri='_local_numref_#%s' % text,
122                              internal=True)
123    return [newnode], []
124
125
126def process_numref(app, doctree, from_docname):
127    """
128    Process the numref nodes once the doctree has been built and prior to
129    writing the files. The processing involves replacing the numref with a
130    link plus text to indicate if it is a Figure or Table link.
131    """
132
133    # Iterate over the reference nodes in the doctree.
134    for node in doctree.traverse(nodes.reference):
135        target = node.get('refuri', '')
136
137        # Look for numref nodes.
138        if target.startswith('_local_numref_#'):
139            target = target.replace('_local_numref_#', '')
140
141            # Get the target label and link information from the Sphinx env.
142            data = app.builder.env.domains['std'].data
143            docname, label, _ = data['labels'].get(target, ('', '', ''))
144            relative_url = app.builder.get_relative_uri(from_docname, docname)
145
146            # Add a text label to the link.
147            if target.startswith('figure'):
148                caption = 'Figure'
149            elif target.startswith('table'):
150                caption = 'Table'
151            else:
152                caption = 'Link'
153
154            # New reference node with the updated link information.
155            newnode = nodes.reference('',
156                                      caption,
157                                      refuri='%s#%s' % (relative_url, label),
158                                      internal=True)
159            node.replace_self(newnode)
160
161
162def generate_overview_table(output_filename, table_id, section, table_name, title):
163    """
164    Function to generate the Overview Table from the ini files that define
165    the features for each driver.
166
167    The default features for the table and their order is defined by the
168    'default.ini' file.
169
170    """
171    # Default warning string.
172    warning = 'Warning generate_overview_table()'
173
174    # Get the default features and order from the 'default.ini' file.
175    ini_path = path_join(dirname(output_filename), 'features')
176    config = configparser.ConfigParser()
177    config.optionxform = str
178    config.read(path_join(ini_path, 'default.ini'))
179    default_features = config.items(section)
180
181    # Create a dict of the valid features to validate the other ini files.
182    valid_features = {}
183    max_feature_length = 0
184    for feature in default_features:
185        key = feature[0]
186        valid_features[key] = ' '
187        max_feature_length = max(max_feature_length, len(key))
188
189    # Get a list of driver ini files, excluding 'default.ini'.
190    ini_files = [basename(file) for file in listdir(ini_path)
191                 if file.endswith('.ini') and file != 'default.ini']
192    ini_files.sort()
193
194    # Build up a list of the table header names from the ini filenames.
195    pmd_names = []
196    for ini_filename in ini_files:
197        name = ini_filename[:-4]
198        name = name.replace('_vf', 'vf')
199        pmd_names.append(name)
200    if not pmd_names:
201        # Add an empty column if table is empty (required by RST syntax)
202        pmd_names.append(' ')
203
204    # Pad the table header names.
205    max_header_len = len(max(pmd_names, key=len))
206    header_names = []
207    for name in pmd_names:
208        if '_vec' in name:
209            pmd, vec = name.split('_')
210            name = '{0:{fill}{align}{width}}vec'.format(pmd,
211                    fill='.', align='<', width=max_header_len-3)
212        else:
213            name = '{0:{fill}{align}{width}}'.format(name,
214                    fill=' ', align='<', width=max_header_len)
215        header_names.append(name)
216
217    # Create a dict of the defined features for each driver from the ini files.
218    ini_data = {}
219    for ini_filename in ini_files:
220        config = configparser.ConfigParser()
221        config.optionxform = str
222        config.read(path_join(ini_path, ini_filename))
223
224        # Initialize the dict with the default.ini value.
225        ini_data[ini_filename] = valid_features.copy()
226
227        # Check for a section.
228        if not config.has_section(section):
229            continue
230
231        # Check for valid features names.
232        for name, value in config.items(section):
233            if name not in valid_features:
234                print("{}: Unknown feature '{}' in '{}'".format(warning,
235                                                                name,
236                                                                ini_filename),
237                                                                file=stderr)
238                if stop_on_error:
239                    raise Exception('Warning is treated as a failure')
240                continue
241
242            if value:
243                # Get the first letter only.
244                ini_data[ini_filename][name] = value[0]
245
246    # Print out the RST Driver Overview table from the ini file data.
247    outfile = open(output_filename, 'w')
248    num_cols = len(header_names)
249
250    print_table_css(outfile, table_id)
251    print('.. _' + table_name + ':', file=outfile)
252    print('.. table:: ' + table_name + '\n', file=outfile)
253    print_table_header(outfile, num_cols, header_names, title)
254    print_table_body(outfile, num_cols, ini_files, ini_data, default_features)
255
256
257def print_table_header(outfile, num_cols, header_names, title):
258    """ Print the RST table header. The header names are vertical. """
259    print_table_divider(outfile, num_cols)
260
261    line = ''
262    for name in header_names:
263        line += ' ' + name[0]
264
265    print_table_row(outfile, title, line)
266
267    for i in range(1, len(header_names[0])):
268        line = ''
269        for name in header_names:
270            line += ' ' + name[i]
271
272        print_table_row(outfile, '', line)
273
274    print_table_divider(outfile, num_cols)
275
276
277def print_table_body(outfile, num_cols, ini_files, ini_data, default_features):
278    """ Print out the body of the table. Each row is a NIC feature. """
279
280    for feature, _ in default_features:
281        line = ''
282
283        for ini_filename in ini_files:
284            line += ' ' + ini_data[ini_filename][feature]
285
286        print_table_row(outfile, feature, line)
287
288    print_table_divider(outfile, num_cols)
289
290
291def print_table_row(outfile, feature, line):
292    """ Print a single row of the table with fixed formatting. """
293    line = line.rstrip()
294    print('   {:<{}}{}'.format(feature, feature_str_len, line), file=outfile)
295
296
297def print_table_divider(outfile, num_cols):
298    """ Print the table divider line. """
299    line = ' '
300    column_dividers = ['='] * num_cols
301    line += ' '.join(column_dividers)
302
303    feature = '=' * feature_str_len
304
305    print_table_row(outfile, feature, line)
306
307
308def print_table_css(outfile, table_id):
309    template = """
310.. raw:: html
311
312   <style>
313      .wy-nav-content {
314         opacity: .99;
315      }
316      table#idx {
317         cursor: default;
318         overflow: hidden;
319      }
320      table#idx p {
321         margin: 0;
322         line-height: inherit;
323      }
324      table#idx th, table#idx td {
325         text-align: center;
326         border: solid 1px #ddd;
327      }
328      table#idx th {
329         padding: 0.5em 0;
330      }
331      table#idx th, table#idx th p {
332         font-size: 11px;
333         white-space: pre-wrap;
334         vertical-align: top;
335         min-width: 0.9em;
336      }
337      table#idx col:first-child {
338         width: 0;
339      }
340      table#idx th:first-child {
341         vertical-align: bottom;
342      }
343      table#idx td {
344         padding: 1px;
345      }
346      table#idx td, table#idx td p {
347         font-size: 11px;
348      }
349      table#idx td:first-child {
350         padding-left: 1em;
351         text-align: left;
352      }
353      table#idx tr:nth-child(2n-1) td {
354         background-color: rgba(210, 210, 210, 0.2);
355      }
356      table#idx th:not(:first-child):hover,
357      table#idx td:not(:first-child):hover {
358         position: relative;
359      }
360      table#idx th:not(:first-child):hover::after,
361      table#idx td:not(:first-child):hover::after {
362         content: '';
363         height: 6000px;
364         top: -3000px;
365         width: 100%;
366         left: 0;
367         position: absolute;
368         z-index: -1;
369         background-color: #ffb;
370      }
371      table#idx tr:hover td {
372         background-color: #ffb;
373      }
374   </style>
375"""
376    print(template.replace("idx", "id%d" % (table_id)), file=outfile)
377
378
379def setup(app):
380    table_file = dirname(__file__) + '/nics/overview_table.txt'
381    generate_overview_table(table_file, 1,
382                            'Features',
383                            'Features availability in networking drivers',
384                            'Feature')
385    table_file = dirname(__file__) + '/nics/rte_flow_items_table.txt'
386    generate_overview_table(table_file, 2,
387                            'rte_flow items',
388                            'rte_flow items availability in networking drivers',
389                            'Item')
390    table_file = dirname(__file__) + '/nics/rte_flow_actions_table.txt'
391    generate_overview_table(table_file, 3,
392                            'rte_flow actions',
393                            'rte_flow actions availability in networking drivers',
394                            'Action')
395    table_file = dirname(__file__) + '/cryptodevs/overview_feature_table.txt'
396    generate_overview_table(table_file, 1,
397                            'Features',
398                            'Features availability in crypto drivers',
399                            'Feature')
400    table_file = dirname(__file__) + '/cryptodevs/overview_cipher_table.txt'
401    generate_overview_table(table_file, 2,
402                            'Cipher',
403                            'Cipher algorithms in crypto drivers',
404                            'Cipher algorithm')
405    table_file = dirname(__file__) + '/cryptodevs/overview_auth_table.txt'
406    generate_overview_table(table_file, 3,
407                            'Auth',
408                            'Authentication algorithms in crypto drivers',
409                            'Authentication algorithm')
410    table_file = dirname(__file__) + '/cryptodevs/overview_aead_table.txt'
411    generate_overview_table(table_file, 4,
412                            'AEAD',
413                            'AEAD algorithms in crypto drivers',
414                            'AEAD algorithm')
415    table_file = dirname(__file__) + '/cryptodevs/overview_asym_table.txt'
416    generate_overview_table(table_file, 5,
417                            'Asymmetric',
418                            'Asymmetric algorithms in crypto drivers',
419                            'Asymmetric algorithm')
420    table_file = dirname(__file__) + '/cryptodevs/overview_os_table.txt'
421    generate_overview_table(table_file, 6,
422                            'OS',
423                            'Operating systems support for crypto drivers',
424                            'Operating system')
425    table_file = dirname(__file__) + '/compressdevs/overview_feature_table.txt'
426    generate_overview_table(table_file, 1,
427                            'Features',
428                            'Features availability in compression drivers',
429                            'Feature')
430    table_file = dirname(__file__) + '/regexdevs/overview_feature_table.txt'
431    generate_overview_table(table_file, 1,
432                            'Features',
433                            'Features availability in regex drivers',
434                            'Feature')
435    table_file = dirname(__file__) + '/vdpadevs/overview_feature_table.txt'
436    generate_overview_table(table_file, 1,
437                            'Features',
438                            'Features availability in vDPA drivers',
439                            'Feature')
440    table_file = dirname(__file__) + '/bbdevs/overview_feature_table.txt'
441    generate_overview_table(table_file, 1,
442                            'Features',
443                            'Features availability in bbdev drivers',
444                            'Feature')
445    table_file = dirname(__file__) + '/gpus/overview_feature_table.txt'
446    generate_overview_table(table_file, 1,
447                            'Features',
448                            'Features availability in GPU drivers',
449                            'Feature')
450    table_file = dirname(__file__) + '/eventdevs/overview_feature_table.txt'
451    generate_overview_table(table_file, 1,
452                            'Scheduling Features',
453                            'Features availability in eventdev drivers',
454                            'Feature')
455    table_file = dirname(__file__) + '/eventdevs/overview_rx_adptr_feature_table.txt'
456    generate_overview_table(table_file, 2,
457                            'Eth Rx adapter Features',
458                            'Features availability for Ethdev Rx adapters',
459                            'Feature')
460    table_file = dirname(__file__) + '/eventdevs/overview_tx_adptr_feature_table.txt'
461    generate_overview_table(table_file, 3,
462                            'Eth Tx adapter Features',
463                            'Features availability for Ethdev Tx adapters',
464                            'Feature')
465    table_file = dirname(__file__) + '/eventdevs/overview_crypto_adptr_feature_table.txt'
466    generate_overview_table(table_file, 4,
467                            'Crypto adapter Features',
468                            'Features availability for Crypto adapters',
469                            'Feature')
470    table_file = dirname(__file__) + '/eventdevs/overview_timer_adptr_feature_table.txt'
471    generate_overview_table(table_file, 5,
472                            'Timer adapter Features',
473                            'Features availability for Timer adapters',
474                            'Feature')
475
476    if Version(sphinx_version) < Version('1.3.1'):
477        print('Upgrade sphinx to version >= 1.3.1 for '
478              'improved Figure/Table number handling.',
479              file=stderr)
480        # Add a role to handle :numref: references.
481        app.add_role('numref', numref_role)
482        # Process the numref references once the doctree has been created.
483        app.connect('doctree-resolved', process_numref)
484
485    try:
486        # New function in sphinx 1.8
487        app.add_css_file('css/custom.css')
488    except:
489        app.add_stylesheet('css/custom.css')
490