Knight KE / Mbed OS Game_Master
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers __init__.py Source File

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