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