xref: /dpdk/doc/guides/conf.py (revision 01ee2e49f6f605f4ba3a85e1e6012d4f2215866b)
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 distutils.version import LooseVersion
7from sphinx import __version__ as sphinx_version
8from sphinx.highlighting import PygmentsBridge
9from pygments.formatters.latex import LatexFormatter
10from os import listdir
11from os import environ
12from os.path import basename
13from os.path import dirname
14from os.path import join as path_join
15from sys import argv, stderr
16
17import configparser
18
19try:
20    import sphinx_rtd_theme
21
22    html_theme = "sphinx_rtd_theme"
23except:
24    print('Install the sphinx ReadTheDocs theme for improved html documentation '
25          'layout: https://sphinx-rtd-theme.readthedocs.io/',
26          file=stderr)
27    pass
28
29stop_on_error = ('-W' in argv)
30
31project = 'Data Plane Development Kit'
32html_logo = '../logo/DPDK_logo_vertical_rev_small.png'
33latex_logo = '../logo/DPDK_logo_horizontal_tag.png'
34html_add_permalinks = ""
35html_show_copyright = False
36highlight_language = 'none'
37
38release = environ.setdefault('DPDK_VERSION', "None")
39version = release
40
41master_doc = 'index'
42
43# Maximum feature description string length
44feature_str_len = 30
45
46# Figures, tables and code-blocks automatically numbered if they have caption
47numfig = True
48
49latex_documents = [
50    ('index',
51     'doc.tex',
52     '',
53     '',
54     'manual')
55]
56
57# Latex directives to be included directly in the latex/pdf docs.
58custom_latex_preamble = r"""
59\usepackage{textalpha}
60\RecustomVerbatimEnvironment{Verbatim}{Verbatim}{xleftmargin=5mm}
61\usepackage{etoolbox}
62\robustify\(
63\robustify\)
64"""
65
66# Configuration for the latex/pdf docs.
67latex_elements = {
68    'papersize': 'a4paper',
69    'pointsize': '11pt',
70    # remove blank pages
71    'classoptions': ',openany,oneside',
72    'babel': '\\usepackage[english]{babel}',
73    # customize Latex formatting
74    'preamble': custom_latex_preamble
75}
76
77
78# Override the default Latex formatter in order to modify the
79# code/verbatim blocks.
80class 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'
85
86# Replace the default latex formatter.
87PygmentsBridge.latex_formatter = CustomLatexFormatter
88
89# Configuration for man pages
90man_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)]
100
101
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.
107def numref_role(reftype, rawtext, text, lineno, inliner):
108    """
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
111    isn't available.
112    """
113    # Add an identifier to distinguish numref from other references.
114    newnode = nodes.reference('',
115                              '',
116                              refuri='_local_numref_#%s' % text,
117                              internal=True)
118    return [newnode], []
119
120
121def process_numref(app, doctree, from_docname):
122    """
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.
126    """
127
128    # Iterate over the reference nodes in the doctree.
129    for node in doctree.traverse(nodes.reference):
130        target = node.get('refuri', '')
131
132        # Look for numref nodes.
133        if target.startswith('_local_numref_#'):
134            target = target.replace('_local_numref_#', '')
135
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)
140
141            # Add a text label to the link.
142            if target.startswith('figure'):
143                caption = 'Figure'
144            elif target.startswith('table'):
145                caption = 'Table'
146            else:
147                caption = 'Link'
148
149            # New reference node with the updated link information.
150            newnode = nodes.reference('',
151                                      caption,
152                                      refuri='%s#%s' % (relative_url, label),
153                                      internal=True)
154            node.replace_self(newnode)
155
156
157def generate_overview_table(output_filename, table_id, section, table_name, title):
158    """
159    Function to generate the Overview Table from the ini files that define
160    the features for each driver.
161
162    The default features for the table and their order is defined by the
163    'default.ini' file.
164
165    """
166    # Default warning string.
167    warning = 'Warning generate_overview_table()'
168
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)
175
176    # Create a dict of the valid features to validate the other ini files.
177    valid_features = {}
178    max_feature_length = 0
179    for feature in default_features:
180        key = feature[0]
181        valid_features[key] = ' '
182        max_feature_length = max(max_feature_length, len(key))
183
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']
187    ini_files.sort()
188
189    # Build up a list of the table header names from the ini filenames.
190    pmd_names = []
191    for ini_filename in ini_files:
192        name = ini_filename[:-4]
193        name = name.replace('_vf', 'vf')
194        pmd_names.append(name)
195
196    # Pad the table header names.
197    max_header_len = len(max(pmd_names, key=len))
198    header_names = []
199    for name in pmd_names:
200        if '_vec' in name:
201            pmd, vec = name.split('_')
202            name = '{0:{fill}{align}{width}}vec'.format(pmd,
203                    fill='.', align='<', width=max_header_len-3)
204        else:
205            name = '{0:{fill}{align}{width}}'.format(name,
206                    fill=' ', align='<', width=max_header_len)
207        header_names.append(name)
208
209    # Create a dict of the defined features for each driver from the ini files.
210    ini_data = {}
211    for ini_filename in ini_files:
212        config = configparser.ConfigParser()
213        config.optionxform = str
214        config.read(path_join(ini_path, ini_filename))
215
216        # Initialize the dict with the default.ini value.
217        ini_data[ini_filename] = valid_features.copy()
218
219        # Check for a valid ini section.
220        if not config.has_section(section):
221            print("{}: File '{}' has no [{}] secton".format(warning,
222                                                            ini_filename,
223                                                            section),
224                                                            file=stderr)
225            if stop_on_error:
226                raise Exception('Warning is treated as a failure')
227            continue
228
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,
233                                                                name,
234                                                                ini_filename),
235                                                                file=stderr)
236                if stop_on_error:
237                    raise Exception('Warning is treated as a failure')
238                continue
239
240            if value:
241                # Get the first letter only.
242                ini_data[ini_filename][name] = value[0]
243
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)
247
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)
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__) + '/cryptodevs/overview_feature_table.txt'
383    generate_overview_table(table_file, 1,
384                            'Features',
385                            'Features availability in crypto drivers',
386                            'Feature')
387    table_file = dirname(__file__) + '/cryptodevs/overview_cipher_table.txt'
388    generate_overview_table(table_file, 2,
389                            'Cipher',
390                            'Cipher algorithms in crypto drivers',
391                            'Cipher algorithm')
392    table_file = dirname(__file__) + '/cryptodevs/overview_auth_table.txt'
393    generate_overview_table(table_file, 3,
394                            'Auth',
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,
399                            'AEAD',
400                            'AEAD algorithms in crypto drivers',
401                            'AEAD algorithm')
402    table_file = dirname(__file__) + '/cryptodevs/overview_asym_table.txt'
403    generate_overview_table(table_file, 5,
404                            'Asymmetric',
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,
409                            'Features',
410                            'Features availability in compression drivers',
411                            'Feature')
412    table_file = dirname(__file__) + '/regexdevs/overview_feature_table.txt'
413    generate_overview_table(table_file, 1,
414                            'Features',
415                            'Features availability in regex drivers',
416                            'Feature')
417    table_file = dirname(__file__) + '/vdpadevs/overview_feature_table.txt'
418    generate_overview_table(table_file, 1,
419                            'Features',
420                            'Features availability in vDPA drivers',
421                            'Feature')
422    table_file = dirname(__file__) + '/bbdevs/overview_feature_table.txt'
423    generate_overview_table(table_file, 1,
424                            'Features',
425                            'Features availability in bbdev drivers',
426                            'Feature')
427
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.',
431              file=stderr)
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)
436
437    try:
438        # New function in sphinx 1.8
439        app.add_css_file('css/custom.css')
440    except:
441        app.add_stylesheet('css/custom.css')
442