immense / Remotely

A remote control and remote scripting solution, built with .NET 8, Blazor, and SignalR.
GNU General Public License v3.0
4.28k stars 1.6k forks source link

c_method_fn(1).txt #881

Closed PmPPolska closed 1 month ago

PmPPolska commented 2 months ago

Sign in

android / trusty / vendor / google / aosp / refs/heads/for/refs/master / . / scripts / aidl / c_wrapper / iface_h2c.py

blob: d0b3a3b4ba02644e1f51e850886480efa6f527c5 [file] [log] [blame]

Copyright (C) 2022 The Android Open Source Project## Licensed under the Apache License, Version 2.0 (the "License");# you may not use this file except in compliance with the License.# You may obtain a copy of the License at## http://www.apache.org/licenses/LICENSE-2.0## Unless required by applicable law or agreed to in writing, software# distributed under the License is distributed on an "AS IS" BASIS,# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.# See the License for the specific language governing permissions and# limitations under the License.#"""Generate a client (proxy) in c, as a wrapper on top of the aidl-generatedbinder proxy cpp class.Requires the aidl-generated interface header as input"""import functoolsfrom jinja2 import FileSystemLoader, Environmentimport jsonfrom pathlib import Pathimport reimport subprocessfrom typing import Listscript_dir = Path(file).parentroot_dir = script_dir / "../../../../../../.."aidl_tool = root_dir / "trusty/prebuilts/aosp/tidl/tidl"jinja_template_loader = FileSystemLoader(searchpath=script_dir / "tpl")jinja_template_env = Environment( loader=jinja_template_loader, trim_blocks=True, lstrip_blocks=True, keep_trailing_newline=True, line_comment_prefix="###",)class Consts: def init(self, const_list: List): self.consts = const_list @functools.cached_property def ordered_strings(self): return sorted( [s for s in self.consts if s["qualType"].find("const char [") == 0], key=lambda s: s["name"], ) @functools.cached_property def ordered_positive_integers(self): return sorted( [ s for s in self.consts if (s["qualType"].find("const int32_t") == 0) and (s["value"][0] != "-") ], key=lambda s: s["value"], ) @functools.cached_property def ordered_negative_integers(self): return sorted( [ s for s in self.consts if (s["qualType"].find("const int32_t") == 0) and (s["value"][0] == "-") ], key=lambda s: s["value"], ) @functools.cached_property def ordered_error_integers(self): return sorted( [ s for s in self.consts if (s["qualType"].find("const int32_t") == 0) and (s["name"].find("ERR") > -1) ], key=lambda s: s["value"], ) @staticmethod def len(ll: List): return len(ll)def clang_ast(hdr_file: Path, filter_name: str, domain: str): completed_process = subprocess.run( " ".join( [ "clang++", "-I{}".format(hdr_file.parent), "-I{}".format( root_dir / "trusty/user/base/experimental/lib/binder-paidl/include" ), " ".join( [ "-I{}".format( root_dir / "external/trusty/bootloader/ql-tipc/include" ), "-I{}".format( root_dir / "external/trusty/bootloader/ql-tipc/include/trusty/sysdeps/aarch64" ), "-I{}".format(root_dir / "external/lk/include/uapi"), "-I{}".format(root_dir / "external/lk/include/shared"), "-I{}".format(root_dir / "external/lk/lib/libc/include"), ] ) if domain == "ql_tipc" else " ".join( [ "-I{}".format(root_dir / "external/lk/include/uapi"), "-I{}".format(root_dir / "external/lk/include/shared"), "-I{}".format(root_dir / "trusty/kernel/include/uapi"), "-I{}".format(root_dir / "trusty/kernel/include/shared"), "-I{}".format(root_dir / "trusty/user/base/lib/tipc/include"), "-I{}".format(root_dir / "trusty/user/base/include/user"), ] ), "-UANDROID", "-DTRUSTY", "-D__QL_TIPC__" if domain == "ql_tipc" else "", "-std=c++17", "-Xclang", "-ast-dump=json", "-Xclang", "-ast-dump-filter", "-Xclang", filter_name, "-fsyntax-only", "-fno-color-diagnostics", "-Wno-visibility", hdr_file.as_posix(), ] ), shell=True, text=True, capture_output=True, ) if completed_process.returncode: print(completed_process.stderr) blobs = re.split("Dumping.\n", completed_process.stdout) ast = [] for b in blobs: if len(b) == 0: continue ast.append(json.loads(b)) return astdef ast_parse_arg(item): def get_spec(arg): m = re.match(r"std::array<([^,]), ([^>])>", arg["qualType"]) if m is not None: (type, size) = m.groups() return dict(isInput=True, isArray=True, arrayType=type, arraySize=size) m = re.match(r"::trusty::aidl::FixedPayload<([^>])>", arg["qualType"]) if m is not None: (size,) = m.groups() return dict(isInput=True, isArray=True, arrayType="uint8t", arraySize=size) m = re.match(r"::trusty::aidl::Payload.*", arg["qualType"]) if m is not None: return dict(isInput=False, isArray=False, isPayload=True) m = re.match(r"::trusty::aidl::Payload.\&", arg["qualType"]) if m is not None: return dict(isInput=True, isArray=False, isPayload=True) if arg["qualType"][-1] == "*": return dict(isInput=False, isArray=False, isPayload=False) return dict(isInput=True, isArray=False, isPayload=False) if item["kind"] != "ParmVarDecl": return None if "name" not in item: return None arg = dict(name=item["name"].replace("arg", ""), qualType=item["type"]["qualType"]) arg["spec"] = get_spec(arg) return argdef ast_parse_field(item): if item["kind"] != "FieldDecl": return None if "name" not in item: return None field = dict(name=item["name"], qualType=item["type"]["qualType"]) return fielddef ast_parse_method(item): return dict( name=item["name"], args=list(filter(None, [ast_parse_arg(arg) for arg in item["inner"]])) if "inner" in item else [], )def ast_parse_struct(item): return dict( name=item["name"], fields=list(filter(None, [ast_parse_field(field) for field in item["inner"]])) if "inner" in item else [], )def ast_parse_const(item): def get_literal_value(item): if item["inner"][0]["kind"] in ["StringLiteral", "IntegerLiteral"]: return item["inner"][0]["value"] if item["inner"][0]["kind"] in ["UnaryOperator"]: return item["inner"][0]["opcode"] + get_literal_value(item["inner"][0]) raise Exception("Cannot parse item {}item".format(item)) try: return dict( name=item["name"], value=get_literal_value(item), qualType=item["type"]["qualType"], ) except Exception as e: print(item)def ast_cross_ref(iface_name, methods, structs): for method in methods: for arg in method["args"]: m = re.match( ".{}::([^:\s])\s+[*\&]+$".format(iface_name), arg["qualType"] ) if m is None: continue (struct,) = m.groups() for s in structs: if s["name"] == struct: arg["xref"] = sdef c_client_wrapper(iface_ast, iface_name, impl_name, c_impl_name, domain): methods = [] structs = [] consts = [] for ast in iface_ast: if ast["name"] != iface_name: continue if ast["kind"] != "CXXRecordDecl": raise Exception( "iface {} shall be defined as a CXXRecordDecl".format(iface_name) ) if ast["tagUsed"] != "class": raise Exception("iface {} shall be defined as a class".format(iface_name)) for item in ast["inner"]: if item["kind"] == "CXXMethodDecl": if "isImplicit" in item and item["isImplicit"]: continue # C++ operators if "pure" not in item or not item["pure"]: continue # no need to implement in c the non-pure methods # as they are inherited by the base class Binder methods.append(ast_parse_method(item)) if item["kind"] == "CXXRecordDecl" and item["tagUsed"] == "struct": structs.append(ast_parse_struct(item)) if item["kind"] == "VarDecl" and item["constexpr"] == True: consts.append(ast_parse_const(item)) ast_cross_ref(iface_name, methods, structs) tm = jinja_template_env.get_template("client_c.j2") tm_env = dict( iface_name=iface_name, impl_name=impl_name, c_impl_name=c_impl_name, methods=methods, structs=structs, consts=Consts(consts), domain=domain, ) c = tm.render(tm_env) tm = jinja_template_env.get_template("client_h.j2") h = tm.render(tm_env) return dict(c=c, h=h, methods=methods, structs=structs)def iface_to_c( iface_hdr: Path, domain: str, out_cpp: str, out_hdr: str, bn=False, append_cpp=False, dbg=False,): if domain not in ["trusty_user", "ql_tipc"]: raise Exception("domain {} not supported", domain) iface_name = iface_hdr.stem impl_name = iface_name[1:] iface_ast = clang_ast(iface_hdr, iface_name, domain) # bp_ast = clang_ast(args.bp_cpp) out_cpp_path = Path(out_cpp) out_cpp_path.mkdir(parents=True, exist_ok=True) out_hdr_path = Path(out_hdr) out_hdr_path.mkdir(parents=True, exist_ok=True) if dbg: with open(out_cpp_path / "{}_ast.json".format(iface_name), "w") as f: json.dump(iface_ast, f, indent=2) # convert impl name from camelCase to snake_case c_implname = re.sub(r"(?<!^)(?=[A-Z])", "", impl_name).lower() c_client = c_client_wrapper(iface_ast, iface_name, impl_name, c_impl_name, domain) if dbg: with open(out_cpp_path / "{}_methods.json".format(c_impl_name), "w") as f: json.dump( dict(methods=c_client["methods"], structs=c_client["structs"]), f, indent=2, ) if not bn: if append_cpp: with open(out_cpp_path / "{}.cpp".format(iface_name), "a") as f: f.write(c_client["c"]) else: with open(out_cpp_path / "{}_CBp.cpp".format(iface_name), "w") as f: f.write(c_client["c"]) with open(out_hdr_path / "{}.h".format(c_impl_name), "w") as f:

f.write(c_client["h"])

Powered by Gitiles| Privacy| Termstxt json