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