[libc-commits] [libc] [libc] newheadergen: script adjusted for cmake (PR #98825)

via libc-commits libc-commits at lists.llvm.org
Sun Jul 14 10:44:32 PDT 2024


https://github.com/aaryanshukla created https://github.com/llvm/llvm-project/pull/98825

- added entrypoints and headerfile parameters depending on target
- fixed nits in yaml files causing errors
- tested with new cmake config
- cmake patch will be seperate


>From 93a1cc9fc7359e1dcdef70b494ca9bd8f96dbe95 Mon Sep 17 00:00:00 2001
From: Aaryan Shukla <aaryanshukla at google.com>
Date: Sun, 14 Jul 2024 17:38:59 +0000
Subject: [PATCH] [libc] newheadergen: script adjusted for cmake

- added entrypoints and headerfile parameters depending on target
- fixed nits in yaml files causing errors
- tested with new cmake config
- cmake patch will be seperate
---
 libc/newhdrgen/header2.py           | 96 +++++++++++++++++++++++++++++
 libc/newhdrgen/yaml/features.yaml   |  8 +++
 libc/newhdrgen/yaml/pthread.yaml    | 31 +---------
 libc/newhdrgen/yaml/sys_random.yaml |  2 +-
 libc/newhdrgen/yaml/time.yaml       |  2 +-
 libc/newhdrgen/yaml_to_classes.py   | 91 +++++++++++++++++++--------
 6 files changed, 173 insertions(+), 57 deletions(-)
 create mode 100644 libc/newhdrgen/header2.py
 create mode 100644 libc/newhdrgen/yaml/features.yaml

diff --git a/libc/newhdrgen/header2.py b/libc/newhdrgen/header2.py
new file mode 100644
index 0000000000000..e115a7e8ef358
--- /dev/null
+++ b/libc/newhdrgen/header2.py
@@ -0,0 +1,96 @@
+#!/usr/bin/env python
+#
+# ===- HeaderFile 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
+#
+# ==-------------------------------------------------------------------------==#
+
+
+class HeaderFile:
+    def __init__(self, name):
+        self.name = name
+        self.macros = []
+        self.types = []
+        self.enumerations = []
+        self.objects = []
+        self.functions = []
+        self.includes = []
+
+    def add_macro(self, macro):
+        self.macros.append(macro)
+
+    def add_type(self, type_):
+        self.types.append(type_)
+
+    def add_enumeration(self, enumeration):
+        self.enumerations.append(enumeration)
+
+    def add_object(self, object):
+        self.objects.append(object)
+
+    def add_function(self, function):
+        self.functions.append(function)
+
+    def add_include(self, include):
+        self.includes.append(include)
+
+    def __str__(self):
+        content = []
+
+        content.append(
+            f"//===-- C standard declarations for {self.name} ------------------------------===//"
+        )
+        content.append("//")
+        content.append(
+            "// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions."
+        )
+        content.append("// See https://llvm.org/LICENSE.txt for license information.")
+        content.append("// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception")
+        content.append("//")
+        content.append(
+            "//===----------------------------------------------------------------------===//\n"
+        )
+
+        header_guard = f"__LLVM_LIBC_DECLARATIONS_{self.name.upper()[:-2]}_H"
+        content.append(f"#ifndef {header_guard}")
+        content.append(f"#define {header_guard}\n")
+
+        content.append("#ifndef __LIBC_ATTRS")
+        content.append("#define __LIBC_ATTRS")
+        content.append("#endif\n")
+
+        content.append("#ifdef __cplusplus")
+        content.append('extern "C" {')
+        content.append("#endif\n")
+
+        for include in self.includes:
+            content.append(str(include))
+
+        for macro in self.macros:
+            content.append(f"{macro}\n")
+
+        for type_ in self.types:
+            content.append(f"{type_}")
+
+        if self.enumerations:
+            combined_enum_content = ",\n  ".join(
+                str(enum) for enum in self.enumerations
+            )
+            content.append(f"\nenum {{\n  {combined_enum_content},\n}};")
+
+        for function in self.functions:
+            content.append(f"{function} __LIBC_ATTRS;\n")
+
+        for object in self.objects:
+            content.append(f"{object} __LIBC_ATTRS;\n")
+
+        content.append("#ifdef __cplusplus")
+        content.append("}")
+        content.append("#endif\n")
+
+        content.append(f"#endif")
+
+        return "\n".join(content)
diff --git a/libc/newhdrgen/yaml/features.yaml b/libc/newhdrgen/yaml/features.yaml
new file mode 100644
index 0000000000000..86bc0acfe89ed
--- /dev/null
+++ b/libc/newhdrgen/yaml/features.yaml
@@ -0,0 +1,8 @@
+header: features.h
+standards: 
+  - stdc
+macros: []
+types: []
+enums: []
+objects: []
+functions: []
diff --git a/libc/newhdrgen/yaml/pthread.yaml b/libc/newhdrgen/yaml/pthread.yaml
index 14a562082d5de..f22767eb1b752 100644
--- a/libc/newhdrgen/yaml/pthread.yaml
+++ b/libc/newhdrgen/yaml/pthread.yaml
@@ -13,33 +13,8 @@ types:
   - type_name: __pthread_start_t
   - type_name: __pthread_once_func_t
   - type_name: __atfork_callback_t
-enums:
-  - name: PTHREAD_CREATE_JOINABLE
-    value: 0x0
-  - name: PTHREAD_CREATE_DETACHED
-    value: 0x1
-  - name: PTHREAD_MUTEX_NORMAL
-    value: 0x0
-  - name: PTHREAD_MUTEX_ERRORCHECK
-    value: 0x1
-  - name: PTHREAD_MUTEX_RECURSIVE
-    value: 0x2
-  - name: PTHREAD_MUTEX_DEFAULT
-    value: 0x0
-  - name: PTHREAD_PROCESS_PRIVATE
-    value: 0x0
-  - name: PTHREAD_PROCESS_SHARED
-    value: 0x1
-  - name: PTHREAD_MUTEX_STALLED
-    value: 0x0
-  - name: PTHREAD_MUTEX_ROBUST
-    value: 0x1
-  - name: PTHREAD_RWLOCK_PREFER_READER_NP
-    value: 0
-  - name: PTHREAD_RWLOCK_PREFER_WRITER_NP
-    value: 1
-  - name: PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP
-    value: 2
+  - type_name: pthread_rwlock_t
+enums: []
 functions:
   - name: pthread_atfork
     standards: 
@@ -184,7 +159,7 @@ functions:
   - name: pthread_exit
     standards: 
       - POSIX
-    return_type: __Noreturn void
+    return_type: _Noreturn void
     arguments:
       - type: void *
   - name: pthread_getname_np
diff --git a/libc/newhdrgen/yaml/sys_random.yaml b/libc/newhdrgen/yaml/sys_random.yaml
index 233fb2c7988cb..6d84056d7dd71 100644
--- a/libc/newhdrgen/yaml/sys_random.yaml
+++ b/libc/newhdrgen/yaml/sys_random.yaml
@@ -4,7 +4,7 @@ types:
   - type_name: ssize_t
   - type_name: size_t
 enums: []
-objects:
+objects: []
 functions:
   - name: getrandom
     standards: 
diff --git a/libc/newhdrgen/yaml/time.yaml b/libc/newhdrgen/yaml/time.yaml
index e7f8de65eeb75..220d4328dbbdb 100644
--- a/libc/newhdrgen/yaml/time.yaml
+++ b/libc/newhdrgen/yaml/time.yaml
@@ -15,7 +15,7 @@ functions:
       - stdc
     return_type: char *
     arguments:
-      - type: struct tm *
+      - type: const struct tm *
   - name: asctime_r
     standard: 
       - stdc
diff --git a/libc/newhdrgen/yaml_to_classes.py b/libc/newhdrgen/yaml_to_classes.py
index 6bccda8e03640..d88ba95ee3d6b 100644
--- a/libc/newhdrgen/yaml_to_classes.py
+++ b/libc/newhdrgen/yaml_to_classes.py
@@ -8,12 +8,11 @@
 #
 # ==-------------------------------------------------------------------------==#
 
-
 import yaml
 import argparse
-
 from pathlib import Path
 from header import HeaderFile
+from header2 import HeaderFile as HeaderFile2
 from class_implementation.classes.macro import Macro
 from class_implementation.classes.type import Type
 from class_implementation.classes.function import Function
@@ -22,18 +21,20 @@
 from class_implementation.classes.object import Object
 
 
-def yaml_to_classes(yaml_data):
+def yaml_to_classes(yaml_data, header_class, entry_points=None):
     """
     Convert YAML data to header classes.
 
     Args:
         yaml_data: The YAML data containing header specifications.
+        header_class: The class to use for creating the header (HeaderFile or HeaderFile2).
+        entry_points: A list of specific function names to include in the header.
 
     Returns:
         HeaderFile: An instance of HeaderFile populated with the data.
     """
     header_name = yaml_data.get("header")
-    header = HeaderFile(header_name)
+    header = header_class(header_name)
 
     for macro_data in yaml_data.get("macros", []):
         header.add_macro(Macro(macro_data["macro_name"], macro_data["macro_value"]))
@@ -49,12 +50,15 @@ def yaml_to_classes(yaml_data):
         )
 
     functions = yaml_data.get("functions", [])
