15f9996aaSopenharmony_ci#!/usr/bin/env python
25f9996aaSopenharmony_ci# -*- coding: utf-8 -*-
35f9996aaSopenharmony_ci# Copyright (c) 2021 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 sys
175f9996aaSopenharmony_ciimport argparse
185f9996aaSopenharmony_ciimport os
195f9996aaSopenharmony_ciimport shutil
205f9996aaSopenharmony_ciimport json
215f9996aaSopenharmony_cifrom interface_mgr import InterfaceMgr
225f9996aaSopenharmony_ci
235f9996aaSopenharmony_cisys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
245f9996aaSopenharmony_cifrom scripts.util.file_utils import read_json_file, write_file, write_json_file  # noqa: E402 E501
255f9996aaSopenharmony_cifrom scripts.util import build_utils  # noqa: E402
265f9996aaSopenharmony_ci
275f9996aaSopenharmony_ciSHARED_LIBRARY_BUILD_TEMPLATE = '''
285f9996aaSopenharmony_ciconfig("%s_config") {
295f9996aaSopenharmony_ci  include_dirs = [ "%s/include", ]
305f9996aaSopenharmony_ci}
315f9996aaSopenharmony_ciohos_prebuilt_shared_library("%s") {
325f9996aaSopenharmony_ci  source = "%s"
335f9996aaSopenharmony_ci  public_configs = [ ":%s_config" ]
345f9996aaSopenharmony_ci  subsystem_name = "%s"
355f9996aaSopenharmony_ci  part_name = "%s"
365f9996aaSopenharmony_ci  install_enable = false
375f9996aaSopenharmony_ci}
385f9996aaSopenharmony_ci
395f9996aaSopenharmony_ci'''
405f9996aaSopenharmony_ciJAR_BUILD_TEMPLATE = '''
415f9996aaSopenharmony_cijava_prebuilt("%s") {
425f9996aaSopenharmony_ci  jar_path = "%s"
435f9996aaSopenharmony_ci'''
445f9996aaSopenharmony_ciMAPLE_BUILD_TEMPLATE = '''
455f9996aaSopenharmony_ciohos_maple_java_prebuilt("%s") {
465f9996aaSopenharmony_ci  mplt = %s
475f9996aaSopenharmony_ci  jar_path = "%s"
485f9996aaSopenharmony_ci'''
495f9996aaSopenharmony_ci
505f9996aaSopenharmony_ci
515f9996aaSopenharmony_ci# check sdk header file signature,
525f9996aaSopenharmony_ci# skip check if file dir not exist
535f9996aaSopenharmony_cidef check_header_files(checkfile_dir: str, subsystem_sdk_dir: str, subsystem_name: str,
545f9996aaSopenharmony_ci                       module_name: str, interface_mgr):
555f9996aaSopenharmony_ci    if checkfile_dir is None or not os.path.exists(checkfile_dir):
565f9996aaSopenharmony_ci        return
575f9996aaSopenharmony_ci    interface_mgr.check(checkfile_dir, subsystem_sdk_dir, subsystem_name,
585f9996aaSopenharmony_ci                        module_name)
595f9996aaSopenharmony_ci
605f9996aaSopenharmony_ci
615f9996aaSopenharmony_cidef get_build_config_from_label(label: str, current_toolchain_dir: str) -> str:
625f9996aaSopenharmony_ci    build_config = label.replace('//', 'gen/').replace(':', '/')
635f9996aaSopenharmony_ci    bc_file = '{}/{}.build_config'.format(current_toolchain_dir, build_config)
645f9996aaSopenharmony_ci    return bc_file
655f9996aaSopenharmony_ci
665f9996aaSopenharmony_ci
675f9996aaSopenharmony_cidef add_dynamic_deps(output: str, build_config: str) -> str:
685f9996aaSopenharmony_ci    external_deps = build_utils.expand_file_args(
695f9996aaSopenharmony_ci        ['@FileArg({}:deps_info:external_deps)'.format(build_config)])
705f9996aaSopenharmony_ci    if external_deps[0] != '[  ]':
715f9996aaSopenharmony_ci        output += "external_deps = " + external_deps[0]
725f9996aaSopenharmony_ci    output += "}"
735f9996aaSopenharmony_ci    return output
745f9996aaSopenharmony_ci
755f9996aaSopenharmony_ci
765f9996aaSopenharmony_ci# Copy the SDK module to the sdk output directory,
775f9996aaSopenharmony_ci# and generate the prebuilt template to BUILD.gn file.
785f9996aaSopenharmony_cidef gen_build_file(input_file: str, sdk_out_dir: str, generate_sig: bool,
795f9996aaSopenharmony_ci                   signature_file_check_dir: str):
805f9996aaSopenharmony_ci    data = read_json_file(input_file)
815f9996aaSopenharmony_ci    if data is None:
825f9996aaSopenharmony_ci        raise Exception(
835f9996aaSopenharmony_ci            "sdk interface description info error, file [{}] does not exist.".
845f9996aaSopenharmony_ci            format(input_file))
855f9996aaSopenharmony_ci
865f9996aaSopenharmony_ci    build_file_content = 'import("//build/ohos.gni")\n'
875f9996aaSopenharmony_ci    sdk_info = {}
885f9996aaSopenharmony_ci    # interface check
895f9996aaSopenharmony_ci    interface_mgr = InterfaceMgr()
905f9996aaSopenharmony_ci    for module_desc in data:
915f9996aaSopenharmony_ci        subsystem_name = module_desc.get('subsystem_name')
925f9996aaSopenharmony_ci        part_name = module_desc.get('part_name')
935f9996aaSopenharmony_ci        origin_name = module_desc.get('origin_name')
945f9996aaSopenharmony_ci        module_type = module_desc.get('type')
955f9996aaSopenharmony_ci        module_name = module_desc.get('name')
965f9996aaSopenharmony_ci        module_info_file = module_desc.get('source_info')
975f9996aaSopenharmony_ci        _current_toolchain_dir = module_desc.get('current_toolchain_dir')
985f9996aaSopenharmony_ci
995f9996aaSopenharmony_ci        # read module_info.json file, get module source path
1005f9996aaSopenharmony_ci        source_data = read_json_file(module_info_file)
1015f9996aaSopenharmony_ci        if not source_data:
1025f9996aaSopenharmony_ci            print("read module [{}] info file failed, filename [{}].".format(
1035f9996aaSopenharmony_ci                module_name, module_info_file))
1045f9996aaSopenharmony_ci            continue
1055f9996aaSopenharmony_ci
1065f9996aaSopenharmony_ci        # copy lib file
1075f9996aaSopenharmony_ci        source = source_data.get('source')
1085f9996aaSopenharmony_ci        if module_type == 'jar':
1095f9996aaSopenharmony_ci            source = source_data.get('alternative_source')
1105f9996aaSopenharmony_ci
1115f9996aaSopenharmony_ci        # check sdk type consistency
1125f9996aaSopenharmony_ci        suffix = module_type
1135f9996aaSopenharmony_ci        if module_type == "none":
1145f9996aaSopenharmony_ci            continue
1155f9996aaSopenharmony_ci        # Don't check suffix for maple sdk.
1165f9996aaSopenharmony_ci        if module_type == "maple":
1175f9996aaSopenharmony_ci            pass
1185f9996aaSopenharmony_ci        elif not source.endswith(suffix):
1195f9996aaSopenharmony_ci            raise Exception(
1205f9996aaSopenharmony_ci                "sdk module [{}] type configuration is inconsistent.".format(
1215f9996aaSopenharmony_ci                    module_name))
1225f9996aaSopenharmony_ci
1235f9996aaSopenharmony_ci        module_sdk_out_dir = os.path.join(sdk_out_dir, module_name)
1245f9996aaSopenharmony_ci        if not os.path.exists(module_sdk_out_dir):
1255f9996aaSopenharmony_ci            os.makedirs(module_sdk_out_dir, exist_ok=True)
1265f9996aaSopenharmony_ci        if module_type == "maple":
1275f9996aaSopenharmony_ci            pass
1285f9996aaSopenharmony_ci        else:
1295f9996aaSopenharmony_ci            shutil.copy(source, module_sdk_out_dir)
1305f9996aaSopenharmony_ci
1315f9996aaSopenharmony_ci        # copy headers file
1325f9996aaSopenharmony_ci        header_base = module_desc.get('header_base')
1335f9996aaSopenharmony_ci        if not header_base:
1345f9996aaSopenharmony_ci            raise Exception("{}: header_base config error.".format(
1355f9996aaSopenharmony_ci                module_desc.get('label')))
1365f9996aaSopenharmony_ci
1375f9996aaSopenharmony_ci        header_files = module_desc.get('header_files')
1385f9996aaSopenharmony_ci        # copy to sdk/{subsystem_name}/{module_name}/include/
1395f9996aaSopenharmony_ci        for header_file in header_files:
1405f9996aaSopenharmony_ci            rel_h_file = os.path.join(header_base, header_file)
1415f9996aaSopenharmony_ci
1425f9996aaSopenharmony_ci            header_file_dest = os.path.join(module_sdk_out_dir, 'include',
1435f9996aaSopenharmony_ci                                            header_file)
1445f9996aaSopenharmony_ci            header_file_dest_dir = os.path.dirname(header_file_dest)
1455f9996aaSopenharmony_ci            if not os.path.exists(header_file_dest_dir):
1465f9996aaSopenharmony_ci                os.makedirs(header_file_dest_dir, exist_ok=True)
1475f9996aaSopenharmony_ci
1485f9996aaSopenharmony_ci            shutil.copy(rel_h_file, header_file_dest)
1495f9996aaSopenharmony_ci
1505f9996aaSopenharmony_ci        # generate or check header files
1515f9996aaSopenharmony_ci        if module_type == 'so' and generate_sig is False:
1525f9996aaSopenharmony_ci            check_header_files(signature_file_check_dir, sdk_out_dir,
1535f9996aaSopenharmony_ci                               origin_name, module_name, interface_mgr)
1545f9996aaSopenharmony_ci
1555f9996aaSopenharmony_ci        # gen build file
1565f9996aaSopenharmony_ci        lib_file = os.path.join(module_name, os.path.basename(source))
1575f9996aaSopenharmony_ci        if module_type == 'so':
1585f9996aaSopenharmony_ci            build_file_content += SHARED_LIBRARY_BUILD_TEMPLATE % (
1595f9996aaSopenharmony_ci                module_name, module_name, module_name, lib_file, module_name,
1605f9996aaSopenharmony_ci                subsystem_name, part_name)
1615f9996aaSopenharmony_ci        elif module_type == 'jar':
1625f9996aaSopenharmony_ci            bc = get_build_config_from_label(source_data.get("label"),
1635f9996aaSopenharmony_ci                                             _current_toolchain_dir)
1645f9996aaSopenharmony_ci            build_file_content += JAR_BUILD_TEMPLATE % (module_name, lib_file)
1655f9996aaSopenharmony_ci            build_file_content = add_dynamic_deps(build_file_content, bc)
1665f9996aaSopenharmony_ci        elif module_type == 'maple':
1675f9996aaSopenharmony_ci            bc = get_build_config_from_label(source_data.get("label"),
1685f9996aaSopenharmony_ci                                             _current_toolchain_dir)
1695f9996aaSopenharmony_ci            bc_mplts = build_utils.expand_file_args(
1705f9996aaSopenharmony_ci                ['@FileArg({}:outputs:output_mplt)'.format(bc)])
1715f9996aaSopenharmony_ci            bc_mplts = build_utils.parse_and_flatten_gn_lists(bc_mplts)
1725f9996aaSopenharmony_ci            sdk_mplts = []
1735f9996aaSopenharmony_ci            base_dir = os.path.basename(module_sdk_out_dir)
1745f9996aaSopenharmony_ci            for mplt in bc_mplts:
1755f9996aaSopenharmony_ci                shutil.copy(mplt, module_sdk_out_dir)
1765f9996aaSopenharmony_ci                sdk_mplts.append(os.path.join(base_dir,
1775f9996aaSopenharmony_ci                                              os.path.basename(mplt)))
1785f9996aaSopenharmony_ci
1795f9996aaSopenharmony_ci            bc_jar_path = build_utils.expand_file_args(
1805f9996aaSopenharmony_ci                ["@FileArg({}:deps_info:unprocessed_jar_path)".format(bc)])
1815f9996aaSopenharmony_ci            bc_jar_path = build_utils.parse_and_flatten_gn_lists(bc_jar_path)
1825f9996aaSopenharmony_ci            sdk_jar_path = []
1835f9996aaSopenharmony_ci            for jar in bc_jar_path:
1845f9996aaSopenharmony_ci                shutil.copy(jar, module_sdk_out_dir)
1855f9996aaSopenharmony_ci                sdk_jar_path.append(
1865f9996aaSopenharmony_ci                    os.path.join(base_dir, os.path.basename(jar)))
1875f9996aaSopenharmony_ci            build_file_content += MAPLE_BUILD_TEMPLATE % (
1885f9996aaSopenharmony_ci                module_name, json.dumps(sdk_mplts, sort_keys=True,
1895f9996aaSopenharmony_ci                                        indent=2), sdk_jar_path[0])
1905f9996aaSopenharmony_ci            build_file_content = add_dynamic_deps(build_file_content, bc)
1915f9996aaSopenharmony_ci        elif module_type == 'rlib':
1925f9996aaSopenharmony_ci            pass
1935f9996aaSopenharmony_ci        else:
1945f9996aaSopenharmony_ci            raise Exception(
1955f9996aaSopenharmony_ci                'The type of sdk module configuration is not supported.')
1965f9996aaSopenharmony_ci
1975f9996aaSopenharmony_ci        module_info = {
1985f9996aaSopenharmony_ci            'source': lib_file,
1995f9996aaSopenharmony_ci            'label': module_desc.get('label'),
2005f9996aaSopenharmony_ci            'type': module_type
2015f9996aaSopenharmony_ci        }
2025f9996aaSopenharmony_ci        sdk_info[module_name] = module_info
2035f9996aaSopenharmony_ci    return build_file_content, sdk_info
2045f9996aaSopenharmony_ci
2055f9996aaSopenharmony_ci
2065f9996aaSopenharmony_cidef generate_sdk(input_file: str, sdk_out_dir: str, output_build_file: str, sdk_info_file: str,
2075f9996aaSopenharmony_ci                 generate_sig: str, signature_file_check_dir: str,
2085f9996aaSopenharmony_ci                 signature_file_gen_dir: str):
2095f9996aaSopenharmony_ci    build_file_content, sdk_info = gen_build_file(input_file, sdk_out_dir,
2105f9996aaSopenharmony_ci                                                  generate_sig,
2115f9996aaSopenharmony_ci                                                  signature_file_check_dir)
2125f9996aaSopenharmony_ci    # write file, build gn file
2135f9996aaSopenharmony_ci    write_file(output_build_file, build_file_content)
2145f9996aaSopenharmony_ci    # sdk info return
2155f9996aaSopenharmony_ci    write_json_file(sdk_info_file, sdk_info)
2165f9996aaSopenharmony_ci
2175f9996aaSopenharmony_ci    # gen signature file
2185f9996aaSopenharmony_ci    if generate_sig is True:
2195f9996aaSopenharmony_ci        interface_mgr = InterfaceMgr()
2205f9996aaSopenharmony_ci        interface_mgr.gen_sig_file_by_subsystem(sdk_out_dir,
2215f9996aaSopenharmony_ci                                                signature_file_gen_dir)
2225f9996aaSopenharmony_ci
2235f9996aaSopenharmony_ci
2245f9996aaSopenharmony_cidef main():
2255f9996aaSopenharmony_ci    parser = argparse.ArgumentParser()
2265f9996aaSopenharmony_ci    parser.add_argument('--input-file', help='', required=True)
2275f9996aaSopenharmony_ci    parser.add_argument('--sdk-out-dir', help='', required=True)
2285f9996aaSopenharmony_ci    parser.add_argument('--output-build-file', help='', required=True)
2295f9996aaSopenharmony_ci    parser.add_argument('--sdk-info-file', help='', required=True)
2305f9996aaSopenharmony_ci    parser.add_argument('--generate-sig',
2315f9996aaSopenharmony_ci                        dest='generate_sig',
2325f9996aaSopenharmony_ci                        action='store_true')
2335f9996aaSopenharmony_ci    parser.set_defaults(generate_sig=False)
2345f9996aaSopenharmony_ci    parser.add_argument('--signature-file-check-dir', help='', required=False)
2355f9996aaSopenharmony_ci    parser.add_argument('--signature-file-gen-dir', help='', required=False)
2365f9996aaSopenharmony_ci    args = parser.parse_args()
2375f9996aaSopenharmony_ci
2385f9996aaSopenharmony_ci    generate_sdk(args.input_file, args.sdk_out_dir, args.output_build_file,
2395f9996aaSopenharmony_ci                 args.sdk_info_file, args.generate_sig,
2405f9996aaSopenharmony_ci                 args.signature_file_check_dir, args.signature_file_gen_dir)
2415f9996aaSopenharmony_ci    return 0
2425f9996aaSopenharmony_ci
2435f9996aaSopenharmony_ci
2445f9996aaSopenharmony_ciif __name__ == '__main__':
2455f9996aaSopenharmony_ci    sys.exit(main())
246