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, subsystem_sdk_dir, subsystem_name, 54 module_name, 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, current_toolchain_dir): 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, build_config): 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, sdk_out_dir, generate_sig, 79 signature_file_check_dir): 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 build_file_content += 'import("//build/config/ohos/rules.gni")\n' 88 sdk_info = {} 89 # interface check 90 interface_mgr = InterfaceMgr() 91 for module_desc in data: 92 subsystem_name = module_desc.get('subsystem_name') 93 part_name = module_desc.get('part_name') 94 origin_name = module_desc.get('origin_name') 95 module_type = module_desc.get('type') 96 module_name = module_desc.get('name') 97 module_info_file = module_desc.get('source_info') 98 _current_toolchain_dir = module_desc.get('current_toolchain_dir') 99 100 # read module_info.json file, get module source path 101 source_data = read_json_file(module_info_file) 102 if not source_data: 103 print("read module [{}] info file failed, filename [{}].".format( 104 module_name, module_info_file)) 105 continue 106 107 # copy lib file 108 source = source_data.get('source') 109 if module_type == 'jar': 110 source = source_data.get('alternative_source') 111 112 # check sdk type consistency 113 suffix = module_type 114 if module_type == "none": 115 continue 116 # Don't check suffix for maple sdk. 117 if module_type == "maple": 118 pass 119 elif not source.endswith(suffix): 120 raise Exception( 121 "sdk module [{}] type configuration is inconsistent.".format( 122 module_name)) 123 124 module_sdk_out_dir = os.path.join(sdk_out_dir, module_name) 125 if not os.path.exists(module_sdk_out_dir): 126 os.makedirs(module_sdk_out_dir, exist_ok=True) 127 if module_type == "maple": 128 pass 129 else: 130 shutil.copy(source, module_sdk_out_dir) 131 132 # copy headers file 133 header_base = module_desc.get('header_base') 134 if not header_base: 135 raise Exception("{}: header_base config error.".format( 136 module_desc.get('label'))) 137 138 header_files = module_desc.get('header_files') 139 # copy to sdk/{subsystem_name}/{module_name}/include/ 140 for header_file in header_files: 141 rel_h_file = os.path.join(header_base, header_file) 142 143 header_file_dest = os.path.join(module_sdk_out_dir, 'include', 144 header_file) 145 header_file_dest_dir = os.path.dirname(header_file_dest) 146 if not os.path.exists(header_file_dest_dir): 147 os.makedirs(header_file_dest_dir, exist_ok=True) 148 149 shutil.copy(rel_h_file, header_file_dest) 150 151 # generate or check header files 152 if module_type == 'so' and generate_sig is False: 153 check_header_files(signature_file_check_dir, sdk_out_dir, 154 origin_name, module_name, interface_mgr) 155 156 # gen build file 157 lib_file = os.path.join(module_name, os.path.basename(source)) 158 if module_type == 'so': 159 build_file_content += SHARED_LIBRARY_BUILD_TEMPLATE % ( 160 module_name, module_name, module_name, lib_file, module_name, 161 subsystem_name, part_name) 162 elif module_type == 'jar': 163 bc = get_build_config_from_label(source_data.get("label"), 164 _current_toolchain_dir) 165 build_file_content += JAR_BUILD_TEMPLATE % (module_name, lib_file) 166 build_file_content = add_dynamic_deps(build_file_content, bc) 167 elif module_type == 'maple': 168 bc = get_build_config_from_label(source_data.get("label"), 169 _current_toolchain_dir) 170 bc_mplts = build_utils.expand_file_args( 171 ['@FileArg({}:outputs:output_mplt)'.format(bc)]) 172 bc_mplts = build_utils.parse_and_flatten_gn_lists(bc_mplts) 173 sdk_mplts = [] 174 base_dir = os.path.basename(module_sdk_out_dir) 175 for mplt in bc_mplts: 176 shutil.copy(mplt, module_sdk_out_dir) 177 sdk_mplts.append(os.path.join(base_dir, 178 os.path.basename(mplt))) 179 180 bc_jar_path = build_utils.expand_file_args( 181 ["@FileArg({}:deps_info:unprocessed_jar_path)".format(bc)]) 182 bc_jar_path = build_utils.parse_and_flatten_gn_lists(bc_jar_path) 183 sdk_jar_path = [] 184 for jar in bc_jar_path: 185 shutil.copy(jar, module_sdk_out_dir) 186 sdk_jar_path.append( 187 os.path.join(base_dir, os.path.basename(jar))) 188 build_file_content += MAPLE_BUILD_TEMPLATE % ( 189 module_name, json.dumps(sdk_mplts, sort_keys=True, 190 indent=2), sdk_jar_path[0]) 191 build_file_content = add_dynamic_deps(build_file_content, bc) 192 else: 193 raise Exception( 194 'The type of sdk module configuration is not supported.') 195 196 module_info = { 197 'source': lib_file, 198 'label': module_desc.get('label'), 199 'type': module_type 200 } 201 sdk_info[module_name] = module_info 202 return build_file_content, sdk_info 203 204 205def generate_sdk(input_file, sdk_out_dir, output_build_file, sdk_info_file, 206 generate_sig, signature_file_check_dir, 207 signature_file_gen_dir): 208 build_file_content, sdk_info = gen_build_file(input_file, sdk_out_dir, 209 generate_sig, 210 signature_file_check_dir) 211 # write file, build gn file 212 write_file(output_build_file, build_file_content) 213 # sdk info return 214 write_json_file(sdk_info_file, sdk_info) 215 216 # gen signature file 217 if generate_sig is True: 218 interface_mgr = InterfaceMgr() 219 interface_mgr.gen_sig_file_by_subsystem(sdk_out_dir, 220 signature_file_gen_dir) 221 222 223def main(): 224 parser = argparse.ArgumentParser() 225 parser.add_argument('--input-file', help='', required=True) 226 parser.add_argument('--sdk-out-dir', help='', required=True) 227 parser.add_argument('--output-build-file', help='', required=True) 228 parser.add_argument('--sdk-info-file', help='', required=True) 229 parser.add_argument('--generate-sig', 230 dest='generate_sig', 231 action='store_true') 232 parser.set_defaults(generate_sig=False) 233 parser.add_argument('--signature-file-check-dir', help='', required=False) 234 parser.add_argument('--signature-file-gen-dir', help='', required=False) 235 args = parser.parse_args() 236 237 generate_sdk(args.input_file, args.sdk_out_dir, args.output_build_file, 238 args.sdk_info_file, args.generate_sig, 239 args.signature_file_check_dir, args.signature_file_gen_dir) 240 return 0 241 242 243if __name__ == '__main__': 244 sys.exit(main()) 245