diff --git a/libc/include/ctype.h.def b/libc/include/ctype.h.def deleted file mode 100644 index a9bb786931ea..000000000000 --- a/libc/include/ctype.h.def +++ /dev/null @@ -1,16 +0,0 @@ -//===-- C standard library header ctype.h --------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_LIBC_CTYPE_H -#define LLVM_LIBC_CTYPE_H - -#include "__llvm-libc-common.h" - -%%public_api() - -#endif // LLVM_LIBC_CTYPE_H diff --git a/libc/include/ctype.yaml b/libc/include/ctype.yaml index 6238f1b88998..278d08b5fafa 100644 --- a/libc/include/ctype.yaml +++ b/libc/include/ctype.yaml @@ -1,8 +1,6 @@ header: ctype.h -header_template: ctype.h.def -macros: [] -types: - - type_name: locale_t +standards: + - stdc enums: [] objects: [] functions: @@ -104,98 +102,98 @@ functions: - type: int - name: isalnum_l standards: - - stdc + - posix return_type: int arguments: - type: int - type: locale_t - name: isalpha_l standards: - - stdc + - posix return_type: int arguments: - type: int - type: locale_t - name: isblank_l standards: - - stdc + - posix return_type: int arguments: - type: int - type: locale_t - name: iscntrl_l standards: - - stdc + - posix return_type: int arguments: - type: int - type: locale_t - name: isdigit_l standards: - - stdc + - posix return_type: int arguments: - type: int - type: locale_t - name: isgraph_l standards: - - stdc + - posix return_type: int arguments: - type: int - type: locale_t - name: islower_l standards: - - stdc + - posix return_type: int arguments: - type: int - type: locale_t - name: isprint_l standards: - - stdc + - posix return_type: int arguments: - type: int - type: locale_t - name: ispunct_l standards: - - stdc + - posix return_type: int arguments: - type: int - type: locale_t - name: isspace_l standards: - - stdc + - posix return_type: int arguments: - type: int - type: locale_t - name: isupper_l standards: - - stdc + - posix return_type: int arguments: - type: int - type: locale_t - name: isxdigit_l standards: - - stdc + - posix return_type: int arguments: - type: int - type: locale_t - name: tolower_l standards: - - stdc + - posix return_type: int arguments: - type: int - type: locale_t - name: toupper_l standards: - - stdc + - posix return_type: int arguments: - type: int diff --git a/libc/utils/hdrgen/header.py b/libc/utils/hdrgen/header.py index b03535ce90bf..685e5730e681 100644 --- a/libc/utils/hdrgen/header.py +++ b/libc/utils/hdrgen/header.py @@ -6,6 +6,7 @@ # # ==-------------------------------------------------------------------------==# +import re from functools import reduce from pathlib import PurePosixPath @@ -30,6 +31,37 @@ COMPILER_HEADER_TYPES = { COMPILER_HEADER_TYPES.update({f"int{size}_t": "" for size in STDINT_SIZES}) COMPILER_HEADER_TYPES.update({f"uint{size}_t": "" for size in STDINT_SIZES}) +NONIDENTIFIER = re.compile("[^a-zA-Z0-9_]+") + +COMMON_HEADER = PurePosixPath("__llvm-libc-common.h") + +# All the canonical identifiers are in lowercase for easy maintenance. +# This maps them to the pretty descriptions to generate in header comments. +LIBRARY_DESCRIPTIONS = { + "stdc": "Standard C", + "posix": "POSIX", + "bsd": "BSD", + "gnu": "GNU", + "linux": "Linux", +} + +HEADER_TEMPLATE = """\ +//===-- {library} header <{header}> --===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// + +#ifndef {guard} +#define {guard} + +%%public_api() + +#endif // {guard} +""" + class HeaderFile: def __init__(self, name): @@ -40,6 +72,7 @@ class HeaderFile: self.enumerations = [] self.objects = [] self.functions = [] + self.standards = [] def add_macro(self, macro): self.macros.append(macro) @@ -63,6 +96,13 @@ class HeaderFile: set(self.types), ) + def all_standards(self): + # FIXME: Only functions have the "standard" field, but all the entity + # types should have one too. + return set(self.standards).union( + *(filter(None, (f.standards for f in self.functions))) + ) + def includes(self): return { PurePosixPath("llvm-libc-macros") / macro.header @@ -75,6 +115,45 @@ class HeaderFile: for typ in self.all_types() } + def header_guard(self): + return "LLVM_LIBC_" + "_".join( + word.upper() for word in NONIDENTIFIER.split(self.name) if word + ) + + def library_description(self): + # If the header itself is in standard C, just call it that. + if "stdc" in self.standards: + return LIBRARY_DESCRIPTIONS["stdc"] + # If the header itself is in POSIX, just call it that. + if "posix" in self.standards: + return LIBRARY_DESCRIPTIONS["posix"] + # Otherwise, consider the standards for each symbol as well. + standards = self.all_standards() + # Otherwise, it's described by all those that apply, but ignoring + # "stdc" and "posix" since this is not a "stdc" or "posix" header. + return " / ".join( + sorted( + LIBRARY_DESCRIPTIONS[standard] + for standard in standards + if standard not in {"stdc", "posix"} + ) + ) + + def template(self, dir, files_read): + if self.template_file is not None: + # There's a custom template file, so just read it in and record + # that it was read as an input file. + template_path = dir / self.template_file + files_read.add(template_path) + return template_path.read_text() + + # Generate the default template. + return HEADER_TEMPLATE.format( + library=self.library_description(), + header=self.name, + guard=self.header_guard(), + ) + def public_api(self): # Python 3.12 has .relative_to(dir, walk_up=True) for this. path_prefix = PurePosixPath("../" * (len(PurePosixPath(self.name).parents) - 1)) @@ -82,7 +161,16 @@ class HeaderFile: def relpath(file): return path_prefix / file - content = [ + content = [] + + if self.template_file is None: + # This always goes before all the other includes, which are sorted. + # It's implicitly emitted here when using the default template so + # it can get the right relative path. Custom template files should + # all have it explicitly with their right particular relative path. + content.append('#include "{file!s}"'.format(file=relpath(COMMON_HEADER))) + + content += [ f"#include {file}" for file in sorted( file if isinstance(file, str) else f'"{relpath(file)!s}"' diff --git a/libc/utils/hdrgen/main.py b/libc/utils/hdrgen/main.py index 5dd392ab6662..af57845582e5 100755 --- a/libc/utils/hdrgen/main.py +++ b/libc/utils/hdrgen/main.py @@ -65,16 +65,10 @@ def main(): header = load_yaml_file(yaml_file, HeaderFile, args.entry_point) - if not header.template_file: - print(f"{yaml_file}: Missing header_template", sys.stderr) - return 2 - # The header_template path is relative to the containing YAML file. - template_path = yaml_file.parent / header.template_file + template = header.template(yaml_file.parent, files_read) - files_read.add(template_path) - with open(template_path) as template: - contents = fill_public_api(header.public_api(), template.read()) + contents = fill_public_api(header.public_api(), template) write_depfile() diff --git a/libc/utils/hdrgen/tests/expected_output/subdir/test.h b/libc/utils/hdrgen/tests/expected_output/subdir/test.h index 53d28e843010..e968f92bf4e6 100644 --- a/libc/utils/hdrgen/tests/expected_output/subdir/test.h +++ b/libc/utils/hdrgen/tests/expected_output/subdir/test.h @@ -1,16 +1,15 @@ -//===-- C standard library header subdir/test.h --------------------------===// +//===-- BSD / GNU header --===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // -//===--------------------------------------------------------------------===// +//===---------------------------------------------------------------------===// #ifndef LLVM_LIBC_SUBDIR_TEST_H #define LLVM_LIBC_SUBDIR_TEST_H #include "../__llvm-libc-common.h" - #include "../llvm-libc-types/type_a.h" #include "../llvm-libc-types/type_b.h" @@ -18,6 +17,8 @@ __BEGIN_C_DECLS type_a func(type_b) __NOEXCEPT; +void gnufunc(type_a) __NOEXCEPT; + __END_C_DECLS #endif // LLVM_LIBC_SUBDIR_TEST_H diff --git a/libc/utils/hdrgen/tests/input/subdir/test.h.def b/libc/utils/hdrgen/tests/input/subdir/test.h.def deleted file mode 100644 index ded06082a51b..000000000000 --- a/libc/utils/hdrgen/tests/input/subdir/test.h.def +++ /dev/null @@ -1,16 +0,0 @@ -//===-- C standard library header subdir/test.h --------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===--------------------------------------------------------------------===// - -#ifndef LLVM_LIBC_SUBDIR_TEST_H -#define LLVM_LIBC_SUBDIR_TEST_H - -#include "../__llvm-libc-common.h" - -%%public_api() - -#endif // LLVM_LIBC_SUBDIR_TEST_H diff --git a/libc/utils/hdrgen/tests/input/subdir/test.yaml b/libc/utils/hdrgen/tests/input/subdir/test.yaml index e68af00849b0..f325363e09cd 100644 --- a/libc/utils/hdrgen/tests/input/subdir/test.yaml +++ b/libc/utils/hdrgen/tests/input/subdir/test.yaml @@ -1,9 +1,14 @@ header: subdir/test.h -header_template: test.h.def +standards: + - bsd functions: - name: func return_type: type_a arguments: - type: type_b + - name: gnufunc + return_type: void + arguments: + - type: type_a standards: - - stdc + - gnu diff --git a/libc/utils/hdrgen/yaml_to_classes.py b/libc/utils/hdrgen/yaml_to_classes.py index 4a3f48633dc1..d7a349648340 100644 --- a/libc/utils/hdrgen/yaml_to_classes.py +++ b/libc/utils/hdrgen/yaml_to_classes.py @@ -36,6 +36,7 @@ def yaml_to_classes(yaml_data, header_class, entry_points=None): header_name = yaml_data.get("header") header = header_class(header_name) header.template_file = yaml_data.get("header_template") + header.standards = yaml_data.get("standards", []) for macro_data in yaml_data.get("macros", []): header.add_macro(