1#!/usr/bin/env python 2# -*- coding: utf-8 -*- 3# Copyright (c) 2021 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 sys 17import argparse 18import os 19import shutil 20import json 21from interface_mgr import InterfaceMgr 22 23sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) 24from scripts.util.file_utils import read_json_file, write_file, write_json_file # noqa: E402 E501 25from scripts.util import build_utils # noqa: E402 26 27SHARED_LIBRARY_BUILD_TEMPLATE = ''' 28config("%s_config") { 29 include_dirs = [ "%s/include", ] 30} 31ohos_prebuilt_shared_library("%s") { 32 source = "%s" 33 public_configs = [ ":%s_config" ] 34 subsystem_name = "%s" 35 part_name = "%s" 36 install_enable = false 37} 38 39''' 40JAR_BUILD_TEMPLATE = ''' 41java_prebuilt("%s") { 42 jar_path = "%s" 43''' 44MAPLE_BUILD_TEMPLATE = ''' 45ohos_maple_java_prebuilt("%s") { 46 mplt = %s 47 jar_path = "%s" 48''' 49 50 51# check sdk header file signature, 52# skip check if file dir not exist 53def check_header_files(checkfile_dir: str, subsystem_sdk_dir: str, subsystem_name: str, 54 module_name: str, interface_mgr): 55 if checkfile_dir is None or not os.path.exists(checkfile_dir): 56 return 57 interface_mgr.check(checkfile_dir, subsystem_sdk_dir, subsystem_name, 58 module_name) 59 60 61def get_build_config_from_label(label: str, current_toolchain_dir: str) -> str: 62 build_config = label.replace('//', 'gen/').replace(':', '/') 63 bc_file = '{}/{}.build_config'.format(current_toolchain_dir, build_config) 64 return bc_file 65 66 67def add_dynamic_deps(output: str, build_config: str) -> str: 68 external_deps = build_utils.expand_file_args( 69 ['@FileArg({}:deps_info:external_deps)'.format(build_config)]) 70 if external_deps[0] != '[ ]': 71 output += "external_deps = " + external_deps[0] 72 output += "}" 73 return output 74 75 76# Copy the SDK module to the sdk output directory, 77# and generate the prebuilt template to BUILD.gn file. 78def gen_build_file(input_file: str, sdk_out_dir: str, generate_sig: bool, 79 signature_file_check_dir: str): 80 data = read_json_file(input_file) 81 if data is None: 82 raise Exception( 83 "sdk interface description info error, file [{}] does not exist.". 84 format(input_file)) 85 86 build_file_content = 'import("//build/ohos.gni")\n' 87 sdk_info = {} 88 # interface check 89 interface_mgr = InterfaceMgr() 90 for module_desc in data: 91 subsystem_name = module_desc.get('subsystem_name') 92 part_name = module_desc.get('part_name') 93 origin_name = module_desc.get('origin_name') 94 module_type = module_desc.get('type') 95 module_name = module_desc.get('name') 96 module_info_file = module_desc.get('source_info') 97 _current_toolchain_dir = module_desc.get('current_toolchain_dir') 98 99 # read module_info.json file, get module source path 100 source_data = read_json_file(module_info_file) 101 if not source_data: 102 print("read module [{}] info file failed, filename [{}].".format( 103 module_name, module_info_file)) 104 continue 105 106 # copy lib file 107 source = source_data.get('source') 108 if module_type == 'jar': 109 source = source_data.get('alternative_source') 110 111 # check sdk type consistency 112 suffix = module_type 113 if module_type == "none": 114 continue 115 # Don't check suffix for maple sdk. 116 if module_type == "maple": 117 pass 118 elif not source.endswith(suffix): 119 raise Exception( 120 "sdk module [{}] type configuration is inconsistent.".format( 121 module_name)) 122 123 module_sdk_out_dir = os.path.join(sdk_out_dir, module_name) 124 if not os.path.exists(module_sdk_out_dir): 125 os.makedirs(module_sdk_out_dir, exist_ok=True) 126 if module_type == "maple": 127 pass 128 else: 129 shutil.copy(source, module_sdk_out_dir) 130 131 # copy headers file 132 header_base = module_desc.get('header_base') 133 if not header_base: 134 raise Exception("{}: header_base config error.".format( 135 module_desc.get('label'))) 136 137 header_files = module_desc.get('header_files') 138 # copy to sdk/{subsystem_name}/{module_name}/include/ 139 for header_file in header_files: 140 rel_h_file = os.path.join(header_base, header_file) 141 142 header_file_dest = os.path.join(module_sdk_out_dir, 'include', 143 header_file) 144 header_file_dest_dir = os.path.dirname(header_file_dest) 145 if not os.path.exists(header_file_dest_dir): 146 os.makedirs(header_file_dest_dir, exist_ok=True) 147 148 shutil.copy(rel_h_file, header_file_dest) 149 150 # generate or check header files 151 if module_type == 'so' and generate_sig is False: 152 check_header_files(signature_file_check_dir, sdk_out_dir, 153 origin_name, module_name, interface_mgr) 154 155 # gen build file 156 lib_file = os.path.join(module_name, os.path.basename(source)) 157 if module_type == 'so': 158 build_file_content += SHARED_LIBRARY_BUILD_TEMPLATE % ( 159 module_name, module_name, module_name, lib_file, module_name, 160 subsystem_name, part_name) 161 elif module_type == 'jar': 162 bc = get_build_config_from_label(source_data.get("label"), 163 _current_toolchain_dir) 164 build_file_content += JAR_BUILD_TEMPLATE % (module_name, lib_file) 165 build_file_content = add_dynamic_deps(build_file_content, bc) 166 elif module_type == 'maple': 167 bc = get_build_config_from_label(source_data.get("label"), 168 _current_toolchain_dir) 169 bc_mplts = build_utils.expand_file_args( 170 ['@FileArg({}:outputs:output_mplt)'.format(bc)]) 171 bc_mplts = build_utils.parse_and_flatten_gn_lists(bc_mplts) 172 sdk_mplts = [] 173 base_dir = os.path.basename(module_sdk_out_dir) 174 for mplt in bc_mplts: 175 shutil.copy(mplt, module_sdk_out_dir) 176 sdk_mplts.append(os.path.join(base_dir, 177 os.path.basename(mplt))) 178 179 bc_jar_path = build_utils.expand_file_args( 180 ["@FileArg({}:deps_info:unprocessed_jar_path)".format(bc)]) 181 bc_jar_path = build_utils.parse_and_flatten_gn_lists(bc_jar_path) 182 sdk_jar_path = [] 183 for jar in bc_jar_path: 184 shutil.copy(jar, module_sdk_out_dir) 185 sdk_jar_path.append( 186 os.path.join(base_dir, os.path.basename(jar))) 187 build_file_content += MAPLE_BUILD_TEMPLATE % ( 188 module_name, json.dumps(sdk_mplts, sort_keys=True, 189 indent=2), sdk_jar_path[0]) 190 build_file_content = add_dynamic_deps(build_file_content, bc) 191 elif module_type == 'rlib': 192 pass 193 else: 194 raise Exception( 195 'The type of sdk module configuration is not supported.') 196 197 module_info = { 198 'source': lib_file, 199 'label': module_desc.get('label'), 200 'type': module_type 201 } 202 sdk_info[module_name] = module_info 203 return build_file_content, sdk_info 204 205 206def generate_sdk(input_file: str, sdk_out_dir: str, output_build_file: str, sdk_info_file: str, 207 generate_sig: str, signature_file_check_dir: str, 208 signature_file_gen_dir: str): 209 build_file_content, sdk_info = gen_build_file(input_file, sdk_out_dir, 210 generate_sig, 211 signature_file_check_dir) 212 # write file, build gn file 213 write_file(output_build_file, build_file_content) 214 # sdk info return 215 write_json_file(sdk_info_file, sdk_info) 216 217 # gen signature file 218 if generate_sig is True: 219 interface_mgr = InterfaceMgr() 220 interface_mgr.gen_sig_file_by_subsystem(sdk_out_dir, 221 signature_file_gen_dir) 222 223 224def main(): 225 parser = argparse.ArgumentParser() 226 parser.add_argument('--input-file', help='', required=True) 227 parser.add_argument('--sdk-out-dir', help='', required=True) 228 parser.add_argument('--output-build-file', help='', required=True) 229 parser.add_argument('--sdk-info-file', help='', required=True) 230 parser.add_argument('--generate-sig', 231 dest='generate_sig', 232 action='store_true') 233 parser.set_defaults(generate_sig=False) 234 parser.add_argument('--signature-file-check-dir', help='', required=False) 235 parser.add_argument('--signature-file-gen-dir', help='', required=False) 236 args = parser.parse_args() 237 238 generate_sdk(args.input_file, args.sdk_out_dir, args.output_build_file, 239 args.sdk_info_file, args.generate_sig, 240 args.signature_file_check_dir, args.signature_file_gen_dir) 241 return 0 242 243 244if __name__ == '__main__': 245 sys.exit(main()) 246