xref: /dpdk/doc/guides/conf.py (revision c053d9e9629b2337093dfd344eb904f0aff703bd)
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"
23    html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
24except:
25    print('Install the sphinx ReadTheDocs theme for improved html documentation '
26          'layout: https://sphinx-rtd-theme.readthedocs.io/',
27          file=stderr)
28    pass
29
30stop_on_error = ('-W' in argv)
31
32project = 'Data Plane Development Kit'
33html_logo = '../logo/DPDK_logo_vertical_rev_small.png'
34latex_logo = '../logo/DPDK_logo_horizontal_tag.png'
35html_add_permalinks = ""
36html_show_copyright = False
37highlight_language = 'none'
38
39release = environ.setdefault('DPDK_VERSION', "None")
40version = release
41
42master_doc = 'index'
43
44# Maximum feature description string length
45feature_str_len = 30
46
47# Figures, tables and code-blocks automatically numbered if they have caption
48numfig = True
49
50latex_documents = [
51    ('index',
52     'doc.tex',
53     '',
54     '',
55     'manual')
56]
57
58# Latex directives to be included directly in the latex/pdf docs.
59custom_latex_preamble = r"""
60\usepackage{textalpha}
61\RecustomVerbatimEnvironment{Verbatim}{Verbatim}{xleftmargin=5mm}
62\usepackage{etoolbox}
63\robustify\(
64\robustify\)
65"""
66
67# Configuration for the latex/pdf docs.
68latex_elements = {
69    'papersize': 'a4paper',
70    'pointsize': '11pt',
71    # remove blank pages
72    'classoptions': ',openany,oneside',
73    'babel': '\\usepackage[english]{babel}',
74    # customize Latex formatting
75    'preamble': custom_latex_preamble
76}
77
78
79# Override the default Latex formatter in order to modify the
80# code/verbatim blocks.
81class 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'
86
87# Replace the default latex formatter.
88PygmentsBridge.latex_formatter = CustomLatexFormatter
89
90# Configuration for man pages
91man_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)]
101
102
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.
108def numref_role(reftype, rawtext, text, lineno, inliner):
109    """
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
112    isn't available.
113    """
114    # Add an identifier to distinguish numref from other references.
115    newnode = nodes.reference('',
116                              '',
117                              refuri='_local_numref_#%s' % text,
118                              internal=True)
119    return [newnode], []
120
121
122def process_numref(app, doctree, from_docname):
123    """
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.
127    """
128
129    # Iterate over the reference nodes in the doctree.
130    for node in doctree.traverse(nodes.reference):
131        target = node.get('refuri', '')
132
133        # Look for numref nodes.
134        if target.startswith('_local_numref_#'):
135            target = target.replace('_local_numref_#', '')
136
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)
141
142            # Add a text label to the link.
143            if target.startswith('figure'):
144                caption = 'Figure'
145            elif target.startswith('table'):
146                caption = 'Table'
147            else:
148                caption = 'Link'
149
150            # New reference node with the updated link information.
151            newnode = nodes.reference('',
152                                      caption,
153                                      refuri='%s#%s' % (relative_url, label),
154                                      internal=True)
155            node.replace_self(newnode)
156
157
158def generate_overview_table(output_filename, table_id, section, table_name, title):
159    """
160    Function to generate the Overview Table from the ini files that define
161    the features for each driver.
162
163    The default features for the table and their order is defined by the
164    'default.ini' file.
165
166    """
167    # Default warning string.
168    warning = 'Warning generate_overview_table()'
169
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)
176
177    # Create a dict of the valid features to validate the other ini files.
178    valid_features = {}
179    max_feature_length = 0
180    for feature in default_features:
181        key = feature[0]
182        valid_features[key] = ' '
183        max_feature_length = max(max_feature_length, len(key))
184
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']
188    ini_files.sort()
189
190    # Build up a list of the table header names from the ini filenames.
191    pmd_names = []
192    for ini_filename in ini_files:
193        name = ini_filename[:-4]
194        name = name.replace('_vf', 'vf')
195        pmd_names.append(name)
196
197    # Pad the table header names.
198    max_header_len = len(max(pmd_names, key=len))
199    header_names = []
200    for name in pmd_names:
201        if '_vec' in name:
202            pmd, vec = name.split('_')
203            name = '{0:{fill}{align}{width}}vec'.format(pmd,
204                    fill='.', align='<', width=max_header_len-3)
205        else:
206            name = '{0:{fill}{align}{width}}'.format(name,
207                    fill=' ', align='<', width=max_header_len)
208        header_names.append(name)
209
210    # Create a dict of the defined features for each driver from the ini files.
211    ini_data = {}
212    for ini_filename in ini_files:
213        config = configparser.ConfigParser()
214        config.optionxform = str
215        config.read(path_join(ini_path, ini_filename))
216
217        # Initialize the dict with the default.ini value.
218        ini_data[ini_filename] = valid_features.copy()
219
220        # Check for a valid ini section.
221        if not config.has_section(section):
222            print("{}: File '{}' has no [{}] secton".format(warning,
223                                                            ini_filename,
224                                                            section),
225                                                            file=stderr)
226            if stop_on_error:
227                raise Exception('Warning is treated as a failure')
228            continue
229
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,
234                                                                name,
235                                                                ini_filename),
236                                                                file=stderr)
237                if stop_on_error:
238                    raise Exception('Warning is treated as a failure')
239                continue
240
241            if value:
242                # Get the first letter only.
243                ini_data[ini_filename][name] = value[0]
244
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)
248
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)
253
254
255def 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)
258
259    line = ''
260    for name in header_names:
261        line += ' ' + name[0]
262
263    print_table_row(outfile, title, line)
264
265    for i in range(1, len(header_names[0])):
266        line = ''
267        for name in header_names:
268            line += ' ' + name[i]
269
270        print_table_row(outfile, '', line)
271
272    print_table_divider(outfile, num_cols)
273
274
275def 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. """
277
278    for feature, _ in default_features:
279        line = ''
280
281        for ini_filename in ini_files:
282            line += ' ' + ini_data[ini_filename][feature]
283
284        print_table_row(outfile, feature, line)
285
286    print_table_divider(outfile, num_cols)
287
288
289def print_table_row(outfile, feature, line):
290    """ Print a single row of the table with fixed formatting. """
291    line = line.rstrip()
292    print('   {:<{}}{}'.format(feature, feature_str_len, line), file=outfile)
293
294
295def print_table_divider(outfile, num_cols):
296    """ Print the table divider line. """
297    line = ' '
298    column_dividers = ['='] * num_cols
299    line += ' '.join(column_dividers)
300
301    feature = '=' * feature_str_len
302
303    print_table_row(outfile, feature, line)
304
305
306def print_table_css(outfile, table_id):
307    template = """
308.. raw:: html
309
310   <style>
311      .wy-nav-content {
312         opacity: .99;
313      }
314      table#idx {
315         cursor: default;
316         overflow: hidden;
317      }
318      table#idx p {
319         margin: 0;
320         line-height: inherit;
321      }
322      table#idx th, table#idx td {
323         text-align: center;
324         border: solid 1px #ddd;
325      }
326      table#idx th {
327         padding: 0.5em 0;
328      }
329      table#idx th, table#idx th p {
330         font-size: 11px;
331         white-space: pre-wrap;
332         vertical-align: top;
333         min-width: 0.9em;
334      }
335      table#idx col:first-child {
336         width: 0;
337      }
338      table#idx th:first-child {
339         vertical-align: bottom;
340      }
341      table#idx td {
342         padding: 1px;
343      }
344      table#idx td, table#idx td p {
345         font-size: 11px;
346      }
347      table#idx td:first-child {
348         padding-left: 1em;
349         text-align: left;
350      }
351      table#idx tr:nth-child(2n-1) td {
352         background-color: rgba(210, 210, 210, 0.2);
353      }
354      table#idx th:not(:first-child):hover,
355      table#idx td:not(:first-child):hover {
356         position: relative;
357      }
358      table#idx th:not(:first-child):hover::after,
359      table#idx td:not(:first-child):hover::after {
360         content: '';
361         height: 6000px;
362         top: -3000px;
363         width: 100%;
364         left: 0;
365         position: absolute;
366         z-index: -1;
367         background-color: #ffb;
368      }
369      table#idx tr:hover td {
370         background-color: #ffb;
371      }
372   </style>
373"""
374    print(template.replace("idx", "id%d" % (table_id)), file=outfile)
375
376
377def setup(app):
378    table_file = dirname(__file__) + '/nics/overview_table.txt'
379    generate_overview_table(table_file, 1,
380                            'Features',
381                            'Features availability in networking drivers',
382                            'Feature')
383    table_file = dirname(__file__) + '/cryptodevs/overview_feature_table.txt'
384    generate_overview_table(table_file, 1,
385                            'Features',
386                            'Features availability in crypto drivers',
387                            'Feature')
388    table_file = dirname(__file__) + '/cryptodevs/overview_cipher_table.txt'
389    generate_overview_table(table_file, 2,
390                            'Cipher',
391                            'Cipher algorithms in crypto drivers',
392                            'Cipher algorithm')
393    table_file = dirname(__file__) + '/cryptodevs/overview_auth_table.txt'
394    generate_overview_table(table_file, 3,
395                            'Auth',
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,
400                            'AEAD',
401                            'AEAD algorithms in crypto drivers',
402                            'AEAD algorithm')
403    table_file = dirname(__file__) + '/cryptodevs/overview_asym_table.txt'
404    generate_overview_table(table_file, 5,
405                            'Asymmetric',
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,
410                            'Features',
411                            'Features availability in compression drivers',
412                            'Feature')
413    table_file = dirname(__file__) + '/regexdevs/overview_feature_table.txt'
414    generate_overview_table(table_file, 1,
415                            'Features',
416                            'Features availability in regex drivers',
417                            'Feature')
418    table_file = dirname(__file__) + '/vdpadevs/overview_feature_table.txt'
419    generate_overview_table(table_file, 1,
420                            'Features',
421                            'Features availability in vDPA drivers',
422                            'Feature')
423    table_file = dirname(__file__) + '/bbdevs/overview_feature_table.txt'
424    generate_overview_table(table_file, 1,
425                            'Features',
426                            'Features availability in bbdev drivers',
427                            'Feature')
428
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.',
432              file=stderr)
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)
437
438    try:
439        # New function in sphinx 1.8
440        app.add_css_file('css/custom.css')
441    except:
442        app.add_stylesheet('css/custom.css')
443