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