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'] 36 37master_doc = 'index' 38 39# Maximum feature description string length 40feature_str_len = 30 41 42# Figures, tables and code-blocks automatically numbered if they have caption 43numfig = True 44 45latex_documents = [ 46 ('index', 47 'doc.tex', 48 '', 49 '', 50 'manual') 51] 52 53# Latex directives to be included directly in the latex/pdf docs. 54custom_latex_preamble = r""" 55\usepackage{textalpha} 56\RecustomVerbatimEnvironment{Verbatim}{Verbatim}{xleftmargin=5mm} 57\usepackage{etoolbox} 58\robustify\( 59\robustify\) 60""" 61 62# Configuration for the latex/pdf docs. 63latex_elements = { 64 'papersize': 'a4paper', 65 'pointsize': '11pt', 66 # remove blank pages 67 'classoptions': ',openany,oneside', 68 'babel': '\\usepackage[english]{babel}', 69 # customize Latex formatting 70 'preamble': custom_latex_preamble 71} 72 73 74# Override the default Latex formatter in order to modify the 75# code/verbatim blocks. 76class CustomLatexFormatter(LatexFormatter): 77 def __init__(self, **options): 78 super(CustomLatexFormatter, self).__init__(**options) 79 # Use the second smallest font size for code/verbatim blocks. 80 self.verboptions = r'formatcom=\footnotesize' 81 82# Replace the default latex formatter. 83PygmentsBridge.latex_formatter = CustomLatexFormatter 84 85# Configuration for man pages 86man_pages = [("testpmd_app_ug/run_app", "testpmd", 87 "tests for dpdk pmds", "", 1), 88 ("tools/pdump", "dpdk-pdump", 89 "enable packet capture on dpdk ports", "", 1), 90 ("tools/proc_info", "dpdk-procinfo", 91 "access dpdk port stats and memory info", "", 1), 92 ("tools/pmdinfo", "dpdk-pmdinfo", 93 "dump a PMDs hardware support info", "", 1), 94 ("tools/devbind", "dpdk-devbind", 95 "check device status and bind/unbind them from drivers", "", 8)] 96 97 98# ####### :numref: fallback ######## 99# The following hook functions add some simple handling for the :numref: 100# directive for Sphinx versions prior to 1.3.1. The functions replace the 101# :numref: reference with a link to the target (for all Sphinx doc types). 102# It doesn't try to label figures/tables. 103def numref_role(reftype, rawtext, text, lineno, inliner): 104 """ 105 Add a Sphinx role to handle numref references. Note, we can't convert 106 the link here because the doctree isn't build and the target information 107 isn't available. 108 """ 109 # Add an identifier to distinguish numref from other references. 110 newnode = nodes.reference('', 111 '', 112 refuri='_local_numref_#%s' % text, 113 internal=True) 114 return [newnode], [] 115 116 117def process_numref(app, doctree, from_docname): 118 """ 119 Process the numref nodes once the doctree has been built and prior to 120 writing the files. The processing involves replacing the numref with a 121 link plus text to indicate if it is a Figure or Table link. 122 """ 123 124 # Iterate over the reference nodes in the doctree. 125 for node in doctree.traverse(nodes.reference): 126 target = node.get('refuri', '') 127 128 # Look for numref nodes. 129 if target.startswith('_local_numref_#'): 130 target = target.replace('_local_numref_#', '') 131 132 # Get the target label and link information from the Sphinx env. 133 data = app.builder.env.domains['std'].data 134 docname, label, _ = data['labels'].get(target, ('', '', '')) 135 relative_url = app.builder.get_relative_uri(from_docname, docname) 136 137 # Add a text label to the link. 138 if target.startswith('figure'): 139 caption = 'Figure' 140 elif target.startswith('table'): 141 caption = 'Table' 142 else: 143 caption = 'Link' 144 145 # New reference node with the updated link information. 146 newnode = nodes.reference('', 147 caption, 148 refuri='%s#%s' % (relative_url, label), 149 internal=True) 150 node.replace_self(newnode) 151 152 153def generate_overview_table(output_filename, table_id, section, table_name, title): 154 """ 155 Function to generate the Overview Table from the ini files that define 156 the features for each driver. 157 158 The default features for the table and their order is defined by the 159 'default.ini' file. 160 161 """ 162 # Default warning string. 163 warning = 'Warning generate_overview_table()' 164 165 # Get the default features and order from the 'default.ini' file. 166 ini_path = path_join(dirname(output_filename), 'features') 167 config = configparser.ConfigParser() 168 config.optionxform = str 169 config.read(path_join(ini_path, 'default.ini')) 170 default_features = config.items(section) 171 172 # Create a dict of the valid features to validate the other ini files. 173 valid_features = {} 174 max_feature_length = 0 175 for feature in default_features: 176 key = feature[0] 177 valid_features[key] = ' ' 178 max_feature_length = max(max_feature_length, len(key)) 179 180 # Get a list of driver ini files, excluding 'default.ini'. 181 ini_files = [basename(file) for file in listdir(ini_path) 182 if file.endswith('.ini') and file != 'default.ini'] 183 ini_files.sort() 184 185 # Build up a list of the table header names from the ini filenames. 186 pmd_names = [] 187 for ini_filename in ini_files: 188 name = ini_filename[:-4] 189 name = name.replace('_vf', 'vf') 190 pmd_names.append(name) 191 192 # Pad the table header names. 193 max_header_len = len(max(pmd_names, key=len)) 194 header_names = [] 195 for name in pmd_names: 196 if '_vec' in name: 197 pmd, vec = name.split('_') 198 name = '{0:{fill}{align}{width}}vec'.format(pmd, 199 fill='.', align='<', width=max_header_len-3) 200 else: 201 name = '{0:{fill}{align}{width}}'.format(name, 202 fill=' ', align='<', width=max_header_len) 203 header_names.append(name) 204 205 # Create a dict of the defined features for each driver from the ini files. 206 ini_data = {} 207 for ini_filename in ini_files: 208 config = configparser.ConfigParser() 209 config.optionxform = str 210 config.read(path_join(ini_path, ini_filename)) 211 212 # Initialize the dict with the default.ini value. 213 ini_data[ini_filename] = valid_features.copy() 214 215 # Check for a valid ini section. 216 if not config.has_section(section): 217 print("{}: File '{}' has no [{}] secton".format(warning, 218 ini_filename, 219 section)) 220 continue 221 222 # Check for valid features names. 223 for name, value in config.items(section): 224 if name not in valid_features: 225 print("{}: Unknown feature '{}' in '{}'".format(warning, 226 name, 227 ini_filename)) 228 continue 229 230 if value: 231 # Get the first letter only. 232 ini_data[ini_filename][name] = value[0] 233 234 # Print out the RST Driver Overview table from the ini file data. 235 outfile = open(output_filename, 'w') 236 num_cols = len(header_names) 237 238 print_table_css(outfile, table_id) 239 print('.. table:: ' + table_name + '\n', file=outfile) 240 print_table_header(outfile, num_cols, header_names, title) 241 print_table_body(outfile, num_cols, ini_files, ini_data, default_features) 242 243 244def print_table_header(outfile, num_cols, header_names, title): 245 """ Print the RST table header. The header names are vertical. """ 246 print_table_divider(outfile, num_cols) 247 248 line = '' 249 for name in header_names: 250 line += ' ' + name[0] 251 252 print_table_row(outfile, title, line) 253 254 for i in range(1, len(header_names[0])): 255 line = '' 256 for name in header_names: 257 line += ' ' + name[i] 258 259 print_table_row(outfile, '', line) 260 261 print_table_divider(outfile, num_cols) 262 263 264def print_table_body(outfile, num_cols, ini_files, ini_data, default_features): 265 """ Print out the body of the table. Each row is a NIC feature. """ 266 267 for feature, _ in default_features: 268 line = '' 269 270 for ini_filename in ini_files: 271 line += ' ' + ini_data[ini_filename][feature] 272 273 print_table_row(outfile, feature, line) 274 275 print_table_divider(outfile, num_cols) 276 277 278def print_table_row(outfile, feature, line): 279 """ Print a single row of the table with fixed formatting. """ 280 line = line.rstrip() 281 print(' {:<{}}{}'.format(feature, feature_str_len, line), file=outfile) 282 283 284def print_table_divider(outfile, num_cols): 285 """ Print the table divider line. """ 286 line = ' ' 287 column_dividers = ['='] * num_cols 288 line += ' '.join(column_dividers) 289 290 feature = '=' * feature_str_len 291 292 print_table_row(outfile, feature, line) 293 294 295def print_table_css(outfile, table_id): 296 template = """ 297.. raw:: html 298 299 <style> 300 .wy-nav-content { 301 opacity: .99; 302 } 303 table#idx { 304 cursor: default; 305 overflow: hidden; 306 } 307 table#idx p { 308 margin: 0; 309 line-height: inherit; 310 } 311 table#idx th, table#idx td { 312 text-align: center; 313 border: solid 1px #ddd; 314 } 315 table#idx th { 316 padding: 0.5em 0; 317 } 318 table#idx th, table#idx th p { 319 font-size: 11px; 320 white-space: pre-wrap; 321 vertical-align: top; 322 min-width: 0.9em; 323 } 324 table#idx col:first-child { 325 width: 0; 326 } 327 table#idx th:first-child { 328 vertical-align: bottom; 329 } 330 table#idx td { 331 padding: 1px; 332 } 333 table#idx td, table#idx td p { 334 font-size: 11px; 335 } 336 table#idx td:first-child { 337 padding-left: 1em; 338 text-align: left; 339 } 340 table#idx tr:nth-child(2n-1) td { 341 background-color: rgba(210, 210, 210, 0.2); 342 } 343 table#idx th:not(:first-child):hover, 344 table#idx td:not(:first-child):hover { 345 position: relative; 346 } 347 table#idx th:not(:first-child):hover::after, 348 table#idx td:not(:first-child):hover::after { 349 content: ''; 350 height: 6000px; 351 top: -3000px; 352 width: 100%; 353 left: 0; 354 position: absolute; 355 z-index: -1; 356 background-color: #ffb; 357 } 358 table#idx tr:hover td { 359 background-color: #ffb; 360 } 361 </style> 362""" 363 print(template.replace("idx", "id%d" % (table_id)), file=outfile) 364 365 366def setup(app): 367 table_file = dirname(__file__) + '/nics/overview_table.txt' 368 generate_overview_table(table_file, 1, 369 'Features', 370 'Features availability in networking drivers', 371 'Feature') 372 table_file = dirname(__file__) + '/cryptodevs/overview_feature_table.txt' 373 generate_overview_table(table_file, 1, 374 'Features', 375 'Features availability in crypto drivers', 376 'Feature') 377 table_file = dirname(__file__) + '/cryptodevs/overview_cipher_table.txt' 378 generate_overview_table(table_file, 2, 379 'Cipher', 380 'Cipher algorithms in crypto drivers', 381 'Cipher algorithm') 382 table_file = dirname(__file__) + '/cryptodevs/overview_auth_table.txt' 383 generate_overview_table(table_file, 3, 384 'Auth', 385 'Authentication algorithms in crypto drivers', 386 'Authentication algorithm') 387 table_file = dirname(__file__) + '/cryptodevs/overview_aead_table.txt' 388 generate_overview_table(table_file, 4, 389 'AEAD', 390 'AEAD algorithms in crypto drivers', 391 'AEAD algorithm') 392 table_file = dirname(__file__) + '/cryptodevs/overview_asym_table.txt' 393 generate_overview_table(table_file, 5, 394 'Asymmetric', 395 'Asymmetric algorithms in crypto drivers', 396 'Asymmetric algorithm') 397 table_file = dirname(__file__) + '/compressdevs/overview_feature_table.txt' 398 generate_overview_table(table_file, 1, 399 'Features', 400 'Features availability in compression drivers', 401 'Feature') 402 table_file = dirname(__file__) + '/regexdevs/overview_feature_table.txt' 403 generate_overview_table(table_file, 1, 404 'Features', 405 'Features availability in regex drivers', 406 'Feature') 407 table_file = dirname(__file__) + '/vdpadevs/overview_feature_table.txt' 408 generate_overview_table(table_file, 1, 409 'Features', 410 'Features availability in vDPA drivers', 411 'Feature') 412 table_file = dirname(__file__) + '/bbdevs/overview_feature_table.txt' 413 generate_overview_table(table_file, 1, 414 'Features', 415 'Features availability in bbdev drivers', 416 'Feature') 417 418 if LooseVersion(sphinx_version) < LooseVersion('1.3.1'): 419 print('Upgrade sphinx to version >= 1.3.1 for ' 420 'improved Figure/Table number handling.') 421 # Add a role to handle :numref: references. 422 app.add_role('numref', numref_role) 423 # Process the numref references once the doctree has been created. 424 app.connect('doctree-resolved', process_numref) 425 426 try: 427 # New function in sphinx 1.8 428 app.add_css_file('css/custom.css') 429 except: 430 app.add_stylesheet('css/custom.css') 431