[{"id":35233,"web_url":"https://patchwork.libcamera.org/comment/35233/","msgid":"<0198beae-303e-4f05-8095-356c830fe4eb@protonmail.com>","date":"2025-07-29T15:24:12","subject":"Re: [PATCH 3/4] Documentation: Use Sphinx doxylink to generate links\n\tto doxygen","submitter":{"id":133,"url":"https://patchwork.libcamera.org/api/people/133/","name":"Pőcze Barnabás","email":"pobrn@protonmail.com"},"content":"Hi\n\n2025. 07. 27. 3:57 keltezéssel, Laurent Pinchart írta:\n> The libcamera Sphinx documentation needs to link to the API\n> documentation generated by Doxygen. The links currently point to the\n> documentation hosted on the official https://libcamera.org/ website.\n> This causes multiple issues:\n> \n> - Doxygen generates URLs with MD5 hashes of function signatures, making\n>    the link targets unstable.\n> \n> - When testing documentation builds that include API changes, links to\n>    new API elements will be broken.\n> \n> - The generated documentation can't be browsed offline.\n> \n> Fix this by using the Sphinx doxylink extension. This allows specifying\n> link targets as class and function names, with the link being\n> automatically generated using the same MD5 hashing as Doxygen. The root\n> of the link target is configured in a central location, which defaults\n> to the build directory and can be overridden to point to the libcamera\n> website when pushing the documentation.\n> \n> This commit only introduces the infrastructure to use doxylink. Manual\n> links will be replaced separately.\n> \n> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> ---\n>   Documentation/Doxyfile-internal.in |  2 ++\n>   Documentation/Doxyfile-public.in   |  2 ++\n>   Documentation/conf.py              | 13 +++++++-\n>   Documentation/meson.build          | 48 ++++++++++++++++--------------\n>   README.rst                         |  3 +-\n>   5 files changed, 44 insertions(+), 24 deletions(-)\n> \n> diff --git a/Documentation/Doxyfile-internal.in b/Documentation/Doxyfile-internal.in\n> index 5343bc2b131c..a422bb0719da 100644\n> --- a/Documentation/Doxyfile-internal.in\n> +++ b/Documentation/Doxyfile-internal.in\n> @@ -3,6 +3,8 @@\n>   @INCLUDE_PATH          = @TOP_BUILDDIR@/Documentation\n>   @INCLUDE               = Doxyfile-common\n> \n> +GENERATE_TAGFILE       = @TOP_BUILDDIR@/Documentation/internal-api-html/tagfile.xml\n> +\n>   HIDE_UNDOC_CLASSES     = NO\n>   HIDE_UNDOC_MEMBERS     = NO\n>   HTML_OUTPUT            = internal-api-html\n> diff --git a/Documentation/Doxyfile-public.in b/Documentation/Doxyfile-public.in\n> index 36bb57584a07..c3a8b0dd003a 100644\n> --- a/Documentation/Doxyfile-public.in\n> +++ b/Documentation/Doxyfile-public.in\n> @@ -3,6 +3,8 @@\n>   @INCLUDE_PATH          = @TOP_BUILDDIR@/Documentation\n>   @INCLUDE               = Doxyfile-common\n> \n> +GENERATE_TAGFILE       = @TOP_BUILDDIR@/Documentation/api-html/tagfile.xml\n> +\n>   HIDE_UNDOC_CLASSES     = YES\n>   HIDE_UNDOC_MEMBERS     = YES\n>   HTML_OUTPUT            = api-html\n> diff --git a/Documentation/conf.py b/Documentation/conf.py\n> index 870937289eb4..f50be60a1559 100644\n> --- a/Documentation/conf.py\n> +++ b/Documentation/conf.py\n> @@ -37,7 +37,8 @@ author = 'The libcamera documentation authors'\n>   # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom\n>   # ones.\n>   extensions = [\n> -    'sphinx.ext.graphviz'\n> +    'sphinx.ext.graphviz',\n> +    'sphinxcontrib.doxylink',\n>   ]\n\nThis was not installed for me, and things failed with a longer error message\nthan I would have expected. I'm wondering if it might make sense to add something like\n\ndiff --git a/Documentation/meson.build b/Documentation/meson.build\nindex 87918bf9a..a4752f787 100644\n--- a/Documentation/meson.build\n+++ b/Documentation/meson.build\n@@ -167,4 +167,6 @@ if sphinx.found()\n                    build_always_stale : true,\n                    input : docs_sources,\n                    output : 'linkcheck')\n+\n+    py_modules += 'sphinxcontrib.doxylink'\n  endif\n\nso that the there is a clear error message from meson as to what the issue is.\nAdmittedly I think it could be possible that sphinx does not use the python installation\nthat is found later by meson. This could be addressed maybe like this:\n\ndiff --git a/Documentation/meson.build b/Documentation/meson.build\nindex 87918bf9a..b74efea6d 100644\n--- a/Documentation/meson.build\n+++ b/Documentation/meson.build\n@@ -117,10 +117,10 @@ endif\n  # Sphinx\n  #\n  \n-sphinx = find_program('sphinx-build-3', 'sphinx-build',\n-                      required : get_option('documentation'))\n+py_mod = import('python')\n+py = py_mod.find_installation('python3', required : get_option('documentation'), modules : ['sphinx', 'sphinxcontrib.doxylink'])\n  \n-if sphinx.found()\n+if py.found()\n      docs_sources = [\n          'camera-sensor-model.rst',\n          'code-of-conduct.rst',\n@@ -149,7 +149,7 @@ if sphinx.found()\n      release = 'release=v' + libcamera_git_version\n  \n      custom_target('documentation',\n-                  command : [sphinx, '-D', release, '-q', '-W', '-b', 'html',\n+                  command : [py, '-m', 'sphinx', '-D', release, '-q', '-W', '-b', 'html',\n                               meson.current_source_dir(), '@OUTPUT@'],\n                    input : docs_sources,\n                    output : 'html',\n@@ -163,7 +163,7 @@ if sphinx.found()\n                    install_tag : 'doc')\n  \n      custom_target('documentation-linkcheck',\n-                  command : [sphinx, '-W', '-b', 'linkcheck', meson.current_source_dir(), '@OUTPUT@'],\n+                  command : [py, '-m', 'sphinx', '-W', '-b', 'linkcheck', meson.current_source_dir(), '@OUTPUT@'],\n                    build_always_stale : true,\n                    input : docs_sources,\n                    output : 'linkcheck')\n\n\nOtherwise the links seem to work nicely.\n\n\nRegards,\nBarnabás Pőcze\n\n\n> \n>   graphviz_output_format = 'svg'\n> @@ -71,6 +72,16 @@ exclude_patterns = [\n>   # The name of the Pygments (syntax highlighting) style to use.\n>   pygments_style = None\n> \n> +doxylink = {\n> +    'doxy-pub': (\n> +        'Documentation/api-html/tagfile.xml',\n> +        '../api-html/',\n> +    ),\n> +    'doxy-int': (\n> +        'Documentation/internal-api-html/tagfile.xml',\n> +        '../internal-api-html/',\n> +    ),\n> +}\n> \n>   # -- Options for HTML output -------------------------------------------------\n> \n> diff --git a/Documentation/meson.build b/Documentation/meson.build\n> index 3afdcc1a87af..87918bf9a921 100644\n> --- a/Documentation/meson.build\n> +++ b/Documentation/meson.build\n> @@ -81,16 +81,16 @@ if doxygen.found() and dot.found()\n>                                    '@INPUT@',\n>                                ])\n> \n> -    custom_target('doxygen-public',\n> -                  input : [\n> -                      doxyfile,\n> -                      doxyfile_common,\n> -                  ],\n> -                  output : 'api-html',\n> -                  command : [doxygen, doxyfile],\n> -                  install : true,\n> -                  install_dir : doc_install_dir,\n> -                  install_tag : 'doc')\n> +    doxygen_public = custom_target('doxygen-public',\n> +                                   input : [\n> +                                       doxyfile,\n> +                                       doxyfile_common,\n> +                                   ],\n> +                                   output : 'api-html',\n> +                                   command : [doxygen, doxyfile],\n> +                                   install : true,\n> +                                   install_dir : doc_install_dir,\n> +                                   install_tag : 'doc')\n> \n>       # This is the internal documentation, which hard-codes a list of directories\n>       # to parse in its doxyfile.\n> @@ -99,18 +99,18 @@ if doxygen.found() and dot.found()\n>                                 output : 'Doxyfile-internal',\n>                                 configuration : cdata)\n> \n> -    custom_target('doxygen-internal',\n> -                  input : [\n> -                      doxyfile,\n> -                      doxyfile_common,\n> -                      doxygen_public_input,\n> -                      doxygen_internal_input,\n> -                  ],\n> -                  output : 'internal-api-html',\n> -                  command : [doxygen, doxyfile],\n> -                  install : true,\n> -                  install_dir : doc_install_dir,\n> -                  install_tag : 'doc-internal')\n> +    doxygen_internal = custom_target('doxygen-internal',\n> +                                     input : [\n> +                                         doxyfile,\n> +                                         doxyfile_common,\n> +                                         doxygen_public_input,\n> +                                         doxygen_internal_input,\n> +                                     ],\n> +                                     output : 'internal-api-html',\n> +                                     command : [doxygen, doxyfile],\n> +                                     install : true,\n> +                                     install_dir : doc_install_dir,\n> +                                     install_tag : 'doc-internal')\n>   endif\n> \n>   #\n> @@ -154,6 +154,10 @@ if sphinx.found()\n>                     input : docs_sources,\n>                     output : 'html',\n>                     build_by_default : true,\n> +                  depends : [\n> +                      doxygen_public,\n> +                      doxygen_internal,\n> +                  ],\n>                     install : true,\n>                     install_dir : doc_install_dir,\n>                     install_tag : 'doc')\n> diff --git a/README.rst b/README.rst\n> index e2a6e275895e..e9a7dd82de74 100644\n> --- a/README.rst\n> +++ b/README.rst\n> @@ -67,7 +67,8 @@ for device hotplug enumeration: [optional]\n>           libudev-dev\n> \n>   for documentation: [optional]\n> -        python3-sphinx doxygen graphviz texlive-latex-extra\n> +        doxygen graphviz python3-sphinx python3-sphinxcontrib.doxylink (>= 1.6.1)\n> +        texlive-latex-extra\n> \n>   for gstreamer: [optional]\n>           libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev\n> --\n> Regards,\n> \n> Laurent Pinchart\n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 35CCDBDC71\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 29 Jul 2025 15:24:38 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id 077AD691DF;\n\tTue, 29 Jul 2025 17:24:37 +0200 (CEST)","from mail-24418.protonmail.ch (mail-24418.protonmail.ch\n\t[109.224.244.18])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 2098F69052\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 29 Jul 2025 17:24:21 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (2048-bit key;\n\tunprotected) header.d=protonmail.com header.i=@protonmail.com\n\theader.b=\"H4QCCyqe\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=protonmail.com;\n\ts=protonmail3; t=1753802657; x=1754061857;\n\tbh=OqPatfy3rya2/rLaShsQeAcKy+F6WuAgKSEbnqjgKmQ=;\n\th=Date:To:From:Subject:Message-ID:In-Reply-To:References:\n\tFeedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID:\n\tMessage-ID:BIMI-Selector;\n\tb=H4QCCyqeXkoPE9SIAOOQD6VsGTFqPcuZ6c1jE2346EjeaOvBLP+7oQHGCkKAbZST+\n\tI6EwowfHpbXefA1AvsoD6lI9MM3WzvNiHFY73OnAWmqXcjqg98/rcanW/m2l07yzHI\n\tSzodMnSNCL+LtxYi4g8yaUyGNR3LSSXIWkDSUkzA2FUdPDLp1239HryOjFi9LTxDjW\n\tNZsW+BzZKq0XtCdlp8IFmIXeP40FVBZybDQ6rjYL2ZEygE8UVzxbtcTZS8R9mfKr/7\n\tXjkex0ofIJhtt+rGaP0Dx0ce7KVCMr/Up4oUorfzFZTB5PBtFULupJuSNwn1HAVSzn\n\tTupYNBRYpEg7g==","Date":"Tue, 29 Jul 2025 15:24:12 +0000","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>,\n\tlibcamera-devel@lists.libcamera.org","From":"=?utf-8?q?P=C5=91cze_Barnab=C3=A1s?= <pobrn@protonmail.com>","Subject":"Re: [PATCH 3/4] Documentation: Use Sphinx doxylink to generate links\n\tto doxygen","Message-ID":"<0198beae-303e-4f05-8095-356c830fe4eb@protonmail.com>","In-Reply-To":"<20250727015720.6867-4-laurent.pinchart@ideasonboard.com>","References":"<20250727015720.6867-1-laurent.pinchart@ideasonboard.com>\n\t<20250727015720.6867-4-laurent.pinchart@ideasonboard.com>","Feedback-ID":"20568564:user:proton","X-Pm-Message-ID":"bd42d3aedc9438653ffdc48f22939bfc0482f6ed","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Transfer-Encoding":"quoted-printable","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":35238,"web_url":"https://patchwork.libcamera.org/comment/35238/","msgid":"<20250729202234.GA13909@pendragon.ideasonboard.com>","date":"2025-07-29T20:22:34","subject":"Re: [PATCH 3/4] Documentation: Use Sphinx doxylink to generate links\n\tto doxygen","submitter":{"id":2,"url":"https://patchwork.libcamera.org/api/people/2/","name":"Laurent Pinchart","email":"laurent.pinchart@ideasonboard.com"},"content":"On Tue, Jul 29, 2025 at 03:24:12PM +0000, Barnabás Pőcze wrote:\n> 2025. 07. 27. 3:57 keltezéssel, Laurent Pinchart írta:\n> > The libcamera Sphinx documentation needs to link to the API\n> > documentation generated by Doxygen. The links currently point to the\n> > documentation hosted on the official https://libcamera.org/ website.\n> > This causes multiple issues:\n> > \n> > - Doxygen generates URLs with MD5 hashes of function signatures, making\n> >    the link targets unstable.\n> > \n> > - When testing documentation builds that include API changes, links to\n> >    new API elements will be broken.\n> > \n> > - The generated documentation can't be browsed offline.\n> > \n> > Fix this by using the Sphinx doxylink extension. This allows specifying\n> > link targets as class and function names, with the link being\n> > automatically generated using the same MD5 hashing as Doxygen. The root\n> > of the link target is configured in a central location, which defaults\n> > to the build directory and can be overridden to point to the libcamera\n> > website when pushing the documentation.\n> > \n> > This commit only introduces the infrastructure to use doxylink. Manual\n> > links will be replaced separately.\n> > \n> > Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n> > ---\n> >   Documentation/Doxyfile-internal.in |  2 ++\n> >   Documentation/Doxyfile-public.in   |  2 ++\n> >   Documentation/conf.py              | 13 +++++++-\n> >   Documentation/meson.build          | 48 ++++++++++++++++--------------\n> >   README.rst                         |  3 +-\n> >   5 files changed, 44 insertions(+), 24 deletions(-)\n> > \n> > diff --git a/Documentation/Doxyfile-internal.in b/Documentation/Doxyfile-internal.in\n> > index 5343bc2b131c..a422bb0719da 100644\n> > --- a/Documentation/Doxyfile-internal.in\n> > +++ b/Documentation/Doxyfile-internal.in\n> > @@ -3,6 +3,8 @@\n> >   @INCLUDE_PATH          = @TOP_BUILDDIR@/Documentation\n> >   @INCLUDE               = Doxyfile-common\n> > \n> > +GENERATE_TAGFILE       = @TOP_BUILDDIR@/Documentation/internal-api-html/tagfile.xml\n> > +\n> >   HIDE_UNDOC_CLASSES     = NO\n> >   HIDE_UNDOC_MEMBERS     = NO\n> >   HTML_OUTPUT            = internal-api-html\n> > diff --git a/Documentation/Doxyfile-public.in b/Documentation/Doxyfile-public.in\n> > index 36bb57584a07..c3a8b0dd003a 100644\n> > --- a/Documentation/Doxyfile-public.in\n> > +++ b/Documentation/Doxyfile-public.in\n> > @@ -3,6 +3,8 @@\n> >   @INCLUDE_PATH          = @TOP_BUILDDIR@/Documentation\n> >   @INCLUDE               = Doxyfile-common\n> > \n> > +GENERATE_TAGFILE       = @TOP_BUILDDIR@/Documentation/api-html/tagfile.xml\n> > +\n> >   HIDE_UNDOC_CLASSES     = YES\n> >   HIDE_UNDOC_MEMBERS     = YES\n> >   HTML_OUTPUT            = api-html\n> > diff --git a/Documentation/conf.py b/Documentation/conf.py\n> > index 870937289eb4..f50be60a1559 100644\n> > --- a/Documentation/conf.py\n> > +++ b/Documentation/conf.py\n> > @@ -37,7 +37,8 @@ author = 'The libcamera documentation authors'\n> >   # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom\n> >   # ones.\n> >   extensions = [\n> > -    'sphinx.ext.graphviz'\n> > +    'sphinx.ext.graphviz',\n> > +    'sphinxcontrib.doxylink',\n> >   ]\n> \n> This was not installed for me, and things failed with a longer error message\n> than I would have expected.\n\nHere's what I get:\n\n--------\nFAILED: Documentation/html\n/usr/bin/sphinx-build -D release=v0.5.1+114-79f47d71 -q -W -b html /home/laurent/src/iob/oss/libcamera/libcamera/Documentation Documentation/html\n\nExtension error!\n\nVersions\n========\n\n* Platform:         linux; (Linux-6.12.31-gentoo-x86_64-Intel-R-_Core-TM-_i7-8550U_CPU_@_1.80GHz-with-glibc2.41)\n* Python version:   3.13.5 (CPython)\n* Sphinx version:   8.2.3\n* Docutils version: 0.21.2\n* Jinja2 version:   3.1.6\n* Pygments version: 2.19.2\n\nLast Messages\n=============\n\nNone.\n\nLoaded Extensions\n=================\n\nNone.\n\nTraceback\n=========\n\n      File \"/usr/lib/python3.13/site-packages/sphinx/registry.py\", line 544, in load_extension\n        raise ExtensionError(\n            __('Could not import extension %s') % extname, err\n        ) from err\n    sphinx.errors.ExtensionError: Could not import extension sphinxcontrib.doxylink (exception: No module named 'sphinxcontrib.doxylink')\n\n\nThe full traceback has been saved in:\n/tmp/sphinx-err-lelwc3u2.log\n\nTo report this error to the developers, please open an issue at <https://github.com/sphinx-doc/sphinx/issues/>. Thanks!\nPlease also report this if it was a user error, so that a better error message can be provided next time.\n--------\n\nIs your experience similar ?\n\n> I'm wondering if it might make sense to add something like\n> \n> diff --git a/Documentation/meson.build b/Documentation/meson.build\n> index 87918bf9a..a4752f787 100644\n> --- a/Documentation/meson.build\n> +++ b/Documentation/meson.build\n> @@ -167,4 +167,6 @@ if sphinx.found()\n>                     build_always_stale : true,\n>                     input : docs_sources,\n>                     output : 'linkcheck')\n> +\n> +    py_modules += 'sphinxcontrib.doxylink'\n>   endif\n> \n> so that the there is a clear error message from meson as to what the issue is.\n> Admittedly I think it could be possible that sphinx does not use the python installation\n> that is found later by meson. This could be addressed maybe like this:\n> \n> diff --git a/Documentation/meson.build b/Documentation/meson.build\n> index 87918bf9a..b74efea6d 100644\n> --- a/Documentation/meson.build\n> +++ b/Documentation/meson.build\n> @@ -117,10 +117,10 @@ endif\n>   # Sphinx\n>   #\n>   \n> -sphinx = find_program('sphinx-build-3', 'sphinx-build',\n> -                      required : get_option('documentation'))\n> +py_mod = import('python')\n> +py = py_mod.find_installation('python3', required : get_option('documentation'), modules : ['sphinx', 'sphinxcontrib.doxylink'])\n>   \n> -if sphinx.found()\n> +if py.found()\n>       docs_sources = [\n>           'camera-sensor-model.rst',\n>           'code-of-conduct.rst',\n> @@ -149,7 +149,7 @@ if sphinx.found()\n>       release = 'release=v' + libcamera_git_version\n>   \n>       custom_target('documentation',\n> -                  command : [sphinx, '-D', release, '-q', '-W', '-b', 'html',\n> +                  command : [py, '-m', 'sphinx', '-D', release, '-q', '-W', '-b', 'html',\n>                                meson.current_source_dir(), '@OUTPUT@'],\n>                     input : docs_sources,\n>                     output : 'html',\n> @@ -163,7 +163,7 @@ if sphinx.found()\n>                     install_tag : 'doc')\n>   \n>       custom_target('documentation-linkcheck',\n> -                  command : [sphinx, '-W', '-b', 'linkcheck', meson.current_source_dir(), '@OUTPUT@'],\n> +                  command : [py, '-m', 'sphinx', '-W', '-b', 'linkcheck', meson.current_source_dir(), '@OUTPUT@'],\n>                     build_always_stale : true,\n>                     input : docs_sources,\n>                     output : 'linkcheck')\n\nI'd prefer the first option, based on py_modules, as it's simpler. I\ntested it locally (Gentoo, distribution-provided sphinxcontrib.doxylink\nversion) and in CI (Debian 11, 12 and 13, with a mix if PyPI and\ndistribution packages) without issues. We can always improve it later if\nneeded.\n\n> Otherwise the links seem to work nicely.\n\nThanks for testing. I'll send a v2 with py_modules.\n\n> >   graphviz_output_format = 'svg'\n> > @@ -71,6 +72,16 @@ exclude_patterns = [\n> >   # The name of the Pygments (syntax highlighting) style to use.\n> >   pygments_style = None\n> > \n> > +doxylink = {\n> > +    'doxy-pub': (\n> > +        'Documentation/api-html/tagfile.xml',\n> > +        '../api-html/',\n> > +    ),\n> > +    'doxy-int': (\n> > +        'Documentation/internal-api-html/tagfile.xml',\n> > +        '../internal-api-html/',\n> > +    ),\n> > +}\n> > \n> >   # -- Options for HTML output -------------------------------------------------\n> > \n> > diff --git a/Documentation/meson.build b/Documentation/meson.build\n> > index 3afdcc1a87af..87918bf9a921 100644\n> > --- a/Documentation/meson.build\n> > +++ b/Documentation/meson.build\n> > @@ -81,16 +81,16 @@ if doxygen.found() and dot.found()\n> >                                    '@INPUT@',\n> >                                ])\n> > \n> > -    custom_target('doxygen-public',\n> > -                  input : [\n> > -                      doxyfile,\n> > -                      doxyfile_common,\n> > -                  ],\n> > -                  output : 'api-html',\n> > -                  command : [doxygen, doxyfile],\n> > -                  install : true,\n> > -                  install_dir : doc_install_dir,\n> > -                  install_tag : 'doc')\n> > +    doxygen_public = custom_target('doxygen-public',\n> > +                                   input : [\n> > +                                       doxyfile,\n> > +                                       doxyfile_common,\n> > +                                   ],\n> > +                                   output : 'api-html',\n> > +                                   command : [doxygen, doxyfile],\n> > +                                   install : true,\n> > +                                   install_dir : doc_install_dir,\n> > +                                   install_tag : 'doc')\n> > \n> >       # This is the internal documentation, which hard-codes a list of directories\n> >       # to parse in its doxyfile.\n> > @@ -99,18 +99,18 @@ if doxygen.found() and dot.found()\n> >                                 output : 'Doxyfile-internal',\n> >                                 configuration : cdata)\n> > \n> > -    custom_target('doxygen-internal',\n> > -                  input : [\n> > -                      doxyfile,\n> > -                      doxyfile_common,\n> > -                      doxygen_public_input,\n> > -                      doxygen_internal_input,\n> > -                  ],\n> > -                  output : 'internal-api-html',\n> > -                  command : [doxygen, doxyfile],\n> > -                  install : true,\n> > -                  install_dir : doc_install_dir,\n> > -                  install_tag : 'doc-internal')\n> > +    doxygen_internal = custom_target('doxygen-internal',\n> > +                                     input : [\n> > +                                         doxyfile,\n> > +                                         doxyfile_common,\n> > +                                         doxygen_public_input,\n> > +                                         doxygen_internal_input,\n> > +                                     ],\n> > +                                     output : 'internal-api-html',\n> > +                                     command : [doxygen, doxyfile],\n> > +                                     install : true,\n> > +                                     install_dir : doc_install_dir,\n> > +                                     install_tag : 'doc-internal')\n> >   endif\n> > \n> >   #\n> > @@ -154,6 +154,10 @@ if sphinx.found()\n> >                     input : docs_sources,\n> >                     output : 'html',\n> >                     build_by_default : true,\n> > +                  depends : [\n> > +                      doxygen_public,\n> > +                      doxygen_internal,\n> > +                  ],\n> >                     install : true,\n> >                     install_dir : doc_install_dir,\n> >                     install_tag : 'doc')\n> > diff --git a/README.rst b/README.rst\n> > index e2a6e275895e..e9a7dd82de74 100644\n> > --- a/README.rst\n> > +++ b/README.rst\n> > @@ -67,7 +67,8 @@ for device hotplug enumeration: [optional]\n> >           libudev-dev\n> > \n> >   for documentation: [optional]\n> > -        python3-sphinx doxygen graphviz texlive-latex-extra\n> > +        doxygen graphviz python3-sphinx python3-sphinxcontrib.doxylink (>= 1.6.1)\n> > +        texlive-latex-extra\n> > \n> >   for gstreamer: [optional]\n> >           libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id C2F5CBDCC1\n\tfor <parsemail@patchwork.libcamera.org>;\n\tTue, 29 Jul 2025 20:22:47 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id EE934691EA;\n\tTue, 29 Jul 2025 22:22:46 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[IPv6:2001:4b98:dc2:55:216:3eff:fef7:d647])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 9487F69052\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tTue, 29 Jul 2025 22:22:44 +0200 (CEST)","from pendragon.ideasonboard.com (81-175-209-231.bb.dnainternet.fi\n\t[81.175.209.231])\n\tby perceval.ideasonboard.com (Postfix) with UTF8SMTPSA id 4DD9C3D5;\n\tTue, 29 Jul 2025 22:22:01 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"n7NGssdb\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1753820521;\n\tbh=tEf0d6UjVwsWHrcujBRJcbb9+5taLEWrNMNn4uglKxY=;\n\th=Date:From:To:Cc:Subject:References:In-Reply-To:From;\n\tb=n7NGssdbb9begWn/tfZz4twfQUA9svgKVsymXg83nKHL0P1fjl37ZXdERkldP+rUr\n\tEW9i61iOBUgwnImS6DXN2DHIn7IuxnZ7j/OASRnblfUUHrlSdVoi1B1Ded3jjH31Js\n\t7XqsjyYRcpU7f3P1Mmlq6ydV/5pwU1n40efKJTBI=","Date":"Tue, 29 Jul 2025 23:22:34 +0300","From":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","To":"=?utf-8?q?P=C5=91cze_Barnab=C3=A1s?= <pobrn@protonmail.com>","Cc":"libcamera-devel@lists.libcamera.org","Subject":"Re: [PATCH 3/4] Documentation: Use Sphinx doxylink to generate links\n\tto doxygen","Message-ID":"<20250729202234.GA13909@pendragon.ideasonboard.com>","References":"<20250727015720.6867-1-laurent.pinchart@ideasonboard.com>\n\t<20250727015720.6867-4-laurent.pinchart@ideasonboard.com>\n\t<0198beae-303e-4f05-8095-356c830fe4eb@protonmail.com>","MIME-Version":"1.0","Content-Type":"text/plain; charset=utf-8","Content-Disposition":"inline","Content-Transfer-Encoding":"8bit","In-Reply-To":"<0198beae-303e-4f05-8095-356c830fe4eb@protonmail.com>","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}},{"id":35240,"web_url":"https://patchwork.libcamera.org/comment/35240/","msgid":"<4fcde111-deef-4214-8d38-b42f22f19d9a@ideasonboard.com>","date":"2025-07-30T07:35:30","subject":"Re: [PATCH 3/4] Documentation: Use Sphinx doxylink to generate links\n\tto doxygen","submitter":{"id":216,"url":"https://patchwork.libcamera.org/api/people/216/","name":"Barnabás Pőcze","email":"barnabas.pocze@ideasonboard.com"},"content":"Hi\n\n2025. 07. 29. 22:22 keltezéssel, Laurent Pinchart írta:\n> On Tue, Jul 29, 2025 at 03:24:12PM +0000, Barnabás Pőcze wrote:\n>> 2025. 07. 27. 3:57 keltezéssel, Laurent Pinchart írta:\n>>> The libcamera Sphinx documentation needs to link to the API\n>>> documentation generated by Doxygen. The links currently point to the\n>>> documentation hosted on the official https://libcamera.org/ website.\n>>> This causes multiple issues:\n>>>\n>>> - Doxygen generates URLs with MD5 hashes of function signatures, making\n>>>     the link targets unstable.\n>>>\n>>> - When testing documentation builds that include API changes, links to\n>>>     new API elements will be broken.\n>>>\n>>> - The generated documentation can't be browsed offline.\n>>>\n>>> Fix this by using the Sphinx doxylink extension. This allows specifying\n>>> link targets as class and function names, with the link being\n>>> automatically generated using the same MD5 hashing as Doxygen. The root\n>>> of the link target is configured in a central location, which defaults\n>>> to the build directory and can be overridden to point to the libcamera\n>>> website when pushing the documentation.\n>>>\n>>> This commit only introduces the infrastructure to use doxylink. Manual\n>>> links will be replaced separately.\n>>>\n>>> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>\n>>> ---\n>>>    Documentation/Doxyfile-internal.in |  2 ++\n>>>    Documentation/Doxyfile-public.in   |  2 ++\n>>>    Documentation/conf.py              | 13 +++++++-\n>>>    Documentation/meson.build          | 48 ++++++++++++++++--------------\n>>>    README.rst                         |  3 +-\n>>>    5 files changed, 44 insertions(+), 24 deletions(-)\n>>>\n>>> diff --git a/Documentation/Doxyfile-internal.in b/Documentation/Doxyfile-internal.in\n>>> index 5343bc2b131c..a422bb0719da 100644\n>>> --- a/Documentation/Doxyfile-internal.in\n>>> +++ b/Documentation/Doxyfile-internal.in\n>>> @@ -3,6 +3,8 @@\n>>>    @INCLUDE_PATH          = @TOP_BUILDDIR@/Documentation\n>>>    @INCLUDE               = Doxyfile-common\n>>>\n>>> +GENERATE_TAGFILE       = @TOP_BUILDDIR@/Documentation/internal-api-html/tagfile.xml\n>>> +\n>>>    HIDE_UNDOC_CLASSES     = NO\n>>>    HIDE_UNDOC_MEMBERS     = NO\n>>>    HTML_OUTPUT            = internal-api-html\n>>> diff --git a/Documentation/Doxyfile-public.in b/Documentation/Doxyfile-public.in\n>>> index 36bb57584a07..c3a8b0dd003a 100644\n>>> --- a/Documentation/Doxyfile-public.in\n>>> +++ b/Documentation/Doxyfile-public.in\n>>> @@ -3,6 +3,8 @@\n>>>    @INCLUDE_PATH          = @TOP_BUILDDIR@/Documentation\n>>>    @INCLUDE               = Doxyfile-common\n>>>\n>>> +GENERATE_TAGFILE       = @TOP_BUILDDIR@/Documentation/api-html/tagfile.xml\n>>> +\n>>>    HIDE_UNDOC_CLASSES     = YES\n>>>    HIDE_UNDOC_MEMBERS     = YES\n>>>    HTML_OUTPUT            = api-html\n>>> diff --git a/Documentation/conf.py b/Documentation/conf.py\n>>> index 870937289eb4..f50be60a1559 100644\n>>> --- a/Documentation/conf.py\n>>> +++ b/Documentation/conf.py\n>>> @@ -37,7 +37,8 @@ author = 'The libcamera documentation authors'\n>>>    # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom\n>>>    # ones.\n>>>    extensions = [\n>>> -    'sphinx.ext.graphviz'\n>>> +    'sphinx.ext.graphviz',\n>>> +    'sphinxcontrib.doxylink',\n>>>    ]\n>>\n>> This was not installed for me, and things failed with a longer error message\n>> than I would have expected.\n> \n> Here's what I get:\n> \n> --------\n> FAILED: Documentation/html\n> /usr/bin/sphinx-build -D release=v0.5.1+114-79f47d71 -q -W -b html /home/laurent/src/iob/oss/libcamera/libcamera/Documentation Documentation/html\n> \n> Extension error!\n> \n> Versions\n> ========\n> \n> * Platform:         linux; (Linux-6.12.31-gentoo-x86_64-Intel-R-_Core-TM-_i7-8550U_CPU_@_1.80GHz-with-glibc2.41)\n> * Python version:   3.13.5 (CPython)\n> * Sphinx version:   8.2.3\n> * Docutils version: 0.21.2\n> * Jinja2 version:   3.1.6\n> * Pygments version: 2.19.2\n> \n> Last Messages\n> =============\n> \n> None.\n> \n> Loaded Extensions\n> =================\n> \n> None.\n> \n> Traceback\n> =========\n> \n>        File \"/usr/lib/python3.13/site-packages/sphinx/registry.py\", line 544, in load_extension\n>          raise ExtensionError(\n>              __('Could not import extension %s') % extname, err\n>          ) from err\n>      sphinx.errors.ExtensionError: Could not import extension sphinxcontrib.doxylink (exception: No module named 'sphinxcontrib.doxylink')\n> \n> \n> The full traceback has been saved in:\n> /tmp/sphinx-err-lelwc3u2.log\n> \n> To report this error to the developers, please open an issue at <https://github.com/sphinx-doc/sphinx/issues/>. Thanks!\n> Please also report this if it was a user error, so that a better error message can be provided next time.\n> --------\n> \n> Is your experience similar ?\n\nI get the same thing.\n\n\nRegards,\nBarnabás Pőcze\n\n\n> \n>> I'm wondering if it might make sense to add something like\n>>\n>> diff --git a/Documentation/meson.build b/Documentation/meson.build\n>> index 87918bf9a..a4752f787 100644\n>> --- a/Documentation/meson.build\n>> +++ b/Documentation/meson.build\n>> @@ -167,4 +167,6 @@ if sphinx.found()\n>>                      build_always_stale : true,\n>>                      input : docs_sources,\n>>                      output : 'linkcheck')\n>> +\n>> +    py_modules += 'sphinxcontrib.doxylink'\n>>    endif\n>>\n>> so that the there is a clear error message from meson as to what the issue is.\n>> Admittedly I think it could be possible that sphinx does not use the python installation\n>> that is found later by meson. This could be addressed maybe like this:\n>>\n>> diff --git a/Documentation/meson.build b/Documentation/meson.build\n>> index 87918bf9a..b74efea6d 100644\n>> --- a/Documentation/meson.build\n>> +++ b/Documentation/meson.build\n>> @@ -117,10 +117,10 @@ endif\n>>    # Sphinx\n>>    #\n>>    \n>> -sphinx = find_program('sphinx-build-3', 'sphinx-build',\n>> -                      required : get_option('documentation'))\n>> +py_mod = import('python')\n>> +py = py_mod.find_installation('python3', required : get_option('documentation'), modules : ['sphinx', 'sphinxcontrib.doxylink'])\n>>    \n>> -if sphinx.found()\n>> +if py.found()\n>>        docs_sources = [\n>>            'camera-sensor-model.rst',\n>>            'code-of-conduct.rst',\n>> @@ -149,7 +149,7 @@ if sphinx.found()\n>>        release = 'release=v' + libcamera_git_version\n>>    \n>>        custom_target('documentation',\n>> -                  command : [sphinx, '-D', release, '-q', '-W', '-b', 'html',\n>> +                  command : [py, '-m', 'sphinx', '-D', release, '-q', '-W', '-b', 'html',\n>>                                 meson.current_source_dir(), '@OUTPUT@'],\n>>                      input : docs_sources,\n>>                      output : 'html',\n>> @@ -163,7 +163,7 @@ if sphinx.found()\n>>                      install_tag : 'doc')\n>>    \n>>        custom_target('documentation-linkcheck',\n>> -                  command : [sphinx, '-W', '-b', 'linkcheck', meson.current_source_dir(), '@OUTPUT@'],\n>> +                  command : [py, '-m', 'sphinx', '-W', '-b', 'linkcheck', meson.current_source_dir(), '@OUTPUT@'],\n>>                      build_always_stale : true,\n>>                      input : docs_sources,\n>>                      output : 'linkcheck')\n> \n> I'd prefer the first option, based on py_modules, as it's simpler. I\n> tested it locally (Gentoo, distribution-provided sphinxcontrib.doxylink\n> version) and in CI (Debian 11, 12 and 13, with a mix if PyPI and\n> distribution packages) without issues. We can always improve it later if\n> needed.\n> \n>> Otherwise the links seem to work nicely.\n> \n> Thanks for testing. I'll send a v2 with py_modules.\n> \n>>>    graphviz_output_format = 'svg'\n>>> @@ -71,6 +72,16 @@ exclude_patterns = [\n>>>    # The name of the Pygments (syntax highlighting) style to use.\n>>>    pygments_style = None\n>>>\n>>> +doxylink = {\n>>> +    'doxy-pub': (\n>>> +        'Documentation/api-html/tagfile.xml',\n>>> +        '../api-html/',\n>>> +    ),\n>>> +    'doxy-int': (\n>>> +        'Documentation/internal-api-html/tagfile.xml',\n>>> +        '../internal-api-html/',\n>>> +    ),\n>>> +}\n>>>\n>>>    # -- Options for HTML output -------------------------------------------------\n>>>\n>>> diff --git a/Documentation/meson.build b/Documentation/meson.build\n>>> index 3afdcc1a87af..87918bf9a921 100644\n>>> --- a/Documentation/meson.build\n>>> +++ b/Documentation/meson.build\n>>> @@ -81,16 +81,16 @@ if doxygen.found() and dot.found()\n>>>                                     '@INPUT@',\n>>>                                 ])\n>>>\n>>> -    custom_target('doxygen-public',\n>>> -                  input : [\n>>> -                      doxyfile,\n>>> -                      doxyfile_common,\n>>> -                  ],\n>>> -                  output : 'api-html',\n>>> -                  command : [doxygen, doxyfile],\n>>> -                  install : true,\n>>> -                  install_dir : doc_install_dir,\n>>> -                  install_tag : 'doc')\n>>> +    doxygen_public = custom_target('doxygen-public',\n>>> +                                   input : [\n>>> +                                       doxyfile,\n>>> +                                       doxyfile_common,\n>>> +                                   ],\n>>> +                                   output : 'api-html',\n>>> +                                   command : [doxygen, doxyfile],\n>>> +                                   install : true,\n>>> +                                   install_dir : doc_install_dir,\n>>> +                                   install_tag : 'doc')\n>>>\n>>>        # This is the internal documentation, which hard-codes a list of directories\n>>>        # to parse in its doxyfile.\n>>> @@ -99,18 +99,18 @@ if doxygen.found() and dot.found()\n>>>                                  output : 'Doxyfile-internal',\n>>>                                  configuration : cdata)\n>>>\n>>> -    custom_target('doxygen-internal',\n>>> -                  input : [\n>>> -                      doxyfile,\n>>> -                      doxyfile_common,\n>>> -                      doxygen_public_input,\n>>> -                      doxygen_internal_input,\n>>> -                  ],\n>>> -                  output : 'internal-api-html',\n>>> -                  command : [doxygen, doxyfile],\n>>> -                  install : true,\n>>> -                  install_dir : doc_install_dir,\n>>> -                  install_tag : 'doc-internal')\n>>> +    doxygen_internal = custom_target('doxygen-internal',\n>>> +                                     input : [\n>>> +                                         doxyfile,\n>>> +                                         doxyfile_common,\n>>> +                                         doxygen_public_input,\n>>> +                                         doxygen_internal_input,\n>>> +                                     ],\n>>> +                                     output : 'internal-api-html',\n>>> +                                     command : [doxygen, doxyfile],\n>>> +                                     install : true,\n>>> +                                     install_dir : doc_install_dir,\n>>> +                                     install_tag : 'doc-internal')\n>>>    endif\n>>>\n>>>    #\n>>> @@ -154,6 +154,10 @@ if sphinx.found()\n>>>                      input : docs_sources,\n>>>                      output : 'html',\n>>>                      build_by_default : true,\n>>> +                  depends : [\n>>> +                      doxygen_public,\n>>> +                      doxygen_internal,\n>>> +                  ],\n>>>                      install : true,\n>>>                      install_dir : doc_install_dir,\n>>>                      install_tag : 'doc')\n>>> diff --git a/README.rst b/README.rst\n>>> index e2a6e275895e..e9a7dd82de74 100644\n>>> --- a/README.rst\n>>> +++ b/README.rst\n>>> @@ -67,7 +67,8 @@ for device hotplug enumeration: [optional]\n>>>            libudev-dev\n>>>\n>>>    for documentation: [optional]\n>>> -        python3-sphinx doxygen graphviz texlive-latex-extra\n>>> +        doxygen graphviz python3-sphinx python3-sphinxcontrib.doxylink (>= 1.6.1)\n>>> +        texlive-latex-extra\n>>>\n>>>    for gstreamer: [optional]\n>>>            libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev\n>","headers":{"Return-Path":"<libcamera-devel-bounces@lists.libcamera.org>","X-Original-To":"parsemail@patchwork.libcamera.org","Delivered-To":"parsemail@patchwork.libcamera.org","Received":["from lancelot.ideasonboard.com (lancelot.ideasonboard.com\n\t[92.243.16.209])\n\tby patchwork.libcamera.org (Postfix) with ESMTPS id 8E797BDC71\n\tfor <parsemail@patchwork.libcamera.org>;\n\tWed, 30 Jul 2025 07:36:02 +0000 (UTC)","from lancelot.ideasonboard.com (localhost [IPv6:::1])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTP id EA167691F0;\n\tWed, 30 Jul 2025 09:36:00 +0200 (CEST)","from perceval.ideasonboard.com (perceval.ideasonboard.com\n\t[213.167.242.64])\n\tby lancelot.ideasonboard.com (Postfix) with ESMTPS id 948C46913B\n\tfor <libcamera-devel@lists.libcamera.org>;\n\tWed, 30 Jul 2025 09:35:36 +0200 (CEST)","from [192.168.33.11] (185.182.214.105.nat.pool.zt.hu\n\t[185.182.214.105])\n\tby perceval.ideasonboard.com (Postfix) with ESMTPSA id 10CB53D5;\n\tWed, 30 Jul 2025 09:34:52 +0200 (CEST)"],"Authentication-Results":"lancelot.ideasonboard.com; dkim=pass (1024-bit key;\n\tunprotected) header.d=ideasonboard.com header.i=@ideasonboard.com\n\theader.b=\"XkjiMZsv\"; dkim-atps=neutral","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/simple; d=ideasonboard.com;\n\ts=mail; t=1753860892;\n\tbh=CBeIOdRqJklzrSEulRbxA7TYtJGhcnU+QglUWGZTWNI=;\n\th=Date:Subject:To:Cc:References:From:In-Reply-To:From;\n\tb=XkjiMZsvKygQk9BUUwttoNMe0DBDnIDU/KSdbdm9kNb+P/VFaoVCUHUuzOgC/SdV7\n\typnR8R1dE41G3sAZMdfqD3ClWE2BUOlOsoMRpVcn60+W/ZPc4Gdx36epAzjKOMQrCM\n\tzspVQzH8nUX1Nxs6WNr8VDM3mXAsJ1BVE41g+4uw=","Message-ID":"<4fcde111-deef-4214-8d38-b42f22f19d9a@ideasonboard.com>","Date":"Wed, 30 Jul 2025 09:35:30 +0200","MIME-Version":"1.0","User-Agent":"Mozilla Thunderbird","Subject":"Re: [PATCH 3/4] Documentation: Use Sphinx doxylink to generate links\n\tto doxygen","To":"Laurent Pinchart <laurent.pinchart@ideasonboard.com>","Cc":"libcamera-devel@lists.libcamera.org","References":"<20250727015720.6867-1-laurent.pinchart@ideasonboard.com>\n\t<20250727015720.6867-4-laurent.pinchart@ideasonboard.com>\n\t<0198beae-303e-4f05-8095-356c830fe4eb@protonmail.com>\n\t<20250729202234.GA13909@pendragon.ideasonboard.com>","From":"=?utf-8?q?Barnab=C3=A1s_P=C5=91cze?= <barnabas.pocze@ideasonboard.com>","Content-Language":"en-US, hu-HU","In-Reply-To":"<20250729202234.GA13909@pendragon.ideasonboard.com>","Content-Type":"text/plain; charset=UTF-8; format=flowed","Content-Transfer-Encoding":"8bit","X-BeenThere":"libcamera-devel@lists.libcamera.org","X-Mailman-Version":"2.1.29","Precedence":"list","List-Id":"<libcamera-devel.lists.libcamera.org>","List-Unsubscribe":"<https://lists.libcamera.org/options/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=unsubscribe>","List-Archive":"<https://lists.libcamera.org/pipermail/libcamera-devel/>","List-Post":"<mailto:libcamera-devel@lists.libcamera.org>","List-Help":"<mailto:libcamera-devel-request@lists.libcamera.org?subject=help>","List-Subscribe":"<https://lists.libcamera.org/listinfo/libcamera-devel>,\n\t<mailto:libcamera-devel-request@lists.libcamera.org?subject=subscribe>","Errors-To":"libcamera-devel-bounces@lists.libcamera.org","Sender":"\"libcamera-devel\" <libcamera-devel-bounces@lists.libcamera.org>"}}]