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