[libc-commits] [libc] [libc][docs] adds macro handling, POSIX status, and validation to docgen (PR #89421)
Nick Desaulniers via libc-commits
libc-commits at lists.llvm.org
Mon Apr 22 12:57:45 PDT 2024
================
@@ -9,61 +9,160 @@
# ==-------------------------------------------------------------------------==#
from argparse import ArgumentParser, Namespace
from pathlib import Path
-from typing import Dict
+from typing import Dict, Generator
import sys
import json
-def load_api(hname: str) -> Dict:
- p = Path(__file__).parent / Path(hname).with_suffix(".json")
- api = p.read_text(encoding="utf-8")
- return json.loads(api)
+class DocgenAPIFormatError(Exception):
+ """Raised on fatal formatting errors with a description of a formatting error"""
-# TODO: we may need to get more sophisticated for less generic implementations.
-# Does libc/src/{hname minus .h suffix}/{fname}.cpp exist?
-def is_implemented(hname: str, fname: str) -> bool:
- path = Path(
- Path(__file__).parent.parent.parent,
- "src",
- hname.rstrip(".h")
- )
+class Header:
+ """
+ Maintains implementation information about a standard header file:
+ * where does its implementation dir live
+ * where is its macros file
+ * where is its docgen json file
- if not path.exists():
- raise FileNotFoundError(f"implementation dir does not exist: {path}")
+ By convention, the macro-only part of a header file is in a header-specific
+ file somewhere in the directory tree with root at
+ ``$LLVM_PROJECT_ROOT/libc/include/llvm-libc-macros``. Docgen expects that
+ if a macro is implemented, that it appears in a string
+ ``#define MACRO_NAME`` in some ``*-macros.h`` file in the directory tree..
+ Docgen searches for this string in the file to set the implementation status
+ shown in the generated rst docs rendered as html for display at
+ <libc.llvm.org>.
- if not path.is_dir():
- raise NotADirectoryError(f"implementation dir is not a dir: {path}")
+ By convention, each function for a header is implemented in a function-specific
+ cpp file somewhere in the directory tree with root at, e.g,
+ ``$LLVM_PROJECT_ROOT/libc/src/fenv``. Some headers have architecture-specific
+ implementations, like ``math``, and some don't, like ``fenv``. Docgen uses the
+ presence of this function-specific cpp file to set the implementation status
+ shown in the generated rst docs rendered as html for display at
+ <libc.llvm.org>.
+ """
- # Recursively search for the target source file in the subdirectories under
- # libc/src/{hname}.
- for _ in path.glob("**/" + fname + ".cpp"):
- return True
+ def __init__(self, header_name: str):
+ """
+ :param header_name: e.g., ``"threads.h"`` or ``"signal.h"``
+ """
+ self.name = header_name
+ self.stem = header_name.rstrip(".h")
+ self.libc_root = Path(__file__).parent.parent.parent
+ self.docgen_root = Path(__file__).parent
+ self.docgen_json = self.docgen_root / Path(header_name).with_suffix(".json")
+ self.fns_dir = Path(self.libc_root, "src", self.stem)
+ self.macros_dir = Path(self.libc_root, "include", "llvm-libc-macros")
- return False
+ def macro_file_exists(self) -> bool:
+ for _ in self.__get_macro_files():
+ return True
+ return False
-def print_functions(header: str, functions: Dict):
- for key in sorted(functions.keys()):
- print(f" * - {key}")
+ def fns_dir_exists(self) -> bool:
+ return self.fns_dir.exists() and self.fns_dir.is_dir()
- if is_implemented(header, key):
- print(" - |check|")
- else:
- print(" -")
+ def implements_fn(self, fn_name: str) -> bool:
+ for _ in self.fns_dir.glob(f"**/{fn_name}.cpp"):
+ return True
- # defined is optional. Having any content is optional.
- if functions[key] is not None and "defined" in functions[key]:
- print(f' - {functions[key]["defined"]}')
- else:
- print(" -")
+ return False
+ def implements_macro(self, m_name: str) -> bool:
+ """
+ Some macro files are in, e.g.,
+ ``$LLVM_PROJECT_ROOT/libc/include/llvm-libc-macros/fenv-macros.h``,
+ but others are in subdirectories, e.g., ``signal.h`` has the macro
+ definitions in
+ ``$LLVM_PROJECT_ROOT/libc/include/llvm-libc-macros/linux/signal-macros.h``.
-def print_header(header: str, api: Dict):
- print(".. include:: check.rst\n")
- fns = f"{header} Functions"
- print(fns)
- print("=" * (len(fns)))
+ :param m_name: name of macro, e.g., ``FE_ALL_EXCEPT``
+ """
+ for f in self.__get_macro_files():
+ if f"#define {m_name}" in f.read_text():
+ return True
+
+ return False
+
+ def __get_macro_files(self) -> Generator[Path, None, None]:
+ return self.macros_dir.glob(f"**/{self.stem}-macros.h")
----------------
nickdesaulniers wrote:
Please add a comment that this uses `glob` with `**` because we might have something like:
- libc/include/llvm-libc-macros/fcntl-macros.h
- libc/include/llvm-libc-macros/linux/fcntl-macros.h
https://github.com/llvm/llvm-project/pull/89421
More information about the libc-commits
mailing list