From nobody Fri Dec 19 17:37:15 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 76B90267B07; Tue, 8 Apr 2025 10:09:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744106997; cv=none; b=QHRPMo0tiZVWM1VDfRYJ2niDRwF6L1C6NNTMXQk5JU/qd8JWKnWHm5jXrVl0wkI+CTZfotMuJvnUkytfRm56ItIWheZBWT1Bj2uWSkJ+wGIFv5PBryI25NnIRzhoMN9ju1jg6v9kIbwm5TbJUMdX2zDGmApcCI4vfYLDcOWI6aQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1744106997; c=relaxed/simple; bh=fECQ0wT3cwyILMq52vt+FKrJbJo2Gu0emu+5UkOVdgM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Bgm6n0IR67XbAYdw7QZx7V27Z/5FoMFhRzCR5HtkolAN89nG2D3pCs2idgsyV1E9sXQhdwNRefi1voLwKCDMo5uh+4QvH6JxksO6rqd4z4q4yRDlv6CLfcecEmYF9pEPeH5vLdpwXkW53oXOe2/yWBQK9Em+vO9vw24oe9ma46M= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=VVtGygnS; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="VVtGygnS" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 9F90CC4AF0D; Tue, 8 Apr 2025 10:09:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1744106997; bh=fECQ0wT3cwyILMq52vt+FKrJbJo2Gu0emu+5UkOVdgM=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=VVtGygnSL21S0Bb+6WFI3FSyVeXdlkaF4bB6gh8jFc3yLM/+Uv4zPZD/oSgzwXl/L TSjXMfLCi+MUcIubTqXDSCLySusbS9xFeL+tgzHo883+J/PtVak5yLqpmWVPV8Fgze +mvbFuupjjadPYwNFtPoR/W381sapvryTeUQfVTQDbOl9b1lu9lH8TQInyGxU3j70J G4ovXGNaiqyPD2PvNWYARsPbJLS3W8iz+ibCYVdehk3Qvrtl7GG/1Vqqpg+LWFwomt c82a5k0ESFEvB/4mrypW7h9+SdHrTzHFL8VazOMXxeuxUAwAIOb3GYodMmEFZYiwTK 6tRH5gV1EVoSg== Received: from mchehab by mail.kernel.org with local (Exim 4.98.2) (envelope-from ) id 1u25tt-00000008RWk-2nBW; Tue, 08 Apr 2025 18:09:49 +0800 From: Mauro Carvalho Chehab To: Linux Doc Mailing List , Jonathan Corbet Cc: Mauro Carvalho Chehab , Sean Anderson , linux-kernel@vger.kernel.org Subject: [PATCH v3 31/33] scripts/kernel_doc.py: better handle exported symbols Date: Tue, 8 Apr 2025 18:09:34 +0800 Message-ID: <6a69ba8d2b7ee6a6427abb53e60d09bd4d3565ee.1744106242.git.mchehab+huawei@kernel.org> X-Mailer: git-send-email 2.49.0 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Sender: Mauro Carvalho Chehab Content-Type: text/plain; charset="utf-8" Change the logic which detects internal/external symbols in a way that we can re-use it when calling via Sphinx extension. While here, remove an unused self.config var and let it clearer that self.config variables are read-only. This helps to allow handling multiple times in parallel if ever needed. Signed-off-by: Mauro Carvalho Chehab --- scripts/kernel-doc.py | 2 +- scripts/lib/kdoc/kdoc_files.py | 142 +++++++++++++++++--------------- scripts/lib/kdoc/kdoc_output.py | 9 +- scripts/lib/kdoc/kdoc_parser.py | 52 ++++++++++-- 4 files changed, 125 insertions(+), 80 deletions(-) diff --git a/scripts/kernel-doc.py b/scripts/kernel-doc.py index 2f2fad813024..12ae66f40bd7 100755 --- a/scripts/kernel-doc.py +++ b/scripts/kernel-doc.py @@ -287,7 +287,7 @@ def main(): =20 for t in kfiles.msg(enable_lineno=3Dargs.enable_lineno, export=3Dargs.= export, internal=3Dargs.internal, symbol=3Dargs.symbol, - nosymbol=3Dargs.nosymbol, + nosymbol=3Dargs.nosymbol, export_file=3Dargs.expor= t_file, no_doc_sections=3Dargs.no_doc_sections): msg =3D t[1] if msg: diff --git a/scripts/lib/kdoc/kdoc_files.py b/scripts/lib/kdoc/kdoc_files.py index 527ab9117268..dd003feefd1b 100644 --- a/scripts/lib/kdoc/kdoc_files.py +++ b/scripts/lib/kdoc/kdoc_files.py @@ -68,6 +68,9 @@ class GlobSourceFiles: handling directories if any """ =20 + if not file_list: + return + for fname in file_list: if self.srctree: f =3D os.path.join(self.srctree, fname) @@ -84,40 +87,70 @@ class GlobSourceFiles: =20 class KernelFiles(): """ - Parse lernel-doc tags on multiple kernel source files. + 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. """ =20 + def warning(self, msg): + """Ancillary routine to output a warning and increment error count= """ + + self.config.log.warning(msg) + self.errors +=3D 1 + + def error(self, msg): + """Ancillary routine to output an error and increment error count"= "" + + self.config.log.error(msg) + self.errors +=3D 1 + def parse_file(self, fname): """ Parse a single Kernel source. """ =20 + # Prevent parsing the same file twice if results are cached + if fname in self.files: + return + doc =3D KernelDoc(self.config, fname) - doc.run() + export_table, entries =3D doc.parse_kdoc() =20 - return doc.entries + self.export_table[fname] =3D export_table + + self.files.add(fname) + self.export_files.add(fname) # parse_kdoc() already check exp= orts + + self.results[fname] =3D entries =20 def process_export_file(self, fname): """ Parses EXPORT_SYMBOL* macros from a single Kernel source file. """ - try: - with open(fname, "r", encoding=3D"utf8", - errors=3D"backslashreplace") as fp: - for line in fp: - KernelDoc.process_export(self.config.function_table, l= ine) - - except IOError: - self.config.log.error("Error: Cannot open fname %s", fname) - self.config.errors +=3D 1 + + # Prevent parsing the same file twice if results are cached + if fname in self.export_files: + return + + doc =3D KernelDoc(self.config, fname) + export_table =3D doc.parse_export() + + if not export_table: + self.error(f"Error: Cannot check EXPORT_SYMBOL* on {fname}") + export_table =3D set() + + self.export_table[fname] =3D export_table + self.export_files.add(fname) =20 def file_not_found_cb(self, fname): """ Callback to warn if a file was not found. """ =20 - self.config.log.error("Cannot find file %s", fname) - self.config.errors +=3D 1 + self.error(f"Cannot find file {fname}") =20 def __init__(self, verbose=3DFalse, out_style=3DNone, werror=3DFalse, wreturn=3DFalse, wshort_desc=3DFalse, @@ -147,7 +180,9 @@ class KernelFiles(): if kdoc_werror: werror =3D kdoc_werror =20 - # Set global config data used on all files + # 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 =3D argparse.Namespace =20 self.config.verbose =3D verbose @@ -156,27 +191,25 @@ class KernelFiles(): self.config.wshort_desc =3D wshort_desc self.config.wcontents_before_sections =3D wcontents_before_sections =20 - self.config.function_table =3D set() - self.config.source_map =3D {} - if not logger: self.config.log =3D logging.getLogger("kernel-doc") else: self.config.log =3D logger =20 - self.config.kernel_version =3D os.environ.get("KERNELVERSION", - "unknown kernel versio= n'") + self.config.warning =3D self.warning + self.config.src_tree =3D os.environ.get("SRCTREE", None) =20 + # Initialize variables that are internal to KernelFiles + self.out_style =3D out_style =20 - # Initialize internal variables - - self.config.errors =3D 0 + self.errors =3D 0 self.results =3D {} =20 self.files =3D set() self.export_files =3D set() + self.export_table =3D {} =20 def parse(self, file_list, export_file=3DNone): """ @@ -185,28 +218,11 @@ class KernelFiles(): =20 glob =3D GlobSourceFiles(srctree=3Dself.config.src_tree) =20 - # Prevent parsing the same file twice to speedup parsing and - # avoid reporting errors multiple times - for fname in glob.parse_files(file_list, self.file_not_found_cb): - if fname not in self.files: - self.results[fname] =3D self.parse_file(fname) - self.files.add(fname) - - # If a list of export files was provided, parse EXPORT_SYMBOL* - # from files that weren't fully parsed - - if not export_file: - return - - self.export_files |=3D self.files - - glob =3D GlobSourceFiles(srctree=3Dself.config.src_tree) + self.parse_file(fname) =20 for fname in glob.parse_files(export_file, self.file_not_found_cb): - if fname not in self.export_files: - self.process_export_file(fname) - self.export_files.add(fname) + self.process_export_file(fname) =20 def out_msg(self, fname, name, arg): """ @@ -223,32 +239,35 @@ class KernelFiles(): =20 def msg(self, enable_lineno=3DFalse, export=3DFalse, internal=3DFalse, symbol=3DNone, nosymbol=3DNone, no_doc_sections=3DFalse, - filenames=3DNone): + filenames=3DNone, export_file=3DNone): """ Interacts over the kernel-doc results and output messages, returning kernel-doc markups on each interaction """ =20 - function_table =3D self.config.function_table - - if symbol: - for s in symbol: - function_table.add(s) - - # Output none mode: only warnings will be shown - if not self.out_style: - return - self.out_style.set_config(self.config) =20 - self.out_style.set_filter(export, internal, symbol, nosymbol, - function_table, enable_lineno, - no_doc_sections) - if not filenames: filenames =3D sorted(self.results.keys()) =20 for fname in filenames: + function_table =3D set() + + if internal or export: + if not export_file: + export_file =3D [fname] + + for f in export_file: + function_table |=3D 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 =3D "" for name, arg in self.results[fname]: msg +=3D self.out_msg(fname, name, arg) @@ -261,12 +280,3 @@ class KernelFiles(): fname, ln, dtype) if msg: yield fname, msg - - @property - def errors(self): - """ - Return a count of the number of warnings found, including - the ones displayed while interacting over self.msg. - """ - - return self.config.errors diff --git a/scripts/lib/kdoc/kdoc_output.py b/scripts/lib/kdoc/kdoc_output= .py index e9b4d0093084..c352b7f8d3fd 100755 --- a/scripts/lib/kdoc/kdoc_output.py +++ b/scripts/lib/kdoc/kdoc_output.py @@ -69,7 +69,7 @@ class OutputFormat: self.enable_lineno =3D None self.nosymbol =3D {} self.symbol =3D None - self.function_table =3D set() + self.function_table =3D None self.config =3D None self.no_doc_sections =3D False =20 @@ -94,10 +94,10 @@ class OutputFormat: =20 self.enable_lineno =3D enable_lineno self.no_doc_sections =3D no_doc_sections + self.function_table =3D function_table =20 if symbol: self.out_mode =3D self.OUTPUT_INCLUDE - function_table =3D symbol elif export: self.out_mode =3D self.OUTPUT_EXPORTED elif internal: @@ -108,8 +108,6 @@ class OutputFormat: if nosymbol: self.nosymbol =3D set(nosymbol) =20 - if function_table: - self.function_table =3D function_table =20 def highlight_block(self, block): """ @@ -129,8 +127,7 @@ class OutputFormat: warnings =3D args.get('warnings', []) =20 for log_msg in warnings: - self.config.log.warning(log_msg) - self.config.errors +=3D 1 + self.config.warning(log_msg) =20 def check_doc(self, name, args): """Check if DOC should be output""" diff --git a/scripts/lib/kdoc/kdoc_parser.py b/scripts/lib/kdoc/kdoc_parser= .py index 43e6ffbdcc2c..33f00c77dd5f 100755 --- a/scripts/lib/kdoc/kdoc_parser.py +++ b/scripts/lib/kdoc/kdoc_parser.py @@ -1133,21 +1133,25 @@ class KernelDoc: self.emit_warning(ln, "error: Cannot parse typedef!") =20 @staticmethod - def process_export(function_table, line): + def process_export(function_set, line): """ process EXPORT_SYMBOL* tags =20 - This method is called both internally and externally, so, it - doesn't use self. + This method doesn't use any variable from the class, so declare it + with a staticmethod decorator. """ =20 + # Note: it accepts only one EXPORT_SYMBOL* per line, as having + # multiple export lines would violate Kernel coding style. + if export_symbol.search(line): symbol =3D export_symbol.group(2) - function_table.add(symbol) + function_set.add(symbol) + return =20 if export_symbol_ns.search(line): symbol =3D export_symbol_ns.group(2) - function_table.add(symbol) + function_set.add(symbol) =20 def process_normal(self, ln, line): """ @@ -1617,17 +1621,39 @@ class KernelDoc: elif doc_content.search(line): self.entry.contents +=3D doc_content.group(1) + "\n" =20 - def run(self): + def parse_export(self): + """ + Parses EXPORT_SYMBOL* macros from a single Kernel source file. + """ + + export_table =3D set() + + try: + with open(self.fname, "r", encoding=3D"utf8", + errors=3D"backslashreplace") as fp: + + for line in fp: + self.process_export(export_table, line) + + except IOError: + return None + + return export_table + + def parse_kdoc(self): """ Open and process each line of a C source file. - he parsing is controlled via a state machine, and the line is pass= ed + The parsing is controlled via a state machine, and the line is pas= sed to a different process function depending on the state. The process function may update the state as needed. + + Besides parsing kernel-doc tags, it also parses export symbols. """ =20 cont =3D False prev =3D "" prev_ln =3D None + export_table =3D set() =20 try: with open(self.fname, "r", encoding=3D"utf8", @@ -1659,6 +1685,16 @@ class KernelDoc: self.st_inline_name[self.inline_= doc_state], line) =20 + # This is an optimization over the original script. + # There, when export_file was used for the same file, + # it was read twice. Here, we use the already-existing + # loop to parse exported symbols as well. + # + # TODO: It should be noticed that not all states are + # needed here. On a future cleanup, process export only + # at the states that aren't handling comment markups. + self.process_export(export_table, line) + # Hand this line to the appropriate state handler if self.state =3D=3D self.STATE_NORMAL: self.process_normal(ln, line) @@ -1675,3 +1711,5 @@ class KernelDoc: self.process_docblock(ln, line) except OSError: self.config.log.error(f"Error: Cannot open file {self.fname}") + + return export_table, self.entries --=20 2.49.0