+    if entry_points:
+        entry_points_set = set(entry_points)
+        functions = [f for f in functions if f["name"] in entry_points_set]
     sorted_functions = sorted(functions, key=lambda x: x["name"])
     guards = []
     guarded_function_dict = {}
     for function_data in sorted_functions:
         guard = function_data.get("guard", None)
-        if guard == None:
+        if guard is None:
             arguments = [arg["type"] for arg in function_data["arguments"]]
             attributes = function_data.get("attributes", None)
             standards = function_data.get("standards", None)
@@ -105,19 +109,21 @@ def yaml_to_classes(yaml_data):
     return header
 
 
-def load_yaml_file(yaml_file):
+def load_yaml_file(yaml_file, header_class, entry_points):
     """
     Load YAML file and convert it to header classes.
 
     Args:
-        yaml_file: The path to the YAML file.
+        yaml_file: Path to the YAML file.
+        header_class: The class to use for creating the header (HeaderFile or HeaderFile2).
+        entry_points: A list of specific function names to include in the header.
 
     Returns:
-        HeaderFile: An instance of HeaderFile populated with the data from the YAML file.
+        HeaderFile: An instance of HeaderFile populated with the data.
     """
     with open(yaml_file, "r") as f:
         yaml_data = yaml.safe_load(f)
