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