Re: [PATCH] kernel-doc: add support for handling global variables

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Em Tue, 9 Sep 2025 00:27:20 -0700
Randy Dunlap <rdunlap@xxxxxxxxxxxxx> escreveu:

> Hi Mauro,
> 
> I have a few patch nits below, then some testing info.
> 
> 
> On 9/7/25 9:22 AM, Mauro Carvalho Chehab wrote:
> > Specially on kAPI, sometimes it is desirable to be able to
> > describe global variables that are part of kAPI.
> > 
> > Documenting vars with Sphinx is simple, as we don't need
> > to parse a data struct. All we need is the variable
> > declaration and use natice C domain ::c:var: to format it
> > for us.
> > 
> > Add support for it.
> > 
> > Link: https://lore.kernel.org/linux-doc/491c3022-cef8-4860-a945-c9c4a3b63c09@xxxxxxxxxxxxx/T/#m947c25d95cb1d96a394410ab1131dc8e9e5013f1
> > Suggested-by: Randy Dunlap <rdunlap@xxxxxxxxxxxxx>
> > Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@xxxxxxxxxx>
> > ---
> >  scripts/lib/kdoc/kdoc_output.py | 31 +++++++++++++++++++++++++++++++
> >  scripts/lib/kdoc/kdoc_parser.py | 25 ++++++++++++++++++++++++-
> >  2 files changed, 55 insertions(+), 1 deletion(-)
> > 
> > diff --git a/scripts/lib/kdoc/kdoc_output.py b/scripts/lib/kdoc/kdoc_output.py
> > index 1eca9a918558..405a5c407522 100644
> > --- a/scripts/lib/kdoc/kdoc_output.py
> > +++ b/scripts/lib/kdoc/kdoc_output.py
> > @@ -199,6 +199,10 @@ class OutputFormat:
> >              self.out_enum(fname, name, args)
> >              return self.data
> >  
> > +        if dtype == "global":
> > +            self.out_global(fname, name, args)
> > +            return self.data
> > +
> >          if dtype == "typedef":
> >              self.out_typedef(fname, name, args)
> >              return self.data
> > @@ -227,6 +231,9 @@ class OutputFormat:
> >      def out_enum(self, fname, name, args):
> >          """Outputs an enum"""
> >  
> > +    def out_global(self, fname, name, args):
> > +        """Outputs a global variable"""
> > +
> >      def out_typedef(self, fname, name, args):
> >          """Outputs a typedef"""
> >  
> > @@ -472,6 +479,18 @@ class RestFormat(OutputFormat):
> >          self.lineprefix = oldprefix
> >          self.out_section(args)
> >  
> > +    def out_global(self, fname, name, args):
> > +        oldprefix = self.lineprefix
> > +        ln = args.declaration_start_line
> > +        prototype = args.other_stuff["var_type"]
> > +
> > +        self.data += f"
> > 
> > .. c:var:: {prototype}
> > 
> > "  
> 
> Are the 5 lines above supposed to be on one line?  Did git send-email split that up for you?
> There are a few others like this below.
> patch(1) complains when I try to apply the patch from this email.

Weird. I'm testing a new mailbomb script... perhaps it is
causing those issues. Yeah, the code snippet is:

+    def out_global(self, fname, name, args):
+        oldprefix = self.lineprefix
+        ln = args.declaration_start_line
+        prototype = args.other_stuff["var_type"]
+
+        self.data += f"\n\n.. c:var:: {prototype}\n\n"
+
+        self.print_lineno(ln)
+        self.lineprefix = "  "
+        self.output_highlight(args.get('purpose', ''))
+        self.data += "\n"

