From 7dc38adcb5b59f5347fcfbcc8b5df261eda704a1 Mon Sep 17 00:00:00 2001 From: Daniel Scally Date: Thu, 8 Aug 2024 15:09:46 +0100 Subject: Documentation: Split public/private documentation The API reference pages generated by Doxygen are comprehensive, but therefore quite overwhelming for application developers who will likely never need to use the majority of the library's objects. To reduce the complexity of the documentation, split it into two runs of doxygen. The first run of doxygen is for the public API. We pass a specific list of source files to parse, which is built from the arrays of public headers and sources in meson build files. This ensures that we only generate the documentation for code from those files. A custom Python script is needed to add the list of input files to Doxyfile, as several of the objects included in the header and source array are custom_tgt objects, which can't be handled as strings to populate a variable in the configuration data. The headers defining the Extensible and Object classes (class.h and object.h respectively), as well as the corresponding source files, are excluded from the public API documentation despite being referenced in the meson public headers and sources arrays. This is due to the fact that public API classes inherit from Extensible and Object, making the Extensible and Object classes part of the public ABI. Those two base classes are however implementation details and must not be accessed directly by application code. The second run of doxygen is for the internal API. This contains documentation for all of the library's objects as it currently does. This set will now be output into build/Documentation/internal-api-html. Signed-off-by: Daniel Scally Co-developed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart Reviewed-by: Kieran Bingham Reviewed-by: Daniel Scally --- Documentation/Doxyfile-common.in | 69 ++++++++++++++++++++++++++++ Documentation/Doxyfile-internal.in | 31 +++++++++++++ Documentation/Doxyfile-public.in | 20 ++++++++ Documentation/Doxyfile.in | 94 -------------------------------------- Documentation/gen-doxyfile.py | 46 +++++++++++++++++++ Documentation/meson.build | 61 ++++++++++++++++++++++--- 6 files changed, 221 insertions(+), 100 deletions(-) create mode 100644 Documentation/Doxyfile-common.in create mode 100644 Documentation/Doxyfile-internal.in create mode 100644 Documentation/Doxyfile-public.in delete mode 100644 Documentation/Doxyfile.in create mode 100755 Documentation/gen-doxyfile.py (limited to 'Documentation') diff --git a/Documentation/Doxyfile-common.in b/Documentation/Doxyfile-common.in new file mode 100644 index 00000000..a70aee43 --- /dev/null +++ b/Documentation/Doxyfile-common.in @@ -0,0 +1,69 @@ +# SPDX-License-Identifier: CC-BY-SA-4.0 +# Doxyfile 1.9.5 + +PROJECT_NAME = "libcamera" +PROJECT_NUMBER = "@VERSION@" +PROJECT_BRIEF = "Supporting cameras in Linux since 2019" + +OUTPUT_DIRECTORY = "@OUTPUT_DIR@" + +STRIP_FROM_PATH = "@TOP_SRCDIR@" + +ALIASES = "context=\xrefitem context \"Thread Safety\" \"Thread Safety\"" \ + "threadbound=\ref thread-bound \"thread-bound\"" \ + "threadsafe=\ref thread-safe \"thread-safe\"" + +EXTENSION_MAPPING = h=C++ + +TOC_INCLUDE_HEADINGS = 0 + +CASE_SENSE_NAMES = YES + +QUIET = YES +WARN_AS_ERROR = @WARN_AS_ERROR@ + +FILE_PATTERNS = *.c \ + *.cpp \ + *.dox \ + *.h + +RECURSIVE = YES + +EXCLUDE_PATTERNS = @TOP_BUILDDIR@/include/libcamera/ipa/*_serializer.h \ + @TOP_BUILDDIR@/include/libcamera/ipa/*_proxy.h \ + @TOP_BUILDDIR@/include/libcamera/ipa/ipu3_*.h \ + @TOP_BUILDDIR@/include/libcamera/ipa/raspberrypi_*.h \ + @TOP_BUILDDIR@/include/libcamera/ipa/rkisp1_*.h \ + @TOP_BUILDDIR@/include/libcamera/ipa/vimc_*.h + +EXCLUDE_SYMBOLS = libcamera::BoundMethodArgs \ + libcamera::BoundMethodBase \ + libcamera::BoundMethodFunctor \ + libcamera::BoundMethodMember \ + libcamera::BoundMethodPack \ + libcamera::BoundMethodPackBase \ + libcamera::BoundMethodStatic \ + libcamera::CameraManager::Private \ + libcamera::SignalBase \ + libcamera::ipa::AlgorithmFactoryBase \ + *::details \ + std::* + +EXCLUDE_SYMLINKS = YES + +GENERATE_LATEX = NO + +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = YES + +INCLUDE_PATH = "@TOP_SRCDIR@/include/libcamera" +INCLUDE_FILE_PATTERNS = *.h + +IMAGE_PATH = "@TOP_SRCDIR@/Documentation/images" + +PREDEFINED = __DOXYGEN__ \ + __cplusplus \ + __attribute__(x)= \ + @PREDEFINED@ + +HAVE_DOT = YES diff --git a/Documentation/Doxyfile-internal.in b/Documentation/Doxyfile-internal.in new file mode 100644 index 00000000..cf982553 --- /dev/null +++ b/Documentation/Doxyfile-internal.in @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: CC-BY-SA-4.0 + +@INCLUDE_PATH = @TOP_BUILDDIR@/Documentation +@INCLUDE = Doxyfile-common + +HIDE_UNDOC_CLASSES = NO +HIDE_UNDOC_MEMBERS = NO +HTML_OUTPUT = internal-api-html +INTERNAL_DOCS = YES +ENABLED_SECTIONS = internal + +INPUT = "@TOP_SRCDIR@/Documentation" \ + "@TOP_SRCDIR@/include/libcamera" \ + "@TOP_SRCDIR@/src/ipa/ipu3" \ + "@TOP_SRCDIR@/src/ipa/libipa" \ + "@TOP_SRCDIR@/src/libcamera" \ + "@TOP_BUILDDIR@/include/libcamera" \ + "@TOP_BUILDDIR@/src/libcamera" + +EXCLUDE = @TOP_SRCDIR@/include/libcamera/base/span.h \ + @TOP_SRCDIR@/include/libcamera/internal/device_enumerator_sysfs.h \ + @TOP_SRCDIR@/include/libcamera/internal/device_enumerator_udev.h \ + @TOP_SRCDIR@/include/libcamera/internal/ipc_pipe_unixsocket.h \ + @TOP_SRCDIR@/src/libcamera/device_enumerator_sysfs.cpp \ + @TOP_SRCDIR@/src/libcamera/device_enumerator_udev.cpp \ + @TOP_SRCDIR@/src/libcamera/ipc_pipe_unixsocket.cpp \ + @TOP_SRCDIR@/src/libcamera/pipeline/ \ + @TOP_SRCDIR@/src/libcamera/tracepoints.cpp \ + @TOP_BUILDDIR@/include/libcamera/internal/tracepoints.h \ + @TOP_BUILDDIR@/include/libcamera/ipa/soft_ipa_interface.h \ + @TOP_BUILDDIR@/src/libcamera/proxy/ diff --git a/Documentation/Doxyfile-public.in b/Documentation/Doxyfile-public.in new file mode 100644 index 00000000..36bb5758 --- /dev/null +++ b/Documentation/Doxyfile-public.in @@ -0,0 +1,20 @@ +# SPDX-License-Identifier: CC-BY-SA-4.0 + +@INCLUDE_PATH = @TOP_BUILDDIR@/Documentation +@INCLUDE = Doxyfile-common + +HIDE_UNDOC_CLASSES = YES +HIDE_UNDOC_MEMBERS = YES +HTML_OUTPUT = api-html +INTERNAL_DOCS = NO + +INPUT = "@TOP_SRCDIR@/Documentation" \ + ${inputs} + +EXCLUDE = @TOP_SRCDIR@/include/libcamera/base/class.h \ + @TOP_SRCDIR@/include/libcamera/base/object.h \ + @TOP_SRCDIR@/include/libcamera/base/span.h \ + @TOP_SRCDIR@/src/libcamera/base/class.cpp \ + @TOP_SRCDIR@/src/libcamera/base/object.cpp + +PREDEFINED += __DOXYGEN_PUBLIC__ diff --git a/Documentation/Doxyfile.in b/Documentation/Doxyfile.in deleted file mode 100644 index 203f8e67..00000000 --- a/Documentation/Doxyfile.in +++ /dev/null @@ -1,94 +0,0 @@ -# SPDX-License-Identifier: CC-BY-SA-4.0 -# Doxyfile 1.9.5 - -PROJECT_NAME = "libcamera" -PROJECT_NUMBER = "@VERSION@" -PROJECT_BRIEF = "Supporting cameras in Linux since 2019" - -OUTPUT_DIRECTORY = "@OUTPUT_DIR@" - -STRIP_FROM_PATH = "@TOP_SRCDIR@" - -ALIASES = "context=\xrefitem context \"Thread Safety\" \"Thread Safety\"" \ - "threadbound=\ref thread-bound \"thread-bound\"" \ - "threadsafe=\ref thread-safe \"thread-safe\"" - -EXTENSION_MAPPING = h=C++ - -TOC_INCLUDE_HEADINGS = 0 - -ENABLED_SECTIONS = internal -INTERNAL_DOCS = YES -CASE_SENSE_NAMES = YES - -QUIET = YES -WARN_AS_ERROR = @WARN_AS_ERROR@ - -INPUT = "@TOP_SRCDIR@/Documentation" \ - "@TOP_SRCDIR@/include/libcamera" \ - "@TOP_SRCDIR@/src/ipa/ipu3" \ - "@TOP_SRCDIR@/src/ipa/libipa" \ - "@TOP_SRCDIR@/src/libcamera" \ - "@TOP_BUILDDIR@/include/libcamera" \ - "@TOP_BUILDDIR@/src/libcamera" - -FILE_PATTERNS = *.c \ - *.cpp \ - *.dox \ - *.h - -RECURSIVE = YES - -EXCLUDE = @TOP_SRCDIR@/include/libcamera/base/span.h \ - @TOP_SRCDIR@/include/libcamera/internal/device_enumerator_sysfs.h \ - @TOP_SRCDIR@/include/libcamera/internal/device_enumerator_udev.h \ - @TOP_SRCDIR@/include/libcamera/internal/ipc_pipe_unixsocket.h \ - @TOP_SRCDIR@/src/libcamera/device_enumerator_sysfs.cpp \ - @TOP_SRCDIR@/src/libcamera/device_enumerator_udev.cpp \ - @TOP_SRCDIR@/src/libcamera/ipc_pipe_unixsocket.cpp \ - @TOP_SRCDIR@/src/libcamera/pipeline/ \ - @TOP_SRCDIR@/src/libcamera/tracepoints.cpp \ - @TOP_BUILDDIR@/include/libcamera/internal/tracepoints.h \ - @TOP_BUILDDIR@/include/libcamera/ipa/soft_ipa_interface.h \ - @TOP_BUILDDIR@/src/libcamera/proxy/ - -EXCLUDE_PATTERNS = @TOP_BUILDDIR@/include/libcamera/ipa/*_serializer.h \ - @TOP_BUILDDIR@/include/libcamera/ipa/*_proxy.h \ - @TOP_BUILDDIR@/include/libcamera/ipa/ipu3_*.h \ - @TOP_BUILDDIR@/include/libcamera/ipa/raspberrypi_*.h \ - @TOP_BUILDDIR@/include/libcamera/ipa/rkisp1_*.h \ - @TOP_BUILDDIR@/include/libcamera/ipa/vimc_*.h - -EXCLUDE_SYMBOLS = libcamera::BoundMethodArgs \ - libcamera::BoundMethodBase \ - libcamera::BoundMethodFunctor \ - libcamera::BoundMethodMember \ - libcamera::BoundMethodPack \ - libcamera::BoundMethodPackBase \ - libcamera::BoundMethodStatic \ - libcamera::CameraManager::Private \ - libcamera::SignalBase \ - libcamera::ipa::AlgorithmFactoryBase \ - *::details \ - std::* - -EXCLUDE_SYMLINKS = YES - -HTML_OUTPUT = api-html - -GENERATE_LATEX = NO - -MACRO_EXPANSION = YES -EXPAND_ONLY_PREDEF = YES - -INCLUDE_PATH = "@TOP_SRCDIR@/include/libcamera" -INCLUDE_FILE_PATTERNS = *.h - -IMAGE_PATH = "@TOP_SRCDIR@/Documentation/images" - -PREDEFINED = __DOXYGEN__ \ - __cplusplus \ - __attribute__(x)= \ - @PREDEFINED@ - -HAVE_DOT = YES diff --git a/Documentation/gen-doxyfile.py b/Documentation/gen-doxyfile.py new file mode 100755 index 00000000..c265bc2f --- /dev/null +++ b/Documentation/gen-doxyfile.py @@ -0,0 +1,46 @@ +#!/usr/bin/env python3 +# SPDX-License-Identifier: GPL-2.0-or-later +# Copyright (C) 2024, Google Inc. +# +# Author: Laurent Pinchart +# +# Generate Doxyfile from a template + +import argparse +import os +import string +import sys + + +def fill_template(template, data): + + template = open(template, 'rb').read() + template = template.decode('utf-8') + template = string.Template(template) + + return template.substitute(data) + + +def main(argv): + + parser = argparse.ArgumentParser() + parser.add_argument('-o', dest='output', metavar='file', + type=argparse.FileType('w', encoding='utf-8'), + default=sys.stdout, + help='Output file name (default: standard output)') + parser.add_argument('template', metavar='doxyfile.tmpl', type=str, + help='Doxyfile template') + parser.add_argument('inputs', type=str, nargs='*', + help='Input files') + + args = parser.parse_args(argv[1:]) + + inputs = [f'"{os.path.realpath(input)}"' for input in args.inputs] + data = fill_template(args.template, {'inputs': (' \\\n' + ' ' * 25).join(inputs)}) + args.output.write(data) + + return 0 + + +if __name__ == '__main__': + sys.exit(main(sys.argv)) diff --git a/Documentation/meson.build b/Documentation/meson.build index 1d84ed81..1ba40fdf 100644 --- a/Documentation/meson.build +++ b/Documentation/meson.build @@ -24,9 +24,9 @@ if doxygen.found() and dot.found() cdata.set('PREDEFINED', ' \\\n\t\t\t '.join(doxygen_predefined)) - doxyfile = configure_file(input : 'Doxyfile.in', - output : 'Doxyfile', - configuration : cdata) + doxyfile_common = configure_file(input : 'Doxyfile-common.in', + output : 'Doxyfile-common', + configuration : cdata) doxygen_public_input = [ libcamera_base_public_headers, @@ -50,17 +50,66 @@ if doxygen.found() and dot.found() doxygen_internal_input += [ipu3_ipa_sources] endif - custom_target('doxygen', + # We run doxygen twice - the first run excludes internal API objects as it + # is intended to document the public API only. A second run covers all of + # the library's objects for libcamera developers. Common configuration is + # set in an initially generated Doxyfile, which is then included by the two + # final Doxyfiles. + + # This is the "public" run of doxygen generating an abridged version of the + # API's documentation. + + doxyfile_tmpl = configure_file(input : 'Doxyfile-public.in', + output : 'Doxyfile-public.tmpl', + configuration : cdata) + + # The set of public input files stored in the doxygen_public_input array + # needs to be set in Doxyfile public. We can't pass them through cdata + # cdata, as some of the array members are custom_tgt instances, which + # configuration_data.set() doesn't support. Using a separate script invoked + # through custom_target(), which supports custom_tgt instances as inputs. + + doxyfile = custom_target('doxyfile-public', + input : [ + doxygen_public_input, + ], + output : 'Doxyfile-public', + command : [ + 'gen-doxyfile.py', + '-o', '@OUTPUT@', + doxyfile_tmpl, + '@INPUT@', + ]) + + custom_target('doxygen-public', input : [ doxyfile, - doxygen_public_input, - doxygen_internal_input, + doxyfile_common, ], output : 'api-html', command : [doxygen, doxyfile], install : true, install_dir : doc_install_dir, install_tag : 'doc') + + # This is the internal documentation, which hard-codes a list of directories + # to parse in its doxyfile. + + doxyfile = configure_file(input : 'Doxyfile-internal.in', + output : 'Doxyfile-internal', + configuration : cdata) + + custom_target('doxygen-internal', + input : [ + doxyfile, + doxyfile_common, + doxygen_internal_input, + ], + output : 'internal-api-html', + command : [doxygen, doxyfile], + install : true, + install_dir : doc_install_dir, + install_tag : 'doc-internal') endif # -- cgit v1.2.1