1#!/usr/bin/env python 2# -*- coding: utf-8 -*- 3# Copyright (c) 2024 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 json 18import os 19import shutil 20import stat 21import utils 22import subprocess 23 24 25def _get_args(): 26 parser = argparse.ArgumentParser(add_help=True) 27 parser.add_argument( 28 "-sp", 29 "--source_code_path", 30 default=r".", 31 type=str, 32 help="Path of source code", 33 ) 34 parser.add_argument( 35 "-hp", 36 "--hpmcache_path", 37 default=r".", 38 type=str, 39 help="Path of .hpmcache", 40 ) 41 parser.add_argument( 42 "-v", 43 "--variants", 44 default=r".", 45 type=str, 46 help="variants of build target", 47 ) 48 parser.add_argument( 49 "-rp", 50 "--root_path", 51 default=r".", 52 type=str, 53 help="Path of root", 54 ) 55 parser.add_argument( 56 "-t", "--test", 57 default=1, type=int, 58 help="whether the target contains test type. default 0 , choices: 0 or 1 2", 59 ) 60 parser.add_argument( 61 "-out", 62 "--out_dir", 63 default="src", 64 type=str, 65 help="the independent build out storage dir. default src , choices: src src_test or test", 66 ) 67 args = parser.parse_args() 68 return args 69 70 71def _get_dependence_json(_path) -> dict: 72 dependences_path = os.path.join(_path, 'dependences.json') 73 _json = utils.get_json(dependences_path) 74 return _json 75 76 77def _get_bundle_path(hpm_cache_path, dependences_json, part_name): 78 bundle_path = (hpm_cache_path + 79 dependences_json[part_name]['installPath'] + os.sep + 'bundle.json') 80 return bundle_path 81 82 83def _get_src_bundle_path(source_code_path): 84 bundle_paths = list() 85 for root, dirs, files in os.walk(source_code_path): 86 for file in files: 87 if file == "bundle.json": 88 bundle_paths.append(os.path.join(root, file)) 89 return bundle_paths 90 91 92def _symlink_src2dest(src_dir, dest_dir): 93 if os.path.exists(dest_dir) and os.path.islink(dest_dir): 94 os.unlink(dest_dir) 95 if os.path.exists(dest_dir) and dest_dir != src_dir: 96 if os.path.isdir(dest_dir): 97 shutil.rmtree(dest_dir) 98 else: 99 os.remove(dest_dir) 100 os.symlink(src_dir, dest_dir) 101 102 103def _symlink_binarys(hpm_cache_path, bundle_json, dependences_json, part_name): 104 path = bundle_json["segment"]["destPath"] 105 link_path = os.path.join("binarys", path) 106 if not os.path.isdir(link_path): 107 try: 108 os.remove(link_path) 109 except FileNotFoundError: 110 pass 111 os.makedirs(link_path, exist_ok=True) 112 real_path = hpm_cache_path + dependences_json[part_name]['installPath'] 113 _symlink_src2dest(real_path, link_path) 114 115 116def _get_target_cpu(code_path, variants): 117 target_cpu_str = "" 118 config_path = os.path.join(code_path, "binarys", "variants", "variants_" + variants, "config", "build_config.json") 119 target_cpu = utils.get_json(config_path).get("target_cpu") 120 if target_cpu == "arm": 121 target_cpu_str = "arm" 122 elif target_cpu == "arm64": 123 target_cpu_str = "aarch64" 124 return target_cpu_str 125 126 127def _link_kernel_binarys(variants, hpm_cache_path, dependences_json, target_cpu): 128 target_path = target_cpu + "-linux-ohos" 129 musl_real_path = hpm_cache_path + dependences_json["musl"]['installPath'] 130 musl_include_link_path = os.path.join("out", variants, "obj/binarys/third_party/musl/usr/include", target_path) 131 musl_lib_link_path = os.path.join("out", variants, "obj/binarys/third_party/musl/usr/lib", target_path) 132 os.makedirs(musl_include_link_path, exist_ok=True) 133 os.makedirs(musl_lib_link_path, exist_ok=True) 134 135 _symlink_src2dest(os.path.join(musl_real_path, 'innerapis', 'includes'), musl_include_link_path) 136 _symlink_src2dest(os.path.join(musl_real_path, 'innerapis', 'libs'), musl_lib_link_path) 137 138 kernel_real_path = hpm_cache_path + dependences_json["linux"]['installPath'] 139 kernel_link_path = os.path.join("kernel", "linux") 140 if not os.path.exists(kernel_link_path): 141 os.makedirs(kernel_link_path) 142 _symlink_src2dest(os.path.join(kernel_real_path, "innerapis"), kernel_link_path) 143 144 145def is_directory_empty(path): 146 return len([f for f in os.listdir(path) if os.path.isdir(os.path.join(path, f))]) == 0 147 148 149def _copy_test_binarys(test_check, variants, hpm_cache_path, dependences_json): 150 if test_check != 0: 151 googletest_real_path = hpm_cache_path + dependences_json["googletest"]['installPath'] 152 googletest_link_path = os.path.join("out", variants, "obj/binarys/third_party/googletest") 153 os.makedirs(googletest_link_path, exist_ok=True) 154 if is_directory_empty(googletest_link_path): 155 shutil.copytree(os.path.join(googletest_real_path, 'innerapis'), 156 os.path.join(googletest_link_path, 'innerapis')) 157 else: 158 shutil.rmtree(googletest_link_path, True) 159 os.makedirs(googletest_link_path, exist_ok=True) 160 shutil.copytree(os.path.join(googletest_real_path, 'innerapis'), 161 os.path.join(googletest_link_path, 'innerapis')) 162 163 164def _gen_components_info(components_json, bundle_json, part_name, src_build_name_list, _part_toolchain_map_dict): 165 subsystem = bundle_json["component"]["subsystem"] 166 path = bundle_json["segment"]["destPath"] 167 try: 168 component = bundle_json["component"]["build"]["inner_kits"] 169 except KeyError: 170 if not bundle_json["component"]["build"]: 171 bundle_json["component"]["build"] = {} 172 if "inner_api" not in bundle_json["component"]["build"].keys(): 173 bundle_json["component"]["build"]["inner_api"] = [] 174 component = bundle_json["component"]["build"]["inner_api"] 175 innerapi_value_list = list() 176 for i in component: 177 innerapi_name = i["name"].split(':')[-1] 178 if part_name == 'musl': 179 innerapi_label = "{}:{}".format(os.path.join("//binarys", path), innerapi_name) 180 elif part_name in src_build_name_list: 181 innerapi_label = i['name'] 182 else: 183 innerapi_label = "{}:{}".format(os.path.join("//binarys", path, "innerapis", innerapi_name), innerapi_name) 184 innerapi_value_list.append({"name": innerapi_name, "label": innerapi_label}) 185 if innerapi_name in _part_toolchain_map_dict.keys() and part_name not in src_build_name_list: 186 _name = innerapi_name 187 innerapi_name = f"{innerapi_name}({_part_toolchain_map_dict[_name]['toolchain_value']})" 188 innerapi_label = "{}:{}".format(os.path.join("//binarys", path, "innerapis", 189 _name, 190 _part_toolchain_map_dict[_name]['toolchain_key']), innerapi_name) 191 innerapi_value_list.append({"name": innerapi_name, "label": innerapi_label}) 192 if part_name == 'cjson': 193 part_name = 'cJSON' 194 if part_name == 'freebsd': 195 part_name = 'FreeBSD' 196 spe_component_names = ['astc_encoder', 'llvm_project', 'alsa_lib', 'alsa_utils', 'abseil_cpp', 'cups_filters', 197 'libnfc_nci', 'vulkan_loader', 'libjpeg_turbo', 'opencl_headers', 'f2fs_tools', 'noto_cjk', 198 'fsverity_utils', 'vk_gl_cts', 199 'spirv_tools', 'spirv_headers', 'vulkan_headers', 'u_boot', 'weex_loader', 'ntfs_3g', 200 'css_what'] 201 if part_name in spe_component_names: 202 part_name = part_name.replace('_', '-') 203 one_component_dict = {part_name: { 204 "innerapis": innerapi_value_list, 205 "path": path, 206 "subsystem": subsystem 207 }} 208 components_json.update(one_component_dict) 209 210 return components_json 211 212 213def _get_src_part_name(src_bundle_paths): 214 _name = '' 215 _path = '' 216 for src_bundle_path in src_bundle_paths: 217 src_bundle_json = utils.get_json(src_bundle_path) 218 part_name = "" 219 try: 220 part_name = src_bundle_json['component']['name'] 221 except KeyError: 222 print(f'--get bundle json component name error--') 223 if part_name.endswith('_lite'): 224 pass 225 else: 226 _name = part_name 227 _path = src_bundle_path 228 return [_name, _path] 229 230 231def _binarys_permissions_handler(): 232 binarys_path = "binarys" 233 cmd = ["chmod", "755", "-R", binarys_path] 234 subprocess.Popen(cmd) 235 236 237def _components_info_handler(part_name_list, source_code_path: str, hpm_cache_path, root_path, dependences_json, 238 _part_toolchain_map_dict): 239 source_code_path_list = source_code_path.split(",") 240 components_json = dict() 241 src_build_name_list = ['build_framework'] 242 243 # 获取源代码路径和组件名称的映射 244 src_bundle_path_dict = { 245 _get_src_part_name(_get_src_bundle_path(src_path))[0]: _get_src_part_name(_get_src_bundle_path(src_path))[1] 246 for src_path in source_code_path_list 247 } 248 # 更新构建名称列表并生成组件信息 249 src_build_name_list.extend(src_bundle_path_dict.keys()) 250 for src_part_name, src_bundle_path in src_bundle_path_dict.items(): 251 components_json = _gen_components_info(components_json, utils.get_json(src_bundle_path), src_part_name, 252 src_build_name_list, _part_toolchain_map_dict) 253 254 # 处理构建框架 255 build_framework_bundle_path = os.path.join(root_path, "build", "bundle.json") 256 components_json = _gen_components_info(components_json, utils.get_json(build_framework_bundle_path), 257 "build_framework", src_build_name_list, _part_toolchain_map_dict) 258 259 # 处理其他组件 260 for part_name in part_name_list: 261 if part_name and part_name not in src_bundle_path_dict: 262 bundle_path = _get_bundle_path(hpm_cache_path, dependences_json, part_name) 263 bundle_json = utils.get_json(bundle_path) 264 _symlink_binarys(hpm_cache_path, bundle_json, dependences_json, part_name) 265 if part_name == 'developer_test': 266 continue 267 components_json = _gen_components_info(components_json, bundle_json, part_name, src_build_name_list, 268 _part_toolchain_map_dict) 269 270 return components_json 271 272 273def _out_components_json(components_json, output_path): 274 file_name = os.path.join(output_path, "components.json") 275 flags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC 276 modes = stat.S_IWUSR | stat.S_IRUSR 277 with os.fdopen(os.open(file_name, flags, modes), 'w') as f: 278 json.dump(components_json, f, indent=4) 279 280 281def _generate_platforms_list(output_path): 282 platforms_list_gni_file = os.path.join(output_path, "platforms_list.gni") 283 platforms_list = ['phone'] 284 platforms_list_strings = ' "," '.join(platforms_list) 285 gni_file_content = [f'target_platform_list = [ "{platforms_list_strings}" ]', 286 f'kits_platform_list = [ "{platforms_list_strings}" ]'] 287 flags = os.O_WRONLY | os.O_CREAT 288 modes = stat.S_IWUSR | stat.S_IRUSR 289 with os.fdopen(os.open(platforms_list_gni_file, flags, modes), 'w') as f: 290 f.write('\n'.join(gni_file_content)) 291 292 293def _get_toolchain_json(_path): 294 toolchain_json = os.path.join(_path, 'build', 'indep_configs', 'variants', 'common', 'toolchain.json') 295 _json = utils.get_json(toolchain_json) 296 return _json 297 298 299def _get_all_have_toolchain_component(toolchain_json, hpm_cache_path): 300 _toolchain_list = toolchain_json.keys() 301 binarys_path = os.path.join(hpm_cache_path, 'binarys') 302 _part_toolchain_map_dict = dict() 303 for toolchain in _toolchain_list: 304 for root, dirs, files in os.walk(binarys_path, topdown=False, followlinks=True): 305 if toolchain in dirs: 306 _part_name = os.path.basename(root) 307 _part_toolchain_map_dict.update({ 308 _part_name: { 309 'toolchain_key': toolchain, 310 'toolchain_value': toolchain_json[toolchain] 311 } 312 }) 313 return _part_toolchain_map_dict 314 315 316def main(): 317 args = _get_args() 318 source_code_path = args.source_code_path 319 hpm_cache_path = args.hpmcache_path 320 variants = args.variants 321 root_path = args.root_path 322 test_check = args.test 323 out_dir = args.out_dir 324 project_path = os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))) 325 output_part_path = os.path.join(project_path, 'out', variants, out_dir, 'build_configs', 'parts_info') 326 output_config_path = os.path.join(project_path, 'out', variants, out_dir, 'build_configs') 327 dependences_json = _get_dependence_json(hpm_cache_path) 328 toolchain_json = _get_toolchain_json(root_path) 329 part_name_list = dependences_json.keys() 330 331 _part_toolchain_map_dict = _get_all_have_toolchain_component(toolchain_json, hpm_cache_path) 332 components_json = _components_info_handler(part_name_list, source_code_path, 333 hpm_cache_path, root_path, dependences_json, _part_toolchain_map_dict) 334 _binarys_permissions_handler() 335 _out_components_json(components_json, output_part_path) 336 _generate_platforms_list(output_config_path) 337 _link_kernel_binarys(variants + os.sep + out_dir, hpm_cache_path, dependences_json, _get_target_cpu(root_path, variants)) 338 _copy_test_binarys(test_check, variants + os.sep + out_dir, hpm_cache_path, dependences_json) 339 340 341if __name__ == '__main__': 342 main() 343