xref: /aosp_15_r20/external/executorch/kernels/test/gen_supported_features.py (revision 523fa7a60841cd1ecfb9cc4201f1ca8b03ed023a)
1# Copyright (c) Meta Platforms, Inc. and affiliates.
2# All rights reserved.
3#
4# This source code is licensed under the BSD-style license found in the
5# LICENSE file in the root directory of this source tree.
6
7import os
8import sys
9from typing import Any, List
10
11import pkg_resources
12import yaml
13
14
15def _to_c_bool(s: Any):
16    if s in [True, False]:
17        return str(s).lower()
18    return s
19
20
21def generate_header(d: dict):
22    """Generates a supported features header file"""
23    ini_path = os.path.join(
24        os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__))),
25        "supported_features_header.ini",
26    )
27    if os.path.isfile(ini_path):
28        header_file = open(ini_path, encoding="utf-8").read()
29    else:
30        header_file = pkg_resources.resource_string(
31            __package__, "supported_features_header.ini"
32        ).decode("utf-8")
33
34    return header_file.replace("$header_entries", "".join(generate_header_entry(d)))
35
36
37def generate_header_entry(d: dict):
38    for entry in d:
39        namespace = entry["namespace"]
40        for feature, properties in entry.items():
41            if feature == "namespace":
42                # we handled namespace previously
43                continue
44            yield generate_header_entry_text(namespace, feature, properties)
45
46
47def generate_header_entry_text(namespace: str, feature: str, properties: dict):
48    if namespace == "global":
49        full_name = feature
50    else:
51        full_name = "_".join([namespace, feature])
52    if "default" in properties:
53        default = _to_c_bool(properties["default"])
54        default = f" = {default}"
55    else:
56        default = ""
57    if "docstring" in properties:
58        docstring = properties["docstring"]
59    else:
60        docstring = "TODO: add docstring for this entry"
61    t = properties["type"]
62    entry = f"{t} {full_name}{default};\n"
63    return f"""
64  // {docstring}
65  {entry}
66"""
67
68
69def generate_definition(d: dict):
70    ini_path = os.path.join(
71        os.path.realpath(os.path.join(os.getcwd(), os.path.dirname(__file__))),
72        "supported_features_definition.ini",
73    )
74    if os.path.isfile(ini_path):
75        definition_file = open(ini_path, encoding="utf-8").read()
76    else:
77        definition_file = pkg_resources.resource_string(
78            __package__, "supported_features_definition.ini"
79        ).decode("utf-8")
80
81    return definition_file.replace(
82        "$definition_entries", "".join(generate_definition_entry(d))
83    )
84
85
86def generate_definition_entry(d: dict):
87    if not d:
88        return []  # noqa: B901
89    for entry in d:
90        namespace = entry["namespace"]
91        for feature, value in entry.items():
92            if feature == "namespace":
93                # we handled namespace previously
94                continue
95            yield generate_definition_entry_text(namespace, feature, value)
96
97
98def generate_definition_entry_text(namespace: str, feature: str, value: Any):
99    if namespace == "global":
100        full_name = feature
101    else:
102        full_name = "_".join([namespace, feature])
103    value = _to_c_bool(value)
104    return f"""
105  .{full_name} = {value},
106"""
107
108
109def main(args: List[Any]) -> None:
110    """
111    This binary generates the supported_features.h from supported_features.yaml
112    from this (//executorch/kernels/test) directory. Then for a specific kernel,
113    we need to supply the overridden supported_features_def.yaml for the kernel.
114    """
115    with open(args[0]) as f:
116        y = yaml.full_load(f)
117        if "supported_features_def" in args[0]:
118            print(generate_definition(y))
119        else:
120            print(generate_header(y))
121
122
123def invoke_main() -> None:
124    if len(sys.argv) != 2:
125        print(
126            "Usage: gen_supported_features.py <path-to>/supported_features{_def}.yaml"
127        )
128        exit(1)
129    main(sys.argv[1:])
130
131
132if __name__ == "__main__":
133    invoke_main()  # pragma: no cover
134