1#!/usr/bin/env python3 2# encoding=utf-8 3# ========================================================================= 4# @brief Project genarator, parse compiler info & generate IAR/Makefile... project file 5 6# Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED. 7# Licensed under the Apache License, Version 2.0 (the "License"); 8# you may not use this file except in compliance with the License. 9# You may obtain a copy of the License at 10# 11# http://www.apache.org/licenses/LICENSE-2.0 12# 13# Unless required by applicable law or agreed to in writing, software 14# distributed under the License is distributed on an "AS IS" BASIS, 15# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16# See the License for the specific language governing permissions and 17# limitations under the License. 18# ========================================================================= 19 20import copy 21import os 22import json 23import re 24import shutil 25import sys 26 27script_dir = os.path.split(os.path.normpath(__file__))[0] 28makefile_template = os.path.join(script_dir, "sdk_template", "makefile") 29 30def load_json(json_file): 31 with open(json_file, 'r') as f: 32 temp = f.read() 33 return json.loads(temp) 34 35class CompileCommandParser: 36 def __init__(self, cc_file): 37 temp = load_json(cc_file) 38 self.compile_info = {} 39 for item in temp: 40 self.compile_info[item['file']] = { 41 'command': item['command'], 42 'directory': item['directory'], 43 } 44 45 def get_src_compile_info(self, src_name): 46 command = self.compile_info[src_name]['command'] 47 defines = re.findall(r"-D([^ ]*)", command) 48 includes = re.findall(r"-I([^ ]*)", command) 49 50 ccflags = list(set(re.findall(r" (-[^ID][^ ]*)", command))) 51 ccflags.remove('-c') 52 ccflags.remove('-o') 53 pre_include = [] 54 if '-include' in ccflags: 55 ccflags.remove('-include') 56 pre_include = list(set(re.findall(r" -include ([^ ]*)", command))) 57 ccflags.extend(['-include ' + x for x in pre_include]) 58 return { 59 "DEFINES": list(set(defines)), 60 "INCLUDES": list(set(includes)), 61 "CCFLAGS": ccflags, 62 "PRE_INCLUDE": pre_include, 63 } 64 65class ComponentParser(CompileCommandParser): 66 def __init__(self, component_info_file, compile_command_file): 67 super(ComponentParser, self).__init__(compile_command_file) 68 with open(component_info_file, 'r') as fp: 69 data = fp.read() 70 data = data.replace('="', r'=\\\"') 71 data = data.replace('";', r'\\\";') 72 data = data.replace(r' \\\";', r' ";') 73 info = json.loads(data) 74 self.component_info = info.pop("COMPONENTS") 75 self.public_info = copy.deepcopy(info) 76 self.public_info["COMPONENT_LIST"] = list(self.component_info.keys()) 77 self.public_info["CHIP"] = chip 78 self.public_info["CORE"] = core 79 self.public_info["ARCH"] = arch 80 self.public_info["TARGET_NAME"] = application_name 81 self.public_info["PKG_TARGET_NAME"] = pkg_target_name 82 for item, value in self.public_info.items(): 83 if isinstance(value, str): 84 self.public_info[item] = [i for i in value.split(";") if i != ''] 85 for component, value in self.component_info.items(): 86 if not value["SOURCES"]: 87 continue 88 89 for component_items in value: 90 if isinstance(value[component_items], str): 91 value[component_items] = [i for i in value[component_items].split(";") if i != ''] 92 src = value["SOURCES"] 93 94class MakefileGenerator(ComponentParser): 95 def __init__(self, component_info_file, compile_command_file, project_file_dir, project_folder): 96 super(MakefileGenerator, self).__init__(component_info_file, compile_command_file) 97 self.replace_map = {} 98 # self.replace_map.update(toolchain) 99 self.project_file_dir = project_file_dir 100 self.project_folder = project_folder 101 self.make_dir = os.path.join(project_file_dir, project_folder, 'makefile') 102 if not os .path.exists(self.make_dir): 103 os.makedirs(self.make_dir) 104 self.gen_toolchain_file() 105 for component_name in self.component_info: 106 self.gen_component_file(component_name) 107 self.gen_root_file() 108 self.gen_makefile_cmd() 109 110 def gen_makefile_cmd(self): 111 with open(os.path.join(sdk_output_dir, f'make.cmd'), 'a+') as f: 112 f.writelines(self.make_dir + '\n') 113 114 def gen_toolchain_file(self): 115 with open(os.path.join(makefile_template, 'toolchain.make'), 'r') as f: 116 lines = f.readlines() 117 toolchain = load_json(toolchain_file) 118 for i, line in enumerate(lines): 119 lines[i] = self.deal_replace(line, toolchain) 120 with open(os.path.join(self.make_dir, f'toolchains.make'), 'w') as f: 121 f.writelines(lines) 122 123 def gen_component_file(self, component_name): 124 compile_info = self.component_info[component_name] 125 template = os.path.join(makefile_template, 'component_template.make') 126 out_path = 'components' 127 if "THIRD_PARTY" in compile_info: 128 print(compile_info["SOURCES"]) 129 if "THIRD_PARTY" in compile_info and compile_info["THIRD_PARTY"][0] == "true": 130 template = os.path.join(makefile_template, 'third_party_template.make') 131 index = compile_info['COMPONENT_CUSTOM_CCFLAGS'].index("-include") 132 if index >= 0: 133 compile_info['COMPONENT_CUSTOM_CCFLAGS'][index] = "-include$(LITEOS_PLATFORM_MENUCONFIG_H)" 134 compile_info['COMPONENT_CUSTOM_CCFLAGS'].pop(index+1) 135 compile_info["COMPONENT_NAME"] = component_name 136 with open(template, 'r') as f: 137 lines = f.readlines() 138 for i, line in enumerate(lines): 139 lines[i] = self.deal_replace(line, compile_info) 140 if not os.path.exists(os.path.join(self.make_dir, out_path)): 141 os.makedirs(os.path.join(self.make_dir, out_path)) 142 with open(os.path.join(self.make_dir, out_path, f'{component_name}.make'), 'w') as f: 143 f.writelines(lines) 144 145 def gen_root_file(self): 146 with open(os.path.join(makefile_template, 'template.mk'), 'r') as f: 147 lines = f.readlines() 148 for i, line in enumerate(lines): 149 lines[i] = self.deal_replace(line, self.public_info) 150 # if not os.path.exists(os.path.join(self.make_dir, 'components')): 151 # os.makedirs(os.path.join(self.make_dir, 'components')) 152 with open(os.path.join(self.make_dir, 'Makefile'), 'w') as f: 153 f.writelines(lines) 154 155 def join_by_clum_num(self, lst, word, clum_num): 156 res = [] 157 if not lst: 158 return res 159 c_word = lst[0] 160 for item in lst: 161 if item == "": 162 continue 163 if c_word == 0: 164 c_word = item 165 continue 166 if len(c_word) + len(word) + len(item) <= clum_num: 167 c_word = f"{c_word}{word}{item}" 168 continue 169 res.append(c_word) 170 c_word = item 171 return res 172 173 def deal_replace(self, line, replace_map): 174 l = re.findall("REPLACE_(\w*)", line) 175 for item in l: 176 if isinstance(replace_map[item], list): 177 replace_str = " \\\n ".join(replace_map[item]) 178 if replace_str: 179 replace_str = " \\\n %s" % (replace_str.strip()) 180 replace_str = replace_str.replace(root_dir, "$(SDK_ROOT)") 181 elif isinstance(replace_map[item], str): 182 replace_str = replace_map[item].replace(root_dir, "$(SDK_ROOT)") 183 else: 184 print(replace_map[item]) 185 line = line.replace(f"REPLACE_{item}", replace_str) 186 return line 187 188if __name__ == "__main__": 189 project_type = sys.argv[1] 190 application_name = sys.argv[2] 191 cc_json = sys.argv[3] 192 project_file_dir = sys.argv[4] 193 root_dir = sys.argv[5] 194 sdk_output_dir = sys.argv[6] 195 chip, core, board, arch, os_kernel, pkg_target_name = sys.argv[7].split(",") 196 toolchain_file = sys.argv[8] 197 component_info_file = sys.argv[9] 198 project_folder = f"{chip}_{core}_{board}_{os_kernel}_{pkg_target_name}" 199 project_type_list = project_type.split(",") 200 if 'makefile' in project_type_list: 201 MakefileGenerator(component_info_file, cc_json, project_file_dir, project_folder) 202