-    return yaml_to_classes(yaml_data)
+    return yaml_to_classes(yaml_data, header_class, entry_points)
 
 
 def fill_public_api(header_str, h_def_content):
@@ -207,7 +213,14 @@ def increase_indent(self, flow=False, indentless=False):
     print(f"Added function {new_function.name} to {yaml_file}")
 
 
-def main(yaml_file, h_def_file, output_dir, add_function=None):
+def main(
+    yaml_file,
+    output_dir=None,
+    h_def_file=None,
+    add_function=None,
+    entry_points=None,
+    export_decls=False,
+):
     """
     Main function to generate header files from YAML and .h.def templates.
 
@@ -216,41 +229,50 @@ def main(yaml_file, h_def_file, output_dir, add_function=None):
         h_def_file: Path to the .h.def template file.
         output_dir: Directory to output the generated header file.
         add_function: Details of the function to be added to the YAML file (if any).
+        entry_points: A list of specific function names to include in the header.
+        export_decls: Flag to use HeaderFile2 for exporting declarations.
     """
-
     if add_function:
         add_function_to_yaml(yaml_file, add_function)
 
-    header = load_yaml_file(yaml_file)
-
-    with open(h_def_file, "r") as f:
-        h_def_content = f.read()
+    header_class = HeaderFile2 if export_decls else HeaderFile
+    header = load_yaml_file(yaml_file, header_class, entry_points)
 
     header_str = str(header)
-    final_header_content = fill_public_api(header_str, h_def_content)
 
-    output_file_name = Path(h_def_file).stem
-    output_file_path = Path(output_dir) / output_file_name
-
-    with open(output_file_path, "w") as f:
-        f.write(final_header_content)
+    if output_dir:
+        output_file_path = Path(output_dir)
+        if output_file_path.is_dir():
+            output_file_path /= f"{Path(yaml_file).stem}.h"
+    else:
+        output_file_path = Path(f"{Path(yaml_file).stem}.h")
+
+    if not export_decls and h_def_file:
+        with open(h_def_file, "r") as f:
+            h_def_content = f.read()
+        final_header_content = fill_public_api(header_str, h_def_content)
+        with open(output_file_path, "w") as f:
+            f.write(final_header_content)
+    else:
+        with open(output_file_path, "w") as f:
+            f.write(header_str)
 
     print(f"Generated header file: {output_file_path}")
 
 
 if __name__ == "__main__":
-    parser = argparse.ArgumentParser(
-        description="Generate header files from YAML and .h.def templates"
-    )
+    parser = argparse.ArgumentParser(description="Generate header files from YAML")
     parser.add_argument(
         "yaml_file", help="Path to the YAML file containing header specification"
     )
-    parser.add_argument("h_def_file", help="Path to the .h.def template file")
     parser.add_argument(
         "--output_dir",
-        default=".",
         help="Directory to output the generated header file",
     )
+    parser.add_argument(
+        "--h_def_file",
+        help="Path to the .h.def template file (required if not using --export_decls)",
+    )
     parser.add_argument(
         "--add_function",
         nargs=6,
@@ -264,6 +286,21 @@ def main(yaml_file, h_def_file, output_dir, add_function=None):
         ),
         help="Add a function to the YAML file",
     )
+    parser.add_argument(
+        "--e", action="append", help="Entry point to include", dest="entry_points"
+    )
+    parser.add_argument(
+        "--export-decls",
+        action="store_true",
+        help="Flag to use HeaderFile2 for exporting declarations",
+    )
     args = parser.parse_args()
 
-    main(args.yaml_file, args.h_def_file, args.output_dir, args.add_function)
+    main(
+        args.yaml_file,
+        args.output_dir,
+        args.h_def_file,
+        args.add_function,
+        args.entry_points,
+        args.export_decls,
+    )



More information about the libc-commits mailing list