• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
3# Copyright (c) 2023 Huawei Device Co., Ltd.
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#     http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15
16import argparse
17import copy
18import os
19import shutil
20import subprocess
21import sys
22
23sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
24from scripts.util.file_utils import read_json_file  # noqa: E402
25
26target_data_dict = dict()
27
28
29def get_value_from_file(file: str, target: list, key: str, must: bool=True):
30    target_name = target[0]
31    target_out_dir = target[1]
32    file_path = os.path.join(target_out_dir, target_name + "_" + file + ".json")
33
34    global target_data_dict
35    target_data = target_data_dict.get(file_path)
36    if target_data is not None:
37        return target_data.get(key)
38
39    if not os.path.exists(file_path):
40        if must:
41            raise Exception("File " + file_path + " not exists!")
42        else:
43            print(file_path + " not exists!")
44            return "Unknown"
45
46    target_data = read_json_file(file_path)
47    target_data_dict[file_path] = target_data
48    return target_data.get(key)
49
50
51def get_valid_deps(module_deps: list, finish_list: list):
52    already_check = []
53    valid_list = []
54    while len(module_deps) > 0:
55        module_deps_copy = copy.deepcopy(module_deps)
56        module_deps = []
57        for module_dep in module_deps_copy:
58            target_name = module_dep.get("target_name")
59            target_out_dir = module_dep.get("target_out_dir")
60
61            element = (target_name, target_out_dir)
62            if already_check.count(element) > 0:
63                continue
64            already_check.append(element)
65
66            target_type = get_value_from_file("deps_data", element, "type", False)
67            if target_type == "Unknown":
68                continue
69            elif target_type == "shared_library" or target_type == "etc":
70                if finish_list.count(element) > 0:
71                    continue
72                valid_list.append(element)
73            else:
74                deps = get_value_from_file("deps_data", element, "module_deps_info", False)
75                for dep in deps:
76                    name = dep.get("target_name")
77                    out_dir = dep.get("target_out_dir")
78                    dep_tup = (name, out_dir)
79                    module_deps.append(dep)
80    return valid_list
81
82
83def check_debug_info(check_file: str, readelf: str):
84    out = subprocess.Popen([readelf, "-S", check_file], shell=False, stdout=subprocess.PIPE)
85    infos = out.stdout.read().splitlines()
86    for info in infos:
87        info_str = info.decode()
88        pos = info_str.find(".debug_info")
89        if pos >= 0:
90            return True
91    return False
92
93
94def do_check(target_out_dir: str, target_name: str, stripped_dir: str, readelf: str,
95             abidiff: str, abidw: str, abi_dumps_path: str):
96    element = (target_name, target_out_dir)
97    prebuilt = get_value_from_file("deps_data", element, "prebuilt")
98    if prebuilt:
99        check_file = get_value_from_file("deps_data", element, "source_path")
100        if not os.path.exists(check_file):
101            raise Exception("File " + check_file + " not exists!")
102        has_debug_info = check_debug_info(check_file, readelf)
103        if not has_debug_info:
104            raise Exception("Prebuilt target should be with debug info!")
105    else:
106        source = get_value_from_file("module_info", element, "source")
107        check_file = os.path.join(stripped_dir, source)
108        if not os.path.exists(check_file):
109            raise Exception("File " + check_file + " not exists!")
110
111    out_file = os.path.join(target_out_dir, target_name + "_abi_info.dump")
112    ret = subprocess.call([abidw, "--out-file", out_file, check_file])
113    if ret != 0:
114        raise Exception("Execute abidw failed! Return value: " + str(ret))
115
116    toolchain = get_value_from_file("deps_data", element, "toolchain")
117    toolchain_name = toolchain.split(':')[-1]
118
119    base_name = os.path.basename(out_file)
120    base_file = os.path.join(abi_dumps_path, toolchain_name, base_name)
121    if not os.path.exists(base_file):
122        raise Exception("File " + base_file + " not exists!")
123    ret = subprocess.call([abidiff, out_file, base_file])
124    if ret != 0:
125        raise Exception("ABI info in " + out_file + " and " + base_file + " are different!")
126
127
128def get_copy_source_path(element: list):
129    prebuilt = get_value_from_file("deps_data", element, "prebuilt")
130    if prebuilt:
131        source = get_value_from_file("deps_data", element, "output_path")
132    else:
133        source = get_value_from_file("module_info", element, "source")
134    return (element, source)
135
136
137def traverse_and_check(check_list: list, readelf: str, abidiff: str, abidw: str, abi_dumps_path: str):
138    copy_list = []
139    finish_list = []
140    loop_count = 0
141    while len(check_list) > 0:
142        check_list_copy = copy.deepcopy(check_list)
143        check_list = []
144        for element in check_list_copy:
145            if finish_list.count(element) > 0:
146                continue
147            finish_list.append(element)
148
149            target_name = element[0]
150            target_out_dir = element[1]
151            target_type = get_value_from_file("deps_data", element, "type")
152            if target_type == "etc":
153                copy_list.append(copy.deepcopy(get_copy_source_path(element)))
154                continue
155
156            stable = get_value_from_file("deps_data", element, "stable")
157            if not stable:
158                if loop_count == 0:
159                    raise Exception("Target '{}' is not stable! Check config in gn".format(target_name))
160                else:
161                    copy_list.append(copy.deepcopy(get_copy_source_path(element)))
162                module_deps = get_value_from_file("deps_data", element, "module_deps_info")
163                check_list.extend(get_valid_deps(module_deps, finish_list))
164            else:
165                stripped_dir = ""
166                if target_type == "shared_library":
167                    stripped_dir = "lib.unstripped"
168                elif target_type == "executable":
169                    stripped_dir = "exe.unstripped"
170                else:
171                    raise Exception("Invalid target type: '{}'".format(target_type))
172
173                do_check(target_out_dir, target_name, stripped_dir, readelf, abidiff, abidw, abi_dumps_path)
174                if loop_count == 0:
175                    copy_list.append(copy.deepcopy(get_copy_source_path(element)))
176
177                    module_deps = get_value_from_file("deps_data", element, "module_deps_info")
178                    check_list.extend(get_valid_deps(module_deps, finish_list))
179        loop_count += 1
180    return copy_list
181
182
183def get_copy_output_path(element: list, parent_output: str):
184    output_path = parent_output
185    target_type = get_value_from_file("deps_data", element, "type")
186    if target_type == "etc":
187        output_path = os.path.join(parent_output, "etc")
188    elif target_type == "executable":
189        output_path = os.path.join(parent_output, "bin")
190    elif target_type == "shared_library":
191        output_path = os.path.join(parent_output, get_value_from_file("module_info", element, "type"))
192    return output_path
193
194
195def main():
196    parser = argparse.ArgumentParser()
197    parser.add_argument('--clang-readelf', required=True)
198    parser.add_argument('--target-out-dir', required=True)
199    parser.add_argument('--check-datas-file', required=True)
200    parser.add_argument('--abidiff-target-name', required=True)
201    parser.add_argument('--abidiff-target-out-dir', required=True)
202    parser.add_argument('--abidw-target-name', required=True)
203    parser.add_argument('--abidw-target-out-dir', required=True)
204    parser.add_argument('--abi-dumps-path', required=True)
205    args = parser.parse_args()
206
207    if not os.path.exists(args.check_datas_file):
208        raise Exception("File " + args.check_datas_file + " not exists!")
209
210    abidiff_element = (args.abidiff_target_name, args.abidiff_target_out_dir)
211    abidiff_bin = get_value_from_file("module_info", abidiff_element, "source")
212    abidw_element = (args.abidw_target_name, args.abidw_target_out_dir)
213    abidw_bin = get_value_from_file("module_info", abidw_element, "source")
214
215    parent_output = os.path.join(args.target_out_dir, "module_package", "img_input")
216    if not os.path.exists(parent_output):
217        os.makedirs(parent_output, exist_ok=True)
218
219    check_list = []
220    check_datas = read_json_file(args.check_datas_file)
221    for check_data in check_datas:
222        element = (check_data.get("target_name"), check_data.get("target_out_dir"))
223        check_list.append(element)
224
225    copy_list = traverse_and_check(check_list, args.clang_readelf, abidiff_bin, abidw_bin, args.abi_dumps_path)
226    for copy_element in copy_list:
227        print("copy_list: '{}'".format(str(copy_element)))
228        output = get_copy_output_path(copy_element[0], parent_output)
229        if not os.path.exists(output):
230            os.makedirs(output, exist_ok=True)
231        if isinstance(copy_element[1], list):
232            for file in copy_element[1]:
233                shutil.copy(file, output)
234        else:
235            shutil.copy(copy_element[1], output)
236    os.remove(args.check_datas_file)
237
238
239if __name__ == '__main__':
240    sys.exit(main())
241