3 # ===- Generate headers for libc functions -------------------*- python -*--==#
5 # Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
6 # See https://llvm.org/LICENSE.txt for license information.
7 # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
9 # ==-------------------------------------------------------------------------==#
13 from pathlib
import Path
14 from header
import HeaderFile
15 from gpu_headers
import GpuHeaderFile
as GpuHeader
16 from class_implementation
.classes
.macro
import Macro
17 from class_implementation
.classes
.type import Type
18 from class_implementation
.classes
.function
import Function
19 from class_implementation
.classes
.enumeration
import Enumeration
20 from class_implementation
.classes
.object import Object
23 def yaml_to_classes(yaml_data
, header_class
, entry_points
=None):
25 Convert YAML data to header classes.
28 yaml_data: The YAML data containing header specifications.
29 header_class: The class to use for creating the header.
30 entry_points: A list of specific function names to include in the header.
33 HeaderFile: An instance of HeaderFile populated with the data.
35 header_name
= yaml_data
.get("header")
36 header
= header_class(header_name
)
38 for macro_data
in yaml_data
.get("macros", []):
39 header
.add_macro(Macro(macro_data
["macro_name"], macro_data
["macro_value"]))
41 types
= yaml_data
.get("types", [])
42 sorted_types
= sorted(types
, key
=lambda x
: x
["type_name"])
43 for type_data
in sorted_types
:
44 header
.add_type(Type(type_data
["type_name"]))
46 for enum_data
in yaml_data
.get("enums", []):
47 header
.add_enumeration(
48 Enumeration(enum_data
["name"], enum_data
.get("value", None))
51 functions
= yaml_data
.get("functions", [])
53 entry_points_set
= set(entry_points
)
54 functions
= [f
for f
in functions
if f
["name"] in entry_points_set
]
55 sorted_functions
= sorted(functions
, key
=lambda x
: x
["name"])
57 guarded_function_dict
= {}
58 for function_data
in sorted_functions
:
59 guard
= function_data
.get("guard", None)
61 arguments
= [arg
["type"] for arg
in function_data
["arguments"]]
62 attributes
= function_data
.get("attributes", None)
63 standards
= function_data
.get("standards", None)
66 function_data
["return_type"],
67 function_data
["name"],
75 if guard
not in guards
:
77 guarded_function_dict
[guard
] = []
78 guarded_function_dict
[guard
].append(function_data
)
80 guarded_function_dict
[guard
].append(function_data
)
81 sorted_guards
= sorted(guards
)
82 for guard
in sorted_guards
:
83 for function_data
in guarded_function_dict
[guard
]:
84 arguments
= [arg
["type"] for arg
in function_data
["arguments"]]
85 attributes
= function_data
.get("attributes", None)
86 standards
= function_data
.get("standards", None)
89 function_data
["return_type"],
90 function_data
["name"],
98 objects
= yaml_data
.get("objects", [])
99 sorted_objects
= sorted(objects
, key
=lambda x
: x
["object_name"])
100 for object_data
in sorted_objects
:
102 Object(object_data
["object_name"], object_data
["object_type"])
108 def load_yaml_file(yaml_file
, header_class
, entry_points
):
110 Load YAML file and convert it to header classes.
113 yaml_file: Path to the YAML file.
114 header_class: The class to use for creating the header (HeaderFile or GpuHeader).
115 entry_points: A list of specific function names to include in the header.
118 HeaderFile: An instance of HeaderFile populated with the data.
120 with
open(yaml_file
, "r") as f
:
121 yaml_data
= yaml
.safe_load(f
)
122 return yaml_to_classes(yaml_data
, header_class
, entry_points
)
125 def fill_public_api(header_str
, h_def_content
):
127 Replace the %%public_api() placeholder in the .h.def content with the generated header content.
130 header_str: The generated header string.
131 h_def_content: The content of the .h.def file.
134 The final header content with the public API filled in.
136 header_str
= header_str
.strip()
137 return h_def_content
.replace("%%public_api()", header_str
, 1)
140 def parse_function_details(details
):
142 Parse function details from a list of strings and return a Function object.
145 details: A list containing function details
148 Function: An instance of Function initialized with the details.
150 return_type
, name
, arguments
, standards
, guard
, attributes
= details
151 standards
= standards
.split(",") if standards
!= "null" else []
152 arguments
= [arg
.strip() for arg
in arguments
.split(",")]
153 attributes
= attributes
.split(",") if attributes
!= "null" else []
156 return_type
=return_type
,
160 guard
=guard
if guard
!= "null" else None,
161 attributes
=attributes
if attributes
else [],
165 def add_function_to_yaml(yaml_file
, function_details
):
167 Add a function to the YAML file.
170 yaml_file: The path to the YAML file.
171 function_details: A list containing function details (return_type, name, arguments, standards, guard, attributes).
173 new_function
= parse_function_details(function_details
)
175 with
open(yaml_file
, "r") as f
:
176 yaml_data
= yaml
.safe_load(f
)
177 if "functions" not in yaml_data
:
178 yaml_data
["functions"] = []
181 "name": new_function
.name
,
182 "standards": new_function
.standards
,
183 "return_type": new_function
.return_type
,
184 "arguments": [{"type": arg
} for arg
in new_function
.arguments
],
187 if new_function
.guard
:
188 function_dict
["guard"] = new_function
.guard
190 if new_function
.attributes
:
191 function_dict
["attributes"] = new_function
.attributes
194 for i
, func
in enumerate(yaml_data
["functions"]):
195 if func
["name"] > new_function
.name
:
199 insert_index
= len(yaml_data
["functions"])
201 yaml_data
["functions"].insert(insert_index
, function_dict
)
203 class IndentYamlListDumper(yaml
.Dumper
):
204 def increase_indent(self
, flow
=False, indentless
=False):
205 return super(IndentYamlListDumper
, self
).increase_indent(flow
, False)
207 with
open(yaml_file
, "w") as f
:
211 Dumper
=IndentYamlListDumper
,
212 default_flow_style
=False,
216 print(f
"Added function {new_function.name} to {yaml_file}")
220 parser
= argparse
.ArgumentParser(description
="Generate header files from YAML")
222 "yaml_file", help="Path to the YAML file containing header specification"
226 help="Directory to output the generated header file",
230 help="Path to the .h.def template file (required if not using --export_decls)",
243 help="Add a function to the YAML file",
246 "--e", action
="append", help="Entry point to include", dest
="entry_points"
251 help="Flag to use GpuHeader for exporting declarations",
253 args
= parser
.parse_args()
255 if args
.add_function
:
256 add_function_to_yaml(args
.yaml_file
, args
.add_function
)
258 header_class
= GpuHeader
if args
.export_decls
else HeaderFile
259 header
= load_yaml_file(args
.yaml_file
, header_class
, args
.entry_points
)
261 header_str
= str(header
)
264 output_file_path
= Path(args
.output_dir
)
265 if output_file_path
.is_dir():
266 output_file_path
/= f
"{Path(args.yaml_file).stem}.h"
268 output_file_path
= Path(f
"{Path(args.yaml_file).stem}.h")
270 if not args
.export_decls
and args
.h_def_file
:
271 with
open(args
.h_def_file
, "r") as f
:
272 h_def_content
= f
.read()
273 final_header_content
= fill_public_api(header_str
, h_def_content
)
274 with
open(output_file_path
, "w") as f
:
275 f
.write(final_header_content
)
277 with
open(output_file_path
, "w") as f
:
281 if __name__
== "__main__":