xref: /llvm-project/libc/utils/docgen/header.py (revision 88bcf7283b35b979ace0c6be32736b13f6b771ae)
10f6c4d8bSMichael Flanders# ====- Information about standard headers used by docgen  ----*- python -*--==#
20f6c4d8bSMichael Flanders#
30f6c4d8bSMichael Flanders# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40f6c4d8bSMichael Flanders# See https://llvm.org/LICENSE.txt for license information.
50f6c4d8bSMichael Flanders# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60f6c4d8bSMichael Flanders#
70f6c4d8bSMichael Flanders# ==-------------------------------------------------------------------------==#
80f6c4d8bSMichael Flandersfrom pathlib import Path
90f6c4d8bSMichael Flandersfrom typing import Generator
100f6c4d8bSMichael Flanders
110f6c4d8bSMichael Flanders
120f6c4d8bSMichael Flandersclass Header:
130f6c4d8bSMichael Flanders    """
140f6c4d8bSMichael Flanders    Maintains implementation information about a standard header file:
150f6c4d8bSMichael Flanders    * where does its implementation dir live
160f6c4d8bSMichael Flanders    * where is its macros file
17*88bcf728SNick Desaulniers    * where is its docgen yaml file
180f6c4d8bSMichael Flanders
190f6c4d8bSMichael Flanders    By convention, the macro-only part of a header file is in a header-specific
200f6c4d8bSMichael Flanders    file somewhere in the directory tree with root at
210f6c4d8bSMichael Flanders    ``$LLVM_PROJECT_ROOT/libc/include/llvm-libc-macros``.  Docgen expects that
220f6c4d8bSMichael Flanders    if a macro is implemented, that it appears in a string
230f6c4d8bSMichael Flanders    ``#define MACRO_NAME`` in some ``*-macros.h`` file in the directory tree.
240f6c4d8bSMichael Flanders    Docgen searches for this string in the file to set the implementation status
250f6c4d8bSMichael Flanders    shown in the generated rst docs rendered as html for display at
260f6c4d8bSMichael Flanders    <libc.llvm.org>.
270f6c4d8bSMichael Flanders
280f6c4d8bSMichael Flanders    By convention, each function for a header is implemented in a function-specific
290f6c4d8bSMichael Flanders    cpp file somewhere in the directory tree with root at, e.g,
300f6c4d8bSMichael Flanders    ``$LLVM_PROJECT_ROOT/libc/src/fenv``. Some headers have architecture-specific
310f6c4d8bSMichael Flanders    implementations, like ``math``, and some don't, like ``fenv``. Docgen uses the
320f6c4d8bSMichael Flanders    presence of this function-specific cpp file to set the implementation status
330f6c4d8bSMichael Flanders    shown in the generated rst docs rendered as html for display at
340f6c4d8bSMichael Flanders    <libc.llvm.org>.
350f6c4d8bSMichael Flanders    """
360f6c4d8bSMichael Flanders
370f6c4d8bSMichael Flanders    def __init__(self, header_name: str):
380f6c4d8bSMichael Flanders        """
390f6c4d8bSMichael Flanders        :param header_name: e.g., ``"threads.h"`` or ``"signal.h"``
400f6c4d8bSMichael Flanders        """
410f6c4d8bSMichael Flanders        self.name = header_name
420f6c4d8bSMichael Flanders        self.stem = header_name.rstrip(".h")
430f6c4d8bSMichael Flanders        self.docgen_root = Path(__file__).parent
440f6c4d8bSMichael Flanders        self.libc_root = self.docgen_root.parent.parent
45*88bcf728SNick Desaulniers        self.docgen_yaml = self.docgen_root / Path(header_name).with_suffix(".yaml")
460f6c4d8bSMichael Flanders        self.fns_dir = Path(self.libc_root, "src", self.stem)
470f6c4d8bSMichael Flanders        self.macros_dir = Path(self.libc_root, "include", "llvm-libc-macros")
480f6c4d8bSMichael Flanders
490f6c4d8bSMichael Flanders    def macro_file_exists(self) -> bool:
500f6c4d8bSMichael Flanders        for _ in self.__get_macro_files():
510f6c4d8bSMichael Flanders            return True
520f6c4d8bSMichael Flanders
530f6c4d8bSMichael Flanders        return False
540f6c4d8bSMichael Flanders
550f6c4d8bSMichael Flanders    def fns_dir_exists(self) -> bool:
560f6c4d8bSMichael Flanders        return self.fns_dir.exists() and self.fns_dir.is_dir()
570f6c4d8bSMichael Flanders
580f6c4d8bSMichael Flanders    def implements_fn(self, fn_name: str) -> bool:
590f6c4d8bSMichael Flanders        for _ in self.fns_dir.glob(f"**/{fn_name}.cpp"):
600f6c4d8bSMichael Flanders            return True
610f6c4d8bSMichael Flanders
620f6c4d8bSMichael Flanders        return False
630f6c4d8bSMichael Flanders
640f6c4d8bSMichael Flanders    def implements_macro(self, m_name: str) -> bool:
650f6c4d8bSMichael Flanders        """
660f6c4d8bSMichael Flanders        Some macro files are in, e.g.,
670f6c4d8bSMichael Flanders        ``$LLVM_PROJECT_ROOT/libc/include/llvm-libc-macros/fenv-macros.h``,
680f6c4d8bSMichael Flanders        but others are in subdirectories, e.g., ``signal.h`` has the macro
690f6c4d8bSMichael Flanders        definitions in
700f6c4d8bSMichael Flanders        ``$LLVM_PROJECT_ROOT/libc/include/llvm-libc-macros/linux/signal-macros.h``.
710f6c4d8bSMichael Flanders
720f6c4d8bSMichael Flanders        :param m_name: name of macro, e.g., ``FE_ALL_EXCEPT``
730f6c4d8bSMichael Flanders        """
740f6c4d8bSMichael Flanders        for f in self.__get_macro_files():
750f6c4d8bSMichael Flanders            if f"#define {m_name}" in f.read_text():
760f6c4d8bSMichael Flanders                return True
770f6c4d8bSMichael Flanders
780f6c4d8bSMichael Flanders        return False
790f6c4d8bSMichael Flanders
800f6c4d8bSMichael Flanders    def __get_macro_files(self) -> Generator[Path, None, None]:
810f6c4d8bSMichael Flanders        """
820f6c4d8bSMichael Flanders        This function uses a glob on, e.g., ``"**/fcntl.macros.h"`` because the
830f6c4d8bSMichael Flanders        macro file might be located in a subdirectory:
840f6c4d8bSMichael Flanders        libc/include/llvm-libc-macros/fcntl-macros.h
850f6c4d8bSMichael Flanders        libc/include/llvm-libc-macros/linux/fcntl-macros.h
86e17d2b58SNick Desaulniers
87e17d2b58SNick Desaulniers        When a header would be nested in a dir (such as arpa/, sys/, etc) we
88e17d2b58SNick Desaulniers        instead use a hyphen in the name.
89e17d2b58SNick Desaulniers        libc/include/llvm-libc-macros/sys-mman-macros.h
900f6c4d8bSMichael Flanders        """
91e17d2b58SNick Desaulniers        stem = self.stem.replace("/", "-")
92e17d2b58SNick Desaulniers        return self.macros_dir.glob(f"**/{stem}-macros.h")
93