• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 os
18import argparse
19
20sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
21from scripts.util.file_utils import read_json_file, read_file, write_file  # noqa: E402 E501
22
23
24def _read_subninja_build(build_dir, subninja_build_file):
25    subninja_build_file = os.path.join(build_dir, subninja_build_file)
26    if not os.path.exists(subninja_build_file):
27        raise Exception("file '{}' doesn't exist.".format(subninja_build_file))
28    subninja_build = read_file(subninja_build_file)
29    if subninja_build is None:
30        raise Exception("read file '{}' failed.".format(subninja_build_file))
31    support_lib_type = ['.a', '.so', '']
32    label_name = ''
33    label_target = ''
34    for _line in subninja_build:
35        if _line.startswith('label_name = '):
36            label_name = _line[len('label_name = '):]
37        elif _line.startswith('build '):
38            _build_info = _line.split(':')[0]
39            build_label = _build_info.split(' ')[1]
40            _, extension = os.path.splitext(build_label)
41            if extension in support_lib_type:
42                label_target = build_label
43
44    if label_target != '':
45        if label_name == '':
46            target_filename = os.path.basename(label_target)
47            label_name, _ = os.path.splitext(target_filename)
48        return {label_name: label_target}
49    return None
50
51
52def _parse_target_label(build_label_list, toolchain_name):
53    phony_targets_dict = {}
54    for build_label in build_label_list:
55        target_filename = os.path.basename(build_label)
56        label_name, _ = os.path.splitext(target_filename)
57        if label_name:
58            phony_targets_dict[label_name] = build_label
59            start_index = len('{}/obj/'.format(toolchain_name))
60        _path = os.path.dirname(build_label)[start_index:]
61        if _path:
62            phony_targets_dict[_path] = build_label
63        if label_name and _path:
64            _label_path = '{}$:{}'.format(_path, label_name)
65            phony_targets_dict[_label_path] = build_label
66    return phony_targets_dict
67
68
69def _read_toolchain_ninja(build_dir, toolchain_ninja_file, toolchain_name):
70    if not os.path.exists(toolchain_ninja_file):
71        raise Exception(
72            "file '{}' doesn't exist.".format(toolchain_ninja_file))
73    toolchain_ninja_rules = read_file(toolchain_ninja_file)
74    if toolchain_ninja_rules is None:
75        raise Exception("read file '{}' failed.".format(toolchain_ninja_file))
76
77    build_label_list = []
78    subninja_targets = {}
79    for _ninja_rule in toolchain_ninja_rules:
80        if _ninja_rule.startswith('build '):
81            _tmp = _ninja_rule.split(':')[0]
82            _label = _tmp[len('build '):]
83            if not _label.endswith('.stamp'):
84                continue
85            build_label_list.append(_label)
86        if _ninja_rule.startswith('subninja '):
87            sbuninja_file = _ninja_rule[len('subninja '):]
88            subninja_target_info = _read_subninja_build(
89                build_dir, sbuninja_file)
90            if subninja_target_info:
91                subninja_targets.update(subninja_target_info)
92    build_phony_targets = _parse_target_label(build_label_list, toolchain_name)
93    build_phony_targets.update(subninja_targets)
94    return build_phony_targets
95
96
97def _read_variants_toolchain_info(variants_toolchain_info_file):
98    if not os.path.exists(variants_toolchain_info_file):
99        raise Exception(
100            "file '{}' doesn't exist.".format(variants_toolchain_info_file))
101    variants_toolchain_info = read_json_file(variants_toolchain_info_file)
102    if variants_toolchain_info is None:
103        raise Exception(
104            "read file '{}' failed.".format(variants_toolchain_info_file))
105    platform_toolchain = variants_toolchain_info.get('platform_toolchain')
106    return platform_toolchain
107
108
109def _read_build_ninja(build_ninja_file):
110    if not os.path.exists(build_ninja_file):
111        raise Exception("file '{}' doesn't exist.".format(build_ninja_file))
112    ninja_targets = read_file(build_ninja_file)
113    if ninja_targets is None:
114        raise Exception("read file '{}' failed.".format(build_ninja_file))
115    return ninja_targets
116
117
118def generate_phony_targets(build_dir, toolchain_ninja_file, platform,
119                           toolchain_name, default_targets_name):
120    build_phony_targets = _read_toolchain_ninja(build_dir,
121                                                toolchain_ninja_file,
122                                                toolchain_name)
123    targets_list = []
124    for key, build_label in build_phony_targets.items():
125        targets_list.append('build {}/{}: phony {}'.format(
126            platform, key, build_label))
127
128    _diff_targets = set(default_targets_name).difference(
129        set(build_phony_targets.keys()))
130    for _diff_target in _diff_targets:
131        targets_list.append('build {}/{}: phony {}'.format(
132            platform, _diff_target, _diff_target))
133    build_file = os.path.join(os.path.dirname(toolchain_ninja_file),
134                              '{}_build.ninja'.format(platform))
135    write_file(build_file, '{}\n\n'.format('\n'.join(targets_list)))
136    return build_file
137
138
139def _update_build_ninja(build_dir, include_files):
140    try:
141        ninja_build_file = os.path.join(build_dir, 'build.ninja')
142        if not os.path.exists(ninja_build_file):
143            raise Exception(
144                "file '{}' doesn't exist.".format(ninja_build_file))
145        with open(ninja_build_file, 'a+') as _file:
146            data = []
147            for line in _file.readlines():
148                _line = line.rstrip('\n')
149                if _line.startswith('subninja '):
150                    data.append(_line)
151            for include_file in include_files:
152                include_info = 'subninja {}'.format(
153                    os.path.relpath(include_file, build_dir))
154                if include_info in data:
155                    continue
156                _file.write('{}\n'.format(include_info))
157            _file.flush()
158    except: # noqa E722
159        raise
160
161
162def update(build_dir, variants_toolchain_info_file):
163    variants_toolchain_info_file = os.path.join(build_dir,
164                                                variants_toolchain_info_file)
165    platform_toolchain = _read_variants_toolchain_info(
166        variants_toolchain_info_file)
167
168    ninja_build_file = os.path.join(build_dir, 'build.ninja')
169    default_ninja_targets = _read_build_ninja(ninja_build_file)
170    default_targets_name = []
171    for _ninja_target in default_ninja_targets:
172        if not _ninja_target.startswith('build '):
173            continue
174        _ninja_target = _ninja_target.split(': ')[0]
175        default_targets_name.append(_ninja_target[len('build '):])
176
177    include_files = []
178    for platform, toolchain_label in platform_toolchain.items():
179        if platform == 'phone':
180            continue
181        toolchain_name = toolchain_label.split(':')[1]
182        toolchain_ninja_file = os.path.join(build_dir, toolchain_name,
183                                            'toolchain.ninja')
184        if not os.path.exists(toolchain_ninja_file):
185            continue
186        _build_file = generate_phony_targets(build_dir, toolchain_ninja_file,
187                                             platform, toolchain_name,
188                                             default_targets_name)
189        include_files.append(_build_file)
190    _update_build_ninja(build_dir, include_files)
191
192
193def main():
194    parser = argparse.ArgumentParser()
195    parser.add_argument('--source-root-dir', required=True)
196    parser.add_argument('--root-build-dir', required=True)
197    parser.add_argument('--variants-toolchain-info-file', required=True)
198    args = parser.parse_args()
199
200    source_root_dir = args.source_root_dir
201    if not os.path.exists(os.path.join(source_root_dir, '.gn')):
202        print('source root dir incorrect.')
203        return 1
204    build_dir = os.path.join(source_root_dir, args.root_build_dir)
205    update(build_dir, args.variants_toolchain_info_file)
206    return 0
207
208
209if __name__ == '__main__':
210    sys.exit(main())
211