xref: /dpdk/doc/guides/conf.py (revision cf9b3c36e5a297200c169dbbf9d6e655d8096948)
1# SPDX-License-Identifier: BSD-3-Clause
2# Copyright(c) 2010-2015 Intel Corporation
3
4from __future__ import print_function
5import subprocess
6from docutils import nodes
7from distutils.version import LooseVersion
8from sphinx import __version__ as sphinx_version
9from sphinx.highlighting import PygmentsBridge
10from pygments.formatters.latex import LatexFormatter
11from os import listdir
12from os import environ
13from os.path import basename
14from os.path import dirname
15from os.path import join as path_join
16
17try:
18    # Python 2.
19    import ConfigParser as configparser
20except:
21    # Python 3.
22    import configparser
23
24try:
25    import sphinx_rtd_theme
26
27    html_theme = "sphinx_rtd_theme"
28    html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
29except:
30    print('Install the sphinx ReadTheDocs theme for improved html documentation '
31          'layout: pip install sphinx_rtd_theme')
32    pass
33
34project = 'Data Plane Development Kit'
35html_logo = '../logo/DPDK_logo_vertical_rev_small.png'
36latex_logo = '../logo/DPDK_logo_horizontal_tag.png'
37html_add_permalinks = ""
38html_show_copyright = False
39highlight_language = 'none'
40
41# If MAKEFLAGS is exported by the user, garbage text might end up in version
42version = subprocess.check_output(['make', '-sRrC', '../../', 'showversion'],
43                                  env=dict(environ, MAKEFLAGS=""))
44version = version.decode('utf-8').rstrip()
45release = version
46
47master_doc = 'index'
48
49# Maximum feature description string length
50feature_str_len = 30
51
52# Figures, tables and code-blocks automatically numbered if they have caption
53numfig = True
54
55latex_documents = [
56    ('index',
57     'doc.tex',
58     '',
59     '',
60     'manual')
61]
62
63# Latex directives to be included directly in the latex/pdf docs.
64custom_latex_preamble = r"""
65\usepackage{textalpha}
66\RecustomVerbatimEnvironment{Verbatim}{Verbatim}{xleftmargin=5mm}
67\usepackage{etoolbox}
68\robustify\(
69\robustify\)
70"""
71
72# Configuration for the latex/pdf docs.
73latex_elements = {
74    'papersize': 'a4paper',
75    'pointsize': '11pt',
76    # remove blank pages
77    'classoptions': ',openany,oneside',
78    'babel': '\\usepackage[english]{babel}',
79    # customize Latex formatting
80    'preamble': custom_latex_preamble
81}
82
83
84# Override the default Latex formatter in order to modify the
85# code/verbatim blocks.
86class CustomLatexFormatter(LatexFormatter):
87    def __init__(self, **options):
88        super(CustomLatexFormatter, self).__init__(**options)
89        # Use the second smallest font size for code/verbatim blocks.
90        self.verboptions = r'formatcom=\footnotesize'
91
92# Replace the default latex formatter.
93PygmentsBridge.latex_formatter = CustomLatexFormatter
94
95# Configuration for man pages
96man_pages = [("testpmd_app_ug/run_app", "testpmd",
97              "tests for dpdk pmds", "", 1),
98             ("tools/pdump", "dpdk-pdump",
99              "enable packet capture on dpdk ports", "", 1),
100             ("tools/proc_info", "dpdk-procinfo",
101              "access dpdk port stats and memory info", "", 1),
102             ("tools/pmdinfo", "dpdk-pmdinfo",
103              "dump a PMDs hardware support info", "", 1),
104             ("tools/devbind", "dpdk-devbind",
105              "check device status and bind/unbind them from drivers", "", 8)]
106
107
108# ####### :numref: fallback ########
109# The following hook functions add some simple handling for the :numref:
110# directive for Sphinx versions prior to 1.3.1. The functions replace the
111# :numref: reference with a link to the target (for all Sphinx doc types).
112# It doesn't try to label figures/tables.
113def numref_role(reftype, rawtext, text, lineno, inliner):
114    """
115    Add a Sphinx role to handle numref references. Note, we can't convert
116    the link here because the doctree isn't build and the target information
117    isn't available.
118    """
119    # Add an identifier to distinguish numref from other references.
120    newnode = nodes.reference('',
121                              '',
122                              refuri='_local_numref_#%s' % text,
123                              internal=True)
124    return [newnode], []
125
126
127def process_numref(app, doctree, from_docname):
128    """
129    Process the numref nodes once the doctree has been built and prior to
130    writing the files. The processing involves replacing the numref with a
131    link plus text to indicate if it is a Figure or Table link.
132    """
133
134    # Iterate over the reference nodes in the doctree.
135    for node in doctree.traverse(nodes.reference):
136        target = node.get('refuri', '')
137
138        # Look for numref nodes.
139        if target.startswith('_local_numref_#'):
140            target = target.replace('_local_numref_#', '')
141
142            # Get the target label and link information from the Sphinx env.
143            data = app.builder.env.domains['std'].data
144            docname, label, _ = data['labels'].get(target, ('', '', ''))
145            relative_url = app.builder.get_relative_uri(from_docname, docname)
146
147            # Add a text label to the link.
148            if target.startswith('figure'):
149                caption = 'Figure'
150            elif target.startswith('table'):
151                caption = 'Table'
152            else:
153                caption = 'Link'
154
155            # New reference node with the updated link information.
156            newnode = nodes.reference('',
157                                      caption,
158                                      refuri='%s#%s' % (relative_url, label),
159                                      internal=True)
160            node.replace_self(newnode)
161
162
163def generate_overview_table(output_filename, table_id, section, table_name, title):
164    """
165    Function to generate the Overview Table from the ini files that define
166    the features for each driver.
167
168    The default features for the table and their order is defined by the
169    'default.ini' file.
170
171    """
172    # Default warning string.
173    warning = 'Warning generate_overview_table()'
174
175    # Get the default features and order from the 'default.ini' file.
176    ini_path = path_join(dirname(output_filename), 'features')
177    config = configparser.ConfigParser()
178    config.optionxform = str
179    config.read(path_join(ini_path, 'default.ini'))
180    default_features = config.items(section)
181
182    # Create a dict of the valid features to validate the other ini files.
183    valid_features = {}
184    max_feature_length = 0
185    for feature in default_features:
186        key = feature[0]
187        valid_features[key] = ' '
188        max_feature_length = max(max_feature_length, len(key))
189
190    # Get a list of driver ini files, excluding 'default.ini'.
191    ini_files = [basename(file) for file in listdir(ini_path)
192                 if file.endswith('.ini') and file != 'default.ini']
193    ini_files.sort()
194
195    # Build up a list of the table header names from the ini filenames.
196    pmd_names = []
197    for ini_filename in ini_files:
198        name = ini_filename[:-4]
199        name = name.replace('_vf', 'vf')
200        pmd_names.append(name)
201
202    # Pad the table header names.
203    max_header_len = len(max(pmd_names, key=len))
204    header_names = []
205    for name in pmd_names:
206        if '_vec' in name:
207            pmd, vec = name.split('_')
208            name = '{0:{fill}{align}{width}}vec'.format(pmd,
209                    fill='.', align='<', width=max_header_len-3)
210        else:
211            name = '{0:{fill}{align}{width}}'.format(name,
212                    fill=' ', align='<', width=max_header_len)
213        header_names.append(name)
214
215    # Create a dict of the defined features for each driver from the ini files.
216    ini_data = {}
217    for ini_filename in ini_files:
218        config = configparser.ConfigParser()
219        config.optionxform = str
220        config.read(path_join(ini_path, ini_filename))
221
222        # Initialize the dict with the default.ini value.
223        ini_data[ini_filename] = valid_features.copy()
224
225        # Check for a valid ini section.
226        if not config.has_section(section):
227            print("{}: File '{}' has no [{}] secton".format(warning,
228                                                            ini_filename,
229                                                            section))
230            continue
231
232        # Check for valid features names.
233        for name, value in config.items(section):
234            if name not in valid_features:
235                print("{}: Unknown feature '{}' in '{}'".format(warning,
236                                                                name,
237                                                                ini_filename))
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        # Add a role to handle :numref: references.
432        app.add_role('numref', numref_role)
433        # Process the numref references once the doctree has been created.
434        app.connect('doctree-resolved', process_numref)
435
436    try:
437        # New function in sphinx 1.8
438        app.add_css_file('css/custom.css')
439    except:
440        app.add_stylesheet('css/custom.css')
441