init
Embed:
(wiki syntax)
Show/hide line numbers
__init__.py
00001 import os 00002 import copy 00003 00004 from os.path import relpath, join, exists, dirname, basename 00005 from os import makedirs 00006 from json import load 00007 00008 from tools.export.exporters import Exporter, apply_supported_whitelist 00009 from tools.targets import TARGET_MAP 00010 from tools.utils import NotSupportedException 00011 from tools.build_api import prepare_toolchain 00012 00013 POST_BINARY_WHITELIST = set([ 00014 "TEENSY3_1Code.binary_hook", 00015 "MCU_NRF51Code.binary_hook", 00016 "LPCTargetCode.lpc_patch", 00017 "LPC4088Code.binary_hook" 00018 ]) 00019 00020 00021 class GNUARMNetbeans(Exporter): 00022 NAME = 'GNU ARM Netbeans' 00023 TOOLCHAIN = 'GCC_ARM' 00024 00025 @classmethod 00026 def is_target_supported(cls, target_name): 00027 target = TARGET_MAP[target_name] 00028 return apply_supported_whitelist( 00029 cls.TOOLCHAIN, POST_BINARY_WHITELIST, target) 00030 00031 @staticmethod 00032 def prepare_sys_lib(libname): 00033 return "-l" + libname 00034 00035 def toolchain_flags(self, toolchain): 00036 """Returns a dictionary of toolchain flags. 00037 Keys of the dictionary are: 00038 cxx_flags - c++ flags 00039 c_flags - c flags 00040 ld_flags - linker flags 00041 asm_flags - assembler flags 00042 common_flags - common options 00043 00044 The difference from the above is that it takes a parameter. 00045 """ 00046 00047 # Note: use the config options from the currently selected toolchain. 00048 config_header = self.toolchain.get_config_header() 00049 00050 flags = {key + "_flags": copy.deepcopy(value) for key, value 00051 in toolchain.flags.iteritems()} 00052 if config_header: 00053 config_header = relpath(config_header, 00054 self.resources.file_basepath[config_header]) 00055 header_options = self.toolchain.get_config_option(config_header) 00056 flags['c_flags'] += header_options 00057 flags['cxx_flags'] += header_options 00058 return flags 00059 00060 @staticmethod 00061 def get_defines_and_remove_from_flags(flags_in, str_key): 00062 defines = [] 00063 flags_temp = copy.deepcopy(flags_in) 00064 for f in flags_temp[str_key]: 00065 f = f.strip() 00066 if f.startswith('-D'): 00067 defines.append(f[2:]) 00068 flags_in[str_key].remove(f) 00069 00070 return defines 00071 00072 @staticmethod 00073 def get_includes_and_remove_from_flags(flags_in, str_key): 00074 includes = [] 00075 flags_temp = copy.deepcopy(flags_in) 00076 next_is_include = False 00077 for f in flags_temp[str_key]: 00078 f = f.strip() 00079 if next_is_include: 00080 includes.append(f) 00081 flags_in[str_key].remove(f) 00082 next_is_include = False 00083 continue 00084 if f == "-include": 00085 flags_in[str_key].remove(f) 00086 next_is_include = True 00087 00088 return includes 00089 00090 @staticmethod 00091 def get_c_std_and_remove_from_flag(flags_in, str_key): 00092 comp_std = '' 00093 c_std = { 00094 'c90': 'c90', 'c89': 'c90', 'gnu90': 'gnu90', 'gnu89': 'gnu90', 00095 'c99': 'c99', 'c9x': 'c99', 'gnu99': 'gnu99', 'gnu9x': 'gnu98', 00096 'c11': 'c11', 'c1x': 'c11', 'gnu11': 'gnu11', 'gnu1x': 'gnu11' 00097 } 00098 cpp_std = { 00099 'c++98': 'cpp98', 'c++03': 'cpp98', 00100 'gnu++98': 'gnucpp98', 'gnu++03': 'gnucpp98', 00101 'c++0x': 'cpp0x', 'gnu++0x': 'gnucpp0x', 00102 'c++11': 'cpp11', 'gnu++11': 'gnucpp11', 00103 'c++1y': 'cpp1y', 'gnu++1y': 'gnucpp1y', 00104 'c++14': 'cpp14', 'gnu++14': 'gnucpp14', 00105 'c++1z': 'cpp1z', 'gnu++1z': 'gnucpp1z', 00106 } 00107 00108 flags_temp = copy.deepcopy(flags_in) 00109 for f in flags_temp[str_key]: 00110 f = f.strip() 00111 if f.startswith('-std='): 00112 comp_std = f[len('-std='):] 00113 flags_in[str_key].remove(f) 00114 elif f.startswith('-'): 00115 std = f[len('-'):] 00116 if std in c_std or std in cpp_std: 00117 comp_std = std 00118 flags_in[str_key].remove(f) 00119 return comp_std 00120 00121 def validate_resources(self): 00122 if not self.resources.linker_script: 00123 raise NotSupportedException("No linker script found.") 00124 00125 def create_jinja_ctx(self): 00126 self.options = {} 00127 flags = {} 00128 self.validate_resources() 00129 # Convert all Backslashes to Forward Slashes 00130 self.resources.win_to_unix() 00131 00132 print 'Include folders: {0}'.format(len(self.resources.inc_dirs)) 00133 00134 print 'Symbols: {0}'.format(len(self.toolchain.get_symbols())) 00135 00136 self.ld_script = self.filter_dot( 00137 self.resources.linker_script) 00138 print 'Linker script: {0}'.format(self.ld_script) 00139 00140 # Read in all profiles, we'll extract compiler options. 00141 profiles = self.get_all_profiles() 00142 00143 profile_ids = [s.lower() for s in profiles] 00144 profile_ids.sort() 00145 for prof_id in profile_ids: 00146 # There are 4 categories of options, a category common too 00147 # all tools and a specific category for each of the tools. 00148 opts = {} 00149 opts['defines'] = {} 00150 opts['common'] = {} 00151 opts['as'] = {} 00152 opts['c'] = {} 00153 opts['cpp'] = {} 00154 opts['ld'] = {} 00155 00156 opts['id'] = prof_id 00157 opts['name'] = opts['id'].capitalize() 00158 00159 print 00160 print 'Build configuration: {0}'.format(opts['name']) 00161 00162 profile = profiles[prof_id] 00163 00164 # A small hack, do not bother with src_path again, 00165 # pass an empty string to avoid crashing. 00166 src_paths = [''] 00167 target_name = self.toolchain.target.name 00168 00169 toolchain = prepare_toolchain( 00170 src_paths, "", target_name, self.TOOLCHAIN, build_profile=[profile]) 00171 00172 flags = self.toolchain_flags(toolchain) 00173 00174 print 'Common flags:', ' '.join(flags['common_flags']) 00175 print 'C++ flags:', ' '.join(flags['cxx_flags']) 00176 print 'C flags:', ' '.join(flags['c_flags']) 00177 print 'ASM flags:', ' '.join(flags['asm_flags']) 00178 print 'Linker flags:', ' '.join(flags['ld_flags']) 00179 00180 opts['defines'] = self.get_defines_and_remove_from_flags(flags, 'common_flags') 00181 opts['forced_includes'] = self.get_includes_and_remove_from_flags(flags, 'common_flags') 00182 opts['common'] = flags['common_flags'] 00183 opts['as'] = flags['asm_flags'] 00184 opts['c'] = flags['c_flags'] 00185 opts['cpp'] = flags['cxx_flags'] 00186 opts['ld'] = flags['ld_flags'] 00187 00188 self.options[prof_id] = opts 00189 00190 sources = [] # list of strings 00191 00192 forced_includes = self.get_includes_and_remove_from_flags(flags, 'c_flags') 00193 forced_includes += self.get_includes_and_remove_from_flags(flags, 'cxx_flags') 00194 00195 # Remove Duplicates 00196 forced_includes = list(set(forced_includes)) 00197 00198 c_std = self.get_c_std_and_remove_from_flag(flags, 'c_flags') 00199 cpp_std = self.get_c_std_and_remove_from_flag(flags, 'cxx_flags') 00200 00201 # Make one list of all resources 00202 for r_type in ['c_sources', 's_sources', 'cpp_sources']: 00203 sources.extend(getattr(self.resources, r_type)) 00204 00205 # Remove all leading './' 00206 c_sources = [self.filter_dot(field) for field in self.resources.c_sources] 00207 cpp_sources = [self.filter_dot(field) for field in self.resources.cpp_sources] 00208 s_sources = [self.filter_dot(field) for field in self.resources.s_sources] 00209 headers = [self.filter_dot(field) for field in self.resources.headers] 00210 sources = [self.filter_dot(field) for field in sources] 00211 include_paths = [self.filter_dot(field) for field in self.resources.inc_dirs] 00212 00213 sys_libs = [self.prepare_sys_lib(lib) for lib 00214 in self.toolchain.sys_libs] 00215 preproc = " ".join([basename(self.toolchain.preproc[0])] + 00216 self.toolchain.preproc[1:] + 00217 self.toolchain.ld[1:]) 00218 00219 if 'nbproject' in include_paths: 00220 include_paths.remove('nbproject') 00221 00222 jinja_ctx = { 00223 'name': self.project_name, 00224 'target': self.toolchain.target.name, 00225 'elf_location': join('BUILD', self.project_name) + '.elf', 00226 'c_symbols': self.toolchain.get_symbols(), 00227 'asm_symbols': self.toolchain.get_symbols(True), 00228 'c_flags': flags['c_flags'], 00229 'cxx_flags': flags['cxx_flags'], 00230 'ld_flags': self.flags['ld_flags'], 00231 'asm_flags': self.flags['asm_flags'], 00232 'common_flags': self.flags['common_flags'], 00233 'include_paths': include_paths, 00234 'forced_includes': forced_includes, 00235 'c_sources': c_sources, 00236 'cpp_sources': cpp_sources, 00237 's_sources': s_sources, 00238 'headers': headers, 00239 'headers_folder': self.get_netbeans_file_list(sorted(headers)), 00240 'sources_folder': self.get_netbeans_file_list(sorted(sources)), 00241 'options': self.options, 00242 'c_std': self.get_netbeans_c_std(c_std), 00243 'cpp_std': self.get_netbeans_cpp_std(cpp_std), 00244 'linker_script': self.ld_script, 00245 'linker_libs': sys_libs, 00246 'pp_cmd': preproc, 00247 'cc_cmd': self.toolchain.cc[0], 00248 'cppc_cmd': self.toolchain.cppc[0], 00249 'asm_cmd': self.toolchain.asm[0], 00250 'ld_cmd': self.toolchain.ld[0], 00251 'elf2bin_cmd': self.toolchain.elf2bin 00252 } 00253 return jinja_ctx 00254 00255 def generate(self): 00256 """Generate Makefile, configurations.xml & project.xml Netbeans project file 00257 """ 00258 jinja_ctx = self.create_jinja_ctx() 00259 00260 print 00261 print 'Create a GNU ARM Netbeans C++ managed project' 00262 print 'Project name: {0}'.format(self.project_name) 00263 print 'Target: {0}'.format(self.toolchain.target.name) 00264 print 'Toolchain: {0}'.format(self.TOOLCHAIN) 00265 00266 if not exists(join(self.export_dir, 'nbproject')): 00267 makedirs(join(self.export_dir, 'nbproject')) 00268 00269 self.gen_file('nb/configurations.tmpl', jinja_ctx, 'nbproject/configurations.xml') 00270 self.gen_file('nb/project.tmpl', jinja_ctx, 'nbproject/project.xml') 00271 self.gen_file('nb/mbedignore.tmpl', jinja_ctx, '.mbedignore') 00272 self.gen_file('nb/Makefile.tmpl', jinja_ctx, 'Makefile') 00273 00274 print 00275 print 'Done. Import the \'{0}\' project in Netbeans.'.format(self.project_name) 00276 00277 # ------------------------------------------------------------------------- 00278 00279 @staticmethod 00280 def filter_dot(str_in): 00281 """ 00282 Remove the './' prefix, if present. 00283 This function assumes that resources.win_to_unix() 00284 replaced all windows backslashes with slashes. 00285 """ 00286 if str_in is None: 00287 return None 00288 if str_in[:2] == './': 00289 return str_in[2:] 00290 return str_in 00291 00292 # ------------------------------------------------------------------------- 00293 00294 @staticmethod 00295 def get_all_profiles(): 00296 tools_path = dirname(dirname(dirname(__file__))) 00297 file_names = [join(tools_path, "profiles", fn) for fn in os.listdir( 00298 join(tools_path, "profiles")) if fn.endswith(".json")] 00299 00300 profiles = {} 00301 00302 for fn in file_names: 00303 content = load(open(fn)) 00304 profile_name = basename(fn).replace(".json", "") 00305 profiles[profile_name] = content 00306 00307 return profiles 00308 00309 @staticmethod 00310 def get_netbeans_file_list(file_list): 00311 cur_dir = '' 00312 prev_dir = '' 00313 output = [] 00314 folder_count = 1 00315 dir_depth = 0 00316 for item in file_list: 00317 cur_dir = os.path.dirname(item) 00318 dir_temp = os.path.normpath(cur_dir) 00319 prev_dir_temp = os.path.normpath(prev_dir) 00320 dir_list = dir_temp.split(os.sep) 00321 prev_dir_list = prev_dir_temp.split(os.sep) 00322 dir_depth = len(dir_list) 00323 00324 # Current File is in Directory: Compare the given dir with previous Dir 00325 if cur_dir and prev_dir != cur_dir: 00326 # evaluate all matched items (from current and previous list) 00327 matched = [] 00328 # Compare the Element in Previous Dir with the Elements in Current Dir 00329 # and add the equal Elements to the match-List 00330 for elem_prev_dir, elem_cur_dir in zip(prev_dir_list, dir_list): 00331 if elem_prev_dir == elem_cur_dir: 00332 matched.append(elem_cur_dir) 00333 00334 # calculate difference between matched and length 00335 diff = dir_depth - len(matched) 00336 00337 # if previous dir was not root 00338 if prev_dir != '': 00339 # if the elements count is not equal we calculate the difference 00340 if len(dir_list) != len(prev_dir_list): 00341 dir_depth_prev = len(prev_dir_list) 00342 delta = dir_depth_prev - len(matched) 00343 00344 for i in range(dir_depth_prev - delta, dir_depth_prev): 00345 output.append('</logicalFolder>') 00346 00347 # if the elements count is equal, we subtract the matched length from the total length 00348 else: 00349 for i in range(len(matched), len(dir_list)): 00350 output.append('</logicalFolder>') 00351 00352 for i in range(dir_depth - diff, dir_depth): 00353 output.append('<logicalFolder name="f' + str(folder_count) + '" displayName="' + str( 00354 dir_list[i]) + '" projectFiles="true">') 00355 folder_count += 1 00356 00357 # Current File is in root 00358 else: 00359 # Close Tag if we are in root and the previous dir wasn't 00360 if cur_dir == '' and prev_dir != '': 00361 for i in range(0, len(prev_dir_list)): 00362 output.append('</logicalFolder>') 00363 00364 # Save the Current Dir 00365 prev_dir = cur_dir 00366 output.append('<itemPath>' + str(item) + '</itemPath>') 00367 00368 if cur_dir != '': 00369 # close all open tags 00370 output.append('</logicalFolder>' * dir_depth) 00371 00372 return output 00373 00374 @staticmethod 00375 def get_netbeans_c_std(c_std): 00376 c_std_netbeans = 0 00377 if '89' in c_std: 00378 c_std_netbeans = 2 00379 elif '99' in c_std: 00380 c_std_netbeans = 3 00381 elif '11' in c_std: 00382 c_std_netbeans = 10 00383 return c_std_netbeans 00384 00385 @staticmethod 00386 def get_netbeans_cpp_std(cpp_std): 00387 cpp_std_netbeans = 0 00388 if '98' in cpp_std: 00389 cpp_std_netbeans = 4 00390 elif '11' in cpp_std: 00391 cpp_std_netbeans = 8 00392 elif '14' in cpp_std: 00393 cpp_std_netbeans = 11 00394 return cpp_std_netbeans
Generated on Tue Jul 12 2022 13:24:28 by
1.7.2