It sounds the mailbomb script replaced "\n" with a new line :-(

> > +        self.print_lineno(ln)
> > +        self.lineprefix = "  "
> > +        self.output_highlight(args.get('purpose', ''))
> > +        self.data += "
> > "
> > +
> >      def out_typedef(self, fname, name, args):
> >  
> >          oldprefix = self.lineprefix
> > @@ -772,6 +791,18 @@ class ManFormat(OutputFormat):
> >              self.data += f'.SH "{section}"' + "
> > "
> >              self.output_highlight(text)
> >  
> > +    def out_global(self, fname, name, args):
> > +        out_name = self.arg_name(args, name)
> > +        prototype = args.other_stuff["var_type"]
> > +
> > +        self.data += f'.TH "{self.modulename}" 9 "{out_name}" "{self.man_date}" "API Manual" LINUX' + "
> > "
> > +
> > +        self.data += ".SH NAME
> > "
> > +        self.data += f"{prototype} \- {args['purpose']}  
> 
> Python complains about the "\-" above. Other places nearby use "\\-"
> so I changed it to that instead. Hope that's OK.
> 

Yes. Again, mailbomb script mangled it. The original code is:

+        self.data += f"{prototype} \\- {args['purpose']}\n"

I'm pasting the full patch at the end.

> > "
> > +
> > +        self.data += ".SH SYNOPSIS
> > "
> > +        self.data += f"enum {name}" + " {
> > "
> > +
> >      def out_typedef(self, fname, name, args):
> >          module = self.modulename
> >          purpose = args.get('purpose')
> > diff --git a/scripts/lib/kdoc/kdoc_parser.py b/scripts/lib/kdoc/kdoc_parser.py
> > index 574972e1f741..e2a3f4574894 100644
> > --- a/scripts/lib/kdoc/kdoc_parser.py
> > +++ b/scripts/lib/kdoc/kdoc_parser.py
> > @@ -64,7 +64,7 @@ type_param = KernRe(r"@(\w*((\.\w+)|(->\w+))*(\.\.\.)?)", cache=False)
> >  # Tests for the beginning of a kerneldoc block in its various forms.
> >  #
> >  doc_block = doc_com + KernRe(r'DOC:\s*(.*)?', cache=False)
> > -doc_begin_data = KernRe(r"^\s*\*?\s*(struct|union|enum|typedef)\s*(\w*)", cache = False)
> > +doc_begin_data = KernRe(r"^\s*\*?\s*(struct|union|enum|typedef|global)\s*(\w*)", cache = False)
> >  doc_begin_func = KernRe(str(doc_com) +			# initial " * '
> >                          r"(?:\w+\s*\*\s*)?" + 		# type (not captured)
> >                          r'(?:define\s+)?' + 		# possible "define" (not captured)
> > @@ -886,6 +886,27 @@ class KernelDoc:
> >          self.output_declaration('enum', declaration_name,
> >                                  purpose=self.entry.declaration_purpose)
> >  
> > +    def dump_global(self, ln, proto):
> > +        """
> > +        Stores global variables that are part of kAPI.
> > +        """
> > +        VAR_ATTRIBS = [
> > +            "extern",
> > +        ]
> > +        OPTIONAL_VAR_ATTR = "^(?:" + "|".join(VAR_ATTRIBS) + ")?"
> > +
> > +        r= KernRe(OPTIONAL_VAR_ATTR + r"(\w.*)\s+([\w_]+)[\d\]\[]*\s*;(?:#.*)?$")
> > +        if not r.match(proto):
> > +           self.emit_msg(ln,f"{proto}: can't parse variable")
> > +           return
> > +
> > +        declaration_name = r.group(2)
> > +        var_type = r.group(0)
> > +
> > +        self.output_declaration("global", declaration_name,
> > +                                var_type=var_type,
> > +                                purpose=self.entry.declaration_purpose)
> > +
> >      def dump_declaration(self, ln, prototype):
> >          """
> >          Stores a data declaration inside self.entries array.
> > @@ -897,6 +918,8 @@ class KernelDoc:
> >              self.dump_typedef(ln, prototype)
> >          elif self.entry.decl_type in ["union", "struct"]:
> >              self.dump_struct(ln, prototype)
> > +        elif self.entry.decl_type == "global":
> > +            self.dump_global(ln, prototype)
> >          else:
> >              # This would be a bug
> >              self.emit_message(ln, f'Unknown declaration type: {self.entry.decl_type}')  
> So, I grabbed some global data from 6-8 places in the kernel and put them intoinit/kdoc-globals-test.c. Then I modified Documentation/core-api/kernel-api.rst
> like this at the end of that file:
> 
> +
> +Kernel Globals
> +==========================
> +
> +.. kernel-doc:: init/kdoc-globals-test.c
> +   :identifiers:
> 
> The html output says
> "Kernel Globals"
> but nothing else.

I usually don't add :identifiers: on kernel-doc entries. If you use
identifiers, you need to explicitly tell what symbols you want.

As a reference, kerneldoc.py logic for identifiers is:

	if 'identifiers' in self.options:                                                                                                                                                                      
            identifiers = self.options.get('identifiers').split()                                                                                                                                                
            if identifiers:
                for i in identifiers:
                    i = i.rstrip("\\").strip()
                    if not i:
                        continue

                    cmd += ['-function', i]
                    self.msg_args["symbol"].append(i)

without it, it will pick the entire set of symbols. 

> My test files are attached. I dumbed down (simplified) a few
> of the globals from fancy types to just unsigned long, but that
> didn't help the output results any.

Looking on your attachment, you can either drop :identifiers:
or list all of them:

	.. kernel-doc:: init/kdoc-globals-test.c
	   :identifiers: ROOT_DEV loop_per_jiffy
	   :identifiers: preset_lpj

(here, it should only show those 3 symbols)

see, having this:

	.. kernel-doc:: init/kdoc-globals-test.c
	   :identifiers: ROOT_DEV 

will run:

	$ ./scripts/kernel-doc init/kdoc-globals-test.c -function ROOT_DEV 


	.. c:var:: unsigned long ROOT_DEV;

	  system root device




> What's happening?
> Thanks.





Thanks,
Mauro

---



[Index of Archives]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux FS]     [Yosemite Forum]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]

  Powered by Linux