diff options
| author | Richard Henderson <richard.henderson@linaro.org> | 2025-08-31 07:37:34 +1000 |
|---|---|---|
| committer | Richard Henderson <richard.henderson@linaro.org> | 2025-08-31 07:37:35 +1000 |
| commit | e101d33792530093fa0b0a6e5f43e4d8cfe4581e (patch) | |
| tree | e7ce5e8e229180d684045b887797ec3e85d2f077 /scripts/lib/kdoc/kdoc_files.py | |
| parent | 4791f22a5f5571cb248b1eddff98630545b3fd3e (diff) | |
| parent | 2e27650bddd35477d994a795a3b1cb57c8ed5c76 (diff) | |
| download | focaccia-qemu-e101d33792530093fa0b0a6e5f43e4d8cfe4581e.tar.gz focaccia-qemu-e101d33792530093fa0b0a6e5f43e4d8cfe4581e.zip | |
Merge tag 'pull-target-arm-20250830' of https://gitlab.com/pm215/qemu into staging
target-arm queue:
* Implement FEAT_SCTLR2
* Implement FEAT_TCR2
* Implement FEAT_CSSC
* Implement FEAT_LSE128
* Clean up of register field definitions
* Trap PMCR when MDCR_EL2.TPMCR is set
* tests/functional: update aarch64 RME test images
* hw/intc/arm_gicv3_kvm: preserve pending interrupts during cpr
* hw/arm: add static NVDIMMs in device tree
* hw/arm/stm32f205_soc: Don't leak TYPE_OR_IRQ objects
* scripts/kernel-doc: Avoid new Perl precedence warning
* scripts/kernel-doc: Update to kernel's new Python implementation
# -----BEGIN PGP SIGNATURE-----
#
# iQJNBAABCAA3FiEE4aXFk81BneKOgxXPPCUl7RQ2DN4FAmizIcAZHHBldGVyLm1h
# eWRlbGxAbGluYXJvLm9yZwAKCRA8JSXtFDYM3tmCD/9Pe4Evw/I2e3Nqr4X87+KC
# JtX3s9U8Gly1ttnWd5a+fRubBqIvpxRsJYf0PJQi7otPGDq4E3TZ5UCRnInArpRh
# hJqyNxi2ELgDU0Z917UYMnxBwpv7+V/635V1/svSOWDf9RPHnf6GwrmlCvu4Llgf
# mVtDlQd+Ta5hoICM0VzrMZfTYevxGqi/cr/oVzCObKmh1YMpPTtSNlfYPMFcY7py
# JLu5e7YNN2krh19nCXieS3iqXMsFoLp31kXcCmKE1BgIKeVPNxTRMfOWa4uNDtUN
# 17iLfHLatNfSWUA1gvUHxv2maCdm4xJZdGowP/uYvzaemquFSjfM/8qaBxxFqZ1v
# 7jdZEzdnn1CX4Kmu3cPvhcuACyYRprlrKZYvCrTH4yCKbJsm0Uo7M66ia3EIF5EQ
# kehnGGwu3rv3qrliTXiXoAr7fC0OOiN0afAkS6a5lAi13s6M+Se2VElnRvIoXR2W
# 0Xw21/05p/WuXLoMNFjEpAaQgWYEc0kQhFAQczcZH+pyGlaU2QxCTTnaeuHUWcke
# y7OtpVBk4Fukaqd4gn0SQtYQLxeFq6vPOL4b1VKR5FuGDSucBUjuVl0dG4gkdbII
# yvCBaTb+IEY4fJ1E8IMTI3Lcydv9yblLyGXLr42e22x/l51SCZs1WvIx2i6u6VST
# lYnoOObEknvf25YAu3rDTw==
# =VItP
# -----END PGP SIGNATURE-----
# gpg: Signature made Sun 31 Aug 2025 02:07:28 AM AEST
# gpg: using RSA key E1A5C593CD419DE28E8315CF3C2525ED14360CDE
# gpg: issuer "peter.maydell@linaro.org"
# gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" [unknown]
# gpg: aka "Peter Maydell <pmaydell@gmail.com>" [unknown]
# gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" [unknown]
# gpg: aka "Peter Maydell <peter@archaic.org.uk>" [unknown]
# gpg: WARNING: The key's User ID is not certified with a trusted signature!
# gpg: There is no indication that the signature belongs to the owner.
# Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE
* tag 'pull-target-arm-20250830' of https://gitlab.com/pm215/qemu: (32 commits)
hw/arm/stm32f205_soc: Don't leak TYPE_OR_IRQ objects
target/arm: Enable FEAT_LSE128 for -cpu max
target/arm: Implement FEAT_LSE128
target/arm: Rename isar_feature_aa64_atomics
tcg: Add tcg_gen_atomic_{xchg,fetch_and,fetch_or}_i128
accel/tcg: Add cpu_atomic_*_mmu for 16-byte xchg, fetch_and, fetch_or
qemu/atomic: Add atomic16 primitives for xchg, fetch_and, fetch_or
qemu/atomic: Finish renaming atomic128-cas.h headers
target/arm: Correct condition of aa64_atomics feature function
MAINTAINERS: Put kernel-doc under the "docs build machinery" section
scripts/kernel-doc: Delete the old Perl kernel-doc script
scripts/kerneldoc: Switch to the Python kernel-doc script
scripts/kernel-doc: tweak for QEMU coding standards
scripts/kernel-doc: strip QEMU_ from function definitions
scripts: Import Python kerneldoc from Linux kernel
tests/qtest/libqtest.h: Remove stray space from doc comment
docs/sphinx/kerneldoc.py: Handle new LINENO syntax
scripts/kernel-doc: Avoid new Perl precedence warning
hw/arm: add static NVDIMMs in device tree
target/arm: Enable FEAT_CSSC for -cpu max
...
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Diffstat (limited to 'scripts/lib/kdoc/kdoc_files.py')
| -rw-r--r-- | scripts/lib/kdoc/kdoc_files.py | 291 |
1 files changed, 291 insertions, 0 deletions
diff --git a/scripts/lib/kdoc/kdoc_files.py b/scripts/lib/kdoc/kdoc_files.py new file mode 100644 index 0000000000..9e09b45b02 --- /dev/null +++ b/scripts/lib/kdoc/kdoc_files.py @@ -0,0 +1,291 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0 +# Copyright(c) 2025: Mauro Carvalho Chehab <mchehab@kernel.org>. +# +# pylint: disable=R0903,R0913,R0914,R0917 + +""" +Parse lernel-doc tags on multiple kernel source files. +""" + +import argparse +import logging +import os +import re + +from kdoc_parser import KernelDoc +from kdoc_output import OutputFormat + + +class GlobSourceFiles: + """ + Parse C source code file names and directories via an Interactor. + """ + + def __init__(self, srctree=None, valid_extensions=None): + """ + Initialize valid extensions with a tuple. + + If not defined, assume default C extensions (.c and .h) + + It would be possible to use python's glob function, but it is + very slow, and it is not interactive. So, it would wait to read all + directories before actually do something. + + So, let's use our own implementation. + """ + + if not valid_extensions: + self.extensions = (".c", ".h") + else: + self.extensions = valid_extensions + + self.srctree = srctree + + def _parse_dir(self, dirname): + """Internal function to parse files recursively""" + + with os.scandir(dirname) as obj: + for entry in obj: + name = os.path.join(dirname, entry.name) + + if entry.is_dir(): + yield from self._parse_dir(name) + + if not entry.is_file(): + continue + + basename = os.path.basename(name) + + if not basename.endswith(self.extensions): + continue + + yield name + + def parse_files(self, file_list, file_not_found_cb): + """ + Define an interator to parse all source files from file_list, + handling directories if any + """ + + if not file_list: + return + + for fname in file_list: + if self.srctree: + f = os.path.join(self.srctree, fname) + else: + f = fname + + if os.path.isdir(f): + yield from self._parse_dir(f) + elif os.path.isfile(f): + yield f + elif file_not_found_cb: + file_not_found_cb(fname) + + +class KernelFiles(): + """ + Parse kernel-doc tags on multiple kernel source files. + + There are two type of parsers defined here: + - self.parse_file(): parses both kernel-doc markups and + EXPORT_SYMBOL* macros; + - self.process_export_file(): parses only EXPORT_SYMBOL* macros. + """ + + def warning(self, msg): + """Ancillary routine to output a warning and increment error count""" + + self.config.log.warning(msg) + self.errors += 1 + + def error(self, msg): + """Ancillary routine to output an error and increment error count""" + + self.config.log.error(msg) + self.errors += 1 + + def parse_file(self, fname): + """ + Parse a single Kernel source. + """ + + # Prevent parsing the same file twice if results are cached + if fname in self.files: + return + + doc = KernelDoc(self.config, fname) + export_table, entries = doc.parse_kdoc() + + self.export_table[fname] = export_table + + self.files.add(fname) + self.export_files.add(fname) # parse_kdoc() already check exports + + self.results[fname] = entries + + def process_export_file(self, fname): + """ + Parses EXPORT_SYMBOL* macros from a single Kernel source file. + """ + + # Prevent parsing the same file twice if results are cached + if fname in self.export_files: + return + + doc = KernelDoc(self.config, fname) + export_table = doc.parse_export() + + if not export_table: + self.error(f"Error: Cannot check EXPORT_SYMBOL* on {fname}") + export_table = set() + + self.export_table[fname] = export_table + self.export_files.add(fname) + + def file_not_found_cb(self, fname): + """ + Callback to warn if a file was not found. + """ + + self.error(f"Cannot find file {fname}") + + def __init__(self, verbose=False, out_style=None, + werror=False, wreturn=False, wshort_desc=False, + wcontents_before_sections=False, + logger=None): + """ + Initialize startup variables and parse all files + """ + + if not verbose: + verbose = bool(os.environ.get("KBUILD_VERBOSE", 0)) + + if out_style is None: + out_style = OutputFormat() + + if not werror: + kcflags = os.environ.get("KCFLAGS", None) + if kcflags: + match = re.search(r"(\s|^)-Werror(\s|$)/", kcflags) + if match: + werror = True + + # reading this variable is for backwards compat just in case + # someone was calling it with the variable from outside the + # kernel's build system + kdoc_werror = os.environ.get("KDOC_WERROR", None) + if kdoc_werror: + werror = kdoc_werror + + # Some variables are global to the parser logic as a whole as they are + # used to send control configuration to KernelDoc class. As such, + # those variables are read-only inside the KernelDoc. + self.config = argparse.Namespace + + self.config.verbose = verbose + self.config.werror = werror + self.config.wreturn = wreturn + self.config.wshort_desc = wshort_desc + self.config.wcontents_before_sections = wcontents_before_sections + + if not logger: + self.config.log = logging.getLogger("kernel-doc") + else: + self.config.log = logger + + self.config.warning = self.warning + + self.config.src_tree = os.environ.get("SRCTREE", None) + + # Initialize variables that are internal to KernelFiles + + self.out_style = out_style + + self.errors = 0 + self.results = {} + + self.files = set() + self.export_files = set() + self.export_table = {} + + def parse(self, file_list, export_file=None): + """ + Parse all files + """ + + glob = GlobSourceFiles(srctree=self.config.src_tree) + + for fname in glob.parse_files(file_list, self.file_not_found_cb): + self.parse_file(fname) + + for fname in glob.parse_files(export_file, self.file_not_found_cb): + self.process_export_file(fname) + + def out_msg(self, fname, name, arg): + """ + Return output messages from a file name using the output style + filtering. + + If output type was not handled by the syler, return None. + """ + + # NOTE: we can add rules here to filter out unwanted parts, + # although OutputFormat.msg already does that. + + return self.out_style.msg(fname, name, arg) + + def msg(self, enable_lineno=False, export=False, internal=False, + symbol=None, nosymbol=None, no_doc_sections=False, + filenames=None, export_file=None): + """ + Interacts over the kernel-doc results and output messages, + returning kernel-doc markups on each interaction + """ + + self.out_style.set_config(self.config) + + if not filenames: + filenames = sorted(self.results.keys()) + + glob = GlobSourceFiles(srctree=self.config.src_tree) + + for fname in filenames: + function_table = set() + + if internal or export: + if not export_file: + export_file = [fname] + + for f in glob.parse_files(export_file, self.file_not_found_cb): + function_table |= self.export_table[f] + + if symbol: + for s in symbol: + function_table.add(s) + + self.out_style.set_filter(export, internal, symbol, nosymbol, + function_table, enable_lineno, + no_doc_sections) + + msg = "" + if fname not in self.results: + self.config.log.warning("No kernel-doc for file %s", fname) + continue + + for arg in self.results[fname]: + m = self.out_msg(fname, arg.name, arg) + + if m is None: + ln = arg.get("ln", 0) + dtype = arg.get('type', "") + + self.config.log.warning("%s:%d Can't handle %s", + fname, ln, dtype) + else: + msg += m + + if msg: + yield fname, msg |