Skip to content

Commit 9f6e72b

Browse files
authored
[libc] Add merge_yaml_files feature to hdrgen (#127269)
This allows a sort of "include" mechanism in the YAML files. A file can have a "merge_yaml_files" list of paths (relative to the containing file's location). These are YAML files in the same syntax, except they cannot have their own "header" entry. Only the lists (types, enums, macros, functions, objects) can appear. The main YAML file is then processed just as if each of its lists were the (sorted) union of each YAML file's corresponding list. This will enable maintaining a single source of truth for each function signature and other such details, where it is necessary to generate the same declaration in more than one header.
1 parent d9b55b7 commit 9f6e72b

File tree

11 files changed

+133
-35
lines changed

11 files changed

+133
-35
lines changed

libc/utils/hdrgen/enumeration.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,24 @@
66
#
77
# ==-------------------------------------------------------------------------==#
88

9+
from functools import total_ordering
910

11+
12+
@total_ordering
1013
class Enumeration:
1114
def __init__(self, name, value):
1215
self.name = name
1316
self.value = value
1417

18+
def __eq__(self, other):
19+
return self.name == other.name
20+
21+
def __lt__(self, other):
22+
return self.name < other.name
23+
24+
def __hash__(self):
25+
return self.name.__hash__()
26+
1527
def __str__(self):
1628
if self.value != None:
1729
return f"{self.name} = {self.value}"

libc/utils/hdrgen/function.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
# ==-------------------------------------------------------------------------==#
88

99
import re
10+
from functools import total_ordering
1011
from type import Type
1112

1213

@@ -36,6 +37,7 @@
3637
NONIDENTIFIER = re.compile("[^a-zA-Z0-9_]+")
3738

3839

40+
@total_ordering
3941
class Function:
4042
def __init__(
4143
self, return_type, name, arguments, standards, guard=None, attributes=[]
@@ -51,6 +53,15 @@ def __init__(
5153
self.guard = guard
5254
self.attributes = attributes or []
5355

56+
def __eq__(self, other):
57+
return self.name == other.name
58+
59+
def __lt__(self, other):
60+
return self.name < other.name
61+
62+
def __hash__(self):
63+
return self.name.__hash__()
64+
5465
def signature_types(self):
5566
def collapse(type_string):
5667
assert type_string

libc/utils/hdrgen/header.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ def __init__(self, name):
7373
self.objects = []
7474
self.functions = []
7575
self.standards = []
76+
self.merge_yaml_files = []
7677

7778
def add_macro(self, macro):
7879
self.macros.append(macro)
@@ -89,6 +90,13 @@ def add_object(self, object):
8990
def add_function(self, function):
9091
self.functions.append(function)
9192

93+
def merge(self, other):
94+
self.macros = sorted(set(self.macros) | set(other.macros))
95+
self.types = sorted(set(self.types) | set(other.types))
96+
self.enumerations = sorted(set(self.enumerations) | set(other.enumerations))
97+
self.objects = sorted(set(self.objects) | set(other.objects))
98+
self.functions = sorted(set(self.functions) | set(other.functions))
99+
92100
def all_types(self):
93101
return reduce(
94102
lambda a, b: a | b,

libc/utils/hdrgen/macro.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,25 @@
66
#
77
# ==-------------------------------------------------------------------------==#
88

9+
from functools import total_ordering
910

11+
12+
@total_ordering
1013
class Macro:
1114
def __init__(self, name, value=None, header=None):
1215
self.name = name
1316
self.value = value
1417
self.header = header
1518

19+
def __eq__(self, other):
20+
return self.name == other.name
21+
22+
def __lt__(self, other):
23+
return self.name < other.name
24+
25+
def __hash__(self):
26+
return self.name.__hash__()
27+
1628
def __str__(self):
1729
if self.header != None:
1830
return ""

libc/utils/hdrgen/main.py

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,7 @@ def main():
5252
)
5353
args = parser.parse_args()
5454

55-
[yaml_file] = args.yaml_file
56-
files_read = {yaml_file}
55+
files_read = set()
5756

5857
def write_depfile():
5958
if not args.depfile:
@@ -63,7 +62,34 @@ def write_depfile():
6362
with open(args.depfile, "w") as depfile:
6463
depfile.write(f"{args.output}: {deps}\n")
6564

66-
header = load_yaml_file(yaml_file, HeaderFile, args.entry_point)
65+
def load_yaml(path):
66+
files_read.add(path)
67+
return load_yaml_file(path, HeaderFile, args.entry_point)
68+
69+
merge_from_files = dict()
70+
71+
def merge_from(paths):
72+
for path in paths:
73+
# Load each file exactly once, in case of redundant merges.
74+
if path in merge_from_files:
75+
continue
76+
header = load_yaml(path)
77+
merge_from_files[path] = header
78+
merge_from(path.parent / f for f in header.merge_yaml_files)
79+
80+
# Load the main file first.
81+
[yaml_file] = args.yaml_file
82+
header = load_yaml(yaml_file)
83+
84+
# Now load all the merge_yaml_files, and any transitive merge_yaml_files.
85+
merge_from(yaml_file.parent / f for f in header.merge_yaml_files)
86+
87+
# Merge in all those files' contents.
88+
for merge_from_path, merge_from_header in merge_from_files.items():
89+
if merge_from_header.name is not None:
90+
print(f"{merge_from_path!s}: Merge file cannot have header field", stderr)
91+
return 2
92+
header.merge(merge_from_header)
6793

6894
# The header_template path is relative to the containing YAML file.
6995
template = header.template(yaml_file.parent, files_read)

libc/utils/hdrgen/object.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,23 @@
66
#
77
# ==-------------------------------------------------------------------------==#
88

9+
from functools import total_ordering
910

11+
12+
@total_ordering
1013
class Object:
1114
def __init__(self, name, type):
1215
self.name = name
1316
self.type = type
1417

18+
def __eq__(self, other):
19+
return self.name == other.name
20+
21+
def __lt__(self, other):
22+
return self.name < other.name
23+
24+
def __hash__(self):
25+
return self.name.__hash__()
26+
1527
def __str__(self):
1628
return f"extern {self.type} {self.name};"
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
macros:
2+
- macro_name: MACRO_A
3+
macro_value: 1
4+
types:
5+
- type_name: type_a
6+
enums:
7+
- name: enum_a
8+
value: value_1
9+
objects:
10+
- object_name: object_1
11+
object_type: obj
12+
functions:
13+
- name: func_a
14+
return_type: void
15+
arguments: []
16+
standards:
17+
- stdc
18+
attributes:
19+
- CONST_FUNC_A
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
macros:
2+
- macro_name: MACRO_B
3+
macro_value: 2
4+
types:
5+
- type_name: type_b
6+
enums:
7+
- name: enum_b
8+
value: value_2
9+
objects:
10+
- object_name: object_2
11+
object_type: obj
12+
functions:
13+
- name: func_b
14+
return_type: float128
15+
arguments: []
16+
standards:
17+
- stdc
18+
guard: LIBC_TYPES_HAS_FLOAT128

libc/utils/hdrgen/tests/input/test_small.yaml

Lines changed: 3 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,15 @@
11
header: test_small.h
22
header_template: test_small.h.def
3+
merge_yaml_files:
4+
- merge1.yaml
5+
- merge2.yaml
36
macros:
4-
- macro_name: MACRO_A
5-
macro_value: 1
6-
- macro_name: MACRO_B
7-
macro_value: 2
87
- macro_name: MACRO_C
98
- macro_name: MACRO_D
109
macro_header: test_small-macros.h
1110
- macro_name: MACRO_E
1211
macro_header: test_more-macros.h
13-
types:
14-
- type_name: type_a
15-
- type_name: type_b
16-
enums:
17-
- name: enum_a
18-
value: value_1
19-
- name: enum_b
20-
value: value_2
21-
objects:
22-
- object_name: object_1
23-
object_type: obj
24-
- object_name: object_2
25-
object_type: obj
2612
functions:
27-
- name: func_a
28-
return_type: void
29-
arguments: []
30-
standards:
31-
- stdc
32-
attributes:
33-
- CONST_FUNC_A
34-
- name: func_b
35-
return_type: float128
36-
arguments: []
37-
standards:
38-
- stdc
39-
guard: LIBC_TYPES_HAS_FLOAT128
4013
- name: func_c
4114
return_type: _Float16
4215
arguments:

libc/utils/hdrgen/type.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@
66
#
77
# ==-------------------------------------------------------------------------==#
88

9+
from functools import total_ordering
910

11+
12+
@total_ordering
1013
class Type:
1114
def __init__(self, type_name):
1215
assert type_name
@@ -15,5 +18,8 @@ def __init__(self, type_name):
1518
def __eq__(self, other):
1619
return self.type_name == other.type_name
1720

21+
def __lt__(self, other):
22+
return self.type_name < other.type_name
23+
1824
def __hash__(self):
1925
return self.type_name.__hash__()

0 commit comments

Comments
 (0)