15f9996aaSopenharmony_ci#!/usr/bin/env python
25f9996aaSopenharmony_ci# -*- coding: utf-8 -*-
35f9996aaSopenharmony_ci# Copyright (c) 2023 Huawei Device Co., Ltd.
45f9996aaSopenharmony_ci# Licensed under the Apache License, Version 2.0 (the "License");
55f9996aaSopenharmony_ci# you may not use this file except in compliance with the License.
65f9996aaSopenharmony_ci# You may obtain a copy of the License at
75f9996aaSopenharmony_ci#
85f9996aaSopenharmony_ci#     http://www.apache.org/licenses/LICENSE-2.0
95f9996aaSopenharmony_ci#
105f9996aaSopenharmony_ci# Unless required by applicable law or agreed to in writing, software
115f9996aaSopenharmony_ci# distributed under the License is distributed on an "AS IS" BASIS,
125f9996aaSopenharmony_ci# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135f9996aaSopenharmony_ci# See the License for the specific language governing permissions and
145f9996aaSopenharmony_ci# limitations under the License.
155f9996aaSopenharmony_ci
165f9996aaSopenharmony_ciimport argparse
175f9996aaSopenharmony_ciimport copy
185f9996aaSopenharmony_ciimport os
195f9996aaSopenharmony_ciimport shutil
205f9996aaSopenharmony_ciimport subprocess
215f9996aaSopenharmony_ciimport sys
225f9996aaSopenharmony_ci
235f9996aaSopenharmony_cisys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
245f9996aaSopenharmony_cifrom scripts.util.file_utils import read_json_file  # noqa: E402
255f9996aaSopenharmony_ci
265f9996aaSopenharmony_citarget_data_dicts = dict()
275f9996aaSopenharmony_ci
285f9996aaSopenharmony_ci
295f9996aaSopenharmony_cidef get_value_from_file(file: str, target: list, key: str, must: bool = True):
305f9996aaSopenharmony_ci    target_name = target[0]
315f9996aaSopenharmony_ci    target_out_dir = target[1]
325f9996aaSopenharmony_ci    file_path = os.path.join(target_out_dir, target_name + "_" + file + ".json")
335f9996aaSopenharmony_ci
345f9996aaSopenharmony_ci    global target_data_dicts
355f9996aaSopenharmony_ci    target_data = target_data_dicts.get(file_path)
365f9996aaSopenharmony_ci    if target_data is not None:
375f9996aaSopenharmony_ci        return target_data.get(key)
385f9996aaSopenharmony_ci
395f9996aaSopenharmony_ci    if not os.path.exists(file_path):
405f9996aaSopenharmony_ci        if must:
415f9996aaSopenharmony_ci            raise Exception("File " + file_path + " not exists!")
425f9996aaSopenharmony_ci        else:
435f9996aaSopenharmony_ci            print(file_path + " not exists!")
445f9996aaSopenharmony_ci            return "Unknown"
455f9996aaSopenharmony_ci
465f9996aaSopenharmony_ci    target_data = read_json_file(file_path)
475f9996aaSopenharmony_ci    target_data_dicts[file_path] = target_data
485f9996aaSopenharmony_ci    return target_data.get(key)
495f9996aaSopenharmony_ci
505f9996aaSopenharmony_ci
515f9996aaSopenharmony_cidef get_valid_deps(module_deps: list, finish_list: list):
525f9996aaSopenharmony_ci    already_check = []
535f9996aaSopenharmony_ci    valid_list = []
545f9996aaSopenharmony_ci    while len(module_deps) > 0:
555f9996aaSopenharmony_ci        module_deps_copy = copy.deepcopy(module_deps)
565f9996aaSopenharmony_ci        module_deps = []
575f9996aaSopenharmony_ci        for module_dep in module_deps_copy:
585f9996aaSopenharmony_ci            target_name = module_dep.get("target_name")
595f9996aaSopenharmony_ci            target_out_dir = module_dep.get("target_out_dir")
605f9996aaSopenharmony_ci
615f9996aaSopenharmony_ci            element = (target_name, target_out_dir)
625f9996aaSopenharmony_ci            if already_check.count(element) > 0:
635f9996aaSopenharmony_ci                continue
645f9996aaSopenharmony_ci            already_check.append(element)
655f9996aaSopenharmony_ci
665f9996aaSopenharmony_ci            target_type = get_value_from_file("deps_data", element, "type", False)
675f9996aaSopenharmony_ci            if target_type == "Unknown":
685f9996aaSopenharmony_ci                continue
695f9996aaSopenharmony_ci            elif target_type == "shared_library" or target_type == "etc":
705f9996aaSopenharmony_ci                if finish_list.count(element) > 0:
715f9996aaSopenharmony_ci                    continue
725f9996aaSopenharmony_ci                valid_list.append(element)
735f9996aaSopenharmony_ci            else:
745f9996aaSopenharmony_ci                deps = get_value_from_file("deps_data", element, "module_deps_info", False)
755f9996aaSopenharmony_ci                for dep in deps:
765f9996aaSopenharmony_ci                    name = dep.get("target_name")
775f9996aaSopenharmony_ci                    out_dir = dep.get("target_out_dir")
785f9996aaSopenharmony_ci                    dep_tup = (name, out_dir)
795f9996aaSopenharmony_ci                    module_deps.append(dep)
805f9996aaSopenharmony_ci    return valid_list
815f9996aaSopenharmony_ci
825f9996aaSopenharmony_ci
835f9996aaSopenharmony_cidef check_debug_info(check_file: str, readelf: str):
845f9996aaSopenharmony_ci    out = subprocess.Popen([readelf, "-S", check_file], shell=False, stdout=subprocess.PIPE)
855f9996aaSopenharmony_ci    infos = out.stdout.read().splitlines()
865f9996aaSopenharmony_ci    for info in infos:
875f9996aaSopenharmony_ci        info_str = info.decode()
885f9996aaSopenharmony_ci        pos = info_str.find(".debug_info")
895f9996aaSopenharmony_ci        if pos >= 0:
905f9996aaSopenharmony_ci            return True
915f9996aaSopenharmony_ci    return False
925f9996aaSopenharmony_ci
935f9996aaSopenharmony_ci
945f9996aaSopenharmony_cidef do_check(target_out_dir: str, target_name: str, stripped_dir: str, readelf: str,
955f9996aaSopenharmony_ci             abidiff: str, abidw: str, abi_dumps_path: str):
965f9996aaSopenharmony_ci    element = (target_name, target_out_dir)
975f9996aaSopenharmony_ci    prebuilt = get_value_from_file("deps_data", element, "prebuilt")
985f9996aaSopenharmony_ci    if prebuilt:
995f9996aaSopenharmony_ci        check_file = get_value_from_file("deps_data", element, "source_path")
1005f9996aaSopenharmony_ci        if not os.path.exists(check_file):
1015f9996aaSopenharmony_ci            raise Exception("File " + check_file + " not exists!")
1025f9996aaSopenharmony_ci        has_debug_info = check_debug_info(check_file, readelf)
1035f9996aaSopenharmony_ci        if not has_debug_info:
1045f9996aaSopenharmony_ci            raise Exception("Prebuilt target should be with debug info!")
1055f9996aaSopenharmony_ci    else:
1065f9996aaSopenharmony_ci        source = get_value_from_file("module_info", element, "source")
1075f9996aaSopenharmony_ci        check_file = os.path.join(stripped_dir, source)
1085f9996aaSopenharmony_ci        if not os.path.exists(check_file):
1095f9996aaSopenharmony_ci            raise Exception("File " + check_file + " not exists!")
1105f9996aaSopenharmony_ci
1115f9996aaSopenharmony_ci    out_file = os.path.join(target_out_dir, target_name + "_abi_info.dump")
1125f9996aaSopenharmony_ci    ret = subprocess.call([abidw, "--out-file", out_file, check_file])
1135f9996aaSopenharmony_ci    if ret != 0:
1145f9996aaSopenharmony_ci        raise Exception("Execute abidw failed! Return value: " + str(ret))
1155f9996aaSopenharmony_ci
1165f9996aaSopenharmony_ci    toolchain = get_value_from_file("deps_data", element, "toolchain")
1175f9996aaSopenharmony_ci    toolchain_name = toolchain.split(':')[-1]
1185f9996aaSopenharmony_ci
1195f9996aaSopenharmony_ci    base_name = os.path.basename(out_file)
1205f9996aaSopenharmony_ci    base_file = os.path.join(abi_dumps_path, toolchain_name, base_name)
1215f9996aaSopenharmony_ci    if not os.path.exists(base_file):
1225f9996aaSopenharmony_ci        raise Exception("File " + base_file + " not exists!")
1235f9996aaSopenharmony_ci    ret = subprocess.call([abidiff, out_file, base_file])
1245f9996aaSopenharmony_ci    if ret != 0:
1255f9996aaSopenharmony_ci        raise Exception("ABI info in " + out_file + " and " + base_file + " are different!")
1265f9996aaSopenharmony_ci
1275f9996aaSopenharmony_ci
1285f9996aaSopenharmony_cidef get_copy_source_path(element: list):
1295f9996aaSopenharmony_ci    prebuilt = get_value_from_file("deps_data", element, "prebuilt")
1305f9996aaSopenharmony_ci    if prebuilt:
1315f9996aaSopenharmony_ci        source = get_value_from_file("deps_data", element, "output_path")
1325f9996aaSopenharmony_ci    else:
1335f9996aaSopenharmony_ci        source = get_value_from_file("module_info", element, "source")
1345f9996aaSopenharmony_ci    return (element, source)
1355f9996aaSopenharmony_ci
1365f9996aaSopenharmony_ci
1375f9996aaSopenharmony_cidef traverse_and_check(check_list: list, readelf: str, abidiff: str, abidw: str, abi_dumps_path: str):
1385f9996aaSopenharmony_ci    copy_list = []
1395f9996aaSopenharmony_ci    finish_list = []
1405f9996aaSopenharmony_ci    loop_count = 0
1415f9996aaSopenharmony_ci    while len(check_list) > 0:
1425f9996aaSopenharmony_ci        check_list_copy = copy.deepcopy(check_list)
1435f9996aaSopenharmony_ci        check_list = []
1445f9996aaSopenharmony_ci        for element in check_list_copy:
1455f9996aaSopenharmony_ci            if finish_list.count(element) > 0:
1465f9996aaSopenharmony_ci                continue
1475f9996aaSopenharmony_ci            finish_list.append(element)
1485f9996aaSopenharmony_ci
1495f9996aaSopenharmony_ci            target_name = element[0]
1505f9996aaSopenharmony_ci            target_out_dir = element[1]
1515f9996aaSopenharmony_ci            target_type = get_value_from_file("deps_data", element, "type")
1525f9996aaSopenharmony_ci            if target_type == "etc":
1535f9996aaSopenharmony_ci                copy_list.append(copy.deepcopy(get_copy_source_path(element)))
1545f9996aaSopenharmony_ci                continue
1555f9996aaSopenharmony_ci
1565f9996aaSopenharmony_ci            stable = get_value_from_file("deps_data", element, "stable")
1575f9996aaSopenharmony_ci            if not stable:
1585f9996aaSopenharmony_ci                if loop_count == 0:
1595f9996aaSopenharmony_ci                    raise Exception("Target '{}' is not stable! Check config in gn".format(target_name))
1605f9996aaSopenharmony_ci                else:
1615f9996aaSopenharmony_ci                    copy_list.append(copy.deepcopy(get_copy_source_path(element)))
1625f9996aaSopenharmony_ci                module_deps = get_value_from_file("deps_data", element, "module_deps_info")
1635f9996aaSopenharmony_ci                check_list.extend(get_valid_deps(module_deps, finish_list))
1645f9996aaSopenharmony_ci            else:
1655f9996aaSopenharmony_ci                stripped_dir = ""
1665f9996aaSopenharmony_ci                if target_type == "shared_library":
1675f9996aaSopenharmony_ci                    stripped_dir = "lib.unstripped"
1685f9996aaSopenharmony_ci                elif target_type == "executable":
1695f9996aaSopenharmony_ci                    stripped_dir = "exe.unstripped"
1705f9996aaSopenharmony_ci                else:
1715f9996aaSopenharmony_ci                    raise Exception("Invalid target type: '{}'".format(target_type))
1725f9996aaSopenharmony_ci
1735f9996aaSopenharmony_ci                do_check(target_out_dir, target_name, stripped_dir, readelf, abidiff, abidw, abi_dumps_path)
1745f9996aaSopenharmony_ci                if loop_count == 0:
1755f9996aaSopenharmony_ci                    copy_list.append(copy.deepcopy(get_copy_source_path(element)))
1765f9996aaSopenharmony_ci
1775f9996aaSopenharmony_ci                    module_deps = get_value_from_file("deps_data", element, "module_deps_info")
1785f9996aaSopenharmony_ci                    check_list.extend(get_valid_deps(module_deps, finish_list))
1795f9996aaSopenharmony_ci        loop_count += 1
1805f9996aaSopenharmony_ci    return copy_list
1815f9996aaSopenharmony_ci
1825f9996aaSopenharmony_ci
1835f9996aaSopenharmony_cidef get_copy_output_path(element: list, parent_output: str):
1845f9996aaSopenharmony_ci    output_path = parent_output
1855f9996aaSopenharmony_ci    target_type = get_value_from_file("deps_data", element, "type")
1865f9996aaSopenharmony_ci    if target_type == "etc":
1875f9996aaSopenharmony_ci        output_path = os.path.join(parent_output, "etc")
1885f9996aaSopenharmony_ci    elif target_type == "executable":
1895f9996aaSopenharmony_ci        output_path = os.path.join(parent_output, "bin")
1905f9996aaSopenharmony_ci    elif target_type == "shared_library":
1915f9996aaSopenharmony_ci        output_path = os.path.join(parent_output, get_value_from_file("module_info", element, "type"))
1925f9996aaSopenharmony_ci    return output_path
1935f9996aaSopenharmony_ci
1945f9996aaSopenharmony_ci
1955f9996aaSopenharmony_cidef main():
1965f9996aaSopenharmony_ci    parser = argparse.ArgumentParser()
1975f9996aaSopenharmony_ci    parser.add_argument('--clang-readelf', required=True)
1985f9996aaSopenharmony_ci    parser.add_argument('--target-out-dir', required=True)
1995f9996aaSopenharmony_ci    parser.add_argument('--check-datas-file', required=True)
2005f9996aaSopenharmony_ci    parser.add_argument('--abidiff-target-name', required=True)
2015f9996aaSopenharmony_ci    parser.add_argument('--abidiff-target-out-dir', required=True)
2025f9996aaSopenharmony_ci    parser.add_argument('--abidw-target-name', required=True)
2035f9996aaSopenharmony_ci    parser.add_argument('--abidw-target-out-dir', required=True)
2045f9996aaSopenharmony_ci    parser.add_argument('--abi-dumps-path', required=True)
2055f9996aaSopenharmony_ci    args = parser.parse_args()
2065f9996aaSopenharmony_ci
2075f9996aaSopenharmony_ci    if not os.path.exists(args.check_datas_file):
2085f9996aaSopenharmony_ci        raise Exception("File " + args.check_datas_file + " not exists!")
2095f9996aaSopenharmony_ci
2105f9996aaSopenharmony_ci    abidiff_element = (args.abidiff_target_name, args.abidiff_target_out_dir)
2115f9996aaSopenharmony_ci    abidiff_bin = get_value_from_file("module_info", abidiff_element, "source")
2125f9996aaSopenharmony_ci    abidw_element = (args.abidw_target_name, args.abidw_target_out_dir)
2135f9996aaSopenharmony_ci    abidw_bin = get_value_from_file("module_info", abidw_element, "source")
2145f9996aaSopenharmony_ci
2155f9996aaSopenharmony_ci    parent_output = os.path.join(args.target_out_dir, "module_package", "img_input")
2165f9996aaSopenharmony_ci    if not os.path.exists(parent_output):
2175f9996aaSopenharmony_ci        os.makedirs(parent_output, exist_ok=True)
2185f9996aaSopenharmony_ci
2195f9996aaSopenharmony_ci    check_list = []
2205f9996aaSopenharmony_ci    check_datas = read_json_file(args.check_datas_file)
2215f9996aaSopenharmony_ci    for check_data in check_datas:
2225f9996aaSopenharmony_ci        element = (check_data.get("target_name"), check_data.get("target_out_dir"))
2235f9996aaSopenharmony_ci        check_list.append(element)
2245f9996aaSopenharmony_ci
2255f9996aaSopenharmony_ci    copy_list = traverse_and_check(check_list, args.clang_readelf, abidiff_bin, abidw_bin, args.abi_dumps_path)
2265f9996aaSopenharmony_ci    for copy_element in copy_list:
2275f9996aaSopenharmony_ci        print("copy_list: '{}'".format(str(copy_element)))
2285f9996aaSopenharmony_ci        output = get_copy_output_path(copy_element[0], parent_output)
2295f9996aaSopenharmony_ci        if not os.path.exists(output):
2305f9996aaSopenharmony_ci            os.makedirs(output, exist_ok=True)
2315f9996aaSopenharmony_ci        if isinstance(copy_element[1], list):
2325f9996aaSopenharmony_ci            for file in copy_element[1]:
2335f9996aaSopenharmony_ci                shutil.copy(file, output)
2345f9996aaSopenharmony_ci        else:
2355f9996aaSopenharmony_ci            shutil.copy(copy_element[1], output)
2365f9996aaSopenharmony_ci    os.remove(args.check_datas_file)
2375f9996aaSopenharmony_ci
2385f9996aaSopenharmony_ci
2395f9996aaSopenharmony_ciif __name__ == '__main__':
2405f9996aaSopenharmony_ci    sys.exit(main())
241