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