xref: /dpdk/doc/guides/conf.py (revision 7e23a23a826a7efea6545363aa6f1e5c63e228dc)
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
15
16import configparser
17
18try:
19    import sphinx_rtd_theme
20
21    html_theme = "sphinx_rtd_theme"
22    html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
23except:
24    print('Install the sphinx ReadTheDocs theme for improved html documentation '
25          'layout: https://sphinx-rtd-theme.readthedocs.io/')
26    pass
27
28project = 'Data Plane Development Kit'
29html_logo = '../logo/DPDK_logo_vertical_rev_small.png'
30latex_logo = '../logo/DPDK_logo_horizontal_tag.png'
31html_add_permalinks = ""
32html_show_copyright = False
33highlight_language = 'none'
34
35release = environ['DPDK_VERSION']
36version = release
37
38master_doc = 'index'
39
40# Maximum feature description string length
41feature_str_len = 30
42
43# Figures, tables and code-blocks automatically numbered if they have caption
44numfig = True
45
46latex_documents = [
47    ('index',
48     'doc.tex',
49     '',
50     '',
51     'manual')
52]
53
54# Latex directives to be included directly in the latex/pdf docs.
55custom_latex_preamble = r"""
56\usepackage{textalpha}
57\RecustomVerbatimEnvironment{Verbatim}{Verbatim}{xleftmargin=5mm}
58\usepackage{etoolbox}
59\robustify\(
60\robustify\)
61"""
62
63# Configuration for the latex/pdf docs.
64latex_elements = {
65    'papersize': 'a4paper',
66    'pointsize': '11pt',
67    # remove blank pages
68    'classoptions': ',openany,oneside',
69    'babel': '\\usepackage[english]{babel}',
70    # customize Latex formatting
71    'preamble': custom_latex_preamble
72}
73
74
75# Override the default Latex formatter in order to modify the
76# code/verbatim blocks.
77class CustomLatexFormatter(LatexFormatter):
78    def __init__(self, **options):
79        super(CustomLatexFormatter, self).__init__(**options)
80        # Use the second smallest font size for code/verbatim blocks.
81        self.verboptions = r'formatcom=\footnotesize'
82
83# Replace the default latex formatter.
84PygmentsBridge.latex_formatter = CustomLatexFormatter
85
86# Configuration for man pages
87man_pages = [("testpmd_app_ug/run_app", "testpmd",
88              "tests for dpdk pmds", "", 1),
89             ("tools/pdump", "dpdk-pdump",
90              "enable packet capture on dpdk ports", "", 1),
91             ("tools/proc_info", "dpdk-procinfo",
92              "access dpdk port stats and memory info", "", 1),
93             ("tools/pmdinfo", "dpdk-pmdinfo",
94              "dump a PMDs hardware support info", "", 1),
95             ("tools/devbind", "dpdk-devbind",
96              "check device status and bind/unbind them from drivers", "", 8)]
97
98
99# ####### :numref: fallback ########
100# The following hook functions add some simple handling for the :numref:
101# directive for Sphinx versions prior to 1.3.1. The functions replace the
102# :numref: reference with a link to the target (for all Sphinx doc types).
103# It doesn't try to label figures/tables.
104def numref_role(reftype, rawtext, text, lineno, inliner):
105    """
106    Add a Sphinx role to handle numref references. Note, we can't convert
107    the link here because the doctree isn't build and the target information
108    isn't available.
109    """
110    # Add an identifier to distinguish numref from other references.
111    newnode = nodes.reference('',
112                              '',
113                              refuri='_local_numref_#%s' % text,
114                              internal=True)
115    return [newnode], []
116
117
118def process_numref(app, doctree, from_docname):
119    """
120    Process the numref nodes once the doctree has been built and prior to
121    writing the files. The processing involves replacing the numref with a
122    link plus text to indicate if it is a Figure or Table link.
123    """
124
125    # Iterate over the reference nodes in the doctree.
126    for node in doctree.traverse(nodes.reference):
127        target = node.get('refuri', '')
128
129        # Look for numref nodes.
130        if target.startswith('_local_numref_#'):
131            target = target.replace('_local_numref_#', '')
132
133            # Get the target label and link information from the Sphinx env.
134            data = app.builder.env.domains['std'].data
135            docname, label, _ = data['labels'].get(target, ('', '', ''))
136            relative_url = app.builder.get_relative_uri(from_docname, docname)
137
138            # Add a text label to the link.
139            if target.startswith('figure'):
140                caption = 'Figure'
141            elif target.startswith('table'):
142                caption = 'Table'
143            else:
144                caption = 'Link'
145
146            # New reference node with the updated link information.
147            newnode = nodes.reference('',
148                                      caption,
149                                      refuri='%s#%s' % (relative_url, label),
150                                      internal=True)
151            node.replace_self(newnode)
152
153
154def generate_overview_table(output_filename, table_id, section, table_name, title):
155    """
156    Function to generate the Overview Table from the ini files that define
157    the features for each driver.
158
159    The default features for the table and their order is defined by the
160    'default.ini' file.
161
162    """
163    # Default warning string.
164    warning = 'Warning generate_overview_table()'
165
166    # Get the default features and order from the 'default.ini' file.
167    ini_path = path_join(dirname(output_filename), 'features')
168    config = configparser.ConfigParser()
169    config.optionxform = str
170    config.read(path_join(ini_path, 'default.ini'))
171    default_features = config.items(section)
172
173    # Create a dict of the valid features to validate the other ini files.
174    valid_features = {}
175    max_feature_length = 0
176    for feature in default_features:
177        key = feature[0]
178        valid_features[key] = ' '
179        max_feature_length = max(max_feature_length, len(key))
180
181    # Get a list of driver ini files, excluding 'default.ini'.
182    ini_files = [basename(file) for file in listdir(ini_path)
183                 if file.endswith('.ini') and file != 'default.ini']
184    ini_files.sort()
185
186    # Build up a list of the table header names from the ini filenames.
187    pmd_names = []
188    for ini_filename in ini_files:
189        name = ini_filename[:-4]
190        name = name.replace('_vf', 'vf')
191        pmd_names.append(name)
192
193    # Pad the table header names.
194    max_header_len = len(max(pmd_names, key=len))
195    header_names = []
196    for name in pmd_names:
197        if '_vec' in name:
198            pmd, vec = name.split('_')
199            name = '{0:{fill}{align}{width}}vec'.format(pmd,
200                    fill='.', align='<', width=max_header_len-3)
201        else:
202            name = '{0:{fill}{align}{width}}'.format(name,
203                    fill=' ', align='<', width=max_header_len)
204        header_names.append(name)
205
206    # Create a dict of the defined features for each driver from the ini files.
207    ini_data = {}
208    for ini_filename in ini_files:
209        config = configparser.ConfigParser()
210        config.optionxform = str
211        config.read(path_join(ini_path, ini_filename))
212
213        # Initialize the dict with the default.ini value.
214        ini_data[ini_filename] = valid_features.copy()
215
216        # Check for a valid ini section.
217        if not config.has_section(section):
218            print("{}: File '{}' has no [{}] secton".format(warning,
219                                                            ini_filename,
220                                                            section))
221            continue
222
223        # Check for valid features names.
224        for name, value in config.items(section):
225            if name not in valid_features:
226                print("{}: Unknown feature '{}' in '{}'".format(warning,
227                                                                name,
228                                                                ini_filename))
229                continue
230
231            if value:
232                # Get the first letter only.
233                ini_data[ini_filename][name] = value[0]
234
235    # Print out the RST Driver Overview table from the ini file data.
236    outfile = open(output_filename, 'w')
237    num_cols = len(header_names)
238
239    print_table_css(outfile, table_id)
240    print('.. table:: ' + table_name + '\n', file=outfile)
241    print_table_header(outfile, num_cols, header_names, title)
242    print_table_body(outfile, num_cols, ini_files, ini_data, default_features)
243
244
245def print_table_header(outfile, num_cols, header_names, title):
246    """ Print the RST table header. The header names are vertical. """
247    print_table_divider(outfile, num_cols)
248
249    line = ''
250    for name in header_names:
251        line += ' ' + name[0]
252
253    print_table_row(outfile, title, line)
254
255    for i in range(1, len(header_names[0])):
256        line = ''
257        for name in header_names:
258            line += ' ' + name[i]
259
260        print_table_row(outfile, '', line)
261
262    print_table_divider(outfile, num_cols)
263
264
265def print_table_body(outfile, num_cols, ini_files, ini_data, default_features):
266    """ Print out the body of the table. Each row is a NIC feature. """
267
268    for feature, _ in default_features:
269        line = ''
270
271        for ini_filename in ini_files:
272            line += ' ' + ini_data[ini_filename][feature]
273
274        print_table_row(outfile, feature, line)
275
276    print_table_divider(outfile, num_cols)
277
278
279def print_table_row(outfile, feature, line):
280    """ Print a single row of the table with fixed formatting. """
281    line = line.rstrip()
282    print('   {:<{}}{}'.format(feature, feature_str_len, line), file=outfile)
283
284
285def print_table_divider(outfile, num_cols):
286    """ Print the table divider line. """
287    line = ' '
288    column_dividers = ['='] * num_cols
289    line += ' '.join(column_dividers)
290
291    feature = '=' * feature_str_len
292
293    print_table_row(outfile, feature, line)
294
295
296def print_table_css(outfile, table_id):
297    template = """
298.. raw:: html
299
300   <style>
301      .wy-nav-content {
302         opacity: .99;
303      }
304      table#idx {
305         cursor: default;
306         overflow: hidden;
307      }
308      table#idx p {
309         margin: 0;
310         line-height: inherit;
311      }
312      table#idx th, table#idx td {
313         text-align: center;
314         border: solid 1px #ddd;
315      }
316      table#idx th {
317         padding: 0.5em 0;
318      }
319      table#idx th, table#idx th p {
320         font-size: 11px;
321         white-space: pre-wrap;
322         vertical-align: top;
323         min-width: 0.9em;
324      }
325      table#idx col:first-child {
326         width: 0;
327      }
328      table#idx th:first-child {
329         vertical-align: bottom;
330      }
331      table#idx td {
332         padding: 1px;
333      }
334      table#idx td, table#idx td p {
335         font-size: 11px;
336      }
337      table#idx td:first-child {
338         padding-left: 1em;
339         text-align: left;
340      }
341      table#idx tr:nth-child(2n-1) td {
342         background-color: rgba(210, 210, 210, 0.2);
343      }
344      table#idx th:not(:first-child):hover,
345      table#idx td:not(:first-child):hover {
346         position: relative;
347      }
348      table#idx th:not(:first-child):hover::after,
349      table#idx td:not(:first-child):hover::after {
350         content: '';
351         height: 6000px;
352         top: -3000px;
353         width: 100%;
354         left: 0;
355         position: absolute;
356         z-index: -1;
357         background-color: #ffb;
358      }
359      table#idx tr:hover td {
360         background-color: #ffb;
361      }
362   </style>
363"""
364    print(template.replace("idx", "id%d" % (table_id)), file=outfile)
365
366
367def setup(app):
368    table_file = dirname(__file__) + '/nics/overview_table.txt'
369    generate_overview_table(table_file, 1,
370                            'Features',
371                            'Features availability in networking drivers',
372                            'Feature')
373    table_file = dirname(__file__) + '/cryptodevs/overview_feature_table.txt'
374    generate_overview_table(table_file, 1,
375                            'Features',
376                            'Features availability in crypto drivers',
377                            'Feature')
378    table_file = dirname(__file__) + '/cryptodevs/overview_cipher_table.txt'
379    generate_overview_table(table_file, 2,
380                            'Cipher',
381                            'Cipher algorithms in crypto drivers',
382                            'Cipher algorithm')
383    table_file = dirname(__file__) + '/cryptodevs/overview_auth_table.txt'
384    generate_overview_table(table_file, 3,
385                            'Auth',
386                            'Authentication algorithms in crypto drivers',
387                            'Authentication algorithm')
388    table_file = dirname(__file__) + '/cryptodevs/overview_aead_table.txt'
389    generate_overview_table(table_file, 4,
390                            'AEAD',
391                            'AEAD algorithms in crypto drivers',
392                            'AEAD algorithm')
393    table_file = dirname(__file__) + '/cryptodevs/overview_asym_table.txt'
394    generate_overview_table(table_file, 5,
395                            'Asymmetric',
396                            'Asymmetric algorithms in crypto drivers',
397                            'Asymmetric algorithm')
398    table_file = dirname(__file__) + '/compressdevs/overview_feature_table.txt'
399    generate_overview_table(table_file, 1,
400                            'Features',
401                            'Features availability in compression drivers',
402                            'Feature')
403    table_file = dirname(__file__) + '/regexdevs/overview_feature_table.txt'
404    generate_overview_table(table_file, 1,
405                            'Features',
406                            'Features availability in regex drivers',
407                            'Feature')
408    table_file = dirname(__file__) + '/vdpadevs/overview_feature_table.txt'
409    generate_overview_table(table_file, 1,
410                            'Features',
411                            'Features availability in vDPA drivers',
412                            'Feature')
413    table_file = dirname(__file__) + '/bbdevs/overview_feature_table.txt'
414    generate_overview_table(table_file, 1,
415                            'Features',
416                            'Features availability in bbdev drivers',
417                            'Feature')
418
419    if LooseVersion(sphinx_version) < LooseVersion('1.3.1'):
420        print('Upgrade sphinx to version >= 1.3.1 for '
421              'improved Figure/Table number handling.')
422        # Add a role to handle :numref: references.
423        app.add_role('numref', numref_role)
424        # Process the numref references once the doctree has been created.
425        app.connect('doctree-resolved', process_numref)
426
427    try:
428        # New function in sphinx 1.8
429        app.add_css_file('css/custom.css')
430    except:
431        app.add_stylesheet('css/custom.css')
432