xref: /dpdk/doc/guides/conf.py (revision f399b0171e6e64c8bbce42599afa35591a9d28f1)
1# SPDX-License-Identifier: BSD-3-Clause
2# Copyright(c) 2010-2015 Intel Corporation
3
4from __future__ import print_function
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
16try:
17    # Python 2.
18    import ConfigParser as configparser
19except:
20    # Python 3.
21    import configparser
22
23try:
24    import sphinx_rtd_theme
25
26    html_theme = "sphinx_rtd_theme"
27    html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
28except:
29    print('Install the sphinx ReadTheDocs theme for improved html documentation '
30          'layout: pip install sphinx_rtd_theme')
31    pass
32
33project = 'Data Plane Development Kit'
34html_logo = '../logo/DPDK_logo_vertical_rev_small.png'
35latex_logo = '../logo/DPDK_logo_horizontal_tag.png'
36html_add_permalinks = ""
37html_show_copyright = False
38highlight_language = 'none'
39
40release = environ['DPDK_VERSION']
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            continue
226
227        # Check for valid features names.
228        for name, value in config.items(section):
229            if name not in valid_features:
230                print("{}: Unknown feature '{}' in '{}'".format(warning,
231                                                                name,
232                                                                ini_filename))
233                continue
234
235            if value:
236                # Get the first letter only.
237                ini_data[ini_filename][name] = value[0]
238
239    # Print out the RST Driver Overview table from the ini file data.
240    outfile = open(output_filename, 'w')
241    num_cols = len(header_names)
242
243    print_table_css(outfile, table_id)
244    print('.. table:: ' + table_name + '\n', file=outfile)
245    print_table_header(outfile, num_cols, header_names, title)
246    print_table_body(outfile, num_cols, ini_files, ini_data, default_features)
247
248
249def print_table_header(outfile, num_cols, header_names, title):
250    """ Print the RST table header. The header names are vertical. """
251    print_table_divider(outfile, num_cols)
252
253    line = ''
254    for name in header_names:
255        line += ' ' + name[0]
256
257    print_table_row(outfile, title, line)
258
259    for i in range(1, len(header_names[0])):
260        line = ''
261        for name in header_names:
262            line += ' ' + name[i]
263
264        print_table_row(outfile, '', line)
265
266    print_table_divider(outfile, num_cols)
267
268
269def print_table_body(outfile, num_cols, ini_files, ini_data, default_features):
270    """ Print out the body of the table. Each row is a NIC feature. """
271
272    for feature, _ in default_features:
273        line = ''
274
275        for ini_filename in ini_files:
276            line += ' ' + ini_data[ini_filename][feature]
277
278        print_table_row(outfile, feature, line)
279
280    print_table_divider(outfile, num_cols)
281
282
283def print_table_row(outfile, feature, line):
284    """ Print a single row of the table with fixed formatting. """
285    line = line.rstrip()
286    print('   {:<{}}{}'.format(feature, feature_str_len, line), file=outfile)
287
288
289def print_table_divider(outfile, num_cols):
290    """ Print the table divider line. """
291    line = ' '
292    column_dividers = ['='] * num_cols
293    line += ' '.join(column_dividers)
294
295    feature = '=' * feature_str_len
296
297    print_table_row(outfile, feature, line)
298
299
300def print_table_css(outfile, table_id):
301    template = """
302.. raw:: html
303
304   <style>
305      .wy-nav-content {
306         opacity: .99;
307      }
308      table#idx {
309         cursor: default;
310         overflow: hidden;
311      }
312      table#idx p {
313         margin: 0;
314         line-height: inherit;
315      }
316      table#idx th, table#idx td {
317         text-align: center;
318         border: solid 1px #ddd;
319      }
320      table#idx th {
321         padding: 0.5em 0;
322      }
323      table#idx th, table#idx th p {
324         font-size: 11px;
325         white-space: pre-wrap;
326         vertical-align: top;
327         min-width: 0.9em;
328      }
329      table#idx col:first-child {
330         width: 0;
331      }
332      table#idx th:first-child {
333         vertical-align: bottom;
334      }
335      table#idx td {
336         padding: 1px;
337      }
338      table#idx td, table#idx td p {
339         font-size: 11px;
340      }
341      table#idx td:first-child {
342         padding-left: 1em;
343         text-align: left;
344      }
345      table#idx tr:nth-child(2n-1) td {
346         background-color: rgba(210, 210, 210, 0.2);
347      }
348      table#idx th:not(:first-child):hover,
349      table#idx td:not(:first-child):hover {
350         position: relative;
351      }
352      table#idx th:not(:first-child):hover::after,
353      table#idx td:not(:first-child):hover::after {
354         content: '';
355         height: 6000px;
356         top: -3000px;
357         width: 100%;
358         left: 0;
359         position: absolute;
360         z-index: -1;
361         background-color: #ffb;
362      }
363      table#idx tr:hover td {
364         background-color: #ffb;
365      }
366   </style>
367"""
368    print(template.replace("idx", "id%d" % (table_id)), file=outfile)
369
370
371def setup(app):
372    table_file = dirname(__file__) + '/nics/overview_table.txt'
373    generate_overview_table(table_file, 1,
374                            'Features',
375                            'Features availability in networking drivers',
376                            'Feature')
377    table_file = dirname(__file__) + '/cryptodevs/overview_feature_table.txt'
378    generate_overview_table(table_file, 1,
379                            'Features',
380                            'Features availability in crypto drivers',
381                            'Feature')
382    table_file = dirname(__file__) + '/cryptodevs/overview_cipher_table.txt'
383    generate_overview_table(table_file, 2,
384                            'Cipher',
385                            'Cipher algorithms in crypto drivers',
386                            'Cipher algorithm')
387    table_file = dirname(__file__) + '/cryptodevs/overview_auth_table.txt'
388    generate_overview_table(table_file, 3,
389                            'Auth',
390                            'Authentication algorithms in crypto drivers',
391                            'Authentication algorithm')
392    table_file = dirname(__file__) + '/cryptodevs/overview_aead_table.txt'
393    generate_overview_table(table_file, 4,
394                            'AEAD',
395                            'AEAD algorithms in crypto drivers',
396                            'AEAD algorithm')
397    table_file = dirname(__file__) + '/cryptodevs/overview_asym_table.txt'
398    generate_overview_table(table_file, 5,
399                            'Asymmetric',
400                            'Asymmetric algorithms in crypto drivers',
401                            'Asymmetric algorithm')
402    table_file = dirname(__file__) + '/compressdevs/overview_feature_table.txt'
403    generate_overview_table(table_file, 1,
404                            'Features',
405                            'Features availability in compression drivers',
406                            'Feature')
407    table_file = dirname(__file__) + '/regexdevs/overview_feature_table.txt'
408    generate_overview_table(table_file, 1,
409                            'Features',
410                            'Features availability in regex drivers',
411                            'Feature')
412    table_file = dirname(__file__) + '/vdpadevs/overview_feature_table.txt'
413    generate_overview_table(table_file, 1,
414                            'Features',
415                            'Features availability in vDPA drivers',
416                            'Feature')
417    table_file = dirname(__file__) + '/bbdevs/overview_feature_table.txt'
418    generate_overview_table(table_file, 1,
419                            'Features',
420                            'Features availability in bbdev drivers',
421                            'Feature')
422
423    if LooseVersion(sphinx_version) < LooseVersion('1.3.1'):
424        print('Upgrade sphinx to version >= 1.3.1 for '
425              'improved Figure/Table number handling.')
426        # Add a role to handle :numref: references.
427        app.add_role('numref', numref_role)
428        # Process the numref references once the doctree has been created.
429        app.connect('doctree-resolved', process_numref)
430
431    try:
432        # New function in sphinx 1.8
433        app.add_css_file('css/custom.css')
434    except:
435        app.add_stylesheet('css/custom.css')
436