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 os
185f9996aaSopenharmony_ciimport argparse
195f9996aaSopenharmony_ci
205f9996aaSopenharmony_cisys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
215f9996aaSopenharmony_cifrom scripts.util.file_utils import read_json_file, read_file, write_file  # noqa: E402 E501
225f9996aaSopenharmony_ci
235f9996aaSopenharmony_ci
245f9996aaSopenharmony_cidef _read_subninja_build(build_dir: str, subninja_build_file: str):
255f9996aaSopenharmony_ci    subninja_build_file = os.path.join(build_dir, subninja_build_file)
265f9996aaSopenharmony_ci    if not os.path.exists(subninja_build_file):
275f9996aaSopenharmony_ci        raise Exception("file '{}' doesn't exist.".format(subninja_build_file))
285f9996aaSopenharmony_ci    subninja_build = read_file(subninja_build_file)
295f9996aaSopenharmony_ci    if subninja_build is None:
305f9996aaSopenharmony_ci        raise Exception("read file '{}' failed.".format(subninja_build_file))
315f9996aaSopenharmony_ci    support_lib_type = ['.a', '.so', '']
325f9996aaSopenharmony_ci    label_name = ''
335f9996aaSopenharmony_ci    label_target = ''
345f9996aaSopenharmony_ci    for _line in subninja_build:
355f9996aaSopenharmony_ci        if _line.startswith('label_name = '):
365f9996aaSopenharmony_ci            label_name = _line[len('label_name = '):]
375f9996aaSopenharmony_ci        elif _line.startswith('build '):
385f9996aaSopenharmony_ci            _build_info = _line.split(':')[0]
395f9996aaSopenharmony_ci            build_label = _build_info.split(' ')[1]
405f9996aaSopenharmony_ci            _, extension = os.path.splitext(build_label)
415f9996aaSopenharmony_ci            if extension in support_lib_type:
425f9996aaSopenharmony_ci                label_target = build_label
435f9996aaSopenharmony_ci
445f9996aaSopenharmony_ci    if label_target != '':
455f9996aaSopenharmony_ci        if label_name == '':
465f9996aaSopenharmony_ci            target_filename = os.path.basename(label_target)
475f9996aaSopenharmony_ci            label_name, _ = os.path.splitext(target_filename)
485f9996aaSopenharmony_ci        return {label_name: label_target}
495f9996aaSopenharmony_ci    return None
505f9996aaSopenharmony_ci
515f9996aaSopenharmony_ci
525f9996aaSopenharmony_cidef _parse_target_label(build_label_list: list, toolchain_name: str):
535f9996aaSopenharmony_ci    phony_targets_dict = {}
545f9996aaSopenharmony_ci    for build_label in build_label_list:
555f9996aaSopenharmony_ci        target_filename = os.path.basename(build_label)
565f9996aaSopenharmony_ci        label_name, _ = os.path.splitext(target_filename)
575f9996aaSopenharmony_ci        if label_name:
585f9996aaSopenharmony_ci            phony_targets_dict[label_name] = build_label
595f9996aaSopenharmony_ci            start_index = len('{}/obj/'.format(toolchain_name))
605f9996aaSopenharmony_ci        _path = os.path.dirname(build_label)[start_index:]
615f9996aaSopenharmony_ci        if _path:
625f9996aaSopenharmony_ci            phony_targets_dict[_path] = build_label
635f9996aaSopenharmony_ci        if label_name and _path:
645f9996aaSopenharmony_ci            _label_path = '{}$:{}'.format(_path, label_name)
655f9996aaSopenharmony_ci            phony_targets_dict[_label_path] = build_label
665f9996aaSopenharmony_ci    return phony_targets_dict
675f9996aaSopenharmony_ci
685f9996aaSopenharmony_ci
695f9996aaSopenharmony_cidef _read_toolchain_ninja(build_dir: str, toolchain_ninja_file: str, toolchain_name: str):
705f9996aaSopenharmony_ci    if not os.path.exists(toolchain_ninja_file):
715f9996aaSopenharmony_ci        raise Exception(
725f9996aaSopenharmony_ci            "file '{}' doesn't exist.".format(toolchain_ninja_file))
735f9996aaSopenharmony_ci    toolchain_ninja_rules = read_file(toolchain_ninja_file)
745f9996aaSopenharmony_ci    if toolchain_ninja_rules is None:
755f9996aaSopenharmony_ci        raise Exception("read file '{}' failed.".format(toolchain_ninja_file))
765f9996aaSopenharmony_ci
775f9996aaSopenharmony_ci    build_label_list = []
785f9996aaSopenharmony_ci    subninja_targets = {}
795f9996aaSopenharmony_ci    for _ninja_rule in toolchain_ninja_rules:
805f9996aaSopenharmony_ci        if _ninja_rule.startswith('build '):
815f9996aaSopenharmony_ci            _tmp = _ninja_rule.split(':')[0]
825f9996aaSopenharmony_ci            _label = _tmp[len('build '):]
835f9996aaSopenharmony_ci            if not _label.endswith('.stamp'):
845f9996aaSopenharmony_ci                continue
855f9996aaSopenharmony_ci            build_label_list.append(_label)
865f9996aaSopenharmony_ci        if _ninja_rule.startswith('subninja '):
875f9996aaSopenharmony_ci            sbuninja_file = _ninja_rule[len('subninja '):]
885f9996aaSopenharmony_ci            subninja_target_info = _read_subninja_build(
895f9996aaSopenharmony_ci                build_dir, sbuninja_file)
905f9996aaSopenharmony_ci            if subninja_target_info:
915f9996aaSopenharmony_ci                subninja_targets.update(subninja_target_info)
925f9996aaSopenharmony_ci    build_phony_targets = _parse_target_label(build_label_list, toolchain_name)
935f9996aaSopenharmony_ci    build_phony_targets.update(subninja_targets)
945f9996aaSopenharmony_ci    return build_phony_targets
955f9996aaSopenharmony_ci
965f9996aaSopenharmony_ci
975f9996aaSopenharmony_cidef _read_variants_toolchain_info(variants_toolchain_info_file: str):
985f9996aaSopenharmony_ci    if not os.path.exists(variants_toolchain_info_file):
995f9996aaSopenharmony_ci        raise Exception(
1005f9996aaSopenharmony_ci            "file '{}' doesn't exist.".format(variants_toolchain_info_file))
1015f9996aaSopenharmony_ci    variants_toolchain_info = read_json_file(variants_toolchain_info_file)
1025f9996aaSopenharmony_ci    if variants_toolchain_info is None:
1035f9996aaSopenharmony_ci        raise Exception(
1045f9996aaSopenharmony_ci            "read file '{}' failed.".format(variants_toolchain_info_file))
1055f9996aaSopenharmony_ci    platform_toolchain = variants_toolchain_info.get('platform_toolchain')
1065f9996aaSopenharmony_ci    return platform_toolchain
1075f9996aaSopenharmony_ci
1085f9996aaSopenharmony_ci
1095f9996aaSopenharmony_cidef _read_build_ninja(build_ninja_file: str):
1105f9996aaSopenharmony_ci    if not os.path.exists(build_ninja_file):
1115f9996aaSopenharmony_ci        raise Exception("file '{}' doesn't exist.".format(build_ninja_file))
1125f9996aaSopenharmony_ci    ninja_targets = read_file(build_ninja_file)
1135f9996aaSopenharmony_ci    if ninja_targets is None:
1145f9996aaSopenharmony_ci        raise Exception("read file '{}' failed.".format(build_ninja_file))
1155f9996aaSopenharmony_ci    return ninja_targets
1165f9996aaSopenharmony_ci
1175f9996aaSopenharmony_ci
1185f9996aaSopenharmony_cidef generate_phony_targets(build_dir: str, toolchain_ninja_file: str, platform: str,
1195f9996aaSopenharmony_ci                           toolchain_name: str, default_targets_name: str):
1205f9996aaSopenharmony_ci    build_phony_targets = _read_toolchain_ninja(build_dir,
1215f9996aaSopenharmony_ci                                                toolchain_ninja_file,
1225f9996aaSopenharmony_ci                                                toolchain_name)
1235f9996aaSopenharmony_ci    targets_list = []
1245f9996aaSopenharmony_ci    for key, build_label in build_phony_targets.items():
1255f9996aaSopenharmony_ci        targets_list.append('build {}/{}: phony {}'.format(
1265f9996aaSopenharmony_ci            platform, key, build_label))
1275f9996aaSopenharmony_ci
1285f9996aaSopenharmony_ci    _diff_targets = set(default_targets_name).difference(
1295f9996aaSopenharmony_ci        set(build_phony_targets.keys()))
1305f9996aaSopenharmony_ci    for _diff_target in _diff_targets:
1315f9996aaSopenharmony_ci        targets_list.append('build {}/{}: phony {}'.format(
1325f9996aaSopenharmony_ci            platform, _diff_target, _diff_target))
1335f9996aaSopenharmony_ci    build_file = os.path.join(os.path.dirname(toolchain_ninja_file),
1345f9996aaSopenharmony_ci                              '{}_build.ninja'.format(platform))
1355f9996aaSopenharmony_ci    write_file(build_file, '{}\n\n'.format('\n'.join(targets_list)))
1365f9996aaSopenharmony_ci    return build_file
1375f9996aaSopenharmony_ci
1385f9996aaSopenharmony_ci
1395f9996aaSopenharmony_cidef _update_build_ninja(build_dir: str, include_files: str):
1405f9996aaSopenharmony_ci    try:
1415f9996aaSopenharmony_ci        ninja_build_file = os.path.join(build_dir, 'build.ninja')
1425f9996aaSopenharmony_ci        if not os.path.exists(ninja_build_file):
1435f9996aaSopenharmony_ci            raise Exception(
1445f9996aaSopenharmony_ci                "file '{}' doesn't exist.".format(ninja_build_file))
1455f9996aaSopenharmony_ci        with open(ninja_build_file, 'a+') as _file:
1465f9996aaSopenharmony_ci            data = []
1475f9996aaSopenharmony_ci            for line in _file.readlines():
1485f9996aaSopenharmony_ci                _line = line.rstrip('\n')
1495f9996aaSopenharmony_ci                if _line.startswith('subninja '):
1505f9996aaSopenharmony_ci                    data.append(_line)
1515f9996aaSopenharmony_ci            for include_file in include_files:
1525f9996aaSopenharmony_ci                include_info = 'subninja {}'.format(
1535f9996aaSopenharmony_ci                    os.path.relpath(include_file, build_dir))
1545f9996aaSopenharmony_ci                if include_info in data:
1555f9996aaSopenharmony_ci                    continue
1565f9996aaSopenharmony_ci                _file.write('{}\n'.format(include_info))
1575f9996aaSopenharmony_ci            _file.flush()
1585f9996aaSopenharmony_ci    except: # noqa E722
1595f9996aaSopenharmony_ci        raise
1605f9996aaSopenharmony_ci
1615f9996aaSopenharmony_ci
1625f9996aaSopenharmony_cidef update(build_dir: str, variants_toolchain_info_file: str):
1635f9996aaSopenharmony_ci    variants_toolchain_info_file = os.path.join(build_dir,
1645f9996aaSopenharmony_ci                                                variants_toolchain_info_file)
1655f9996aaSopenharmony_ci    platform_toolchain = _read_variants_toolchain_info(
1665f9996aaSopenharmony_ci        variants_toolchain_info_file)
1675f9996aaSopenharmony_ci
1685f9996aaSopenharmony_ci    ninja_build_file = os.path.join(build_dir, 'build.ninja')
1695f9996aaSopenharmony_ci    default_ninja_targets = _read_build_ninja(ninja_build_file)
1705f9996aaSopenharmony_ci    default_targets_name = []
1715f9996aaSopenharmony_ci    for _ninja_target in default_ninja_targets:
1725f9996aaSopenharmony_ci        if not _ninja_target.startswith('build '):
1735f9996aaSopenharmony_ci            continue
1745f9996aaSopenharmony_ci        _ninja_target = _ninja_target.split(': ')[0]
1755f9996aaSopenharmony_ci        default_targets_name.append(_ninja_target[len('build '):])
1765f9996aaSopenharmony_ci
1775f9996aaSopenharmony_ci    include_files = []
1785f9996aaSopenharmony_ci    for platform, toolchain_label in platform_toolchain.items():
1795f9996aaSopenharmony_ci        if platform == 'phone':
1805f9996aaSopenharmony_ci            continue
1815f9996aaSopenharmony_ci        toolchain_name = toolchain_label.split(':')[1]
1825f9996aaSopenharmony_ci        toolchain_ninja_file = os.path.join(build_dir, toolchain_name,
1835f9996aaSopenharmony_ci                                            'toolchain.ninja')
1845f9996aaSopenharmony_ci        if not os.path.exists(toolchain_ninja_file):
1855f9996aaSopenharmony_ci            continue
1865f9996aaSopenharmony_ci        _build_file = generate_phony_targets(build_dir, toolchain_ninja_file,
1875f9996aaSopenharmony_ci                                             platform, toolchain_name,
1885f9996aaSopenharmony_ci                                             default_targets_name)
1895f9996aaSopenharmony_ci        include_files.append(_build_file)
1905f9996aaSopenharmony_ci    _update_build_ninja(build_dir, include_files)
1915f9996aaSopenharmony_ci
1925f9996aaSopenharmony_ci
1935f9996aaSopenharmony_cidef main():
1945f9996aaSopenharmony_ci    parser = argparse.ArgumentParser()
1955f9996aaSopenharmony_ci    parser.add_argument('--source-root-dir', required=True)
1965f9996aaSopenharmony_ci    parser.add_argument('--root-build-dir', required=True)
1975f9996aaSopenharmony_ci    parser.add_argument('--variants-toolchain-info-file', required=True)
1985f9996aaSopenharmony_ci    args = parser.parse_args()
1995f9996aaSopenharmony_ci
2005f9996aaSopenharmony_ci    source_root_dir = args.source_root_dir
2015f9996aaSopenharmony_ci    if not os.path.exists(os.path.join(source_root_dir, '.gn')):
2025f9996aaSopenharmony_ci        print('source root dir incorrect.')
2035f9996aaSopenharmony_ci        return 1
2045f9996aaSopenharmony_ci    build_dir = os.path.join(source_root_dir, args.root_build_dir)
2055f9996aaSopenharmony_ci    update(build_dir, args.variants_toolchain_info_file)
2065f9996aaSopenharmony_ci    return 0
2075f9996aaSopenharmony_ci
2085f9996aaSopenharmony_ci
2095f9996aaSopenharmony_ciif __name__ == '__main__':
2105f9996aaSopenharmony_ci    sys.exit(main())
211