1819667bcSMauro Carvalho Chehab#!/usr/bin/env python3 2819667bcSMauro Carvalho Chehab# SPDX-License-Identifier: GPL-2.0 3819667bcSMauro Carvalho Chehab# Copyright (C) 2025 Mauro Carvalho Chehab <mchehab+huawei@kernel.org> 4819667bcSMauro Carvalho Chehab# 5819667bcSMauro Carvalho Chehab# pylint: disable=R0902, R0912, R0913, R0914, R0915, R0917, C0103 6819667bcSMauro Carvalho Chehab# 7819667bcSMauro Carvalho Chehab# Converted from docs Makefile and parallel-wrapper.sh, both under 8819667bcSMauro Carvalho Chehab# GPLv2, copyrighted since 2008 by the following authors: 9819667bcSMauro Carvalho Chehab# 10819667bcSMauro Carvalho Chehab# Akira Yokosawa <akiyks@gmail.com> 11819667bcSMauro Carvalho Chehab# Arnd Bergmann <arnd@arndb.de> 12819667bcSMauro Carvalho Chehab# Breno Leitao <leitao@debian.org> 13819667bcSMauro Carvalho Chehab# Carlos Bilbao <carlos.bilbao@amd.com> 14819667bcSMauro Carvalho Chehab# Dave Young <dyoung@redhat.com> 15819667bcSMauro Carvalho Chehab# Donald Hunter <donald.hunter@gmail.com> 16819667bcSMauro Carvalho Chehab# Geert Uytterhoeven <geert+renesas@glider.be> 17819667bcSMauro Carvalho Chehab# Jani Nikula <jani.nikula@intel.com> 18819667bcSMauro Carvalho Chehab# Jan Stancek <jstancek@redhat.com> 19819667bcSMauro Carvalho Chehab# Jonathan Corbet <corbet@lwn.net> 20819667bcSMauro Carvalho Chehab# Joshua Clayton <stillcompiling@gmail.com> 21819667bcSMauro Carvalho Chehab# Kees Cook <keescook@chromium.org> 22819667bcSMauro Carvalho Chehab# Linus Torvalds <torvalds@linux-foundation.org> 23819667bcSMauro Carvalho Chehab# Magnus Damm <damm+renesas@opensource.se> 24819667bcSMauro Carvalho Chehab# Masahiro Yamada <masahiroy@kernel.org> 25819667bcSMauro Carvalho Chehab# Mauro Carvalho Chehab <mchehab+huawei@kernel.org> 26819667bcSMauro Carvalho Chehab# Maxim Cournoyer <maxim.cournoyer@gmail.com> 27819667bcSMauro Carvalho Chehab# Peter Foley <pefoley2@pefoley.com> 28819667bcSMauro Carvalho Chehab# Randy Dunlap <rdunlap@infradead.org> 29819667bcSMauro Carvalho Chehab# Rob Herring <robh@kernel.org> 30819667bcSMauro Carvalho Chehab# Shuah Khan <shuahkh@osg.samsung.com> 31819667bcSMauro Carvalho Chehab# Thorsten Blum <thorsten.blum@toblux.com> 32819667bcSMauro Carvalho Chehab# Tomas Winkler <tomas.winkler@intel.com> 33819667bcSMauro Carvalho Chehab 34819667bcSMauro Carvalho Chehab 35819667bcSMauro Carvalho Chehab""" 36819667bcSMauro Carvalho ChehabSphinx build wrapper that handles Kernel-specific business rules: 37819667bcSMauro Carvalho Chehab 38819667bcSMauro Carvalho Chehab- it gets the Kernel build environment vars; 39819667bcSMauro Carvalho Chehab- it determines what's the best parallelism; 40819667bcSMauro Carvalho Chehab- it handles SPHINXDIRS 41819667bcSMauro Carvalho Chehab 42819667bcSMauro Carvalho ChehabThis tool ensures that MIN_PYTHON_VERSION is satisfied. If version is 43819667bcSMauro Carvalho Chehabbelow that, it seeks for a new Python version. If found, it re-runs using 44819667bcSMauro Carvalho Chehabthe newer version. 45819667bcSMauro Carvalho Chehab""" 46819667bcSMauro Carvalho Chehab 47819667bcSMauro Carvalho Chehabimport argparse 4882c294d4SMauro Carvalho Chehabimport locale 49819667bcSMauro Carvalho Chehabimport os 507e8a8143SMauro Carvalho Chehabimport re 51819667bcSMauro Carvalho Chehabimport shlex 52819667bcSMauro Carvalho Chehabimport shutil 53819667bcSMauro Carvalho Chehabimport subprocess 54819667bcSMauro Carvalho Chehabimport sys 55819667bcSMauro Carvalho Chehab 5608e14bc1SMauro Carvalho Chehabfrom concurrent import futures 577e8a8143SMauro Carvalho Chehabfrom glob import glob 5808e14bc1SMauro Carvalho Chehab 59819667bcSMauro Carvalho Chehabfrom lib.python_version import PythonVersion 60819667bcSMauro Carvalho Chehabfrom lib.latex_fonts import LatexFontChecker 61819667bcSMauro Carvalho Chehab 62819667bcSMauro Carvalho ChehabLIB_DIR = "../../scripts/lib" 63819667bcSMauro Carvalho ChehabSRC_DIR = os.path.dirname(os.path.realpath(__file__)) 64819667bcSMauro Carvalho Chehab 65819667bcSMauro Carvalho Chehabsys.path.insert(0, os.path.join(SRC_DIR, LIB_DIR)) 66819667bcSMauro Carvalho Chehab 67819667bcSMauro Carvalho Chehabfrom jobserver import JobserverExec # pylint: disable=C0413,C0411,E0401 68819667bcSMauro Carvalho Chehab 69819667bcSMauro Carvalho Chehab# 70819667bcSMauro Carvalho Chehab# Some constants 71819667bcSMauro Carvalho Chehab# 72819667bcSMauro Carvalho ChehabMIN_PYTHON_VERSION = PythonVersion("3.7").version 73819667bcSMauro Carvalho ChehabPAPER = ["", "a4", "letter"] 74819667bcSMauro Carvalho Chehab 75819667bcSMauro Carvalho ChehabTARGETS = { 76819667bcSMauro Carvalho Chehab "cleandocs": { "builder": "clean" }, 77819667bcSMauro Carvalho Chehab "linkcheckdocs": { "builder": "linkcheck" }, 78819667bcSMauro Carvalho Chehab "htmldocs": { "builder": "html" }, 79819667bcSMauro Carvalho Chehab "epubdocs": { "builder": "epub", "out_dir": "epub" }, 80819667bcSMauro Carvalho Chehab "texinfodocs": { "builder": "texinfo", "out_dir": "texinfo" }, 81819667bcSMauro Carvalho Chehab "infodocs": { "builder": "texinfo", "out_dir": "texinfo" }, 827e8a8143SMauro Carvalho Chehab "mandocs": { "builder": "man", "out_dir": "man" }, 83819667bcSMauro Carvalho Chehab "latexdocs": { "builder": "latex", "out_dir": "latex" }, 84819667bcSMauro Carvalho Chehab "pdfdocs": { "builder": "latex", "out_dir": "latex" }, 85819667bcSMauro Carvalho Chehab "xmldocs": { "builder": "xml", "out_dir": "xml" }, 86819667bcSMauro Carvalho Chehab} 87819667bcSMauro Carvalho Chehab 88819667bcSMauro Carvalho Chehab 89819667bcSMauro Carvalho Chehab# 90819667bcSMauro Carvalho Chehab# SphinxBuilder class 91819667bcSMauro Carvalho Chehab# 92819667bcSMauro Carvalho Chehab 93819667bcSMauro Carvalho Chehabclass SphinxBuilder: 94819667bcSMauro Carvalho Chehab """ 95819667bcSMauro Carvalho Chehab Handles a sphinx-build target, adding needed arguments to build 96819667bcSMauro Carvalho Chehab with the Kernel. 97819667bcSMauro Carvalho Chehab """ 98819667bcSMauro Carvalho Chehab 99819667bcSMauro Carvalho Chehab def get_path(self, path, use_cwd=False, abs_path=False): 100819667bcSMauro Carvalho Chehab """ 101819667bcSMauro Carvalho Chehab Ancillary routine to handle patches the right way, as shell does. 102819667bcSMauro Carvalho Chehab 103819667bcSMauro Carvalho Chehab It first expands "~" and "~user". Then, if patch is not absolute, 104819667bcSMauro Carvalho Chehab join self.srctree. Finally, if requested, convert to abspath. 105819667bcSMauro Carvalho Chehab """ 106819667bcSMauro Carvalho Chehab 107819667bcSMauro Carvalho Chehab path = os.path.expanduser(path) 108819667bcSMauro Carvalho Chehab if not path.startswith("/"): 109819667bcSMauro Carvalho Chehab if use_cwd: 110819667bcSMauro Carvalho Chehab base = os.getcwd() 111819667bcSMauro Carvalho Chehab else: 112819667bcSMauro Carvalho Chehab base = self.srctree 113819667bcSMauro Carvalho Chehab 114819667bcSMauro Carvalho Chehab path = os.path.join(base, path) 115819667bcSMauro Carvalho Chehab 116819667bcSMauro Carvalho Chehab if abs_path: 117819667bcSMauro Carvalho Chehab return os.path.abspath(path) 118819667bcSMauro Carvalho Chehab 119819667bcSMauro Carvalho Chehab return path 120819667bcSMauro Carvalho Chehab 121819667bcSMauro Carvalho Chehab def get_sphinx_extra_opts(self, n_jobs): 122819667bcSMauro Carvalho Chehab """ 123819667bcSMauro Carvalho Chehab Get the number of jobs to be used for docs build passed via command 124819667bcSMauro Carvalho Chehab line and desired sphinx verbosity. 125819667bcSMauro Carvalho Chehab 126819667bcSMauro Carvalho Chehab The number of jobs can be on different places: 127819667bcSMauro Carvalho Chehab 128819667bcSMauro Carvalho Chehab 1) It can be passed via "-j" argument; 129819667bcSMauro Carvalho Chehab 2) The SPHINXOPTS="-j8" env var may have "-j"; 130819667bcSMauro Carvalho Chehab 3) if called via GNU make, -j specifies the desired number of jobs. 131819667bcSMauro Carvalho Chehab with GNU makefile, this number is available via POSIX jobserver; 132819667bcSMauro Carvalho Chehab 4) if none of the above is available, it should default to "-jauto", 133819667bcSMauro Carvalho Chehab and let sphinx decide the best value. 134819667bcSMauro Carvalho Chehab """ 135819667bcSMauro Carvalho Chehab 136819667bcSMauro Carvalho Chehab # 137819667bcSMauro Carvalho Chehab # SPHINXOPTS env var, if used, contains extra arguments to be used 138819667bcSMauro Carvalho Chehab # by sphinx-build time. Among them, it may contain sphinx verbosity 139819667bcSMauro Carvalho Chehab # and desired number of parallel jobs. 140819667bcSMauro Carvalho Chehab # 141819667bcSMauro Carvalho Chehab parser = argparse.ArgumentParser() 142819667bcSMauro Carvalho Chehab parser.add_argument('-j', '--jobs', type=int) 143819667bcSMauro Carvalho Chehab parser.add_argument('-q', '--quiet', type=int) 144819667bcSMauro Carvalho Chehab 145819667bcSMauro Carvalho Chehab # 146819667bcSMauro Carvalho Chehab # Other sphinx-build arguments go as-is, so place them 147819667bcSMauro Carvalho Chehab # at self.sphinxopts, using shell parser 148819667bcSMauro Carvalho Chehab # 149819667bcSMauro Carvalho Chehab sphinxopts = shlex.split(os.environ.get("SPHINXOPTS", "")) 150819667bcSMauro Carvalho Chehab 151819667bcSMauro Carvalho Chehab # 152819667bcSMauro Carvalho Chehab # Build a list of sphinx args, honoring verbosity here if specified 153819667bcSMauro Carvalho Chehab # 154819667bcSMauro Carvalho Chehab 155819667bcSMauro Carvalho Chehab verbose = self.verbose 156819667bcSMauro Carvalho Chehab sphinx_args, self.sphinxopts = parser.parse_known_args(sphinxopts) 157819667bcSMauro Carvalho Chehab if sphinx_args.quiet is True: 158819667bcSMauro Carvalho Chehab verbose = False 159819667bcSMauro Carvalho Chehab 160819667bcSMauro Carvalho Chehab # 161819667bcSMauro Carvalho Chehab # If the user explicitly sets "-j" at command line, use it. 162819667bcSMauro Carvalho Chehab # Otherwise, pick it from SPHINXOPTS args 163819667bcSMauro Carvalho Chehab # 164819667bcSMauro Carvalho Chehab if n_jobs: 165819667bcSMauro Carvalho Chehab self.n_jobs = n_jobs 166819667bcSMauro Carvalho Chehab elif sphinx_args.jobs: 167819667bcSMauro Carvalho Chehab self.n_jobs = sphinx_args.jobs 168819667bcSMauro Carvalho Chehab else: 169819667bcSMauro Carvalho Chehab self.n_jobs = None 170819667bcSMauro Carvalho Chehab 171819667bcSMauro Carvalho Chehab if not verbose: 172819667bcSMauro Carvalho Chehab self.sphinxopts += ["-q"] 173819667bcSMauro Carvalho Chehab 1742f99b85eSMauro Carvalho Chehab def __init__(self, builddir, verbose=False, n_jobs=None, interactive=None): 175819667bcSMauro Carvalho Chehab """Initialize internal variables""" 176819667bcSMauro Carvalho Chehab self.verbose = None 177819667bcSMauro Carvalho Chehab 178819667bcSMauro Carvalho Chehab # 179819667bcSMauro Carvalho Chehab # Normal variables passed from Kernel's makefile 180819667bcSMauro Carvalho Chehab # 181819667bcSMauro Carvalho Chehab self.kernelversion = os.environ.get("KERNELVERSION", "unknown") 182819667bcSMauro Carvalho Chehab self.kernelrelease = os.environ.get("KERNELRELEASE", "unknown") 183819667bcSMauro Carvalho Chehab self.pdflatex = os.environ.get("PDFLATEX", "xelatex") 1842f99b85eSMauro Carvalho Chehab 1852f99b85eSMauro Carvalho Chehab if not interactive: 186819667bcSMauro Carvalho Chehab self.latexopts = os.environ.get("LATEXOPTS", "-interaction=batchmode -no-shell-escape") 1872f99b85eSMauro Carvalho Chehab else: 1882f99b85eSMauro Carvalho Chehab self.latexopts = os.environ.get("LATEXOPTS", "") 189819667bcSMauro Carvalho Chehab 190819667bcSMauro Carvalho Chehab if not verbose: 191819667bcSMauro Carvalho Chehab verbose = bool(os.environ.get("KBUILD_VERBOSE", "") != "") 192819667bcSMauro Carvalho Chehab 193819667bcSMauro Carvalho Chehab if verbose is not None: 194819667bcSMauro Carvalho Chehab self.verbose = verbose 195819667bcSMauro Carvalho Chehab 196819667bcSMauro Carvalho Chehab # 197819667bcSMauro Carvalho Chehab # Source tree directory. This needs to be at os.environ, as 198819667bcSMauro Carvalho Chehab # Sphinx extensions use it 199819667bcSMauro Carvalho Chehab # 200819667bcSMauro Carvalho Chehab self.srctree = os.environ.get("srctree") 201819667bcSMauro Carvalho Chehab if not self.srctree: 202819667bcSMauro Carvalho Chehab self.srctree = "." 203819667bcSMauro Carvalho Chehab os.environ["srctree"] = self.srctree 204819667bcSMauro Carvalho Chehab 205819667bcSMauro Carvalho Chehab # 206819667bcSMauro Carvalho Chehab # Now that we can expand srctree, get other directories as well 207819667bcSMauro Carvalho Chehab # 208819667bcSMauro Carvalho Chehab self.sphinxbuild = os.environ.get("SPHINXBUILD", "sphinx-build") 209819667bcSMauro Carvalho Chehab self.kerneldoc = self.get_path(os.environ.get("KERNELDOC", 210819667bcSMauro Carvalho Chehab "scripts/kernel-doc.py")) 211819667bcSMauro Carvalho Chehab self.builddir = self.get_path(builddir, use_cwd=True, abs_path=True) 212819667bcSMauro Carvalho Chehab 213819667bcSMauro Carvalho Chehab # 214819667bcSMauro Carvalho Chehab # Get directory locations for LaTeX build toolchain 215819667bcSMauro Carvalho Chehab # 216819667bcSMauro Carvalho Chehab self.pdflatex_cmd = shutil.which(self.pdflatex) 217819667bcSMauro Carvalho Chehab self.latexmk_cmd = shutil.which("latexmk") 218819667bcSMauro Carvalho Chehab 219819667bcSMauro Carvalho Chehab self.env = os.environ.copy() 220819667bcSMauro Carvalho Chehab 221819667bcSMauro Carvalho Chehab self.get_sphinx_extra_opts(n_jobs) 222819667bcSMauro Carvalho Chehab 223819667bcSMauro Carvalho Chehab def run_sphinx(self, sphinx_build, build_args, *args, **pwargs): 224819667bcSMauro Carvalho Chehab """ 225819667bcSMauro Carvalho Chehab Executes sphinx-build using current python3 command. 226819667bcSMauro Carvalho Chehab 227819667bcSMauro Carvalho Chehab When calling via GNU make, POSIX jobserver is used to tell how 228819667bcSMauro Carvalho Chehab many jobs are still available from a job pool. claim all remaining 229819667bcSMauro Carvalho Chehab jobs, as we don't want sphinx-build to run in parallel with other 230819667bcSMauro Carvalho Chehab jobs. 231819667bcSMauro Carvalho Chehab 232819667bcSMauro Carvalho Chehab Despite that, the user may actually force a different value than 233819667bcSMauro Carvalho Chehab the number of available jobs via command line. 234819667bcSMauro Carvalho Chehab 235819667bcSMauro Carvalho Chehab The "with" logic here is used to ensure that the claimed jobs will 236819667bcSMauro Carvalho Chehab be freed once subprocess finishes 237819667bcSMauro Carvalho Chehab """ 238819667bcSMauro Carvalho Chehab 239819667bcSMauro Carvalho Chehab with JobserverExec() as jobserver: 240819667bcSMauro Carvalho Chehab if jobserver.claim: 241819667bcSMauro Carvalho Chehab # 242819667bcSMauro Carvalho Chehab # when GNU make is used, claim available jobs from jobserver 243819667bcSMauro Carvalho Chehab # 244819667bcSMauro Carvalho Chehab n_jobs = str(jobserver.claim) 245819667bcSMauro Carvalho Chehab else: 246819667bcSMauro Carvalho Chehab # 247819667bcSMauro Carvalho Chehab # Otherwise, let sphinx decide by default 248819667bcSMauro Carvalho Chehab # 249819667bcSMauro Carvalho Chehab n_jobs = "auto" 250819667bcSMauro Carvalho Chehab 251819667bcSMauro Carvalho Chehab # 252819667bcSMauro Carvalho Chehab # If explicitly requested via command line, override default 253819667bcSMauro Carvalho Chehab # 254819667bcSMauro Carvalho Chehab if self.n_jobs: 255819667bcSMauro Carvalho Chehab n_jobs = str(self.n_jobs) 256819667bcSMauro Carvalho Chehab 257819667bcSMauro Carvalho Chehab cmd = [sys.executable, sphinx_build] 258819667bcSMauro Carvalho Chehab cmd += [f"-j{n_jobs}"] 259819667bcSMauro Carvalho Chehab cmd += self.sphinxopts 260819667bcSMauro Carvalho Chehab cmd += build_args 261819667bcSMauro Carvalho Chehab 262819667bcSMauro Carvalho Chehab if self.verbose: 263819667bcSMauro Carvalho Chehab print(" ".join(cmd)) 264819667bcSMauro Carvalho Chehab 265819667bcSMauro Carvalho Chehab return subprocess.call(cmd, *args, **pwargs) 266819667bcSMauro Carvalho Chehab 267*2118ba7dSMauro Carvalho Chehab def handle_html(self, css, output_dir, rustdoc): 268819667bcSMauro Carvalho Chehab """ 269819667bcSMauro Carvalho Chehab Extra steps for HTML and epub output. 270819667bcSMauro Carvalho Chehab 271819667bcSMauro Carvalho Chehab For such targets, we need to ensure that CSS will be properly 272819667bcSMauro Carvalho Chehab copied to the output _static directory 273819667bcSMauro Carvalho Chehab """ 274819667bcSMauro Carvalho Chehab 275*2118ba7dSMauro Carvalho Chehab if css: 276819667bcSMauro Carvalho Chehab css = os.path.expanduser(css) 277819667bcSMauro Carvalho Chehab if not css.startswith("/"): 278819667bcSMauro Carvalho Chehab css = os.path.join(self.srctree, css) 279819667bcSMauro Carvalho Chehab 280819667bcSMauro Carvalho Chehab static_dir = os.path.join(output_dir, "_static") 281819667bcSMauro Carvalho Chehab os.makedirs(static_dir, exist_ok=True) 282819667bcSMauro Carvalho Chehab 283819667bcSMauro Carvalho Chehab try: 284819667bcSMauro Carvalho Chehab shutil.copy2(css, static_dir) 285819667bcSMauro Carvalho Chehab except (OSError, IOError) as e: 286819667bcSMauro Carvalho Chehab print(f"Warning: Failed to copy CSS: {e}", file=sys.stderr) 287819667bcSMauro Carvalho Chehab 288*2118ba7dSMauro Carvalho Chehab if rustdoc: 289*2118ba7dSMauro Carvalho Chehab if "MAKE" in self.env: 290*2118ba7dSMauro Carvalho Chehab cmd = [self.env["MAKE"]] 291*2118ba7dSMauro Carvalho Chehab else: 292*2118ba7dSMauro Carvalho Chehab cmd = ["make", "LLVM=1"] 293*2118ba7dSMauro Carvalho Chehab 294*2118ba7dSMauro Carvalho Chehab cmd += [ "rustdoc"] 295*2118ba7dSMauro Carvalho Chehab if self.verbose: 296*2118ba7dSMauro Carvalho Chehab print(" ".join(cmd)) 297*2118ba7dSMauro Carvalho Chehab 298*2118ba7dSMauro Carvalho Chehab try: 299*2118ba7dSMauro Carvalho Chehab subprocess.run(cmd, check=True) 300*2118ba7dSMauro Carvalho Chehab except subprocess.CalledProcessError as e: 301*2118ba7dSMauro Carvalho Chehab print(f"Ignored errors when building rustdoc: {e}. Is RUST enabled?", 302*2118ba7dSMauro Carvalho Chehab file=sys.stderr) 303*2118ba7dSMauro Carvalho Chehab 30408e14bc1SMauro Carvalho Chehab def build_pdf_file(self, latex_cmd, from_dir, path): 30508e14bc1SMauro Carvalho Chehab """Builds a single pdf file using latex_cmd""" 30608e14bc1SMauro Carvalho Chehab try: 30708e14bc1SMauro Carvalho Chehab subprocess.run(latex_cmd + [path], 30808e14bc1SMauro Carvalho Chehab cwd=from_dir, check=True, env=self.env) 30908e14bc1SMauro Carvalho Chehab 31008e14bc1SMauro Carvalho Chehab return True 31108e14bc1SMauro Carvalho Chehab except subprocess.CalledProcessError: 31208e14bc1SMauro Carvalho Chehab return False 31308e14bc1SMauro Carvalho Chehab 31408e14bc1SMauro Carvalho Chehab def pdf_parallel_build(self, tex_suffix, latex_cmd, tex_files, n_jobs): 31508e14bc1SMauro Carvalho Chehab """Build PDF files in parallel if possible""" 31608e14bc1SMauro Carvalho Chehab builds = {} 31708e14bc1SMauro Carvalho Chehab build_failed = False 31808e14bc1SMauro Carvalho Chehab max_len = 0 31908e14bc1SMauro Carvalho Chehab has_tex = False 32008e14bc1SMauro Carvalho Chehab 32108e14bc1SMauro Carvalho Chehab # 32208e14bc1SMauro Carvalho Chehab # LaTeX PDF error code is almost useless for us: 32308e14bc1SMauro Carvalho Chehab # any warning makes it non-zero. For kernel doc builds it always return 32408e14bc1SMauro Carvalho Chehab # non-zero even when build succeeds. So, let's do the best next thing: 32508e14bc1SMauro Carvalho Chehab # Ignore build errors. At the end, check if all PDF files were built, 32608e14bc1SMauro Carvalho Chehab # printing a summary with the built ones and returning 0 if all of 32708e14bc1SMauro Carvalho Chehab # them were actually built. 32808e14bc1SMauro Carvalho Chehab # 32908e14bc1SMauro Carvalho Chehab with futures.ThreadPoolExecutor(max_workers=n_jobs) as executor: 33008e14bc1SMauro Carvalho Chehab jobs = {} 33108e14bc1SMauro Carvalho Chehab 33208e14bc1SMauro Carvalho Chehab for from_dir, pdf_dir, entry in tex_files: 33308e14bc1SMauro Carvalho Chehab name = entry.name 33408e14bc1SMauro Carvalho Chehab 33508e14bc1SMauro Carvalho Chehab if not name.endswith(tex_suffix): 33608e14bc1SMauro Carvalho Chehab continue 33708e14bc1SMauro Carvalho Chehab 33808e14bc1SMauro Carvalho Chehab name = name[:-len(tex_suffix)] 33908e14bc1SMauro Carvalho Chehab has_tex = True 34008e14bc1SMauro Carvalho Chehab 34108e14bc1SMauro Carvalho Chehab future = executor.submit(self.build_pdf_file, latex_cmd, 34208e14bc1SMauro Carvalho Chehab from_dir, entry.path) 34308e14bc1SMauro Carvalho Chehab jobs[future] = (from_dir, pdf_dir, name) 34408e14bc1SMauro Carvalho Chehab 34508e14bc1SMauro Carvalho Chehab for future in futures.as_completed(jobs): 34608e14bc1SMauro Carvalho Chehab from_dir, pdf_dir, name = jobs[future] 34708e14bc1SMauro Carvalho Chehab 34808e14bc1SMauro Carvalho Chehab pdf_name = name + ".pdf" 34908e14bc1SMauro Carvalho Chehab pdf_from = os.path.join(from_dir, pdf_name) 3500d9abc76SMauro Carvalho Chehab pdf_to = os.path.join(pdf_dir, pdf_name) 3510d9abc76SMauro Carvalho Chehab out_name = os.path.relpath(pdf_to, self.builddir) 3520d9abc76SMauro Carvalho Chehab max_len = max(max_len, len(out_name)) 35308e14bc1SMauro Carvalho Chehab 35408e14bc1SMauro Carvalho Chehab try: 35508e14bc1SMauro Carvalho Chehab success = future.result() 35608e14bc1SMauro Carvalho Chehab 35708e14bc1SMauro Carvalho Chehab if success and os.path.exists(pdf_from): 35808e14bc1SMauro Carvalho Chehab os.rename(pdf_from, pdf_to) 35908e14bc1SMauro Carvalho Chehab 36008e14bc1SMauro Carvalho Chehab # 36108e14bc1SMauro Carvalho Chehab # if verbose, get the name of built PDF file 36208e14bc1SMauro Carvalho Chehab # 36308e14bc1SMauro Carvalho Chehab if self.verbose: 3640d9abc76SMauro Carvalho Chehab builds[out_name] = "SUCCESS" 36508e14bc1SMauro Carvalho Chehab else: 3660d9abc76SMauro Carvalho Chehab builds[out_name] = "FAILED" 36708e14bc1SMauro Carvalho Chehab build_failed = True 36808e14bc1SMauro Carvalho Chehab except futures.Error as e: 3690d9abc76SMauro Carvalho Chehab builds[out_name] = f"FAILED ({repr(e)})" 37008e14bc1SMauro Carvalho Chehab build_failed = True 37108e14bc1SMauro Carvalho Chehab 37208e14bc1SMauro Carvalho Chehab # 37308e14bc1SMauro Carvalho Chehab # Handle case where no .tex files were found 37408e14bc1SMauro Carvalho Chehab # 37508e14bc1SMauro Carvalho Chehab if not has_tex: 3760d9abc76SMauro Carvalho Chehab out_name = "LaTeX files" 3770d9abc76SMauro Carvalho Chehab max_len = max(max_len, len(out_name)) 3780d9abc76SMauro Carvalho Chehab builds[out_name] = "FAILED: no .tex files were generated" 37908e14bc1SMauro Carvalho Chehab build_failed = True 38008e14bc1SMauro Carvalho Chehab 38108e14bc1SMauro Carvalho Chehab return builds, build_failed, max_len 38208e14bc1SMauro Carvalho Chehab 383819667bcSMauro Carvalho Chehab def handle_pdf(self, output_dirs, deny_vf): 384819667bcSMauro Carvalho Chehab """ 385819667bcSMauro Carvalho Chehab Extra steps for PDF output. 386819667bcSMauro Carvalho Chehab 387819667bcSMauro Carvalho Chehab As PDF is handled via a LaTeX output, after building the .tex file, 388819667bcSMauro Carvalho Chehab a new build is needed to create the PDF output from the latex 389819667bcSMauro Carvalho Chehab directory. 390819667bcSMauro Carvalho Chehab """ 391819667bcSMauro Carvalho Chehab builds = {} 392819667bcSMauro Carvalho Chehab max_len = 0 39308e14bc1SMauro Carvalho Chehab tex_suffix = ".tex" 39408e14bc1SMauro Carvalho Chehab tex_files = [] 395819667bcSMauro Carvalho Chehab 396819667bcSMauro Carvalho Chehab # 397819667bcSMauro Carvalho Chehab # Since early 2024, Fedora and openSUSE tumbleweed have started 398819667bcSMauro Carvalho Chehab # deploying variable-font format of "Noto CJK", causing LaTeX 399819667bcSMauro Carvalho Chehab # to break with CJK. Work around it, by denying the variable font 400819667bcSMauro Carvalho Chehab # usage during xelatex build by passing the location of a config 401819667bcSMauro Carvalho Chehab # file with a deny list. 402819667bcSMauro Carvalho Chehab # 403819667bcSMauro Carvalho Chehab # See tools/docs/lib/latex_fonts.py for more details. 404819667bcSMauro Carvalho Chehab # 405819667bcSMauro Carvalho Chehab if deny_vf: 406819667bcSMauro Carvalho Chehab deny_vf = os.path.expanduser(deny_vf) 407819667bcSMauro Carvalho Chehab if os.path.isdir(deny_vf): 408819667bcSMauro Carvalho Chehab self.env["XDG_CONFIG_HOME"] = deny_vf 409819667bcSMauro Carvalho Chehab 410819667bcSMauro Carvalho Chehab for from_dir in output_dirs: 411819667bcSMauro Carvalho Chehab pdf_dir = os.path.join(from_dir, "../pdf") 412819667bcSMauro Carvalho Chehab os.makedirs(pdf_dir, exist_ok=True) 413819667bcSMauro Carvalho Chehab 414819667bcSMauro Carvalho Chehab if self.latexmk_cmd: 415819667bcSMauro Carvalho Chehab latex_cmd = [self.latexmk_cmd, f"-{self.pdflatex}"] 416819667bcSMauro Carvalho Chehab else: 417819667bcSMauro Carvalho Chehab latex_cmd = [self.pdflatex] 418819667bcSMauro Carvalho Chehab 419819667bcSMauro Carvalho Chehab latex_cmd.extend(shlex.split(self.latexopts)) 420819667bcSMauro Carvalho Chehab 42108e14bc1SMauro Carvalho Chehab # Get a list of tex files to process 422819667bcSMauro Carvalho Chehab with os.scandir(from_dir) as it: 423819667bcSMauro Carvalho Chehab for entry in it: 42408e14bc1SMauro Carvalho Chehab if entry.name.endswith(tex_suffix): 42508e14bc1SMauro Carvalho Chehab tex_files.append((from_dir, pdf_dir, entry)) 426819667bcSMauro Carvalho Chehab 427819667bcSMauro Carvalho Chehab # 42808e14bc1SMauro Carvalho Chehab # When using make, this won't be used, as the number of jobs comes 42908e14bc1SMauro Carvalho Chehab # from POSIX jobserver. So, this covers the case where build comes 43008e14bc1SMauro Carvalho Chehab # from command line. On such case, serialize by default, except if 43108e14bc1SMauro Carvalho Chehab # the user explicitly sets the number of jobs. 432819667bcSMauro Carvalho Chehab # 43308e14bc1SMauro Carvalho Chehab n_jobs = 1 43408e14bc1SMauro Carvalho Chehab 43508e14bc1SMauro Carvalho Chehab # n_jobs is either an integer or "auto". Only use it if it is a number 43608e14bc1SMauro Carvalho Chehab if self.n_jobs: 437819667bcSMauro Carvalho Chehab try: 43808e14bc1SMauro Carvalho Chehab n_jobs = int(self.n_jobs) 43908e14bc1SMauro Carvalho Chehab except ValueError: 440819667bcSMauro Carvalho Chehab pass 441819667bcSMauro Carvalho Chehab 44208e14bc1SMauro Carvalho Chehab # 44308e14bc1SMauro Carvalho Chehab # When using make, jobserver.claim is the number of jobs that were 44408e14bc1SMauro Carvalho Chehab # used with "-j" and that aren't used by other make targets 44508e14bc1SMauro Carvalho Chehab # 44608e14bc1SMauro Carvalho Chehab with JobserverExec() as jobserver: 44708e14bc1SMauro Carvalho Chehab n_jobs = 1 448819667bcSMauro Carvalho Chehab 44908e14bc1SMauro Carvalho Chehab # 45008e14bc1SMauro Carvalho Chehab # Handle the case when a parameter is passed via command line, 45108e14bc1SMauro Carvalho Chehab # using it as default, if jobserver doesn't claim anything 45208e14bc1SMauro Carvalho Chehab # 45308e14bc1SMauro Carvalho Chehab if self.n_jobs: 45408e14bc1SMauro Carvalho Chehab try: 45508e14bc1SMauro Carvalho Chehab n_jobs = int(self.n_jobs) 45608e14bc1SMauro Carvalho Chehab except ValueError: 45708e14bc1SMauro Carvalho Chehab pass 458819667bcSMauro Carvalho Chehab 45908e14bc1SMauro Carvalho Chehab if jobserver.claim: 46008e14bc1SMauro Carvalho Chehab n_jobs = jobserver.claim 461819667bcSMauro Carvalho Chehab 46208e14bc1SMauro Carvalho Chehab builds, build_failed, max_len = self.pdf_parallel_build(tex_suffix, 46308e14bc1SMauro Carvalho Chehab latex_cmd, 46408e14bc1SMauro Carvalho Chehab tex_files, 46508e14bc1SMauro Carvalho Chehab n_jobs) 466819667bcSMauro Carvalho Chehab 46708e14bc1SMauro Carvalho Chehab # 46808e14bc1SMauro Carvalho Chehab # In verbose mode, print a summary with the build results per file. 46908e14bc1SMauro Carvalho Chehab # Otherwise, print a single line with all failures, if any. 47008e14bc1SMauro Carvalho Chehab # On both cases, return code 1 indicates build failures, 47108e14bc1SMauro Carvalho Chehab # 47208e14bc1SMauro Carvalho Chehab if self.verbose: 473819667bcSMauro Carvalho Chehab msg = "Summary" 474819667bcSMauro Carvalho Chehab msg += "\n" + "=" * len(msg) 475819667bcSMauro Carvalho Chehab print() 476819667bcSMauro Carvalho Chehab print(msg) 477819667bcSMauro Carvalho Chehab 478819667bcSMauro Carvalho Chehab for pdf_name, pdf_file in builds.items(): 479819667bcSMauro Carvalho Chehab print(f"{pdf_name:<{max_len}}: {pdf_file}") 480819667bcSMauro Carvalho Chehab 481819667bcSMauro Carvalho Chehab print() 482819667bcSMauro Carvalho Chehab if build_failed: 483819667bcSMauro Carvalho Chehab msg = LatexFontChecker().check() 484819667bcSMauro Carvalho Chehab if msg: 485819667bcSMauro Carvalho Chehab print(msg) 486819667bcSMauro Carvalho Chehab 48708e14bc1SMauro Carvalho Chehab sys.exit("Error: not all PDF files were created.") 48808e14bc1SMauro Carvalho Chehab 48908e14bc1SMauro Carvalho Chehab elif build_failed: 49008e14bc1SMauro Carvalho Chehab n_failures = len(builds) 49108e14bc1SMauro Carvalho Chehab failures = ", ".join(builds.keys()) 49208e14bc1SMauro Carvalho Chehab 49308e14bc1SMauro Carvalho Chehab msg = LatexFontChecker().check() 49408e14bc1SMauro Carvalho Chehab if msg: 49508e14bc1SMauro Carvalho Chehab print(msg) 49608e14bc1SMauro Carvalho Chehab 49708e14bc1SMauro Carvalho Chehab sys.exit(f"Error: Can't build {n_failures} PDF file(s): {failures}") 498819667bcSMauro Carvalho Chehab 499819667bcSMauro Carvalho Chehab def handle_info(self, output_dirs): 500819667bcSMauro Carvalho Chehab """ 501819667bcSMauro Carvalho Chehab Extra steps for Info output. 502819667bcSMauro Carvalho Chehab 503819667bcSMauro Carvalho Chehab For texinfo generation, an additional make is needed from the 504819667bcSMauro Carvalho Chehab texinfo directory. 505819667bcSMauro Carvalho Chehab """ 506819667bcSMauro Carvalho Chehab 507819667bcSMauro Carvalho Chehab for output_dir in output_dirs: 508819667bcSMauro Carvalho Chehab try: 509819667bcSMauro Carvalho Chehab subprocess.run(["make", "info"], cwd=output_dir, check=True) 510819667bcSMauro Carvalho Chehab except subprocess.CalledProcessError as e: 511819667bcSMauro Carvalho Chehab sys.exit(f"Error generating info docs: {e}") 512819667bcSMauro Carvalho Chehab 5137e8a8143SMauro Carvalho Chehab def handle_man(self, kerneldoc, docs_dir, src_dir, output_dir): 5147e8a8143SMauro Carvalho Chehab """ 5157e8a8143SMauro Carvalho Chehab Create man pages from kernel-doc output 5167e8a8143SMauro Carvalho Chehab """ 5177e8a8143SMauro Carvalho Chehab 5187e8a8143SMauro Carvalho Chehab re_kernel_doc = re.compile(r"^\.\.\s+kernel-doc::\s*(\S+)") 5197e8a8143SMauro Carvalho Chehab re_man = re.compile(r'^\.TH "[^"]*" (\d+) "([^"]*)"') 5207e8a8143SMauro Carvalho Chehab 5217e8a8143SMauro Carvalho Chehab if docs_dir == src_dir: 5227e8a8143SMauro Carvalho Chehab # 5237e8a8143SMauro Carvalho Chehab # Pick the entire set of kernel-doc markups from the entire tree 5247e8a8143SMauro Carvalho Chehab # 5257e8a8143SMauro Carvalho Chehab kdoc_files = set([self.srctree]) 5267e8a8143SMauro Carvalho Chehab else: 5277e8a8143SMauro Carvalho Chehab kdoc_files = set() 5287e8a8143SMauro Carvalho Chehab 5297e8a8143SMauro Carvalho Chehab for fname in glob(os.path.join(src_dir, "**"), recursive=True): 5307e8a8143SMauro Carvalho Chehab if os.path.isfile(fname) and fname.endswith(".rst"): 5317e8a8143SMauro Carvalho Chehab with open(fname, "r", encoding="utf-8") as in_fp: 5327e8a8143SMauro Carvalho Chehab data = in_fp.read() 5337e8a8143SMauro Carvalho Chehab 5347e8a8143SMauro Carvalho Chehab for line in data.split("\n"): 5357e8a8143SMauro Carvalho Chehab match = re_kernel_doc.match(line) 5367e8a8143SMauro Carvalho Chehab if match: 5377e8a8143SMauro Carvalho Chehab if os.path.isfile(match.group(1)): 5387e8a8143SMauro Carvalho Chehab kdoc_files.add(match.group(1)) 5397e8a8143SMauro Carvalho Chehab 5407e8a8143SMauro Carvalho Chehab if not kdoc_files: 5417e8a8143SMauro Carvalho Chehab sys.exit(f"Directory {src_dir} doesn't contain kernel-doc tags") 5427e8a8143SMauro Carvalho Chehab 5437e8a8143SMauro Carvalho Chehab cmd = [ kerneldoc, "-m" ] + sorted(kdoc_files) 5447e8a8143SMauro Carvalho Chehab try: 5457e8a8143SMauro Carvalho Chehab if self.verbose: 5467e8a8143SMauro Carvalho Chehab print(" ".join(cmd)) 5477e8a8143SMauro Carvalho Chehab 5487e8a8143SMauro Carvalho Chehab result = subprocess.run(cmd, stdout=subprocess.PIPE, text= True) 5497e8a8143SMauro Carvalho Chehab 5507e8a8143SMauro Carvalho Chehab if result.returncode: 5517e8a8143SMauro Carvalho Chehab print(f"Warning: kernel-doc returned {result.returncode} warnings") 5527e8a8143SMauro Carvalho Chehab 5537e8a8143SMauro Carvalho Chehab except (OSError, ValueError, subprocess.SubprocessError) as e: 5547e8a8143SMauro Carvalho Chehab sys.exit(f"Failed to create man pages for {src_dir}: {repr(e)}") 5557e8a8143SMauro Carvalho Chehab 5567e8a8143SMauro Carvalho Chehab fp = None 5577e8a8143SMauro Carvalho Chehab try: 5587e8a8143SMauro Carvalho Chehab for line in result.stdout.split("\n"): 5597e8a8143SMauro Carvalho Chehab match = re_man.match(line) 5607e8a8143SMauro Carvalho Chehab if not match: 5617e8a8143SMauro Carvalho Chehab if fp: 5627e8a8143SMauro Carvalho Chehab fp.write(line + '\n') 5637e8a8143SMauro Carvalho Chehab continue 5647e8a8143SMauro Carvalho Chehab 5657e8a8143SMauro Carvalho Chehab if fp: 5667e8a8143SMauro Carvalho Chehab fp.close() 5677e8a8143SMauro Carvalho Chehab 5687e8a8143SMauro Carvalho Chehab fname = f"{output_dir}/{match.group(2)}.{match.group(1)}" 5697e8a8143SMauro Carvalho Chehab 5707e8a8143SMauro Carvalho Chehab if self.verbose: 5717e8a8143SMauro Carvalho Chehab print(f"Creating {fname}") 5727e8a8143SMauro Carvalho Chehab fp = open(fname, "w", encoding="utf-8") 5737e8a8143SMauro Carvalho Chehab fp.write(line + '\n') 5747e8a8143SMauro Carvalho Chehab finally: 5757e8a8143SMauro Carvalho Chehab if fp: 5767e8a8143SMauro Carvalho Chehab fp.close() 5777e8a8143SMauro Carvalho Chehab 578819667bcSMauro Carvalho Chehab def cleandocs(self, builder): # pylint: disable=W0613 579819667bcSMauro Carvalho Chehab """Remove documentation output directory""" 580819667bcSMauro Carvalho Chehab shutil.rmtree(self.builddir, ignore_errors=True) 581819667bcSMauro Carvalho Chehab 582819667bcSMauro Carvalho Chehab def build(self, target, sphinxdirs=None, conf="conf.py", 583*2118ba7dSMauro Carvalho Chehab theme=None, css=None, paper=None, deny_vf=None, rustdoc=False): 584819667bcSMauro Carvalho Chehab """ 585819667bcSMauro Carvalho Chehab Build documentation using Sphinx. This is the core function of this 586819667bcSMauro Carvalho Chehab module. It prepares all arguments required by sphinx-build. 587819667bcSMauro Carvalho Chehab """ 588819667bcSMauro Carvalho Chehab 589819667bcSMauro Carvalho Chehab builder = TARGETS[target]["builder"] 590819667bcSMauro Carvalho Chehab out_dir = TARGETS[target].get("out_dir", "") 591819667bcSMauro Carvalho Chehab 592819667bcSMauro Carvalho Chehab # 593819667bcSMauro Carvalho Chehab # Cleandocs doesn't require sphinx-build 594819667bcSMauro Carvalho Chehab # 595819667bcSMauro Carvalho Chehab if target == "cleandocs": 596819667bcSMauro Carvalho Chehab self.cleandocs(builder) 597819667bcSMauro Carvalho Chehab return 598819667bcSMauro Carvalho Chehab 599819667bcSMauro Carvalho Chehab if theme: 600819667bcSMauro Carvalho Chehab os.environ["DOCS_THEME"] = theme 601819667bcSMauro Carvalho Chehab 602819667bcSMauro Carvalho Chehab # 603819667bcSMauro Carvalho Chehab # Other targets require sphinx-build, so check if it exists 604819667bcSMauro Carvalho Chehab # 605819667bcSMauro Carvalho Chehab sphinxbuild = shutil.which(self.sphinxbuild, path=self.env["PATH"]) 6067e8a8143SMauro Carvalho Chehab if not sphinxbuild and target != "mandocs": 607819667bcSMauro Carvalho Chehab sys.exit(f"Error: {self.sphinxbuild} not found in PATH.\n") 608819667bcSMauro Carvalho Chehab 609819667bcSMauro Carvalho Chehab if builder == "latex": 610819667bcSMauro Carvalho Chehab if not self.pdflatex_cmd and not self.latexmk_cmd: 611819667bcSMauro Carvalho Chehab sys.exit("Error: pdflatex or latexmk required for PDF generation") 612819667bcSMauro Carvalho Chehab 613819667bcSMauro Carvalho Chehab docs_dir = os.path.abspath(os.path.join(self.srctree, "Documentation")) 614819667bcSMauro Carvalho Chehab 615819667bcSMauro Carvalho Chehab # 616819667bcSMauro Carvalho Chehab # Fill in base arguments for Sphinx build 617819667bcSMauro Carvalho Chehab # 618819667bcSMauro Carvalho Chehab kerneldoc = self.kerneldoc 619819667bcSMauro Carvalho Chehab if kerneldoc.startswith(self.srctree): 620819667bcSMauro Carvalho Chehab kerneldoc = os.path.relpath(kerneldoc, self.srctree) 621819667bcSMauro Carvalho Chehab 622819667bcSMauro Carvalho Chehab args = [ "-b", builder, "-c", docs_dir ] 623819667bcSMauro Carvalho Chehab 624819667bcSMauro Carvalho Chehab if builder == "latex": 625819667bcSMauro Carvalho Chehab if not paper: 626819667bcSMauro Carvalho Chehab paper = PAPER[1] 627819667bcSMauro Carvalho Chehab 628819667bcSMauro Carvalho Chehab args.extend(["-D", f"latex_elements.papersize={paper}paper"]) 629819667bcSMauro Carvalho Chehab 630*2118ba7dSMauro Carvalho Chehab if rustdoc: 631819667bcSMauro Carvalho Chehab args.extend(["-t", "rustdoc"]) 632819667bcSMauro Carvalho Chehab 633819667bcSMauro Carvalho Chehab if conf: 634819667bcSMauro Carvalho Chehab self.env["SPHINX_CONF"] = self.get_path(conf, abs_path=True) 635819667bcSMauro Carvalho Chehab 636819667bcSMauro Carvalho Chehab if not sphinxdirs: 637819667bcSMauro Carvalho Chehab sphinxdirs = os.environ.get("SPHINXDIRS", ".") 638819667bcSMauro Carvalho Chehab 639819667bcSMauro Carvalho Chehab # 64082c294d4SMauro Carvalho Chehab # The sphinx-build tool has a bug: internally, it tries to set 64182c294d4SMauro Carvalho Chehab # locale with locale.setlocale(locale.LC_ALL, ''). This causes a 64282c294d4SMauro Carvalho Chehab # crash if language is not set. Detect and fix it. 64382c294d4SMauro Carvalho Chehab # 64482c294d4SMauro Carvalho Chehab try: 64582c294d4SMauro Carvalho Chehab locale.setlocale(locale.LC_ALL, '') 64682c294d4SMauro Carvalho Chehab except locale.Error: 64782c294d4SMauro Carvalho Chehab self.env["LC_ALL"] = "C" 64882c294d4SMauro Carvalho Chehab 64982c294d4SMauro Carvalho Chehab # 650819667bcSMauro Carvalho Chehab # sphinxdirs can be a list or a whitespace-separated string 651819667bcSMauro Carvalho Chehab # 652819667bcSMauro Carvalho Chehab sphinxdirs_list = [] 653819667bcSMauro Carvalho Chehab for sphinxdir in sphinxdirs: 654819667bcSMauro Carvalho Chehab if isinstance(sphinxdir, list): 655819667bcSMauro Carvalho Chehab sphinxdirs_list += sphinxdir 656819667bcSMauro Carvalho Chehab else: 657819667bcSMauro Carvalho Chehab sphinxdirs_list += sphinxdir.split() 658819667bcSMauro Carvalho Chehab 659819667bcSMauro Carvalho Chehab # 660819667bcSMauro Carvalho Chehab # Step 1: Build each directory in separate. 661819667bcSMauro Carvalho Chehab # 662819667bcSMauro Carvalho Chehab # This is not the best way of handling it, as cross-references between 663819667bcSMauro Carvalho Chehab # them will be broken, but this is what we've been doing since 664819667bcSMauro Carvalho Chehab # the beginning. 665819667bcSMauro Carvalho Chehab # 666819667bcSMauro Carvalho Chehab output_dirs = [] 667819667bcSMauro Carvalho Chehab for sphinxdir in sphinxdirs_list: 668819667bcSMauro Carvalho Chehab src_dir = os.path.join(docs_dir, sphinxdir) 669819667bcSMauro Carvalho Chehab doctree_dir = os.path.join(self.builddir, ".doctrees") 670819667bcSMauro Carvalho Chehab output_dir = os.path.join(self.builddir, sphinxdir, out_dir) 671819667bcSMauro Carvalho Chehab 672819667bcSMauro Carvalho Chehab # 673819667bcSMauro Carvalho Chehab # Make directory names canonical 674819667bcSMauro Carvalho Chehab # 675819667bcSMauro Carvalho Chehab src_dir = os.path.normpath(src_dir) 676819667bcSMauro Carvalho Chehab doctree_dir = os.path.normpath(doctree_dir) 677819667bcSMauro Carvalho Chehab output_dir = os.path.normpath(output_dir) 678819667bcSMauro Carvalho Chehab 679819667bcSMauro Carvalho Chehab os.makedirs(doctree_dir, exist_ok=True) 680819667bcSMauro Carvalho Chehab os.makedirs(output_dir, exist_ok=True) 681819667bcSMauro Carvalho Chehab 682819667bcSMauro Carvalho Chehab output_dirs.append(output_dir) 683819667bcSMauro Carvalho Chehab 684819667bcSMauro Carvalho Chehab build_args = args + [ 685819667bcSMauro Carvalho Chehab "-d", doctree_dir, 686819667bcSMauro Carvalho Chehab "-D", f"kerneldoc_bin={kerneldoc}", 687819667bcSMauro Carvalho Chehab "-D", f"version={self.kernelversion}", 688819667bcSMauro Carvalho Chehab "-D", f"release={self.kernelrelease}", 689819667bcSMauro Carvalho Chehab "-D", f"kerneldoc_srctree={self.srctree}", 690819667bcSMauro Carvalho Chehab src_dir, 691819667bcSMauro Carvalho Chehab output_dir, 692819667bcSMauro Carvalho Chehab ] 693819667bcSMauro Carvalho Chehab 6947e8a8143SMauro Carvalho Chehab if target == "mandocs": 6957e8a8143SMauro Carvalho Chehab self.handle_man(kerneldoc, docs_dir, src_dir, output_dir) 6967e8a8143SMauro Carvalho Chehab else: 697819667bcSMauro Carvalho Chehab try: 698819667bcSMauro Carvalho Chehab self.run_sphinx(sphinxbuild, build_args, env=self.env) 699819667bcSMauro Carvalho Chehab except (OSError, ValueError, subprocess.SubprocessError) as e: 700819667bcSMauro Carvalho Chehab sys.exit(f"Build failed: {repr(e)}") 701819667bcSMauro Carvalho Chehab 702819667bcSMauro Carvalho Chehab # 703819667bcSMauro Carvalho Chehab # Ensure that each html/epub output will have needed static files 704819667bcSMauro Carvalho Chehab # 705819667bcSMauro Carvalho Chehab if target in ["htmldocs", "epubdocs"]: 706*2118ba7dSMauro Carvalho Chehab self.handle_html(css, output_dir, rustdoc) 707819667bcSMauro Carvalho Chehab 708819667bcSMauro Carvalho Chehab # 709819667bcSMauro Carvalho Chehab # Step 2: Some targets (PDF and info) require an extra step once 710819667bcSMauro Carvalho Chehab # sphinx-build finishes 711819667bcSMauro Carvalho Chehab # 712819667bcSMauro Carvalho Chehab if target == "pdfdocs": 713819667bcSMauro Carvalho Chehab self.handle_pdf(output_dirs, deny_vf) 714819667bcSMauro Carvalho Chehab elif target == "infodocs": 715819667bcSMauro Carvalho Chehab self.handle_info(output_dirs) 716819667bcSMauro Carvalho Chehab 717819667bcSMauro Carvalho Chehabdef jobs_type(value): 718819667bcSMauro Carvalho Chehab """ 719819667bcSMauro Carvalho Chehab Handle valid values for -j. Accepts Sphinx "-jauto", plus a number 720819667bcSMauro Carvalho Chehab equal or bigger than one. 721819667bcSMauro Carvalho Chehab """ 722819667bcSMauro Carvalho Chehab if value is None: 723819667bcSMauro Carvalho Chehab return None 724819667bcSMauro Carvalho Chehab 725819667bcSMauro Carvalho Chehab if value.lower() == 'auto': 726819667bcSMauro Carvalho Chehab return value.lower() 727819667bcSMauro Carvalho Chehab 728819667bcSMauro Carvalho Chehab try: 729819667bcSMauro Carvalho Chehab if int(value) >= 1: 730819667bcSMauro Carvalho Chehab return value 731819667bcSMauro Carvalho Chehab 732819667bcSMauro Carvalho Chehab raise argparse.ArgumentTypeError(f"Minimum jobs is 1, got {value}") 733819667bcSMauro Carvalho Chehab except ValueError: 734819667bcSMauro Carvalho Chehab raise argparse.ArgumentTypeError(f"Must be 'auto' or positive integer, got {value}") # pylint: disable=W0707 735819667bcSMauro Carvalho Chehab 736819667bcSMauro Carvalho Chehabdef main(): 737819667bcSMauro Carvalho Chehab """ 738819667bcSMauro Carvalho Chehab Main function. The only mandatory argument is the target. If not 739819667bcSMauro Carvalho Chehab specified, the other arguments will use default values if not 740819667bcSMauro Carvalho Chehab specified at os.environ. 741819667bcSMauro Carvalho Chehab """ 742819667bcSMauro Carvalho Chehab parser = argparse.ArgumentParser(description="Kernel documentation builder") 743819667bcSMauro Carvalho Chehab 744819667bcSMauro Carvalho Chehab parser.add_argument("target", choices=list(TARGETS.keys()), 745819667bcSMauro Carvalho Chehab help="Documentation target to build") 746819667bcSMauro Carvalho Chehab parser.add_argument("--sphinxdirs", nargs="+", 747819667bcSMauro Carvalho Chehab help="Specific directories to build") 748819667bcSMauro Carvalho Chehab parser.add_argument("--conf", default="conf.py", 749819667bcSMauro Carvalho Chehab help="Sphinx configuration file") 750819667bcSMauro Carvalho Chehab parser.add_argument("--builddir", default="output", 751819667bcSMauro Carvalho Chehab help="Sphinx configuration file") 752819667bcSMauro Carvalho Chehab 753819667bcSMauro Carvalho Chehab parser.add_argument("--theme", help="Sphinx theme to use") 754819667bcSMauro Carvalho Chehab 755819667bcSMauro Carvalho Chehab parser.add_argument("--css", help="Custom CSS file for HTML/EPUB") 756819667bcSMauro Carvalho Chehab 757819667bcSMauro Carvalho Chehab parser.add_argument("--paper", choices=PAPER, default=PAPER[0], 758819667bcSMauro Carvalho Chehab help="Paper size for LaTeX/PDF output") 759819667bcSMauro Carvalho Chehab 760819667bcSMauro Carvalho Chehab parser.add_argument('--deny-vf', 761819667bcSMauro Carvalho Chehab help="Configuration to deny variable fonts on pdf builds") 762819667bcSMauro Carvalho Chehab 763*2118ba7dSMauro Carvalho Chehab parser.add_argument('--rustdoc', action="store_true", 764*2118ba7dSMauro Carvalho Chehab help="Enable rustdoc build. Requires CONFIG_RUST") 765*2118ba7dSMauro Carvalho Chehab 766819667bcSMauro Carvalho Chehab parser.add_argument("-v", "--verbose", action='store_true', 767819667bcSMauro Carvalho Chehab help="place build in verbose mode") 768819667bcSMauro Carvalho Chehab 769819667bcSMauro Carvalho Chehab parser.add_argument('-j', '--jobs', type=jobs_type, 770819667bcSMauro Carvalho Chehab help="Sets number of jobs to use with sphinx-build") 771819667bcSMauro Carvalho Chehab 7722f99b85eSMauro Carvalho Chehab parser.add_argument('-i', '--interactive', action='store_true', 7732f99b85eSMauro Carvalho Chehab help="Change latex default to run in interactive mode") 7742f99b85eSMauro Carvalho Chehab 775819667bcSMauro Carvalho Chehab args = parser.parse_args() 776819667bcSMauro Carvalho Chehab 777819667bcSMauro Carvalho Chehab PythonVersion.check_python(MIN_PYTHON_VERSION) 778819667bcSMauro Carvalho Chehab 779819667bcSMauro Carvalho Chehab builder = SphinxBuilder(builddir=args.builddir, 7802f99b85eSMauro Carvalho Chehab verbose=args.verbose, n_jobs=args.jobs, 7812f99b85eSMauro Carvalho Chehab interactive=args.interactive) 782819667bcSMauro Carvalho Chehab 783819667bcSMauro Carvalho Chehab builder.build(args.target, sphinxdirs=args.sphinxdirs, conf=args.conf, 784819667bcSMauro Carvalho Chehab theme=args.theme, css=args.css, paper=args.paper, 785*2118ba7dSMauro Carvalho Chehab rustdoc=args.rustdoc, deny_vf=args.deny_vf) 786819667bcSMauro Carvalho Chehab 787819667bcSMauro Carvalho Chehabif __name__ == "__main__": 788819667bcSMauro Carvalho Chehab main() 789