93 lines · python
1# ====- Information about standard headers used by docgen ----*- python -*--==#2#3# Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4# See https://llvm.org/LICENSE.txt for license information.5# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6#7# ==-------------------------------------------------------------------------==#8from pathlib import Path9from typing import Generator10 11 12class Header:13 """14 Maintains implementation information about a standard header file:15 * where does its implementation dir live16 * where is its macros file17 * where is its docgen yaml file18 19 By convention, the macro-only part of a header file is in a header-specific20 file somewhere in the directory tree with root at21 ``$LLVM_PROJECT_ROOT/libc/include/llvm-libc-macros``. Docgen expects that22 if a macro is implemented, that it appears in a string23 ``#define MACRO_NAME`` in some ``*-macros.h`` file in the directory tree.24 Docgen searches for this string in the file to set the implementation status25 shown in the generated rst docs rendered as html for display at26 <libc.llvm.org>.27 28 By convention, each function for a header is implemented in a function-specific29 cpp file somewhere in the directory tree with root at, e.g,30 ``$LLVM_PROJECT_ROOT/libc/src/fenv``. Some headers have architecture-specific31 implementations, like ``math``, and some don't, like ``fenv``. Docgen uses the32 presence of this function-specific cpp file to set the implementation status33 shown in the generated rst docs rendered as html for display at34 <libc.llvm.org>.35 """36 37 def __init__(self, header_name: str):38 """39 :param header_name: e.g., ``"threads.h"`` or ``"signal.h"``40 """41 self.name = header_name42 self.stem = header_name.rstrip(".h")43 self.docgen_root = Path(__file__).parent44 self.libc_root = self.docgen_root.parent.parent45 self.docgen_yaml = self.docgen_root / Path(header_name).with_suffix(".yaml")46 self.fns_dir = Path(self.libc_root, "src", self.stem)47 self.macros_dir = Path(self.libc_root, "include", "llvm-libc-macros")48 49 def macro_file_exists(self) -> bool:50 for _ in self.__get_macro_files():51 return True52 53 return False54 55 def fns_dir_exists(self) -> bool:56 return self.fns_dir.exists() and self.fns_dir.is_dir()57 58 def implements_fn(self, fn_name: str) -> bool:59 for _ in self.fns_dir.glob(f"**/{fn_name}.cpp"):60 return True61 62 return False63 64 def implements_macro(self, m_name: str) -> bool:65 """66 Some macro files are in, e.g.,67 ``$LLVM_PROJECT_ROOT/libc/include/llvm-libc-macros/fenv-macros.h``,68 but others are in subdirectories, e.g., ``signal.h`` has the macro69 definitions in70 ``$LLVM_PROJECT_ROOT/libc/include/llvm-libc-macros/linux/signal-macros.h``.71 72 :param m_name: name of macro, e.g., ``FE_ALL_EXCEPT``73 """74 for f in self.__get_macro_files():75 if f"#define {m_name}" in f.read_text():76 return True77 78 return False79 80 def __get_macro_files(self) -> Generator[Path, None, None]:81 """82 This function uses a glob on, e.g., ``"**/fcntl.macros.h"`` because the83 macro file might be located in a subdirectory:84 libc/include/llvm-libc-macros/fcntl-macros.h85 libc/include/llvm-libc-macros/linux/fcntl-macros.h86 87 When a header would be nested in a dir (such as arpa/, sys/, etc) we88 instead use a hyphen in the name.89 libc/include/llvm-libc-macros/sys-mman-macros.h90 """91 stem = self.stem.replace("/", "-")92 return self.macros_dir.glob(f"**/{stem}-macros.h")93