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