xref: /dpdk/doc/guides/conf.py (revision b935bdc3da26ab86ec775dfad3aa63a1a61f5667)
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']
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    # DTS docstring options.
80    add_module_names = False
81    toc_object_entries = True
82    toc_object_entries_show_parents = 'hide'
83    # DTS Sidebar config.
84    if html_theme == "sphinx_rtd_theme":
85        html_theme_options = {
86            'collapse_navigation': False,
87            'navigation_depth': -1,  # unlimited depth
88        }
89
90    # Add path to DTS sources so that Sphinx can find them.
91    dpdk_root = dirname(dirname(dirname(__file__)))
92    path.append(path_join(dpdk_root, 'dts'))
93
94    # Get missing DTS dependencies. Add path to buildtools to find the get_missing_imports function.
95    path.append(path_join(dpdk_root, 'buildtools'))
96    import importlib
97    # Ignore missing imports from DTS dependencies, allowing us to build the docs without them.
98    # There's almost no difference between docs built with and without dependencies.
99    # The qualified names of imported objects are fully expanded with dependencies, such as:
100    # fabric.Connection (without) vs. fabric.connection.Connection (with)
101    autodoc_mock_imports = importlib.import_module('check-dts-requirements').get_missing_imports()
102
103
104# ####### :numref: fallback ########
105# The following hook functions add some simple handling for the :numref:
106# directive for Sphinx versions prior to 1.3.1. The functions replace the
107# :numref: reference with a link to the target (for all Sphinx doc types).
108# It doesn't try to label figures/tables.
109def numref_role(reftype, rawtext, text, lineno, inliner):
110    """
111    Add a Sphinx role to handle numref references. Note, we can't convert
112    the link here because the doctree isn't build and the target information
113    isn't available.
114    """
115    # Add an identifier to distinguish numref from other references.
116    newnode = nodes.reference('',
117                              '',
118                              refuri='_local_numref_#%s' % text,
119                              internal=True)
120    return [newnode], []
121
122
123def process_numref(app, doctree, from_docname):
124    """
125    Process the numref nodes once the doctree has been built and prior to
126    writing the files. The processing involves replacing the numref with a
127    link plus text to indicate if it is a Figure or Table link.
128    """
129
130    # Iterate over the reference nodes in the doctree.
131    for node in doctree.traverse(nodes.reference):
132        target = node.get('refuri', '')
133
134        # Look for numref nodes.
135        if target.startswith('_local_numref_#'):
136            target = target.replace('_local_numref_#', '')
137
138            # Get the target label and link information from the Sphinx env.
139            data = app.builder.env.domains['std'].data
140            docname, label, _ = data['labels'].get(target, ('', '', ''))
141            relative_url = app.builder.get_relative_uri(from_docname, docname)
142
143            # Add a text label to the link.
144            if target.startswith('figure'):
145                caption = 'Figure'
146            elif target.startswith('table'):
147                caption = 'Table'
148            else:
149                caption = 'Link'
150
151            # New reference node with the updated link information.
152            newnode = nodes.reference('',
153                                      caption,
154                                      refuri='%s#%s' % (relative_url, label),
155                                      internal=True)
156            node.replace_self(newnode)
157
158
159def generate_overview_table(output_filename, table_id, section, table_name, title):
160    """
161    Function to generate the Overview Table from the ini files that define
162    the features for each driver.
163
164    The default features for the table and their order is defined by the
165    'default.ini' file.
166
167    """
168    # Default warning string.
169    warning = 'Warning generate_overview_table()'
170
171    # Get the default features and order from the 'default.ini' file.
172    ini_path = path_join(dirname(output_filename), 'features')
173    config = configparser.ConfigParser()
174    config.optionxform = str
175    config.read(path_join(ini_path, 'default.ini'))
176    default_features = config.items(section)
177
178    # Create a dict of the valid features to validate the other ini files.
179    valid_features = {}
180    max_feature_length = 0
181    for feature in default_features:
182        key = feature[0]
183        valid_features[key] = ' '
184        max_feature_length = max(max_feature_length, len(key))
185
186    # Get a list of driver ini files, excluding 'default.ini'.
187    ini_files = [basename(file) for file in listdir(ini_path)
188                 if file.endswith('.ini') and file != 'default.ini']
189    ini_files.sort()
190
191    # Build up a list of the table header names from the ini filenames.
192    pmd_names = []
193    for ini_filename in ini_files:
194        name = ini_filename[:-4]
195        name = name.replace('_vf', 'vf')
196        pmd_names.append(name)
197    if not pmd_names:
198        # Add an empty column if table is empty (required by RST syntax)
199        pmd_names.append(' ')
200
201    # Pad the table header names.
202    max_header_len = len(max(pmd_names, key=len))
203    header_names = []
204    for name in pmd_names:
205        if '_vec' in name:
206            pmd, vec = name.split('_')
207            name = '{0:{fill}{align}{width}}vec'.format(pmd,
208                    fill='.', align='<', width=max_header_len-3)
209        else:
210            name = '{0:{fill}{align}{width}}'.format(name,
211                    fill=' ', align='<', width=max_header_len)
212        header_names.append(name)
213
214    # Create a dict of the defined features for each driver from the ini files.
215    ini_data = {}
216    for ini_filename in ini_files:
217        config = configparser.ConfigParser()
218        config.optionxform = str
219        config.read(path_join(ini_path, ini_filename))
220
221        # Initialize the dict with the default.ini value.
222        ini_data[ini_filename] = valid_features.copy()
223
224        # Check for a section.
225        if not config.has_section(section):
226            continue
227
228        # Check for valid features names.
229        for name, value in config.items(section):
230            if name not in valid_features:
231                print("{}: Unknown feature '{}' in '{}'".format(warning,
232                                                                name,
233                                                                ini_filename),
234                                                                file=stderr)
235                if stop_on_error:
236                    raise Exception('Warning is treated as a failure')
237                continue
238
239            if value:
240                # Get the first letter only.
241                ini_data[ini_filename][name] = value[0]
242
243    # Print out the RST Driver Overview table from the ini file data.
244    outfile = open(output_filename, 'w')
245    num_cols = len(header_names)
246
247    print_table_css(outfile, table_id)
248    print('.. _' + table_name + ':', file=outfile)
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)
252
253
254def 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)
257
258    line = ''
259    for name in header_names:
260        line += ' ' + name[0]
261
262    print_table_row(outfile, title, line)
263
264    for i in range(1, len(header_names[0])):
265        line = ''
266        for name in header_names:
267            line += ' ' + name[i]
268
269        print_table_row(outfile, '', line)
270
271    print_table_divider(outfile, num_cols)
272
273
274def 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. """
276
277    for feature, _ in default_features:
278        line = ''
279
280        for ini_filename in ini_files:
281            line += ' ' + ini_data[ini_filename][feature]
282
283        print_table_row(outfile, feature, line)
284
285    print_table_divider(outfile, num_cols)
286
287
288def print_table_row(outfile, feature, line):
289    """ Print a single row of the table with fixed formatting. """
290    line = line.rstrip()
291    print('   {:<{}}{}'.format(feature, feature_str_len, line), file=outfile)
292
293
294def print_table_divider(outfile, num_cols):
295    """ Print the table divider line. """
296    line = ' '
297    column_dividers = ['='] * num_cols
298    line += ' '.join(column_dividers)
299
300    feature = '=' * feature_str_len
301
302    print_table_row(outfile, feature, line)
303
304
305def print_table_css(outfile, table_id):
306    template = """
307.. raw:: html
308
309   <style>
310      .wy-nav-content {
311         opacity: .99;
312      }
313      table#idx {
314         cursor: default;
315         overflow: hidden;
316      }
317      table#idx p {
318         margin: 0;
319         line-height: inherit;
320      }
321      table#idx th, table#idx td {
322         text-align: center;
323         border: solid 1px #ddd;
324      }
325      table#idx th {
326         padding: 0.5em 0;
327      }
328      table#idx th, table#idx th p {
329         font-size: 11px;
330         white-space: pre-wrap;
331         vertical-align: top;
332         min-width: 0.9em;
333      }
334      table#idx col:first-child {
335         width: 0;
336      }
337      table#idx th:first-child {
338         vertical-align: bottom;
339      }
340      table#idx td {
341         padding: 1px;
342      }
343      table#idx td, table#idx td p {
344         font-size: 11px;
345      }
346      table#idx td:first-child {
347         padding-left: 1em;
348         text-align: left;
349      }
350      table#idx tr:nth-child(2n-1) td {
351         background-color: rgba(210, 210, 210, 0.2);
352      }
353      table#idx th:not(:first-child):hover,
354      table#idx td:not(:first-child):hover {
355         position: relative;
356      }
357      table#idx th:not(:first-child):hover::after,
358      table#idx td:not(:first-child):hover::after {
359         content: '';
360         height: 6000px;
361         top: -3000px;
362         width: 100%;
363         left: 0;
364         position: absolute;
365         z-index: -1;
366         background-color: #ffb;
367      }
368      table#idx tr:hover td {
369         background-color: #ffb;
370      }
371   </style>
372"""
373    print(template.replace("idx", "id%d" % (table_id)), file=outfile)
374
375
376def setup(app):
377    table_file = dirname(__file__) + '/nics/overview_table.txt'
378    generate_overview_table(table_file, 1,
379                            'Features',
380                            'Features availability in networking drivers',
381                            'Feature')
382    table_file = dirname(__file__) + '/nics/rte_flow_items_table.txt'
383    generate_overview_table(table_file, 2,
384                            'rte_flow items',
385                            'rte_flow items availability in networking drivers',
386                            'Item')
387    table_file = dirname(__file__) + '/nics/rte_flow_actions_table.txt'
388    generate_overview_table(table_file, 3,
389                            'rte_flow actions',
390                            'rte_flow actions availability in networking drivers',
391                            'Action')
392    table_file = dirname(__file__) + '/cryptodevs/overview_feature_table.txt'
393    generate_overview_table(table_file, 1,
394                            'Features',
395                            'Features availability in crypto drivers',
396                            'Feature')
397    table_file = dirname(__file__) + '/cryptodevs/overview_cipher_table.txt'
398    generate_overview_table(table_file, 2,
399                            'Cipher',
400                            'Cipher algorithms in crypto drivers',
401                            'Cipher algorithm')
402    table_file = dirname(__file__) + '/cryptodevs/overview_auth_table.txt'
403    generate_overview_table(table_file, 3,
404                            'Auth',
405                            'Authentication algorithms in crypto drivers',
406                            'Authentication algorithm')
407    table_file = dirname(__file__) + '/cryptodevs/overview_aead_table.txt'
408    generate_overview_table(table_file, 4,
409                            'AEAD',
410                            'AEAD algorithms in crypto drivers',
411                            'AEAD algorithm')
412    table_file = dirname(__file__) + '/cryptodevs/overview_asym_table.txt'
413    generate_overview_table(table_file, 5,
414                            'Asymmetric',
415                            'Asymmetric algorithms in crypto drivers',
416                            'Asymmetric algorithm')
417    table_file = dirname(__file__) + '/cryptodevs/overview_os_table.txt'
418    generate_overview_table(table_file, 6,
419                            'OS',
420                            'Operating systems support for crypto drivers',
421                            'Operating system')
422    table_file = dirname(__file__) + '/compressdevs/overview_feature_table.txt'
423    generate_overview_table(table_file, 1,
424                            'Features',
425                            'Features availability in compression drivers',
426                            'Feature')
427    table_file = dirname(__file__) + '/regexdevs/overview_feature_table.txt'
428    generate_overview_table(table_file, 1,
429                            'Features',
430                            'Features availability in regex drivers',
431                            'Feature')
432    table_file = dirname(__file__) + '/vdpadevs/overview_feature_table.txt'
433    generate_overview_table(table_file, 1,
434                            'Features',
435                            'Features availability in vDPA drivers',
436                            'Feature')
437    table_file = dirname(__file__) + '/bbdevs/overview_feature_table.txt'
438    generate_overview_table(table_file, 1,
439                            'Features',
440                            'Features availability in bbdev drivers',
441                            'Feature')
442    table_file = dirname(__file__) + '/gpus/overview_feature_table.txt'
443    generate_overview_table(table_file, 1,
444                            'Features',
445                            'Features availability in GPU drivers',
446                            'Feature')
447    table_file = dirname(__file__) + '/eventdevs/overview_feature_table.txt'
448    generate_overview_table(table_file, 1,
449                            'Scheduling Features',
450                            'Features availability in eventdev drivers',
451                            'Feature')
452    table_file = dirname(__file__) + '/eventdevs/overview_rx_adptr_feature_table.txt'
453    generate_overview_table(table_file, 2,
454                            'Eth Rx adapter Features',
455                            'Features availability for Ethdev Rx adapters',
456                            'Feature')
457    table_file = dirname(__file__) + '/eventdevs/overview_tx_adptr_feature_table.txt'
458    generate_overview_table(table_file, 3,
459                            'Eth Tx adapter Features',
460                            'Features availability for Ethdev Tx adapters',
461                            'Feature')
462    table_file = dirname(__file__) + '/eventdevs/overview_crypto_adptr_feature_table.txt'
463    generate_overview_table(table_file, 4,
464                            'Crypto adapter Features',
465                            'Features availability for Crypto adapters',
466                            'Feature')
467    table_file = dirname(__file__) + '/eventdevs/overview_timer_adptr_feature_table.txt'
468    generate_overview_table(table_file, 5,
469                            'Timer adapter Features',
470                            'Features availability for Timer adapters',
471                            'Feature')
472
473    if Version(sphinx_version) < Version('1.3.1'):
474        print('Upgrade sphinx to version >= 1.3.1 for '
475              'improved Figure/Table number handling.',
476              file=stderr)
477        # Add a role to handle :numref: references.
478        app.add_role('numref', numref_role)
479        # Process the numref references once the doctree has been created.
480        app.connect('doctree-resolved', process_numref)
481
482    try:
483        # New function in sphinx 1.8
484        app.add_css_file('css/custom.css')
485    except:
486        app.add_stylesheet('css/custom.css')
487