aboutsummaryrefslogtreecommitdiff
path: root/libc/utils/hdrgen
diff options
context:
space:
mode:
Diffstat (limited to 'libc/utils/hdrgen')
-rw-r--r--libc/utils/hdrgen/hdrgen/enumeration.py16
-rw-r--r--libc/utils/hdrgen/hdrgen/function.py16
-rw-r--r--libc/utils/hdrgen/hdrgen/header.py81
-rw-r--r--libc/utils/hdrgen/hdrgen/macro.py16
-rwxr-xr-xlibc/utils/hdrgen/hdrgen/main.py1
-rw-r--r--libc/utils/hdrgen/hdrgen/object.py16
-rw-r--r--libc/utils/hdrgen/hdrgen/symbol.py41
-rw-r--r--libc/utils/hdrgen/hdrgen/type.py20
-rw-r--r--libc/utils/hdrgen/hdrgen/yaml_to_classes.py2
-rw-r--r--libc/utils/hdrgen/tests/expected_output/custom.h21
-rw-r--r--libc/utils/hdrgen/tests/expected_output/sorting.h24
-rw-r--r--libc/utils/hdrgen/tests/expected_output/test_header.h1
-rw-r--r--libc/utils/hdrgen/tests/expected_output/test_small.json1
-rw-r--r--libc/utils/hdrgen/tests/input/custom-common.yaml6
-rw-r--r--libc/utils/hdrgen/tests/input/custom.yaml13
-rw-r--r--libc/utils/hdrgen/tests/input/sorting.yaml20
-rw-r--r--libc/utils/hdrgen/tests/test_integration.py14
17 files changed, 224 insertions, 85 deletions
diff --git a/libc/utils/hdrgen/hdrgen/enumeration.py b/libc/utils/hdrgen/hdrgen/enumeration.py
index 19872082..1e0f64a 100644
--- a/libc/utils/hdrgen/hdrgen/enumeration.py
+++ b/libc/utils/hdrgen/hdrgen/enumeration.py
@@ -6,24 +6,14 @@
#
# ==-------------------------------------------------------------------------==#
-from functools import total_ordering
+from hdrgen.symbol import Symbol
-@total_ordering
-class Enumeration:
+class Enumeration(Symbol):
def __init__(self, name, value):
- self.name = name
+ super().__init__(name)
self.value = value
- def __eq__(self, other):
- return self.name == other.name
-
- def __lt__(self, other):
- return self.name < other.name
-
- def __hash__(self):
- return self.name.__hash__()
-
def __str__(self):
if self.value != None:
return f"{self.name} = {self.value}"
diff --git a/libc/utils/hdrgen/hdrgen/function.py b/libc/utils/hdrgen/hdrgen/function.py
index f039996..4de3406 100644
--- a/libc/utils/hdrgen/hdrgen/function.py
+++ b/libc/utils/hdrgen/hdrgen/function.py
@@ -7,7 +7,7 @@
# ==-------------------------------------------------------------------------==#
import re
-from functools import total_ordering
+from hdrgen.symbol import Symbol
from hdrgen.type import Type
@@ -37,14 +37,13 @@ KEYWORDS = [
NONIDENTIFIER = re.compile("[^a-zA-Z0-9_]+")
-@total_ordering
-class Function:
+class Function(Symbol):
def __init__(
self, return_type, name, arguments, standards, guard=None, attributes=[]
):
+ super().__init__(name)
assert return_type
self.return_type = return_type
- self.name = name
self.arguments = [
arg if isinstance(arg, str) else arg["type"] for arg in arguments
]
@@ -53,15 +52,6 @@ class Function:
self.guard = guard
self.attributes = attributes or []
- def __eq__(self, other):
- return self.name == other.name
-
- def __lt__(self, other):
- return self.name < other.name
-
- def __hash__(self):
- return self.name.__hash__()
-
def signature_types(self):
def collapse(type_string):
assert type_string
diff --git a/libc/utils/hdrgen/hdrgen/header.py b/libc/utils/hdrgen/hdrgen/header.py
index 715d4b7..f592327 100644
--- a/libc/utils/hdrgen/hdrgen/header.py
+++ b/libc/utils/hdrgen/hdrgen/header.py
@@ -35,6 +35,13 @@ NONIDENTIFIER = re.compile("[^a-zA-Z0-9_]+")
COMMON_HEADER = PurePosixPath("__llvm-libc-common.h")
+# These "attributes" are known macros defined in COMMON_HEADER.
+# Others are found in "llvm-libc-macros/{name}.h".
+COMMON_ATTRIBUTES = {
+ "_Noreturn",
+ "_Returns_twice",
+}
+
# All the canonical identifiers are in lowercase for easy maintenance.
# This maps them to the pretty descriptions to generate in header comments.
LIBRARY_DESCRIPTIONS = {
@@ -50,9 +57,7 @@ LIBRARY_DESCRIPTIONS = {
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
+{license_lines}
//
//===---------------------------------------------------------------------===//
@@ -64,6 +69,12 @@ HEADER_TEMPLATE = """\
#endif // {guard}
"""
+LLVM_LICENSE_TEXT = [
+ "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",
+]
+
class HeaderFile:
def __init__(self, name):
@@ -74,8 +85,10 @@ class HeaderFile:
self.enumerations = []
self.objects = []
self.functions = []
+ self.extra_standards = {}
self.standards = []
self.merge_yaml_files = []
+ self.license_text = []
def add_macro(self, macro):
self.macros.append(macro)
@@ -98,6 +111,11 @@ class HeaderFile:
self.enumerations = sorted(set(self.enumerations) | set(other.enumerations))
self.objects = sorted(set(self.objects) | set(other.objects))
self.functions = sorted(set(self.functions) | set(other.functions))
+ self.extra_standards |= other.extra_standards
+ if self.license_text:
+ assert not other.license_text, "only one `license_text` allowed"
+ else:
+ self.license_text = other.license_text
def all_types(self):
return reduce(
@@ -106,6 +124,13 @@ class HeaderFile:
set(self.types),
)
+ def all_attributes(self):
+ return reduce(
+ lambda a, b: a | b,
+ [set(f.attributes) for f in self.functions],
+ set(),
+ )
+
def all_standards(self):
# FIXME: Only functions have the "standard" field, but all the entity
# types should have one too.
@@ -114,16 +139,24 @@ class HeaderFile:
)
def includes(self):
- return {
- PurePosixPath("llvm-libc-macros") / macro.header
- for macro in self.macros
- if macro.header is not None
- } | {
- COMPILER_HEADER_TYPES.get(
- typ.type_name, PurePosixPath("llvm-libc-types") / f"{typ.type_name}.h"
- )
- for typ in self.all_types()
- }
+ return (
+ {
+ PurePosixPath("llvm-libc-macros") / macro.header
+ for macro in self.macros
+ if macro.header is not None
+ }
+ | {
+ COMPILER_HEADER_TYPES.get(
+ typ.name,
+ PurePosixPath("llvm-libc-types") / f"{typ.name}.h",
+ )
+ for typ in self.all_types()
+ }
+ | {
+ PurePosixPath("llvm-libc-macros") / f"{attr}.h"
+ for attr in self.all_attributes() - COMMON_ATTRIBUTES
+ }
+ )
def header_guard(self):
return "_LLVM_LIBC_" + "_".join(
@@ -131,24 +164,29 @@ class HeaderFile:
)
def library_description(self):
+ descriptions = LIBRARY_DESCRIPTIONS | self.extra_standards
# If the header itself is in standard C, just call it that.
if "stdc" in self.standards:
- return LIBRARY_DESCRIPTIONS["stdc"]
+ return descriptions["stdc"]
# If the header itself is in POSIX, just call it that.
if "posix" in self.standards:
- return LIBRARY_DESCRIPTIONS["posix"]
+ return 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]
+ descriptions[standard]
for standard in standards
if standard not in {"stdc", "posix"}
)
)
+ def license_lines(self):
+ lines = self.license_text or LLVM_LICENSE_TEXT
+ return "\n".join([f"// {line}" for line in lines])
+
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
@@ -162,6 +200,7 @@ class HeaderFile:
library=self.library_description(),
header=self.name,
guard=self.header_guard(),
+ license_lines=self.license_lines(),
)
def public_api(self):
@@ -188,7 +227,7 @@ class HeaderFile:
)
]
- for macro in self.macros:
+ for macro in sorted(self.macros):
# When there is nothing to define, the Macro object converts to str
# as an empty string. Don't emit a blank line for those cases.
if str(macro):
@@ -203,7 +242,12 @@ class HeaderFile:
content.append("\n__BEGIN_C_DECLS\n")
current_guard = None
- for function in self.functions:
+ last_name = None
+ for function in sorted(self.functions):
+ # If the last function's name was the same after underscores,
+ # elide the blank line between the declarations.
+ if last_name == function.name_without_underscores():
+ content.pop()
if function.guard == None and current_guard == None:
content.append(str(function) + " __NOEXCEPT;")
content.append("")
@@ -225,6 +269,7 @@ class HeaderFile:
content.append(f"#ifdef {current_guard}")
content.append(str(function) + " __NOEXCEPT;")
content.append("")
+ last_name = function.name_without_underscores()
if current_guard != None:
content.pop()
content.append(f"#endif // {current_guard}")
diff --git a/libc/utils/hdrgen/hdrgen/macro.py b/libc/utils/hdrgen/hdrgen/macro.py
index e42e828..4664d9f 100644
--- a/libc/utils/hdrgen/hdrgen/macro.py
+++ b/libc/utils/hdrgen/hdrgen/macro.py
@@ -6,25 +6,15 @@
#
# ==-------------------------------------------------------------------------==#
-from functools import total_ordering
+from hdrgen.symbol import Symbol
-@total_ordering
-class Macro:
+class Macro(Symbol):
def __init__(self, name, value=None, header=None):
- self.name = name
+ super().__init__(name)
self.value = value
self.header = header
- def __eq__(self, other):
- return self.name == other.name
-
- def __lt__(self, other):
- return self.name < other.name
-
- def __hash__(self):
- return self.name.__hash__()
-
def __str__(self):
if self.header != None:
return ""
diff --git a/libc/utils/hdrgen/hdrgen/main.py b/libc/utils/hdrgen/hdrgen/main.py
index 25df41e..c12e89e 100755
--- a/libc/utils/hdrgen/hdrgen/main.py
+++ b/libc/utils/hdrgen/hdrgen/main.py
@@ -105,6 +105,7 @@ def main():
return 2
header.merge(merge_from_header)
+ assert header.name, f"`header: name.h` line is required in {yaml_file}"
return header
if args.json:
diff --git a/libc/utils/hdrgen/hdrgen/object.py b/libc/utils/hdrgen/hdrgen/object.py
index a311c37..a2ab496b 100644
--- a/libc/utils/hdrgen/hdrgen/object.py
+++ b/libc/utils/hdrgen/hdrgen/object.py
@@ -6,23 +6,13 @@
#
# ==-------------------------------------------------------------------------==#
-from functools import total_ordering
+from hdrgen.symbol import Symbol
-@total_ordering
-class Object:
+class Object(Symbol):
def __init__(self, name, type):
- self.name = name
+ super().__init__(name)
self.type = type
- def __eq__(self, other):
- return self.name == other.name
-
- def __lt__(self, other):
- return self.name < other.name
-
- def __hash__(self):
- return self.name.__hash__()
-
def __str__(self):
return f"extern {self.type} {self.name};"
diff --git a/libc/utils/hdrgen/hdrgen/symbol.py b/libc/utils/hdrgen/hdrgen/symbol.py
new file mode 100644
index 0000000..28e9def
--- /dev/null
+++ b/libc/utils/hdrgen/hdrgen/symbol.py
@@ -0,0 +1,41 @@
+# ====-- Symbol class for libc function headers----------------*- python -*--==#
+#
+# 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
+#
+# ==-------------------------------------------------------------------------==#
+
+from functools import total_ordering
+
+
+@total_ordering
+class Symbol:
+ """
+ Symbol is the common superclass for each kind of entity named by an
+ identifier. It provides the name field, and defines sort ordering,
+ hashing, and equality based only on the name. The sorting is pretty
+ presentation order for identifiers, which is to say it first sorts
+ lexically but ignores leading underscores and secondarily sorts with the
+ fewest underscores first.
+ """
+
+ def __init__(self, name):
+ assert name
+ self.name = name
+
+ def __eq__(self, other):
+ return self.name == other.name
+
+ def __hash__(self):
+ return self.name.__hash__()
+
+ def name_without_underscores(self):
+ return self.name.lstrip("_")
+
+ def name_sort_key(self):
+ ident = self.name_without_underscores()
+ return ident, len(self.name) - len(ident)
+
+ def __lt__(self, other):
+ return self.name_sort_key() < other.name_sort_key()
diff --git a/libc/utils/hdrgen/hdrgen/type.py b/libc/utils/hdrgen/hdrgen/type.py
index 0c0af85..20c1881 100644
--- a/libc/utils/hdrgen/hdrgen/type.py
+++ b/libc/utils/hdrgen/hdrgen/type.py
@@ -6,20 +6,10 @@
#
# ==-------------------------------------------------------------------------==#
-from functools import total_ordering
+from hdrgen.symbol import Symbol
-@total_ordering
-class Type:
- def __init__(self, type_name):
- assert type_name
- self.type_name = type_name
-
- def __eq__(self, other):
- return self.type_name == other.type_name
-
- def __lt__(self, other):
- return self.type_name < other.type_name
-
- def __hash__(self):
- return self.type_name.__hash__()
+class Type(Symbol):
+ # A type so far carries no specific information beyond its name.
+ def __init__(self, name):
+ super().__init__(name)
diff --git a/libc/utils/hdrgen/hdrgen/yaml_to_classes.py b/libc/utils/hdrgen/hdrgen/yaml_to_classes.py
index ebe7781d..9eddbe6 100644
--- a/libc/utils/hdrgen/hdrgen/yaml_to_classes.py
+++ b/libc/utils/hdrgen/hdrgen/yaml_to_classes.py
@@ -37,6 +37,8 @@ def yaml_to_classes(yaml_data, header_class, entry_points=None):
header = header_class(header_name)
header.template_file = yaml_data.get("header_template")
header.standards = yaml_data.get("standards", [])
+ header.extra_standards = yaml_data.get("extra_standards", {})
+ header.license_text = yaml_data.get("license_text", [])
header.merge_yaml_files = yaml_data.get("merge_yaml_files", [])
for macro_data in yaml_data.get("macros", []):
diff --git a/libc/utils/hdrgen/tests/expected_output/custom.h b/libc/utils/hdrgen/tests/expected_output/custom.h
new file mode 100644
index 0000000..5f9ed23
--- /dev/null
+++ b/libc/utils/hdrgen/tests/expected_output/custom.h
@@ -0,0 +1,21 @@
+//===-- Wile E. Coyote header <custom.h> --===//
+//
+// Caveat emptor.
+// I never studied law.
+//
+//===---------------------------------------------------------------------===//
+
+#ifndef _LLVM_LIBC_CUSTOM_H
+#define _LLVM_LIBC_CUSTOM_H
+
+#include "__llvm-libc-common.h"
+#include "llvm-libc-types/meep.h"
+#include "llvm-libc-types/road.h"
+
+__BEGIN_C_DECLS
+
+road runner(meep, meep) __NOEXCEPT;
+
+__END_C_DECLS
+
+#endif // _LLVM_LIBC_CUSTOM_H
diff --git a/libc/utils/hdrgen/tests/expected_output/sorting.h b/libc/utils/hdrgen/tests/expected_output/sorting.h
new file mode 100644
index 0000000..a091a42
--- /dev/null
+++ b/libc/utils/hdrgen/tests/expected_output/sorting.h
@@ -0,0 +1,24 @@
+//===-- Standard C header <sorting.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_SORTING_H
+#define _LLVM_LIBC_SORTING_H
+
+#include "__llvm-libc-common.h"
+
+__BEGIN_C_DECLS
+
+void func_with_aliases(int) __NOEXCEPT;
+void _func_with_aliases(int) __NOEXCEPT;
+void __func_with_aliases(int) __NOEXCEPT;
+
+void gunk(const char *) __NOEXCEPT;
+
+__END_C_DECLS
+
+#endif // _LLVM_LIBC_SORTING_H
diff --git a/libc/utils/hdrgen/tests/expected_output/test_header.h b/libc/utils/hdrgen/tests/expected_output/test_header.h
index 748c098..49112a3 100644
--- a/libc/utils/hdrgen/tests/expected_output/test_header.h
+++ b/libc/utils/hdrgen/tests/expected_output/test_header.h
@@ -12,6 +12,7 @@
#include "__llvm-libc-common.h"
#include "llvm-libc-macros/float16-macros.h"
+#include "llvm-libc-macros/CONST_FUNC_A.h"
#include "llvm-libc-macros/test_more-macros.h"
#include "llvm-libc-macros/test_small-macros.h"
#include "llvm-libc-types/float128.h"
diff --git a/libc/utils/hdrgen/tests/expected_output/test_small.json b/libc/utils/hdrgen/tests/expected_output/test_small.json
index 9cc73d0..8502df2 100644
--- a/libc/utils/hdrgen/tests/expected_output/test_small.json
+++ b/libc/utils/hdrgen/tests/expected_output/test_small.json
@@ -4,6 +4,7 @@
"standards": [],
"includes": [
"__llvm-libc-common.h",
+ "llvm-libc-macros/CONST_FUNC_A.h",
"llvm-libc-macros/test_more-macros.h",
"llvm-libc-macros/test_small-macros.h",
"llvm-libc-types/float128.h",
diff --git a/libc/utils/hdrgen/tests/input/custom-common.yaml b/libc/utils/hdrgen/tests/input/custom-common.yaml
new file mode 100644
index 0000000..909a3ba
--- /dev/null
+++ b/libc/utils/hdrgen/tests/input/custom-common.yaml
@@ -0,0 +1,6 @@
+license_text:
+ - Caveat emptor.
+ - I never studied law.
+
+extra_standards:
+ acme: Wile E. Coyote
diff --git a/libc/utils/hdrgen/tests/input/custom.yaml b/libc/utils/hdrgen/tests/input/custom.yaml
new file mode 100644
index 0000000..7d3ff8e
--- /dev/null
+++ b/libc/utils/hdrgen/tests/input/custom.yaml
@@ -0,0 +1,13 @@
+merge_yaml_files:
+ - custom-common.yaml
+
+header: custom.h
+standards:
+ - acme
+
+functions:
+ - name: runner
+ return_type: road
+ arguments:
+ - type: meep
+ - type: meep
diff --git a/libc/utils/hdrgen/tests/input/sorting.yaml b/libc/utils/hdrgen/tests/input/sorting.yaml
new file mode 100644
index 0000000..3c26cde
--- /dev/null
+++ b/libc/utils/hdrgen/tests/input/sorting.yaml
@@ -0,0 +1,20 @@
+header: sorting.h
+standards:
+ - stdc
+functions:
+ - name: gunk
+ return_type: void
+ arguments:
+ - type: const char *
+ - name: _func_with_aliases
+ return_type: void
+ arguments:
+ - type: int
+ - name: func_with_aliases
+ return_type: void
+ arguments:
+ - type: int
+ - name: __func_with_aliases
+ return_type: void
+ arguments:
+ - type: int
diff --git a/libc/utils/hdrgen/tests/test_integration.py b/libc/utils/hdrgen/tests/test_integration.py
index bf393d2..b975d8f 100644
--- a/libc/utils/hdrgen/tests/test_integration.py
+++ b/libc/utils/hdrgen/tests/test_integration.py
@@ -59,6 +59,13 @@ class TestHeaderGenIntegration(unittest.TestCase):
self.run_script(yaml_file, output_file)
self.compare_files(output_file, expected_output_file)
+ def test_custom_license_and_standards(self):
+ yaml_file = self.source_dir / "input" / "custom.yaml"
+ expected_output_file = self.source_dir / "expected_output" / "custom.h"
+ output_file = self.output_dir / "custom.h"
+ self.run_script(yaml_file, output_file)
+ self.compare_files(output_file, expected_output_file)
+
def test_generate_json(self):
yaml_file = self.source_dir / "input/test_small.yaml"
expected_output_file = self.source_dir / "expected_output/test_small.json"
@@ -68,6 +75,13 @@ class TestHeaderGenIntegration(unittest.TestCase):
self.compare_files(output_file, expected_output_file)
+ def test_sorting(self):
+ yaml_file = self.source_dir / "input" / "sorting.yaml"
+ expected_output_file = self.source_dir / "expected_output" / "sorting.h"
+ output_file = self.output_dir / "sorting.h"
+ self.run_script(yaml_file, output_file)
+ self.compare_files(output_file, expected_output_file)
+
def main():
parser = argparse.ArgumentParser(description="TestHeaderGenIntegration arguments")