doc: add support for kerneldoc API tools
Some ACRN kernel components are using the API documentation methods of the Linux kernel. While they use Sphinx for generating their documentation, they don't use doxygen to collect the API information as we do for the rest of the project. Instead, they use their own tools called "kerneldoc". This PR incorporates those tools into our documentation build process. There is a prescribed directory structure for this to work: that the acrn-hypervisor and acrn-kernel repos are cloned to sibling folders, e.g.: projectacrn acrn-hypervisor acrn-kernel so that documentation references from acrn_hypervisor/doc can access the source code in ../../acrn-kernel to do the kerneldoc processing. A full display of the kerneldoc API material for a source file in the acrn-kernel tree can be done using a sphinx extension directive: .. kernel-doc:: /tools/virtio/linux/scatterlist.h where the assumed root of these file references is ../../acrn-kernel. The format for kerneldoc comments is documented in https://www.kernel.org/doc/html/latest/doc-guide/kernel-doc.html and references to kerneldoc API material in .rst files is documented in https://www.kernel.org/doc/html/latest/doc-guide/kernel-doc.html#including-kernel-doc-comments Without options, the kernel-doc directive includes all documentation comments from the source file. With options, you can display subsets of these comments. The intention is to limit use of kerneldoc comments to the acrn-kernel repo and not use them elsewhere within the ACRN project (where doxygen comments are expected.) While I'd prefer NOT to include the kerneldoc perl script here (it is already in the acrn-kernel/sphinx folder), I don't want to create a dependency on the acrn-kernel folder existing for documentation generation, but this might be unavoidable once we have part of the API material coming from there. We can update this in a later PR. Signed-off-by: David B. Kinder <david.b.kinder@intel.com>
This commit is contained in:
parent
85a5668b90
commit
b0deb1b5bd
12
doc/conf.py
12
doc/conf.py
|
@ -30,7 +30,17 @@ sys.path.insert(0, os.path.abspath('.'))
|
||||||
# Add any Sphinx extension module names here, as strings. They can be
|
# Add any Sphinx extension module names here, as strings. They can be
|
||||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||||
# ones.
|
# ones.
|
||||||
extensions = ['breathe', 'sphinx.ext.graphviz']
|
|
||||||
|
sys.path.insert(0, os.path.join(os.path.abspath('.'), 'extensions'))
|
||||||
|
extensions = ['breathe', 'sphinx.ext.graphviz', 'kerneldoc']
|
||||||
|
|
||||||
|
# kernel-doc extension configuration for running Sphinx directly (e.g. by Read
|
||||||
|
# the Docs). In a normal build, these are supplied from the Makefile via command
|
||||||
|
# line arguments.
|
||||||
|
|
||||||
|
kerneldoc_bin = 'scripts/kernel-doc'
|
||||||
|
kerneldoc_srctree = '../../acrn-kernel'
|
||||||
|
|
||||||
|
|
||||||
graphviz_output_format='png'
|
graphviz_output_format='png'
|
||||||
graphviz_dot_args=[
|
graphviz_dot_args=[
|
||||||
|
|
|
@ -0,0 +1,146 @@
|
||||||
|
# coding=utf-8
|
||||||
|
#
|
||||||
|
# Copyright © 2016 Intel Corporation
|
||||||
|
#
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
# copy of this software and associated documentation files (the "Software"),
|
||||||
|
# to deal in the Software without restriction, including without limitation
|
||||||
|
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
# and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
# Software is furnished to do so, subject to the following conditions:
|
||||||
|
#
|
||||||
|
# The above copyright notice and this permission notice (including the next
|
||||||
|
# paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
# Software.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
# IN THE SOFTWARE.
|
||||||
|
#
|
||||||
|
# Authors:
|
||||||
|
# Jani Nikula <jani.nikula@intel.com>
|
||||||
|
#
|
||||||
|
# Please make sure this works on both python2 and python3.
|
||||||
|
#
|
||||||
|
|
||||||
|
import codecs
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import re
|
||||||
|
import glob
|
||||||
|
|
||||||
|
from docutils import nodes, statemachine
|
||||||
|
from docutils.statemachine import ViewList
|
||||||
|
from docutils.parsers.rst import directives, Directive
|
||||||
|
from sphinx.ext.autodoc import AutodocReporter
|
||||||
|
|
||||||
|
__version__ = '1.0'
|
||||||
|
|
||||||
|
class KernelDocDirective(Directive):
|
||||||
|
"""Extract kernel-doc comments from the specified file"""
|
||||||
|
required_argument = 1
|
||||||
|
optional_arguments = 4
|
||||||
|
option_spec = {
|
||||||
|
'doc': directives.unchanged_required,
|
||||||
|
'functions': directives.unchanged_required,
|
||||||
|
'export': directives.unchanged,
|
||||||
|
'internal': directives.unchanged,
|
||||||
|
}
|
||||||
|
has_content = False
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
env = self.state.document.settings.env
|
||||||
|
cmd = [env.config.kerneldoc_bin, '-rst', '-enable-lineno']
|
||||||
|
|
||||||
|
filename = env.config.kerneldoc_srctree + '/' + self.arguments[0]
|
||||||
|
export_file_patterns = []
|
||||||
|
|
||||||
|
# Tell sphinx of the dependency
|
||||||
|
env.note_dependency(os.path.abspath(filename))
|
||||||
|
|
||||||
|
tab_width = self.options.get('tab-width', self.state.document.settings.tab_width)
|
||||||
|
|
||||||
|
# FIXME: make this nicer and more robust against errors
|
||||||
|
if 'export' in self.options:
|
||||||
|
cmd += ['-export']
|
||||||
|
export_file_patterns = str(self.options.get('export')).split()
|
||||||
|
elif 'internal' in self.options:
|
||||||
|
cmd += ['-internal']
|
||||||
|
export_file_patterns = str(self.options.get('internal')).split()
|
||||||
|
elif 'doc' in self.options:
|
||||||
|
cmd += ['-function', str(self.options.get('doc'))]
|
||||||
|
elif 'functions' in self.options:
|
||||||
|
for f in str(self.options.get('functions')).split():
|
||||||
|
cmd += ['-function', f]
|
||||||
|
|
||||||
|
for pattern in export_file_patterns:
|
||||||
|
for f in glob.glob(env.config.kerneldoc_srctree + '/' + pattern):
|
||||||
|
env.note_dependency(os.path.abspath(f))
|
||||||
|
cmd += ['-export-file', f]
|
||||||
|
|
||||||
|
cmd += [filename]
|
||||||
|
|
||||||
|
try:
|
||||||
|
env.app.verbose('calling kernel-doc \'%s\'' % (" ".join(cmd)))
|
||||||
|
|
||||||
|
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||||
|
out, err = p.communicate()
|
||||||
|
|
||||||
|
out, err = codecs.decode(out, 'utf-8'), codecs.decode(err, 'utf-8')
|
||||||
|
|
||||||
|
if p.returncode != 0:
|
||||||
|
sys.stderr.write(err)
|
||||||
|
|
||||||
|
env.app.warn('kernel-doc \'%s\' failed with return code %d' % (" ".join(cmd), p.returncode))
|
||||||
|
return [nodes.error(None, nodes.paragraph(text = "kernel-doc missing"))]
|
||||||
|
elif env.config.kerneldoc_verbosity > 0:
|
||||||
|
sys.stderr.write(err)
|
||||||
|
|
||||||
|
lines = statemachine.string2lines(out, tab_width, convert_whitespace=True)
|
||||||
|
result = ViewList()
|
||||||
|
|
||||||
|
lineoffset = 0;
|
||||||
|
line_regex = re.compile("^#define LINENO ([0-9]+)$")
|
||||||
|
for line in lines:
|
||||||
|
match = line_regex.search(line)
|
||||||
|
if match:
|
||||||
|
# sphinx counts lines from 0
|
||||||
|
lineoffset = int(match.group(1)) - 1
|
||||||
|
# we must eat our comments since the upset the markup
|
||||||
|
else:
|
||||||
|
result.append(line, filename, lineoffset)
|
||||||
|
lineoffset += 1
|
||||||
|
|
||||||
|
node = nodes.section()
|
||||||
|
buf = self.state.memo.title_styles, self.state.memo.section_level, self.state.memo.reporter
|
||||||
|
self.state.memo.reporter = AutodocReporter(result, self.state.memo.reporter)
|
||||||
|
self.state.memo.title_styles, self.state.memo.section_level = [], 0
|
||||||
|
try:
|
||||||
|
self.state.nested_parse(result, 0, node, match_titles=1)
|
||||||
|
finally:
|
||||||
|
self.state.memo.title_styles, self.state.memo.section_level, self.state.memo.reporter = buf
|
||||||
|
|
||||||
|
return node.children
|
||||||
|
|
||||||
|
except Exception as e: # pylint: disable=W0703
|
||||||
|
env.app.warn('kernel-doc \'%s\' processing failed with: %s' %
|
||||||
|
(" ".join(cmd), str(e)))
|
||||||
|
return [nodes.error(None, nodes.paragraph(text = "kernel-doc missing"))]
|
||||||
|
|
||||||
|
def setup(app):
|
||||||
|
app.add_config_value('kerneldoc_bin', None, 'env')
|
||||||
|
app.add_config_value('kerneldoc_srctree', None, 'env')
|
||||||
|
app.add_config_value('kerneldoc_verbosity', 1, 'env')
|
||||||
|
|
||||||
|
app.add_directive('kernel-doc', KernelDocDirective)
|
||||||
|
|
||||||
|
return dict(
|
||||||
|
version = __version__,
|
||||||
|
parallel_read_safe = True,
|
||||||
|
parallel_write_safe = True
|
||||||
|
)
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue