Re: [docs] [PATCH v2 3/4] tools: add gen-doc-links to generate documentation link flags

Quentin Schulz <[email protected]> Mon, 20 Jul 2026 18:39:49 +0200
Newsgroups org.yoctoproject.lists.docs
Message-ID <[email protected]>
Hi Antonin,

On 7/16/26 2:18 PM, Antonin Godard via lists.yoctoproject.org wrote:
> The gen-doc-links utility can be used to generate a configuration to be
> included in any project that want to get access to documentation links
> for documented variables. For that it opens the objects.inv file
> generate by our HTML build and creates links for existing variables and
> tasks.
> 
> Signed-off-by: Antonin Godard <[email protected]>
> ---
>   documentation/oecore/doclinks.conf | 1064 ++++++++++++++++++++++++++++++++++++
>   documentation/tools/gen-doc-links  |  112 ++++
>   2 files changed, 1176 insertions(+)
> 
[...]
> diff --git a/documentation/tools/gen-doc-links b/documentation/tools/gen-doc-links
> new file mode 100755
> index 000000000..11b3ef858
> --- /dev/null
> +++ b/documentation/tools/gen-doc-links
> @@ -0,0 +1,112 @@
> +#!/usr/bin/env python3
> +#
> +# SPDX-License-Identifier: MIT
> +#
> +# Author: Antonin Godard <[email protected]>
> +#
> +# Copyright (C) 2026 Bootlin
> +#
> +
> +import argparse
> +import sys
> +
> +from pathlib import Path
> +from sphinx.util.inventory import InventoryFile
> +
> +
> +YOCTO_DOCS_URL = "https://docs.yoctoproject.org/${LAYERSERIES_COMPAT_core}"
> +BITBAKE_DOCS_URL = "https://docs.yoctoproject.org/bitbake/${LAYERSERIES_COMPAT_core}"

Sorry for the mangled link, but this is invalid. We only have bitbake 
version number, and not Yocto release name so this won't work.

> +DOCS_DIR = Path(__file__).parent.parent
> +PREAMBLE = """#
> +# This file is automatically generated with tools/gen-doc-links, do not edit manually.
> +#
> +"""
> +YOCTO_DOCS_SECTION = """
> +# yocto-docs
> +
> +"""
> +BITBAKE_SECTION = """
> +# bitbake
> +
> +"""
> +
> +
> +def parse_arguments() -> argparse.Namespace:
> +    parser = argparse.ArgumentParser(description="Generate glossaries from Sphinx text output")
> +
> +    parser.add_argument("--yocto-docs-inv",
> +                        type=Path,
> +                        default=DOCS_DIR / "_build/html/objects.inv",
> +                        help="Input yocto-docs inventory file")
> +
> +    parser.add_argument("--bitbake-inv",
> +                        type=Path,
> +                        default=DOCS_DIR / "_build/doctrees/__intersphinx_cache__/bitbake_objects.inv",
> +                        help="Input bitbake inventory file")
> +
> +    parser.add_argument("-o", "--output",
> +                        type=Path,
> +                        default=DOCS_DIR / "oecore/doclinks.conf",
> +                        help="Output doclinks.conf file")
> +
> +    return parser.parse_args()
> +
> +
> +def doclink(name: str, uri) -> str:
> +    return f'{name}[doclink] = "{uri}"\n'
> +
> +
> +def main():
> +    args = parse_arguments()
> +
> +    yocto_docs_dict = {}
> +
> +    if not args.yocto_docs_inv.exists():
> +        print(f"yocto-docs inventory not found at {args.yocto_docs_inv}, "
> +              "use the --yocto-docs-inv option or set YOCTO_DOCS_INV_PATH "
> +              "in your environment")
> +        sys.exit(0)
> +
> +    if not args.bitbake_inv.exists():
> +        print(f"bitbake inventory not found at {args.yocto_docs_inv}, "
> +              "use the --bitbake-inv option or set BITBAKE_INV_PATH "
> +              "in your environment")
> +        sys.exit(0)

Don't you want to sys.exit(1) here (and above) instead to show the user 
this is an error?

> +
> +    yocto_docs_data = args.yocto_docs_inv.read_bytes()
> +    yocto_docs_inv = InventoryFile.loads(yocto_docs_data, uri=YOCTO_DOCS_URL)
> +
> +    yocto_docs_uris = (
> +        f"{YOCTO_DOCS_URL}/ref-manual/variables.html#term-",
> +        f"{YOCTO_DOCS_URL}/ref-manual/tasks.html#term-",
> +    )
> +
> +    for key in sorted(yocto_docs_inv.data):
> +        inv_entries = sorted(yocto_docs_inv.data[key].items())
> +        for entry, inv_item in inv_entries:
> +            if inv_item.uri.startswith(yocto_docs_uris):
> +                yocto_docs_dict[entry] = inv_item.uri
> +
> +    bitbake_dict = {}
> +    bitbake_data = args.bitbake_inv.read_bytes()
> +    bitbake_inv = InventoryFile.loads(bitbake_data, uri=BITBAKE_DOCS_URL)
> +
> +    bitbake_uris = (
> +        f"{BITBAKE_DOCS_URL}/bitbake-user-manual/bitbake-user-manual-ref-variables.html#term-",
> +    )
> +
> +    for key in sorted(bitbake_inv.data):
> +        inv_entries = sorted(bitbake_inv.data[key].items())
> +        for entry, inv_item in inv_entries:
> +            if inv_item.uri.startswith(bitbake_uris) and entry not in yocto_docs_dict:
> +                bitbake_dict[entry] = inv_item.uri
> +

1. Does the uri need to be YOCTO_DOCS_URL? We only need to have it in 
the output file, which we can add in the write calls below. But we could 
also simply have the empty ('') string. This should make it faster to 
compare (fewer letters to compare against).
2. Why do we need to check that it startswith()? I'm assuming you want 
to avoid the ref-manual/terms.html entries? Please document this with a 
comment.
3. Can't you avoid the first for-loop and directly iterate over 
bitbake_inv.data['std:term'].items() since that's the only thing we're 
interested in?

> +    with open(args.output, "w") as links_conf:
> +        links_conf.write(PREAMBLE)
> +        links_conf.write(YOCTO_DOCS_SECTION)
> +        [links_conf.write(doclink(name, uri)) for name, uri in yocto_docs_dict.items()]
> +        links_conf.write(BITBAKE_SECTION)
> +        [links_conf.write(doclink(name, uri)) for name, uri in bitbake_dict.items()]

I'm also a bit concerned about the use of $(LAYERSERIES_COMPAT_core} as 
this may induce some mismatch between what OE-Core is at and the version 
used to generate this file. We may actually document a variable that 
shouldn't be used anymore, or that isn't accessible yet due to a 
different major version being used. We do know what we're building the 
docs for (c.f. conf.py) so maybe we should hardcode that?

Cheers,
Quentin