init
Embed:
(wiki syntax)
Show/hide line numbers
__init__.py
00001 """ 00002 mbed SDK 00003 Copyright (c) 2011-2017 ARM Limited 00004 00005 Licensed under the Apache License, Version 2.0 (the "License"); 00006 you may not use this file except in compliance with the License. 00007 You may obtain a copy of the License at 00008 00009 http://www.apache.org/licenses/LICENSE-2.0 00010 00011 Unless required by applicable law or agreed to in writing, software 00012 distributed under the License is distributed on an "AS IS" BASIS, 00013 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 See the License for the specific language governing permissions and 00015 limitations under the License. 00016 00017 Title: GNU ARM Eclipse (http://gnuarmeclipse.github.io) exporter. 00018 00019 Description: Creates a managed build project that can be imported by 00020 the GNU ARM Eclipse plug-ins. 00021 00022 Author: Liviu Ionescu <ilg@livius.net> 00023 """ 00024 00025 import os 00026 import copy 00027 import tempfile 00028 import shutil 00029 import copy 00030 00031 from subprocess import call, Popen, PIPE 00032 from os.path import splitext, basename, relpath, dirname, exists, join, dirname 00033 from random import randint 00034 from json import load 00035 00036 from tools.export.exporters import Exporter, apply_supported_whitelist 00037 from tools.options import list_profiles 00038 from tools.targets import TARGET_MAP 00039 from tools.utils import NotSupportedException 00040 from tools.build_api import prepare_toolchain 00041 00042 # ============================================================================= 00043 00044 00045 class UID : 00046 """ 00047 Helper class, used to generate unique ids required by .cproject symbols. 00048 """ 00049 @property 00050 def id(self): 00051 return "%0.9u" % randint(0, 999999999) 00052 00053 # Global UID generator instance. 00054 # Passed to the template engine, and referred as {{u.id}}. 00055 # Each invocation generates a new number. 00056 u = UID() 00057 00058 # ============================================================================= 00059 00060 00061 POST_BINARY_WHITELIST = set([ 00062 "TEENSY3_1Code.binary_hook", 00063 "MCU_NRF51Code.binary_hook", 00064 "LPCTargetCode.lpc_patch", 00065 "LPC4088Code.binary_hook" 00066 ]) 00067 00068 class GNUARMEclipse(Exporter ): 00069 NAME = 'GNU ARM Eclipse' 00070 TOOLCHAIN = 'GCC_ARM' 00071 00072 @classmethod 00073 def is_target_supported(cls, target_name): 00074 target = TARGET_MAP[target_name] 00075 return apply_supported_whitelist( 00076 cls.TOOLCHAIN, POST_BINARY_WHITELIST, target) 00077 00078 # override 00079 @property 00080 def flags(self): 00081 """Returns a dictionary of toolchain flags. 00082 Keys of the dictionary are: 00083 cxx_flags - c++ flags 00084 c_flags - c flags 00085 ld_flags - linker flags 00086 asm_flags - assembler flags 00087 common_flags - common options 00088 00089 The difference from the parent function is that it does not 00090 add macro definitions, since they are passed separately. 00091 """ 00092 00093 config_header = self.toolchain.get_config_header() 00094 flags = {key + "_flags": copy.deepcopy(value) for key, value 00095 in self.toolchain.flags.items()} 00096 if config_header: 00097 config_header = relpath(config_header, 00098 self.resources.file_basepath[config_header]) 00099 flags['c_flags'] += self.toolchain.get_config_option(config_header) 00100 flags['cxx_flags'] += self.toolchain.get_config_option( 00101 config_header) 00102 return flags 00103 00104 def toolchain_flags(self, toolchain): 00105 """Returns a dictionary of toolchain flags. 00106 Keys of the dictionary are: 00107 cxx_flags - c++ flags 00108 c_flags - c flags 00109 ld_flags - linker flags 00110 asm_flags - assembler flags 00111 common_flags - common options 00112 00113 The difference from the above is that it takes a parameter. 00114 """ 00115 00116 # Note: use the config options from the currently selected toolchain. 00117 config_header = self.toolchain.get_config_header() 00118 00119 flags = {key + "_flags": copy.deepcopy(value) for key, value 00120 in toolchain.flags.items()} 00121 if config_header: 00122 config_header = relpath(config_header, 00123 self.resources.file_basepath[config_header]) 00124 header_options = self.toolchain.get_config_option(config_header) 00125 flags['c_flags'] += header_options 00126 flags['cxx_flags'] += header_options 00127 return flags 00128 00129 def validate_resources(self): 00130 if not self.resources.linker_script: 00131 raise NotSupportedException("No linker script found.") 00132 00133 def create_jinja_ctx(self): 00134 00135 self.validate_resources() 00136 00137 self.resources.win_to_unix() 00138 00139 # TODO: use some logger to display additional info if verbose 00140 00141 libraries = [] 00142 # print 'libraries' 00143 # print self.resources.libraries 00144 for lib in self.resources.libraries: 00145 l, _ = splitext(basename(lib)) 00146 libraries.append(l[3:]) 00147 00148 self.system_libraries = [ 00149 'stdc++', 'supc++', 'm', 'c', 'gcc', 'nosys' 00150 ] 00151 00152 # Read in all profiles, we'll extract compiler options. 00153 profiles = self.get_all_profiles() 00154 00155 profile_ids = [s.lower() for s in profiles] 00156 profile_ids.sort() 00157 00158 # TODO: get the list from existing .cproject 00159 build_folders = [s.capitalize() for s in profile_ids] 00160 build_folders.append('BUILD') 00161 # print build_folders 00162 00163 objects = [self.filter_dot(s) for s in self.resources.objects] 00164 for bf in build_folders: 00165 objects = [o for o in objects if not o.startswith(bf + '/')] 00166 # print 'objects' 00167 # print objects 00168 00169 self.compute_exclusions() 00170 00171 self.include_path = [ 00172 self.filter_dot(s) for s in self.resources.inc_dirs] 00173 print 'Include folders: {0}'.format(len(self.include_path)) 00174 00175 self.as_defines = self.toolchain.get_symbols(True) 00176 self.c_defines = self.toolchain.get_symbols() 00177 self.cpp_defines = self.c_defines 00178 print 'Symbols: {0}'.format(len(self.c_defines)) 00179 00180 self.ld_script = self.filter_dot( 00181 self.resources.linker_script) 00182 print 'Linker script: {0}'.format(self.ld_script) 00183 00184 self.options = {} 00185 for id in profile_ids: 00186 00187 # There are 4 categories of options, a category common too 00188 # all tools and a specific category for each of the tools. 00189 opts = {} 00190 opts['common'] = {} 00191 opts['as'] = {} 00192 opts['c'] = {} 00193 opts['cpp'] = {} 00194 opts['ld'] = {} 00195 00196 opts['id'] = id 00197 opts['name'] = opts['id'].capitalize() 00198 00199 print 00200 print 'Build configuration: {0}'.format(opts['name']) 00201 00202 profile = profiles[id] 00203 00204 # A small hack, do not bother with src_path again, 00205 # pass an empty string to avoid crashing. 00206 src_paths = [''] 00207 target_name = self.toolchain.target.name 00208 toolchain = prepare_toolchain( 00209 src_paths, "", target_name, self.TOOLCHAIN, build_profile=[profile]) 00210 00211 # Hack to fill in build_dir 00212 toolchain.build_dir = self.toolchain.build_dir 00213 toolchain.config = self.toolchain.config 00214 toolchain.set_config_data(self.toolchain.config.get_config_data()) 00215 00216 flags = self.toolchain_flags(toolchain) 00217 00218 print 'Common flags:', ' '.join(flags['common_flags']) 00219 print 'C++ flags:', ' '.join(flags['cxx_flags']) 00220 print 'C flags:', ' '.join(flags['c_flags']) 00221 print 'ASM flags:', ' '.join(flags['asm_flags']) 00222 print 'Linker flags:', ' '.join(flags['ld_flags']) 00223 00224 # Most GNU ARM Eclipse options have a parent, 00225 # either debug or release. 00226 if '-O0' in flags['common_flags'] or '-Og' in flags['common_flags']: 00227 opts['parent_id'] = 'debug' 00228 else: 00229 opts['parent_id'] = 'release' 00230 00231 self.process_options(opts, flags) 00232 00233 opts['as']['defines'] = self.as_defines 00234 opts['c']['defines'] = self.c_defines 00235 opts['cpp']['defines'] = self.cpp_defines 00236 00237 opts['common']['include_paths'] = self.include_path 00238 opts['common']['excluded_folders'] = '|'.join( 00239 self.excluded_folders) 00240 00241 opts['ld']['library_paths'] = [ 00242 self.filter_dot(s) for s in self.resources.lib_dirs] 00243 00244 opts['ld']['object_files'] = objects 00245 opts['ld']['user_libraries'] = libraries 00246 opts['ld']['system_libraries'] = self.system_libraries 00247 opts['ld']['script'] = join(id.capitalize(), 00248 "linker-script-%s.ld" % id) 00249 opts['cpp_cmd'] = '"{}"'.format(toolchain.preproc[0]) + " " + " ".join(toolchain.preproc[1:]) 00250 00251 # Unique IDs used in multiple places. 00252 # Those used only once are implemented with {{u.id}}. 00253 uid = {} 00254 uid['config'] = u.id 00255 uid['tool_c_compiler'] = u.id 00256 uid['tool_c_compiler_input'] = u.id 00257 uid['tool_cpp_compiler'] = u.id 00258 uid['tool_cpp_compiler_input'] = u.id 00259 00260 opts['uid'] = uid 00261 00262 self.options[id] = opts 00263 00264 jinja_ctx = { 00265 'name': self.project_name, 00266 'ld_script': self.ld_script, 00267 00268 # Compiler & linker command line options 00269 'options': self.options, 00270 00271 # Must be an object with an `id` property, which 00272 # will be called repeatedly, to generate multiple UIDs. 00273 'u': u, 00274 } 00275 return jinja_ctx 00276 00277 # override 00278 def generate(self): 00279 """ 00280 Generate the .project and .cproject files. 00281 """ 00282 jinja_ctx = self.create_jinja_ctx() 00283 00284 print 00285 print 'Create a GNU ARM Eclipse C++ managed project' 00286 print 'Project name: {0}'.format(self.project_name) 00287 print 'Target: {0}'.format(self.toolchain.target.name) 00288 print 'Toolchain: {0}'.format(self.TOOLCHAIN) 00289 00290 self.gen_file('gnuarmeclipse/.project.tmpl', jinja_ctx, 00291 '.project', trim_blocks=True, lstrip_blocks=True) 00292 self.gen_file('gnuarmeclipse/.cproject.tmpl', jinja_ctx, 00293 '.cproject', trim_blocks=True, lstrip_blocks=True) 00294 self.gen_file('gnuarmeclipse/makefile.targets.tmpl', jinja_ctx, 00295 'makefile.targets', trim_blocks=True, lstrip_blocks=True) 00296 self.gen_file('gnuarmeclipse/mbedignore.tmpl', jinja_ctx, '.mbedignore') 00297 00298 print 00299 print 'Done. Import the \'{0}\' project in Eclipse.'.format(self.project_name) 00300 00301 # override 00302 @staticmethod 00303 def build(project_name, log_name="build_log.txt", cleanup=True): 00304 """ 00305 Headless build an Eclipse project. 00306 00307 The following steps are performed: 00308 - a temporary workspace is created, 00309 - the project is imported, 00310 - a clean build of all configurations is performed and 00311 - the temporary workspace is removed. 00312 00313 The build results are in the Debug & Release folders. 00314 00315 All executables (eclipse & toolchain) must be in the PATH. 00316 00317 The general method to start a headless Eclipse build is: 00318 00319 $ eclipse \ 00320 --launcher.suppressErrors \ 00321 -nosplash \ 00322 -application org.eclipse.cdt.managedbuilder.core.headlessbuild \ 00323 -data /path/to/workspace \ 00324 -import /path/to/project \ 00325 -cleanBuild "project[/configuration] | all" 00326 """ 00327 00328 # TODO: possibly use the log file. 00329 00330 # Create a temporary folder for the workspace. 00331 tmp_folder = tempfile.mkdtemp() 00332 00333 cmd = [ 00334 'eclipse', 00335 '--launcher.suppressErrors', 00336 '-nosplash', 00337 '-application org.eclipse.cdt.managedbuilder.core.headlessbuild', 00338 '-data', tmp_folder, 00339 '-import', os.getcwd(), 00340 '-cleanBuild', project_name 00341 ] 00342 00343 p = Popen(' '.join(cmd), shell=True, stdout=PIPE, stderr=PIPE) 00344 out, err = p.communicate() 00345 ret_code = p.returncode 00346 stdout_string = "=" * 10 + "STDOUT" + "=" * 10 + "\n" 00347 err_string = "=" * 10 + "STDERR" + "=" * 10 + "\n" 00348 err_string += err 00349 00350 ret_string = "SUCCESS\n" 00351 if ret_code != 0: 00352 ret_string += "FAILURE\n" 00353 00354 print "%s\n%s\n%s\n%s" % (stdout_string, out, err_string, ret_string) 00355 00356 if log_name: 00357 # Write the output to the log file 00358 with open(log_name, 'w+') as f: 00359 f.write(stdout_string) 00360 f.write(out) 00361 f.write(err_string) 00362 f.write(ret_string) 00363 00364 # Cleanup the exported and built files 00365 if cleanup: 00366 if exists(log_name): 00367 os.remove(log_name) 00368 os.remove('.project') 00369 os.remove('.cproject') 00370 if exists('Debug'): 00371 shutil.rmtree('Debug') 00372 if exists('Release'): 00373 shutil.rmtree('Release') 00374 if exists('makefile.targets'): 00375 os.remove('makefile.targets') 00376 00377 # Always remove the temporary folder. 00378 if exists(tmp_folder): 00379 shutil.rmtree(tmp_folder) 00380 00381 if ret_code == 0: 00382 # Return Success 00383 return 0 00384 00385 # Seems like something went wrong. 00386 return -1 00387 00388 # ------------------------------------------------------------------------- 00389 00390 @staticmethod 00391 def get_all_profiles(): 00392 tools_path = dirname(dirname(dirname(__file__))) 00393 file_names = [join(tools_path, "profiles", fn) for fn in os.listdir( 00394 join(tools_path, "profiles")) if fn.endswith(".json")] 00395 00396 # print file_names 00397 00398 profile_names = [basename(fn).replace(".json", "") 00399 for fn in file_names] 00400 # print profile_names 00401 00402 profiles = {} 00403 00404 for fn in file_names: 00405 content = load(open(fn)) 00406 profile_name = basename(fn).replace(".json", "") 00407 profiles[profile_name] = content 00408 00409 return profiles 00410 00411 # ------------------------------------------------------------------------- 00412 # Process source files/folders exclusions. 00413 00414 def compute_exclusions(self): 00415 """ 00416 With the project root as the only source folder known to CDT, 00417 based on the list of source files, compute the folders to not 00418 be included in the build. 00419 00420 The steps are: 00421 - get the list of source folders, as dirname(source_file) 00422 - compute the top folders (subfolders of the project folder) 00423 - iterate all subfolders and add them to a tree, with all 00424 nodes markes as 'not used' 00425 - iterate the source folders and mark them as 'used' in the 00426 tree, including all intermediate nodes 00427 - recurse the tree and collect all unused folders; descend 00428 the hierarchy only for used nodes 00429 """ 00430 source_folders = [self.filter_dot(s) for s in set(dirname( 00431 src) for src in self.resources.c_sources + self.resources.cpp_sources + self.resources.s_sources)] 00432 00433 self.excluded_folders = set(self.resources.ignored_dirs) - set(self.resources.inc_dirs) 00434 print 'Source folders: {0}, with {1} exclusions'.format(len(source_folders), len(self.excluded_folders)) 00435 00436 00437 # ------------------------------------------------------------------------- 00438 00439 @staticmethod 00440 def filter_dot(str): 00441 """ 00442 Remove the './' prefix, if present. 00443 This function assumes that resources.win_to_unix() 00444 replaced all windows backslashes with slashes. 00445 """ 00446 if str == None: 00447 return None 00448 if str[:2] == './': 00449 return str[2:] 00450 return str 00451 00452 # ------------------------------------------------------------------------- 00453 00454 def dump_tree(self, nodes, depth=0): 00455 for k in nodes.keys(): 00456 node = nodes[k] 00457 parent_name = node['parent'][ 00458 'name'] if 'parent' in node.keys() else '' 00459 print ' ' * depth, node['name'], node['is_used'], parent_name 00460 if len(node['children'].keys()) != 0: 00461 self.dump_tree(node['children'], depth + 1) 00462 00463 def dump_paths(self, nodes, depth=0): 00464 for k in nodes.keys(): 00465 node = nodes[k] 00466 parts = [] 00467 while True: 00468 parts.insert(0, node['name']) 00469 if 'parent' not in node: 00470 break 00471 node = node['parent'] 00472 path = '/'.join(parts) 00473 print path, nodes[k]['is_used'] 00474 self.dump_paths(nodes[k]['children'], depth + 1) 00475 00476 # ------------------------------------------------------------------------- 00477 00478 def process_options(self, opts, flags_in): 00479 """ 00480 CDT managed projects store lots of build options in separate 00481 variables, with separate IDs in the .cproject file. 00482 When the CDT build is started, all these options are brought 00483 together to compose the compiler and linker command lines. 00484 00485 Here the process is reversed, from the compiler and linker 00486 command lines, the options are identified and various flags are 00487 set to control the template generation process. 00488 00489 Once identified, the options are removed from the command lines. 00490 00491 The options that were not identified are options that do not 00492 have CDT equivalents and will be passed in the 'Other options' 00493 categories. 00494 00495 Although this process does not have a very complicated logic, 00496 given the large number of explicit configuration options 00497 used by the GNU ARM Eclipse managed build plug-in, it is tedious... 00498 """ 00499 00500 # Make a copy of the flags, to be one by one removed after processing. 00501 flags = copy.deepcopy(flags_in) 00502 00503 if False: 00504 print 00505 print 'common_flags', flags['common_flags'] 00506 print 'asm_flags', flags['asm_flags'] 00507 print 'c_flags', flags['c_flags'] 00508 print 'cxx_flags', flags['cxx_flags'] 00509 print 'ld_flags', flags['ld_flags'] 00510 00511 # Initialise the 'last resort' options where all unrecognised 00512 # options will be collected. 00513 opts['as']['other'] = '' 00514 opts['c']['other'] = '' 00515 opts['cpp']['other'] = '' 00516 opts['ld']['other'] = '' 00517 00518 MCPUS = { 00519 'Cortex-M0': {'mcpu': 'cortex-m0', 'fpu_unit': None}, 00520 'Cortex-M0+': {'mcpu': 'cortex-m0plus', 'fpu_unit': None}, 00521 'Cortex-M1': {'mcpu': 'cortex-m1', 'fpu_unit': None}, 00522 'Cortex-M3': {'mcpu': 'cortex-m3', 'fpu_unit': None}, 00523 'Cortex-M4': {'mcpu': 'cortex-m4', 'fpu_unit': None}, 00524 'Cortex-M4F': {'mcpu': 'cortex-m4', 'fpu_unit': 'fpv4spd16'}, 00525 'Cortex-M7': {'mcpu': 'cortex-m7', 'fpu_unit': None}, 00526 'Cortex-M7F': {'mcpu': 'cortex-m7', 'fpu_unit': 'fpv4spd16'}, 00527 'Cortex-M7FD': {'mcpu': 'cortex-m7', 'fpu_unit': 'fpv5d16'}, 00528 'Cortex-A9': {'mcpu': 'cortex-a9', 'fpu_unit': 'vfpv3'} 00529 } 00530 00531 # Remove options that are supplied by CDT 00532 self.remove_option(flags['common_flags'], '-c') 00533 self.remove_option(flags['common_flags'], '-MMD') 00534 00535 # As 'plan B', get the CPU from the target definition. 00536 core = self.toolchain.target.core 00537 00538 opts['common']['arm.target.family'] = None 00539 00540 # cortex-m0, cortex-m0-small-multiply, cortex-m0plus, 00541 # cortex-m0plus-small-multiply, cortex-m1, cortex-m1-small-multiply, 00542 # cortex-m3, cortex-m4, cortex-m7. 00543 str = self.find_options(flags['common_flags'], '-mcpu=') 00544 if str != None: 00545 opts['common']['arm.target.family'] = str[len('-mcpu='):] 00546 self.remove_option(flags['common_flags'], str) 00547 self.remove_option(flags['ld_flags'], str) 00548 else: 00549 if core not in MCPUS: 00550 raise NotSupportedException( 00551 'Target core {0} not supported.'.format(core)) 00552 opts['common']['arm.target.family'] = MCPUS[core]['mcpu'] 00553 00554 opts['common']['arm.target.arch'] = 'none' 00555 str = self.find_options(flags['common_flags'], '-march=') 00556 arch = str[len('-march='):] 00557 archs = {'armv6-m': 'armv6-m', 'armv7-m': 'armv7-m', 'armv7-a': 'armv7-a'} 00558 if arch in archs: 00559 opts['common']['arm.target.arch'] = archs[arch] 00560 self.remove_option(flags['common_flags'], str) 00561 00562 opts['common']['arm.target.instructionset'] = 'thumb' 00563 if '-mthumb' in flags['common_flags']: 00564 self.remove_option(flags['common_flags'], '-mthumb') 00565 self.remove_option(flags['ld_flags'], '-mthumb') 00566 elif '-marm' in flags['common_flags']: 00567 opts['common']['arm.target.instructionset'] = 'arm' 00568 self.remove_option(flags['common_flags'], '-marm') 00569 self.remove_option(flags['ld_flags'], '-marm') 00570 00571 opts['common']['arm.target.thumbinterwork'] = False 00572 if '-mthumb-interwork' in flags['common_flags']: 00573 opts['common']['arm.target.thumbinterwork'] = True 00574 self.remove_option(flags['common_flags'], '-mthumb-interwork') 00575 00576 opts['common']['arm.target.endianness'] = None 00577 if '-mlittle-endian' in flags['common_flags']: 00578 opts['common']['arm.target.endianness'] = 'little' 00579 self.remove_option(flags['common_flags'], '-mlittle-endian') 00580 elif '-mbig-endian' in flags['common_flags']: 00581 opts['common']['arm.target.endianness'] = 'big' 00582 self.remove_option(flags['common_flags'], '-mbig-endian') 00583 00584 opts['common']['arm.target.fpu.unit'] = None 00585 # default, fpv4spd16, fpv5d16, fpv5spd16 00586 str = self.find_options(flags['common_flags'], '-mfpu=') 00587 if str != None: 00588 fpu = str[len('-mfpu='):] 00589 fpus = { 00590 'fpv4-sp-d16': 'fpv4spd16', 00591 'fpv5-d16': 'fpv5d16', 00592 'fpv5-sp-d16': 'fpv5spd16' 00593 } 00594 if fpu in fpus: 00595 opts['common']['arm.target.fpu.unit'] = fpus[fpu] 00596 00597 self.remove_option(flags['common_flags'], str) 00598 self.remove_option(flags['ld_flags'], str) 00599 if opts['common']['arm.target.fpu.unit'] == None: 00600 if core not in MCPUS: 00601 raise NotSupportedException( 00602 'Target core {0} not supported.'.format(core)) 00603 if MCPUS[core]['fpu_unit']: 00604 opts['common'][ 00605 'arm.target.fpu.unit'] = MCPUS[core]['fpu_unit'] 00606 00607 # soft, softfp, hard. 00608 str = self.find_options(flags['common_flags'], '-mfloat-abi=') 00609 if str != None: 00610 opts['common']['arm.target.fpu.abi'] = str[ 00611 len('-mfloat-abi='):] 00612 self.remove_option(flags['common_flags'], str) 00613 self.remove_option(flags['ld_flags'], str) 00614 00615 opts['common']['arm.target.unalignedaccess'] = None 00616 if '-munaligned-access' in flags['common_flags']: 00617 opts['common']['arm.target.unalignedaccess'] = 'enabled' 00618 self.remove_option(flags['common_flags'], '-munaligned-access') 00619 elif '-mno-unaligned-access' in flags['common_flags']: 00620 opts['common']['arm.target.unalignedaccess'] = 'disabled' 00621 self.remove_option(flags['common_flags'], '-mno-unaligned-access') 00622 00623 # Default optimisation level for Release. 00624 opts['common']['optimization.level'] = '-Os' 00625 00626 # If the project defines an optimisation level, it is used 00627 # only for the Release configuration, the Debug one used '-Og'. 00628 str = self.find_options(flags['common_flags'], '-O') 00629 if str != None: 00630 levels = { 00631 '-O0': 'none', '-O1': 'optimize', '-O2': 'more', 00632 '-O3': 'most', '-Os': 'size', '-Og': 'debug' 00633 } 00634 if str in levels: 00635 opts['common']['optimization.level'] = levels[str] 00636 self.remove_option(flags['common_flags'], str) 00637 00638 include_files = [] 00639 for all_flags in [flags['common_flags'], flags['c_flags'], flags['cxx_flags']]: 00640 while '-include' in all_flags: 00641 ix = all_flags.index('-include') 00642 str = all_flags[ix + 1] 00643 if str not in include_files: 00644 include_files.append(str) 00645 self.remove_option(all_flags, '-include') 00646 self.remove_option(all_flags, str) 00647 00648 opts['common']['include_files'] = include_files 00649 00650 if '-ansi' in flags['c_flags']: 00651 opts['c']['compiler.std'] = '-ansi' 00652 self.remove_option(flags['c_flags'], str) 00653 else: 00654 str = self.find_options(flags['c_flags'], '-std') 00655 std = str[len('-std='):] 00656 c_std = { 00657 'c90': 'c90', 'c89': 'c90', 'gnu90': 'gnu90', 'gnu89': 'gnu90', 00658 'c99': 'c99', 'c9x': 'c99', 'gnu99': 'gnu99', 'gnu9x': 'gnu98', 00659 'c11': 'c11', 'c1x': 'c11', 'gnu11': 'gnu11', 'gnu1x': 'gnu11' 00660 } 00661 if std in c_std: 00662 opts['c']['compiler.std'] = c_std[std] 00663 self.remove_option(flags['c_flags'], str) 00664 00665 if '-ansi' in flags['cxx_flags']: 00666 opts['cpp']['compiler.std'] = '-ansi' 00667 self.remove_option(flags['cxx_flags'], str) 00668 else: 00669 str = self.find_options(flags['cxx_flags'], '-std') 00670 std = str[len('-std='):] 00671 cpp_std = { 00672 'c++98': 'cpp98', 'c++03': 'cpp98', 00673 'gnu++98': 'gnucpp98', 'gnu++03': 'gnucpp98', 00674 'c++0x': 'cpp0x', 'gnu++0x': 'gnucpp0x', 00675 'c++11': 'cpp11', 'gnu++11': 'gnucpp11', 00676 'c++1y': 'cpp1y', 'gnu++1y': 'gnucpp1y', 00677 'c++14': 'cpp14', 'gnu++14': 'gnucpp14', 00678 'c++1z': 'cpp1z', 'gnu++1z': 'gnucpp1z', 00679 } 00680 if std in cpp_std: 00681 opts['cpp']['compiler.std'] = cpp_std[std] 00682 self.remove_option(flags['cxx_flags'], str) 00683 00684 # Common optimisation options. 00685 optimization_options = { 00686 '-fmessage-length=0': 'optimization.messagelength', 00687 '-fsigned-char': 'optimization.signedchar', 00688 '-ffunction-sections': 'optimization.functionsections', 00689 '-fdata-sections': 'optimization.datasections', 00690 '-fno-common': 'optimization.nocommon', 00691 '-fno-inline-functions': 'optimization.noinlinefunctions', 00692 '-ffreestanding': 'optimization.freestanding', 00693 '-fno-builtin': 'optimization.nobuiltin', 00694 '-fsingle-precision-constant': 'optimization.spconstant', 00695 '-fPIC': 'optimization.PIC', 00696 '-fno-move-loop-invariants': 'optimization.nomoveloopinvariants', 00697 } 00698 00699 for option in optimization_options: 00700 opts['common'][optimization_options[option]] = False 00701 if option in flags['common_flags']: 00702 opts['common'][optimization_options[option]] = True 00703 self.remove_option(flags['common_flags'], option) 00704 00705 # Common warning options. 00706 warning_options = { 00707 '-fsyntax-only': 'warnings.syntaxonly', 00708 '-pedantic': 'warnings.pedantic', 00709 '-pedantic-errors': 'warnings.pedanticerrors', 00710 '-w': 'warnings.nowarn', 00711 '-Wunused': 'warnings.unused', 00712 '-Wuninitialized': 'warnings.uninitialized', 00713 '-Wall': 'warnings.allwarn', 00714 '-Wextra': 'warnings.extrawarn', 00715 '-Wmissing-declarations': 'warnings.missingdeclaration', 00716 '-Wconversion': 'warnings.conversion', 00717 '-Wpointer-arith': 'warnings.pointerarith', 00718 '-Wpadded': 'warnings.padded', 00719 '-Wshadow': 'warnings.shadow', 00720 '-Wlogical-op': 'warnings.logicalop', 00721 '-Waggregate-return': 'warnings.agreggatereturn', 00722 '-Wfloat-equal': 'warnings.floatequal', 00723 '-Werror': 'warnings.toerrors', 00724 } 00725 00726 for option in warning_options: 00727 opts['common'][warning_options[option]] = False 00728 if option in flags['common_flags']: 00729 opts['common'][warning_options[option]] = True 00730 self.remove_option(flags['common_flags'], option) 00731 00732 # Common debug options. 00733 debug_levels = { 00734 '-g': 'default', 00735 '-g1': 'minimal', 00736 '-g3': 'max', 00737 } 00738 opts['common']['debugging.level'] = 'none' 00739 for option in debug_levels: 00740 if option in flags['common_flags']: 00741 opts['common'][ 00742 'debugging.level'] = debug_levels[option] 00743 self.remove_option(flags['common_flags'], option) 00744 00745 debug_formats = { 00746 '-ggdb': 'gdb', 00747 '-gstabs': 'stabs', 00748 '-gstabs+': 'stabsplus', 00749 '-gdwarf-2': 'dwarf2', 00750 '-gdwarf-3': 'dwarf3', 00751 '-gdwarf-4': 'dwarf4', 00752 '-gdwarf-5': 'dwarf5', 00753 } 00754 00755 opts['common']['debugging.format'] = '' 00756 for option in debug_levels: 00757 if option in flags['common_flags']: 00758 opts['common'][ 00759 'debugging.format'] = debug_formats[option] 00760 self.remove_option(flags['common_flags'], option) 00761 00762 opts['common']['debugging.prof'] = False 00763 if '-p' in flags['common_flags']: 00764 opts['common']['debugging.prof'] = True 00765 self.remove_option(flags['common_flags'], '-p') 00766 00767 opts['common']['debugging.gprof'] = False 00768 if '-pg' in flags['common_flags']: 00769 opts['common']['debugging.gprof'] = True 00770 self.remove_option(flags['common_flags'], '-gp') 00771 00772 # Assembler options. 00773 opts['as']['usepreprocessor'] = False 00774 while '-x' in flags['asm_flags']: 00775 ix = flags['asm_flags'].index('-x') 00776 str = flags['asm_flags'][ix + 1] 00777 00778 if str == 'assembler-with-cpp': 00779 opts['as']['usepreprocessor'] = True 00780 else: 00781 # Collect all other assembler options. 00782 opts['as']['other'] += ' -x ' + str 00783 00784 self.remove_option(flags['asm_flags'], '-x') 00785 self.remove_option(flags['asm_flags'], 'assembler-with-cpp') 00786 00787 opts['as']['nostdinc'] = False 00788 if '-nostdinc' in flags['asm_flags']: 00789 opts['as']['nostdinc'] = True 00790 self.remove_option(flags['asm_flags'], '-nostdinc') 00791 00792 opts['as']['verbose'] = False 00793 if '-v' in flags['asm_flags']: 00794 opts['as']['verbose'] = True 00795 self.remove_option(flags['asm_flags'], '-v') 00796 00797 # C options. 00798 opts['c']['nostdinc'] = False 00799 if '-nostdinc' in flags['c_flags']: 00800 opts['c']['nostdinc'] = True 00801 self.remove_option(flags['c_flags'], '-nostdinc') 00802 00803 opts['c']['verbose'] = False 00804 if '-v' in flags['c_flags']: 00805 opts['c']['verbose'] = True 00806 self.remove_option(flags['c_flags'], '-v') 00807 00808 warning_options = { 00809 '-Wmissing-prototypes': 'warnings.missingprototypes', 00810 '-Wstrict-prototypes': 'warnings.strictprototypes', 00811 '-Wbad-function-cast': 'warnings.badfunctioncast', 00812 } 00813 00814 for option in warning_options: 00815 opts['c'][warning_options[option]] = False 00816 if option in flags['common_flags']: 00817 opts['c'][warning_options[option]] = True 00818 self.remove_option(flags['common_flags'], option) 00819 00820 # C++ options. 00821 opts['cpp']['nostdinc'] = False 00822 if '-nostdinc' in flags['cxx_flags']: 00823 opts['cpp']['nostdinc'] = True 00824 self.remove_option(flags['cxx_flags'], '-nostdinc') 00825 00826 opts['cpp']['nostdincpp'] = False 00827 if '-nostdinc++' in flags['cxx_flags']: 00828 opts['cpp']['nostdincpp'] = True 00829 self.remove_option(flags['cxx_flags'], '-nostdinc++') 00830 00831 optimization_options = { 00832 '-fno-exceptions': 'optimization.noexceptions', 00833 '-fno-rtti': 'optimization.nortti', 00834 '-fno-use-cxa-atexit': 'optimization.nousecxaatexit', 00835 '-fno-threadsafe-statics': 'optimization.nothreadsafestatics', 00836 } 00837 00838 for option in optimization_options: 00839 opts['cpp'][optimization_options[option]] = False 00840 if option in flags['cxx_flags']: 00841 opts['cpp'][optimization_options[option]] = True 00842 self.remove_option(flags['cxx_flags'], option) 00843 if option in flags['common_flags']: 00844 opts['cpp'][optimization_options[option]] = True 00845 self.remove_option(flags['common_flags'], option) 00846 00847 warning_options = { 00848 '-Wabi': 'warnabi', 00849 '-Wctor-dtor-privacy': 'warnings.ctordtorprivacy', 00850 '-Wnoexcept': 'warnings.noexcept', 00851 '-Wnon-virtual-dtor': 'warnings.nonvirtualdtor', 00852 '-Wstrict-null-sentinel': 'warnings.strictnullsentinel', 00853 '-Wsign-promo': 'warnings.signpromo', 00854 '-Weffc++': 'warneffc', 00855 } 00856 00857 for option in warning_options: 00858 opts['cpp'][warning_options[option]] = False 00859 if option in flags['cxx_flags']: 00860 opts['cpp'][warning_options[option]] = True 00861 self.remove_option(flags['cxx_flags'], option) 00862 if option in flags['common_flags']: 00863 opts['cpp'][warning_options[option]] = True 00864 self.remove_option(flags['common_flags'], option) 00865 00866 opts['cpp']['verbose'] = False 00867 if '-v' in flags['cxx_flags']: 00868 opts['cpp']['verbose'] = True 00869 self.remove_option(flags['cxx_flags'], '-v') 00870 00871 # Linker options. 00872 linker_options = { 00873 '-nostartfiles': 'nostart', 00874 '-nodefaultlibs': 'nodeflibs', 00875 '-nostdlib': 'nostdlibs', 00876 } 00877 00878 for option in linker_options: 00879 opts['ld'][linker_options[option]] = False 00880 if option in flags['ld_flags']: 00881 opts['ld'][linker_options[option]] = True 00882 self.remove_option(flags['ld_flags'], option) 00883 00884 opts['ld']['gcsections'] = False 00885 if '-Wl,--gc-sections' in flags['ld_flags']: 00886 opts['ld']['gcsections'] = True 00887 self.remove_option(flags['ld_flags'], '-Wl,--gc-sections') 00888 00889 opts['ld']['flags'] = [] 00890 to_remove = [] 00891 for opt in flags['ld_flags']: 00892 if opt.startswith('-Wl,--wrap,'): 00893 opts['ld']['flags'].append( 00894 '--wrap=' + opt[len('-Wl,--wrap,'):]) 00895 to_remove.append(opt) 00896 for opt in to_remove: 00897 self.remove_option(flags['ld_flags'], opt) 00898 00899 # Other tool remaining options are separated by category. 00900 opts['as']['otherwarnings'] = self.find_options( 00901 flags['asm_flags'], '-W') 00902 00903 opts['c']['otherwarnings'] = self.find_options( 00904 flags['c_flags'], '-W') 00905 opts['c']['otheroptimizations'] = self.find_options(flags[ 00906 'c_flags'], '-f') 00907 00908 opts['cpp']['otherwarnings'] = self.find_options( 00909 flags['cxx_flags'], '-W') 00910 opts['cpp']['otheroptimizations'] = self.find_options( 00911 flags['cxx_flags'], '-f') 00912 00913 # Other common remaining options are separated by category. 00914 opts['common']['optimization.other'] = self.find_options( 00915 flags['common_flags'], '-f') 00916 opts['common']['warnings.other'] = self.find_options( 00917 flags['common_flags'], '-W') 00918 00919 # Remaining common flags are added to each tool. 00920 opts['as']['other'] += ' ' + \ 00921 ' '.join(flags['common_flags']) + ' ' + \ 00922 ' '.join(flags['asm_flags']) 00923 opts['c']['other'] += ' ' + \ 00924 ' '.join(flags['common_flags']) + ' ' + ' '.join(flags['c_flags']) 00925 opts['cpp']['other'] += ' ' + \ 00926 ' '.join(flags['common_flags']) + ' ' + \ 00927 ' '.join(flags['cxx_flags']) 00928 opts['ld']['other'] += ' ' + \ 00929 ' '.join(flags['common_flags']) + ' ' + ' '.join(flags['ld_flags']) 00930 00931 if len(self.system_libraries) > 0: 00932 opts['ld']['other'] += ' -Wl,--start-group ' 00933 opts['ld'][ 00934 'other'] += ' '.join('-l' + s for s in self.system_libraries) 00935 opts['ld']['other'] += ' -Wl,--end-group ' 00936 00937 # Strip all 'other' flags, since they might have leading spaces. 00938 opts['as']['other'] = opts['as']['other'].strip() 00939 opts['c']['other'] = opts['c']['other'].strip() 00940 opts['cpp']['other'] = opts['cpp']['other'].strip() 00941 opts['ld']['other'] = opts['ld']['other'].strip() 00942 00943 if False: 00944 print 00945 print opts 00946 00947 print 00948 print 'common_flags', flags['common_flags'] 00949 print 'asm_flags', flags['asm_flags'] 00950 print 'c_flags', flags['c_flags'] 00951 print 'cxx_flags', flags['cxx_flags'] 00952 print 'ld_flags', flags['ld_flags'] 00953 00954 @staticmethod 00955 def find_options(lst, option): 00956 tmp = [str for str in lst if str.startswith(option)] 00957 if len(tmp) > 0: 00958 return tmp[0] 00959 else: 00960 return None 00961 00962 @staticmethod 00963 def find_options(lst, prefix): 00964 other = '' 00965 opts = [str for str in lst if str.startswith(prefix)] 00966 if len(opts) > 0: 00967 for opt in opts: 00968 other += ' ' + opt 00969 GNUARMEclipse.remove_option(lst, opt) 00970 return other.strip() 00971 00972 @staticmethod 00973 def remove_option(lst, option): 00974 if option in lst: 00975 lst.remove(option) 00976 00977 # =============================================================================
Generated on Tue Jul 12 2022 13:24:28 by
1.7.2