1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301
|
#!/usr/bin/env python
#
# ===- Generate headers for libc functions -------------------*- 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
#
# ==-------------------------------------------------------------------------==#
import yaml
import argparse
from pathlib import Path
from header import HeaderFile
from gpu_headers import GpuHeaderFile as GpuHeader
from class_implementation.classes.macro import Macro
from class_implementation.classes.type import Type
from class_implementation.classes.function import Function
from class_implementation.classes.enumeration import Enumeration
from class_implementation.classes.object import Object
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.
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 = header_class(header_name)
for macro_data in yaml_data.get("macros", []):
header.add_macro(Macro(macro_data["macro_name"], macro_data["macro_value"]))
types = yaml_data.get("types", [])
sorted_types = sorted(types, key=lambda x: x["type_name"])
for type_data in sorted_types:
header.add_type(Type(type_data["type_name"]))
for enum_data in yaml_data.get("enums", []):
header.add_enumeration(
Enumeration(enum_data["name"], enum_data.get("value", None))
)
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 is None:
arguments = [arg["type"] for arg in function_data["arguments"]]
attributes = function_data.get("attributes", None)
standards = function_data.get("standards", None)
header.add_function(
Function(
function_data["return_type"],
function_data["name"],
arguments,
standards,
guard,
attributes,
)
)
else:
if guard not in guards:
guards.append(guard)
guarded_function_dict[guard] = []
guarded_function_dict[guard].append(function_data)
else:
guarded_function_dict[guard].append(function_data)
sorted_guards = sorted(guards)
for guard in sorted_guards:
for function_data in guarded_function_dict[guard]:
arguments = [arg["type"] for arg in function_data["arguments"]]
attributes = function_data.get("attributes", None)
standards = function_data.get("standards", None)
header.add_function(
Function(
function_data["return_type"],
function_data["name"],
arguments,
standards,
guard,
attributes,
)
)
objects = yaml_data.get("objects", [])
sorted_objects = sorted(objects, key=lambda x: x["object_name"])
for object_data in sorted_objects:
header.add_object(
Object(object_data["object_name"], object_data["object_type"])
)
return header
def load_yaml_file(yaml_file, header_class, entry_points):
"""
Load YAML file and convert it to header classes.
Args:
yaml_file: Path to the YAML file.
header_class: The class to use for creating the header (HeaderFile or GpuHeader).
entry_points: A list of specific function names to include in the header.
Returns:
HeaderFile: An instance of HeaderFile populated with the data.
"""
with open(yaml_file, "r") as f:
yaml_data = yaml.load(f, Loader=yaml.FullLoader)
return yaml_to_classes(yaml_data, header_class, entry_points)
def fill_public_api(header_str, h_def_content):
"""
Replace the %%public_api() placeholder in the .h.def content with the generated header content.
Args:
header_str: The generated header string.
h_def_content: The content of the .h.def file.
Returns:
The final header content with the public API filled in.
"""
header_str = header_str.strip()
return h_def_content.replace("%%public_api()", header_str, 1)
def parse_function_details(details):
"""
Parse function details from a list of strings and return a Function object.
Args:
details: A list containing function details
Returns:
Function: An instance of Function initialized with the details.
"""
return_type, name, arguments, standards, guard, attributes = details
standards = standards.split(",") if standards != "null" else []
arguments = [arg.strip() for arg in arguments.split(",")]
attributes = attributes.split(",") if attributes != "null" else []
return Function(
return_type=return_type,
name=name,
arguments=arguments,
standards=standards,
guard=guard if guard != "null" else None,
attributes=attributes if attributes else [],
)
def add_function_to_yaml(yaml_file, function_details):
"""
Add a function to the YAML file.
Args:
yaml_file: The path to the YAML file.
function_details: A list containing function details (return_type, name, arguments, standards, guard, attributes).
"""
new_function = parse_function_details(function_details)
with open(yaml_file, "r") as f:
yaml_data = yaml.load(f, Loader=yaml.FullLoader)
if "functions" not in yaml_data:
yaml_data["functions"] = []
function_dict = {
"name": new_function.name,
"standards": new_function.standards,
"return_type": new_function.return_type,
"arguments": [{"type": arg} for arg in new_function.arguments],
}
if new_function.guard:
function_dict["guard"] = new_function.guard
if new_function.attributes:
function_dict["attributes"] = new_function.attributes
yaml_data["functions"].append(function_dict)
class IndentYamlListDumper(yaml.Dumper):
def increase_indent(self, flow=False, indentless=False):
return super(IndentYamlListDumper, self).increase_indent(flow, False)
with open(yaml_file, "w") as f:
yaml.dump(
yaml_data,
f,
Dumper=IndentYamlListDumper,
default_flow_style=False,
sort_keys=False,
)
print(f"Added function {new_function.name} to {yaml_file}")
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.
Args:
yaml_file: Path to the YAML file containing header specification.
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 GpuHeader for exporting declarations.
"""
if add_function:
add_function_to_yaml(yaml_file, add_function)
header_class = GpuHeader if export_decls else HeaderFile
header = load_yaml_file(yaml_file, header_class, entry_points)
header_str = str(header)
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")
parser.add_argument(
"yaml_file", help="Path to the YAML file containing header specification"
)
parser.add_argument(
"--output_dir",
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,
metavar=(
"RETURN_TYPE",
"NAME",
"ARGUMENTS",
"STANDARDS",
"GUARD",
"ATTRIBUTES",
),
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 GpuHeader for exporting declarations",
)
args = parser.parse_args()
main(
args.yaml_file,
args.output_dir,
args.h_def_file,
args.add_function,
args.entry_points,
args.export_decls,
)
|