mirror of https://github.com/ARMmbed/mbed-os.git
				
				
				
			
		
			
				
	
	
		
			871 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			Python
		
	
	
			
		
		
	
	
			871 lines
		
	
	
		
			32 KiB
		
	
	
	
		
			Python
		
	
	
"""
 | 
						|
mbed SDK
 | 
						|
Copyright (c) 2011-2017 ARM Limited
 | 
						|
 | 
						|
Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
you may not use this file except in compliance with the License.
 | 
						|
You may obtain a copy of the License at
 | 
						|
 | 
						|
    http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
 | 
						|
Unless required by applicable law or agreed to in writing, software
 | 
						|
distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
See the License for the specific language governing permissions and
 | 
						|
limitations under the License.
 | 
						|
 | 
						|
Title: GNU ARM Eclipse (http://gnuarmeclipse.github.io) exporter.
 | 
						|
 | 
						|
Description: Creates a managed build project that can be imported by
 | 
						|
the GNU ARM Eclipse plug-ins.
 | 
						|
 | 
						|
Author: Liviu Ionescu <ilg@livius.net>
 | 
						|
"""
 | 
						|
from __future__ import print_function, absolute_import
 | 
						|
from builtins import str
 | 
						|
 | 
						|
import os
 | 
						|
import copy
 | 
						|
import tempfile
 | 
						|
import shutil
 | 
						|
import copy
 | 
						|
 | 
						|
from subprocess import call, Popen, PIPE
 | 
						|
from os.path import splitext, basename, relpath, dirname, exists, join, dirname
 | 
						|
from random import randint
 | 
						|
from json import load
 | 
						|
 | 
						|
from tools.export.exporters import Exporter, apply_supported_whitelist
 | 
						|
from tools.options import list_profiles
 | 
						|
from tools.targets import TARGET_MAP
 | 
						|
from tools.utils import NotSupportedException
 | 
						|
from tools.build_api import prepare_toolchain
 | 
						|
 | 
						|
# =============================================================================
 | 
						|
 | 
						|
 | 
						|
class UID:
 | 
						|
    """
 | 
						|
    Helper class, used to generate unique ids required by .cproject symbols.
 | 
						|
    """
 | 
						|
    @property
 | 
						|
    def id(self):
 | 
						|
        return "%0.9u" % randint(0, 999999999)
 | 
						|
 | 
						|
# Global UID generator instance.
 | 
						|
# Passed to the template engine, and referred as {{u.id}}.
 | 
						|
# Each invocation generates a new number.
 | 
						|
u = UID()
 | 
						|
 | 
						|
# =============================================================================
 | 
						|
 | 
						|
 | 
						|
POST_BINARY_WHITELIST = set([
 | 
						|
    "MCU_NRF51Code.binary_hook",
 | 
						|
    "LPCTargetCode.lpc_patch",
 | 
						|
    "PSOC6Code.complete"
 | 
						|
])
 | 
						|
 | 
						|
class GNUARMEclipse(Exporter):
 | 
						|
    NAME = 'GNU ARM Eclipse'
 | 
						|
    TOOLCHAIN = 'GCC_ARM'
 | 
						|
 | 
						|
    @classmethod
 | 
						|
    def is_target_supported(cls, target_name):
 | 
						|
        target = TARGET_MAP[target_name]
 | 
						|
        return apply_supported_whitelist(
 | 
						|
            cls.TOOLCHAIN, POST_BINARY_WHITELIST, target)
 | 
						|
 | 
						|
    def validate_resources(self):
 | 
						|
        if not self.resources.linker_script:
 | 
						|
            raise NotSupportedException("No linker script found.")
 | 
						|
 | 
						|
    def create_jinja_ctx(self):
 | 
						|
 | 
						|
        self.validate_resources()
 | 
						|
 | 
						|
        self.resources.win_to_unix()
 | 
						|
 | 
						|
        # TODO: use some logger to display additional info if verbose
 | 
						|
 | 
						|
        libraries = []
 | 
						|
        library_files = []
 | 
						|
        for lib in self.libraries:
 | 
						|
            library_files.append(self.filter_dot(lib))
 | 
						|
            l, _ = splitext(basename(lib))
 | 
						|
            libraries.append(l[3:])
 | 
						|
 | 
						|
        self.system_libraries = [
 | 
						|
            'stdc++', 'supc++', 'm', 'c', 'gcc', 'nosys'
 | 
						|
        ]
 | 
						|
 | 
						|
        # Read in all profiles, we'll extract compiler options.
 | 
						|
        profiles = self.get_all_profiles()
 | 
						|
 | 
						|
        profile_ids = [s.lower() for s in profiles]
 | 
						|
        profile_ids.sort()
 | 
						|
 | 
						|
        # TODO: get the list from existing .cproject
 | 
						|
        build_folders = [s.capitalize() for s in profile_ids]
 | 
						|
        build_folders.append('BUILD')
 | 
						|
 | 
						|
        objects = [self.filter_dot(s) for s in self.resources.objects]
 | 
						|
        for bf in build_folders:
 | 
						|
            objects = [o for o in objects if not o.startswith(bf + '/')]
 | 
						|
 | 
						|
        self.compute_exclusions()
 | 
						|
 | 
						|
        self.include_path = [
 | 
						|
            self.filter_dot(s) for s in self.resources.inc_dirs]
 | 
						|
 | 
						|
        self.as_defines = self.toolchain.get_symbols(True)
 | 
						|
        self.c_defines = self.toolchain.get_symbols()
 | 
						|
        self.cpp_defines = self.c_defines
 | 
						|
 | 
						|
        self.ld_script = self.filter_dot(
 | 
						|
            self.resources.linker_script)
 | 
						|
 | 
						|
        self.options = {}
 | 
						|
        for id in profile_ids:
 | 
						|
 | 
						|
            # There are 4 categories of options, a category common too
 | 
						|
            # all tools and a specific category for each of the tools.
 | 
						|
            opts = {}
 | 
						|
            opts['common'] = {}
 | 
						|
            opts['as'] = {}
 | 
						|
            opts['c'] = {}
 | 
						|
            opts['cpp'] = {}
 | 
						|
            opts['ld'] = {}
 | 
						|
 | 
						|
            opts['id'] = id
 | 
						|
            opts['name'] = opts['id'].capitalize()
 | 
						|
 | 
						|
 | 
						|
            profile = profiles[id]
 | 
						|
 | 
						|
            # A small hack, do not bother with src_path again,
 | 
						|
            # pass an empty string to avoid crashing.
 | 
						|
            src_paths = ['']
 | 
						|
            target_name = self.toolchain.target.name
 | 
						|
            toolchain = prepare_toolchain(
 | 
						|
                src_paths, "", target_name, self.TOOLCHAIN, build_profile=[profile])
 | 
						|
 | 
						|
            # Hack to fill in build_dir
 | 
						|
            toolchain.build_dir = self.toolchain.build_dir
 | 
						|
            toolchain.config = self.toolchain.config
 | 
						|
            toolchain.set_config_data(self.toolchain.config.get_config_data())
 | 
						|
 | 
						|
            flags = self.toolchain_flags(toolchain)
 | 
						|
 | 
						|
            # Most GNU ARM Eclipse options have a parent,
 | 
						|
            # either debug or release.
 | 
						|
            if '-O0' in flags['common_flags'] or '-Og' in flags['common_flags']:
 | 
						|
                opts['parent_id'] = 'debug'
 | 
						|
            else:
 | 
						|
                opts['parent_id'] = 'release'
 | 
						|
 | 
						|
            self.process_options(opts, flags)
 | 
						|
 | 
						|
            opts['as']['defines'] = self.as_defines
 | 
						|
            opts['c']['defines'] = self.c_defines
 | 
						|
            opts['cpp']['defines'] = self.cpp_defines
 | 
						|
 | 
						|
            opts['common']['include_paths'] = self.include_path
 | 
						|
            opts['common']['excluded_folders'] = '|'.join(
 | 
						|
                self.excluded_folders)
 | 
						|
 | 
						|
            opts['ld']['library_paths'] = [
 | 
						|
                self.filter_dot(s) for s in self.resources.lib_dirs]
 | 
						|
 | 
						|
            opts['ld']['object_files'] = objects
 | 
						|
            opts['ld']['user_libraries'] = libraries
 | 
						|
            opts['ld']['user_library_files'] = library_files
 | 
						|
            opts['ld']['system_libraries'] = self.system_libraries
 | 
						|
            opts['ld']['script'] = join(id.capitalize(),
 | 
						|
                                        "linker-script-%s.ld" % id)
 | 
						|
            opts['cpp_cmd'] = '"{}"'.format(toolchain.preproc[0]) + " " + " ".join(toolchain.preproc[1:])
 | 
						|
 | 
						|
            # Unique IDs used in multiple places.
 | 
						|
            # Those used only once are implemented with {{u.id}}.
 | 
						|
            uid = {}
 | 
						|
            uid['config'] = u.id
 | 
						|
            uid['tool_c_compiler'] = u.id
 | 
						|
            uid['tool_c_compiler_input'] = u.id
 | 
						|
            uid['tool_cpp_compiler'] = u.id
 | 
						|
            uid['tool_cpp_compiler_input'] = u.id
 | 
						|
 | 
						|
            opts['uid'] = uid
 | 
						|
 | 
						|
            self.options[id] = opts
 | 
						|
 | 
						|
        jinja_ctx = {
 | 
						|
            'name': self.project_name,
 | 
						|
            'ld_script': self.ld_script,
 | 
						|
 | 
						|
            # Compiler & linker command line options
 | 
						|
            'options': self.options,
 | 
						|
 | 
						|
            # Must be an object with an `id` property, which
 | 
						|
            # will be called repeatedly, to generate multiple UIDs.
 | 
						|
            'u': u,
 | 
						|
        }
 | 
						|
        return jinja_ctx
 | 
						|
 | 
						|
    # override
 | 
						|
    def generate(self):
 | 
						|
        """
 | 
						|
        Generate the .project and .cproject files.
 | 
						|
        """
 | 
						|
        jinja_ctx = self.create_jinja_ctx()
 | 
						|
 | 
						|
 | 
						|
        self.gen_file('gnuarmeclipse/.project.tmpl', jinja_ctx,
 | 
						|
                      '.project', trim_blocks=True, lstrip_blocks=True)
 | 
						|
        self.gen_file('gnuarmeclipse/.cproject.tmpl', jinja_ctx,
 | 
						|
                      '.cproject', trim_blocks=True, lstrip_blocks=True)
 | 
						|
        self.gen_file('gnuarmeclipse/makefile.targets.tmpl', jinja_ctx,
 | 
						|
                      'makefile.targets', trim_blocks=True, lstrip_blocks=True)
 | 
						|
        self.gen_file_nonoverwrite('gnuarmeclipse/mbedignore.tmpl', jinja_ctx,
 | 
						|
                                   '.mbedignore')
 | 
						|
 | 
						|
        print('Done. Import the \'{0}\' project in Eclipse.'.format(self.project_name))
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def clean(_):
 | 
						|
        os.remove('.project')
 | 
						|
        os.remove('.cproject')
 | 
						|
        if exists('Debug'):
 | 
						|
            shutil.rmtree('Debug')
 | 
						|
        if exists('Release'):
 | 
						|
            shutil.rmtree('Release')
 | 
						|
        if exists('makefile.targets'):
 | 
						|
            os.remove('makefile.targets')
 | 
						|
 | 
						|
    # override
 | 
						|
    @staticmethod
 | 
						|
    def build(project_name, log_name="build_log.txt", cleanup=True):
 | 
						|
        """
 | 
						|
        Headless build an Eclipse project.
 | 
						|
 | 
						|
        The following steps are performed:
 | 
						|
        - a temporary workspace is created,
 | 
						|
        - the project is imported,
 | 
						|
        - a clean build of all configurations is performed and
 | 
						|
        - the temporary workspace is removed.
 | 
						|
 | 
						|
        The build results are in the Debug & Release folders.
 | 
						|
 | 
						|
        All executables (eclipse & toolchain) must be in the PATH.
 | 
						|
 | 
						|
        The general method to start a headless Eclipse build is:
 | 
						|
 | 
						|
        $ eclipse \
 | 
						|
        --launcher.suppressErrors \
 | 
						|
        -nosplash \
 | 
						|
        -application org.eclipse.cdt.managedbuilder.core.headlessbuild \
 | 
						|
        -data /path/to/workspace \
 | 
						|
        -import /path/to/project \
 | 
						|
        -cleanBuild "project[/configuration] | all"
 | 
						|
        """
 | 
						|
 | 
						|
        # TODO: possibly use the log file.
 | 
						|
 | 
						|
        # Create a temporary folder for the workspace.
 | 
						|
        tmp_folder = tempfile.mkdtemp()
 | 
						|
 | 
						|
        cmd = [
 | 
						|
            'eclipse',
 | 
						|
            '--launcher.suppressErrors',
 | 
						|
            '-nosplash',
 | 
						|
            '-application org.eclipse.cdt.managedbuilder.core.headlessbuild',
 | 
						|
            '-data', tmp_folder,
 | 
						|
            '-import', os.getcwd(),
 | 
						|
            '-cleanBuild', project_name
 | 
						|
        ]
 | 
						|
 | 
						|
        p = Popen(' '.join(cmd), shell=True, stdout=PIPE, stderr=PIPE)
 | 
						|
        out, err = p.communicate()
 | 
						|
        ret_code = p.returncode
 | 
						|
        stdout_string = "=" * 10 + "STDOUT" + "=" * 10 + "\n"
 | 
						|
        err_string = "=" * 10 + "STDERR" + "=" * 10 + "\n"
 | 
						|
        err_string += err
 | 
						|
 | 
						|
        ret_string = "SUCCESS\n"
 | 
						|
        if ret_code != 0:
 | 
						|
            ret_string += "FAILURE\n"
 | 
						|
 | 
						|
        print("%s\n%s\n%s\n%s" % (stdout_string, out, err_string, ret_string))
 | 
						|
 | 
						|
        if log_name:
 | 
						|
            # Write the output to the log file
 | 
						|
            with open(log_name, 'w+') as f:
 | 
						|
                f.write(stdout_string)
 | 
						|
                f.write(out)
 | 
						|
                f.write(err_string)
 | 
						|
                f.write(ret_string)
 | 
						|
 | 
						|
        # Cleanup the exported and built files
 | 
						|
        if cleanup:
 | 
						|
            if exists(log_name):
 | 
						|
                os.remove(log_name)
 | 
						|
 | 
						|
        # Always remove the temporary folder.
 | 
						|
        if exists(tmp_folder):
 | 
						|
            shutil.rmtree(tmp_folder)
 | 
						|
 | 
						|
        if ret_code == 0:
 | 
						|
            # Return Success
 | 
						|
            return 0
 | 
						|
 | 
						|
        # Seems like something went wrong.
 | 
						|
        return -1
 | 
						|
 | 
						|
   # -------------------------------------------------------------------------
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def get_all_profiles():
 | 
						|
        tools_path = dirname(dirname(dirname(__file__)))
 | 
						|
        file_names = [join(tools_path, "profiles", fn) for fn in os.listdir(
 | 
						|
            join(tools_path, "profiles")) if fn.endswith(".json")]
 | 
						|
 | 
						|
 | 
						|
        profile_names = [basename(fn).replace(".json", "")
 | 
						|
                         for fn in file_names]
 | 
						|
 | 
						|
        profiles = {}
 | 
						|
 | 
						|
        for fn in file_names:
 | 
						|
            content = load(open(fn))
 | 
						|
            profile_name = basename(fn).replace(".json", "")
 | 
						|
            profiles[profile_name] = content
 | 
						|
 | 
						|
        return profiles
 | 
						|
 | 
						|
    # -------------------------------------------------------------------------
 | 
						|
    # Process source files/folders exclusions.
 | 
						|
 | 
						|
    def compute_exclusions(self):
 | 
						|
        """
 | 
						|
        With the project root as the only source folder known to CDT,
 | 
						|
        based on the list of source files, compute the folders to not
 | 
						|
        be included in the build.
 | 
						|
 | 
						|
        The steps are:
 | 
						|
        - get the list of source folders, as dirname(source_file)
 | 
						|
        - compute the top folders (subfolders of the project folder)
 | 
						|
        - iterate all subfolders and add them to a tree, with all
 | 
						|
        nodes markes as 'not used'
 | 
						|
        - iterate the source folders and mark them as 'used' in the
 | 
						|
        tree, including all intermediate nodes
 | 
						|
        - recurse the tree and collect all unused folders; descend
 | 
						|
        the hierarchy only for used nodes
 | 
						|
        """
 | 
						|
        self.excluded_folders = set(self.resources.ignored_dirs) - set(self.resources.inc_dirs)
 | 
						|
 | 
						|
 | 
						|
    # -------------------------------------------------------------------------
 | 
						|
 | 
						|
    def dump_tree(self, nodes, depth=0):
 | 
						|
        for k in list(nodes):
 | 
						|
            node = nodes[k]
 | 
						|
            parent_name = node['parent'][
 | 
						|
                'name'] if 'parent' in list(node) else ''
 | 
						|
            if len(node['children'].keys()) != 0:
 | 
						|
                self.dump_tree(node['children'], depth + 1)
 | 
						|
 | 
						|
    def dump_paths(self, nodes, depth=0):
 | 
						|
        for k in list(nodes):
 | 
						|
            node = nodes[k]
 | 
						|
            parts = []
 | 
						|
            while True:
 | 
						|
                parts.insert(0, node['name'])
 | 
						|
                if 'parent' not in node:
 | 
						|
                    break
 | 
						|
                node = node['parent']
 | 
						|
            path = '/'.join(parts)
 | 
						|
            self.dump_paths(nodes[k]['children'], depth + 1)
 | 
						|
 | 
						|
    # -------------------------------------------------------------------------
 | 
						|
 | 
						|
    def process_options(self, opts, flags_in):
 | 
						|
        """
 | 
						|
        CDT managed projects store lots of build options in separate
 | 
						|
        variables, with separate IDs in the .cproject file.
 | 
						|
        When the CDT build is started, all these options are brought
 | 
						|
        together to compose the compiler and linker command lines.
 | 
						|
 | 
						|
        Here the process is reversed, from the compiler and linker
 | 
						|
        command lines, the options are identified and various flags are
 | 
						|
        set to control the template generation process.
 | 
						|
 | 
						|
        Once identified, the options are removed from the command lines.
 | 
						|
 | 
						|
        The options that were not identified are options that do not
 | 
						|
        have CDT equivalents and will be passed in the 'Other options'
 | 
						|
        categories.
 | 
						|
 | 
						|
        Although this process does not have a very complicated logic,
 | 
						|
        given the large number of explicit configuration options
 | 
						|
        used by the GNU ARM Eclipse managed build plug-in, it is tedious...
 | 
						|
        """
 | 
						|
 | 
						|
        # Make a copy of the flags, to be one by one removed after processing.
 | 
						|
        flags = copy.deepcopy(flags_in)
 | 
						|
 | 
						|
        # Initialise the 'last resort' options where all unrecognised
 | 
						|
        # options will be collected.
 | 
						|
        opts['as']['other'] = ''
 | 
						|
        opts['c']['other'] = ''
 | 
						|
        opts['cpp']['other'] = ''
 | 
						|
        opts['ld']['other'] = ''
 | 
						|
 | 
						|
        MCPUS = {
 | 
						|
            'Cortex-M0': {'mcpu': 'cortex-m0', 'fpu_unit': None},
 | 
						|
            'Cortex-M0+': {'mcpu': 'cortex-m0plus', 'fpu_unit': None},
 | 
						|
            'Cortex-M1': {'mcpu': 'cortex-m1', 'fpu_unit': None},
 | 
						|
            'Cortex-M3': {'mcpu': 'cortex-m3', 'fpu_unit': None},
 | 
						|
            'Cortex-M4': {'mcpu': 'cortex-m4', 'fpu_unit': None},
 | 
						|
            'Cortex-M4F': {'mcpu': 'cortex-m4', 'fpu_unit': 'fpv4spd16'},
 | 
						|
            'Cortex-M7': {'mcpu': 'cortex-m7', 'fpu_unit': None},
 | 
						|
            'Cortex-M7F': {'mcpu': 'cortex-m7', 'fpu_unit': 'fpv4spd16'},
 | 
						|
            'Cortex-M7FD': {'mcpu': 'cortex-m7', 'fpu_unit': 'fpv5d16'},
 | 
						|
            'Cortex-A9': {'mcpu': 'cortex-a9', 'fpu_unit': 'vfpv3'}
 | 
						|
        }
 | 
						|
 | 
						|
        # Remove options that are supplied by CDT
 | 
						|
        self.remove_option(flags['common_flags'], '-c')
 | 
						|
        self.remove_option(flags['common_flags'], '-MMD')
 | 
						|
 | 
						|
        # As 'plan B', get the CPU from the target definition.
 | 
						|
        core = self.toolchain.target.core
 | 
						|
 | 
						|
        opts['common']['arm.target.family'] = None
 | 
						|
 | 
						|
        # cortex-m0, cortex-m0-small-multiply, cortex-m0plus,
 | 
						|
        # cortex-m0plus-small-multiply, cortex-m1, cortex-m1-small-multiply,
 | 
						|
        # cortex-m3, cortex-m4, cortex-m7.
 | 
						|
        str = self.find_options(flags['common_flags'], '-mcpu=')
 | 
						|
        if str != None:
 | 
						|
            opts['common']['arm.target.family'] = str[len('-mcpu='):]
 | 
						|
            self.remove_option(flags['common_flags'], str)
 | 
						|
            self.remove_option(flags['ld_flags'], str)
 | 
						|
        else:
 | 
						|
            if core not in MCPUS:
 | 
						|
                raise NotSupportedException(
 | 
						|
                    'Target core {0} not supported.'.format(core))
 | 
						|
            opts['common']['arm.target.family'] = MCPUS[core]['mcpu']
 | 
						|
 | 
						|
        opts['common']['arm.target.arch'] = 'none'
 | 
						|
        str = self.find_options(flags['common_flags'], '-march=')
 | 
						|
        arch = str[len('-march='):]
 | 
						|
        archs = {'armv6-m': 'armv6-m', 'armv7-m': 'armv7-m', 'armv7-a': 'armv7-a'}
 | 
						|
        if arch in archs:
 | 
						|
            opts['common']['arm.target.arch'] = archs[arch]
 | 
						|
            self.remove_option(flags['common_flags'], str)
 | 
						|
 | 
						|
        opts['common']['arm.target.instructionset'] = 'thumb'
 | 
						|
        if '-mthumb' in flags['common_flags']:
 | 
						|
            self.remove_option(flags['common_flags'], '-mthumb')
 | 
						|
            self.remove_option(flags['ld_flags'], '-mthumb')
 | 
						|
        elif '-marm' in flags['common_flags']:
 | 
						|
            opts['common']['arm.target.instructionset'] = 'arm'
 | 
						|
            self.remove_option(flags['common_flags'], '-marm')
 | 
						|
            self.remove_option(flags['ld_flags'], '-marm')
 | 
						|
 | 
						|
        opts['common']['arm.target.thumbinterwork'] = False
 | 
						|
        if '-mthumb-interwork' in flags['common_flags']:
 | 
						|
            opts['common']['arm.target.thumbinterwork'] = True
 | 
						|
            self.remove_option(flags['common_flags'], '-mthumb-interwork')
 | 
						|
 | 
						|
        opts['common']['arm.target.endianness'] = None
 | 
						|
        if '-mlittle-endian' in flags['common_flags']:
 | 
						|
            opts['common']['arm.target.endianness'] = 'little'
 | 
						|
            self.remove_option(flags['common_flags'], '-mlittle-endian')
 | 
						|
        elif '-mbig-endian' in flags['common_flags']:
 | 
						|
            opts['common']['arm.target.endianness'] = 'big'
 | 
						|
            self.remove_option(flags['common_flags'], '-mbig-endian')
 | 
						|
 | 
						|
        opts['common']['arm.target.fpu.unit'] = None
 | 
						|
        # default, fpv4spd16, fpv5d16, fpv5spd16
 | 
						|
        str = self.find_options(flags['common_flags'], '-mfpu=')
 | 
						|
        if str != None:
 | 
						|
            fpu = str[len('-mfpu='):]
 | 
						|
            fpus = {
 | 
						|
                'fpv4-sp-d16': 'fpv4spd16',
 | 
						|
                'fpv5-d16': 'fpv5d16',
 | 
						|
                'fpv5-sp-d16': 'fpv5spd16'
 | 
						|
            }
 | 
						|
            if fpu in fpus:
 | 
						|
                opts['common']['arm.target.fpu.unit'] = fpus[fpu]
 | 
						|
 | 
						|
                self.remove_option(flags['common_flags'], str)
 | 
						|
                self.remove_option(flags['ld_flags'], str)
 | 
						|
        if opts['common']['arm.target.fpu.unit'] == None:
 | 
						|
            if core not in MCPUS:
 | 
						|
                raise NotSupportedException(
 | 
						|
                    'Target core {0} not supported.'.format(core))
 | 
						|
            if MCPUS[core]['fpu_unit']:
 | 
						|
                opts['common'][
 | 
						|
                    'arm.target.fpu.unit'] = MCPUS[core]['fpu_unit']
 | 
						|
 | 
						|
        # soft, softfp, hard.
 | 
						|
        str = self.find_options(flags['common_flags'], '-mfloat-abi=')
 | 
						|
        if str != None:
 | 
						|
            opts['common']['arm.target.fpu.abi'] = str[
 | 
						|
                len('-mfloat-abi='):]
 | 
						|
            self.remove_option(flags['common_flags'], str)
 | 
						|
            self.remove_option(flags['ld_flags'], str)
 | 
						|
 | 
						|
        opts['common']['arm.target.unalignedaccess'] = None
 | 
						|
        if '-munaligned-access' in flags['common_flags']:
 | 
						|
            opts['common']['arm.target.unalignedaccess'] = 'enabled'
 | 
						|
            self.remove_option(flags['common_flags'], '-munaligned-access')
 | 
						|
        elif '-mno-unaligned-access' in flags['common_flags']:
 | 
						|
            opts['common']['arm.target.unalignedaccess'] = 'disabled'
 | 
						|
            self.remove_option(flags['common_flags'], '-mno-unaligned-access')
 | 
						|
 | 
						|
        # Default optimisation level for Release.
 | 
						|
        opts['common']['optimization.level'] = '-Os'
 | 
						|
 | 
						|
        # If the project defines an optimisation level, it is used
 | 
						|
        # only for the Release configuration, the Debug one used '-Og'.
 | 
						|
        str = self.find_options(flags['common_flags'], '-O')
 | 
						|
        if str != None:
 | 
						|
            levels = {
 | 
						|
                '-O0': 'none', '-O1': 'optimize', '-O2': 'more',
 | 
						|
                '-O3': 'most', '-Os': 'size', '-Og': 'debug'
 | 
						|
            }
 | 
						|
            if str in levels:
 | 
						|
                opts['common']['optimization.level'] = levels[str]
 | 
						|
                self.remove_option(flags['common_flags'], str)
 | 
						|
 | 
						|
        include_files = []
 | 
						|
        for all_flags in [flags['common_flags'], flags['c_flags'], flags['cxx_flags']]:
 | 
						|
            while '-include' in all_flags:
 | 
						|
                ix = all_flags.index('-include')
 | 
						|
                str = all_flags[ix + 1]
 | 
						|
                if str not in include_files:
 | 
						|
                    include_files.append(str)
 | 
						|
                self.remove_option(all_flags, '-include')
 | 
						|
                self.remove_option(all_flags, str)
 | 
						|
 | 
						|
        opts['common']['include_files'] = include_files
 | 
						|
 | 
						|
        if '-ansi' in flags['c_flags']:
 | 
						|
            opts['c']['compiler.std'] = '-ansi'
 | 
						|
            self.remove_option(flags['c_flags'], str)
 | 
						|
        else:
 | 
						|
            str = self.find_options(flags['c_flags'], '-std')
 | 
						|
            std = str[len('-std='):]
 | 
						|
            c_std = {
 | 
						|
                'c90': 'c90', 'c89': 'c90', 'gnu90': 'gnu90', 'gnu89': 'gnu90',
 | 
						|
                'c99': 'c99', 'c9x': 'c99', 'gnu99': 'gnu99', 'gnu9x': 'gnu98',
 | 
						|
                'c11': 'c11', 'c1x': 'c11', 'gnu11': 'gnu11', 'gnu1x': 'gnu11'
 | 
						|
            }
 | 
						|
            if std in c_std:
 | 
						|
                opts['c']['compiler.std'] = c_std[std]
 | 
						|
                self.remove_option(flags['c_flags'], str)
 | 
						|
 | 
						|
        if '-ansi' in flags['cxx_flags']:
 | 
						|
            opts['cpp']['compiler.std'] = '-ansi'
 | 
						|
            self.remove_option(flags['cxx_flags'], str)
 | 
						|
        else:
 | 
						|
            str = self.find_options(flags['cxx_flags'], '-std')
 | 
						|
            std = str[len('-std='):]
 | 
						|
            cpp_std = {
 | 
						|
                'c++98': 'cpp98', 'c++03': 'cpp98',
 | 
						|
                'gnu++98': 'gnucpp98', 'gnu++03': 'gnucpp98',
 | 
						|
                'c++0x': 'cpp0x', 'gnu++0x': 'gnucpp0x',
 | 
						|
                'c++11': 'cpp11', 'gnu++11': 'gnucpp11',
 | 
						|
                'c++1y': 'cpp1y', 'gnu++1y': 'gnucpp1y',
 | 
						|
                'c++14': 'cpp14', 'gnu++14': 'gnucpp14',
 | 
						|
                'c++1z': 'cpp1z', 'gnu++1z': 'gnucpp1z',
 | 
						|
            }
 | 
						|
            if std in cpp_std:
 | 
						|
                opts['cpp']['compiler.std'] = cpp_std[std]
 | 
						|
                self.remove_option(flags['cxx_flags'], str)
 | 
						|
 | 
						|
        # Common optimisation options.
 | 
						|
        optimization_options = {
 | 
						|
            '-fmessage-length=0': 'optimization.messagelength',
 | 
						|
            '-fsigned-char': 'optimization.signedchar',
 | 
						|
            '-ffunction-sections': 'optimization.functionsections',
 | 
						|
            '-fdata-sections': 'optimization.datasections',
 | 
						|
            '-fno-common': 'optimization.nocommon',
 | 
						|
            '-fno-inline-functions': 'optimization.noinlinefunctions',
 | 
						|
            '-ffreestanding': 'optimization.freestanding',
 | 
						|
            '-fno-builtin': 'optimization.nobuiltin',
 | 
						|
            '-fsingle-precision-constant': 'optimization.spconstant',
 | 
						|
            '-fPIC': 'optimization.PIC',
 | 
						|
            '-fno-move-loop-invariants': 'optimization.nomoveloopinvariants',
 | 
						|
        }
 | 
						|
 | 
						|
        for option in optimization_options:
 | 
						|
            opts['common'][optimization_options[option]] = False
 | 
						|
            if option in flags['common_flags']:
 | 
						|
                opts['common'][optimization_options[option]] = True
 | 
						|
                self.remove_option(flags['common_flags'], option)
 | 
						|
 | 
						|
        # Common warning options.
 | 
						|
        warning_options = {
 | 
						|
            '-fsyntax-only': 'warnings.syntaxonly',
 | 
						|
            '-pedantic': 'warnings.pedantic',
 | 
						|
            '-pedantic-errors': 'warnings.pedanticerrors',
 | 
						|
            '-w': 'warnings.nowarn',
 | 
						|
            '-Wunused': 'warnings.unused',
 | 
						|
            '-Wuninitialized': 'warnings.uninitialized',
 | 
						|
            '-Wall': 'warnings.allwarn',
 | 
						|
            '-Wextra': 'warnings.extrawarn',
 | 
						|
            '-Wmissing-declarations': 'warnings.missingdeclaration',
 | 
						|
            '-Wconversion': 'warnings.conversion',
 | 
						|
            '-Wpointer-arith': 'warnings.pointerarith',
 | 
						|
            '-Wpadded': 'warnings.padded',
 | 
						|
            '-Wshadow': 'warnings.shadow',
 | 
						|
            '-Wlogical-op': 'warnings.logicalop',
 | 
						|
            '-Waggregate-return': 'warnings.agreggatereturn',
 | 
						|
            '-Wfloat-equal': 'warnings.floatequal',
 | 
						|
            '-Werror': 'warnings.toerrors',
 | 
						|
        }
 | 
						|
 | 
						|
        for option in warning_options:
 | 
						|
            opts['common'][warning_options[option]] = False
 | 
						|
            if option in flags['common_flags']:
 | 
						|
                opts['common'][warning_options[option]] = True
 | 
						|
                self.remove_option(flags['common_flags'], option)
 | 
						|
 | 
						|
        # Common debug options.
 | 
						|
        debug_levels = {
 | 
						|
            '-g': 'default',
 | 
						|
            '-g1': 'minimal',
 | 
						|
            '-g3': 'max',
 | 
						|
        }
 | 
						|
        opts['common']['debugging.level'] = 'none'
 | 
						|
        for option in debug_levels:
 | 
						|
            if option in flags['common_flags']:
 | 
						|
                opts['common'][
 | 
						|
                    'debugging.level'] = debug_levels[option]
 | 
						|
                self.remove_option(flags['common_flags'], option)
 | 
						|
 | 
						|
        debug_formats = {
 | 
						|
            '-ggdb': 'gdb',
 | 
						|
            '-gstabs': 'stabs',
 | 
						|
            '-gstabs+': 'stabsplus',
 | 
						|
            '-gdwarf-2': 'dwarf2',
 | 
						|
            '-gdwarf-3': 'dwarf3',
 | 
						|
            '-gdwarf-4': 'dwarf4',
 | 
						|
            '-gdwarf-5': 'dwarf5',
 | 
						|
        }
 | 
						|
 | 
						|
        opts['common']['debugging.format'] = ''
 | 
						|
        for option in debug_levels:
 | 
						|
            if option in flags['common_flags']:
 | 
						|
                opts['common'][
 | 
						|
                    'debugging.format'] = debug_formats[option]
 | 
						|
                self.remove_option(flags['common_flags'], option)
 | 
						|
 | 
						|
        opts['common']['debugging.prof'] = False
 | 
						|
        if '-p' in flags['common_flags']:
 | 
						|
            opts['common']['debugging.prof'] = True
 | 
						|
            self.remove_option(flags['common_flags'], '-p')
 | 
						|
 | 
						|
        opts['common']['debugging.gprof'] = False
 | 
						|
        if '-pg' in flags['common_flags']:
 | 
						|
            opts['common']['debugging.gprof'] = True
 | 
						|
            self.remove_option(flags['common_flags'], '-gp')
 | 
						|
 | 
						|
        # Assembler options.
 | 
						|
        opts['as']['usepreprocessor'] = False
 | 
						|
        while '-x' in flags['asm_flags']:
 | 
						|
            ix = flags['asm_flags'].index('-x')
 | 
						|
            str = flags['asm_flags'][ix + 1]
 | 
						|
 | 
						|
            if str == 'assembler-with-cpp':
 | 
						|
                opts['as']['usepreprocessor'] = True
 | 
						|
            else:
 | 
						|
                # Collect all other assembler options.
 | 
						|
                opts['as']['other'] += ' -x ' + str
 | 
						|
 | 
						|
            self.remove_option(flags['asm_flags'], '-x')
 | 
						|
            self.remove_option(flags['asm_flags'], 'assembler-with-cpp')
 | 
						|
 | 
						|
        opts['as']['nostdinc'] = False
 | 
						|
        if '-nostdinc' in flags['asm_flags']:
 | 
						|
            opts['as']['nostdinc'] = True
 | 
						|
            self.remove_option(flags['asm_flags'], '-nostdinc')
 | 
						|
 | 
						|
        opts['as']['verbose'] = False
 | 
						|
        if '-v' in flags['asm_flags']:
 | 
						|
            opts['as']['verbose'] = True
 | 
						|
            self.remove_option(flags['asm_flags'], '-v')
 | 
						|
 | 
						|
        # C options.
 | 
						|
        opts['c']['nostdinc'] = False
 | 
						|
        if '-nostdinc' in flags['c_flags']:
 | 
						|
            opts['c']['nostdinc'] = True
 | 
						|
            self.remove_option(flags['c_flags'], '-nostdinc')
 | 
						|
 | 
						|
        opts['c']['verbose'] = False
 | 
						|
        if '-v' in flags['c_flags']:
 | 
						|
            opts['c']['verbose'] = True
 | 
						|
            self.remove_option(flags['c_flags'], '-v')
 | 
						|
 | 
						|
        warning_options = {
 | 
						|
            '-Wmissing-prototypes': 'warnings.missingprototypes',
 | 
						|
            '-Wstrict-prototypes': 'warnings.strictprototypes',
 | 
						|
            '-Wbad-function-cast': 'warnings.badfunctioncast',
 | 
						|
        }
 | 
						|
 | 
						|
        for option in warning_options:
 | 
						|
            opts['c'][warning_options[option]] = False
 | 
						|
            if option in flags['common_flags']:
 | 
						|
                opts['c'][warning_options[option]] = True
 | 
						|
                self.remove_option(flags['common_flags'], option)
 | 
						|
 | 
						|
        # C++ options.
 | 
						|
        opts['cpp']['nostdinc'] = False
 | 
						|
        if '-nostdinc' in flags['cxx_flags']:
 | 
						|
            opts['cpp']['nostdinc'] = True
 | 
						|
            self.remove_option(flags['cxx_flags'], '-nostdinc')
 | 
						|
 | 
						|
        opts['cpp']['nostdincpp'] = False
 | 
						|
        if '-nostdinc++' in flags['cxx_flags']:
 | 
						|
            opts['cpp']['nostdincpp'] = True
 | 
						|
            self.remove_option(flags['cxx_flags'], '-nostdinc++')
 | 
						|
 | 
						|
        optimization_options = {
 | 
						|
            '-fno-exceptions': 'optimization.noexceptions',
 | 
						|
            '-fno-rtti': 'optimization.nortti',
 | 
						|
            '-fno-use-cxa-atexit': 'optimization.nousecxaatexit',
 | 
						|
            '-fno-threadsafe-statics': 'optimization.nothreadsafestatics',
 | 
						|
        }
 | 
						|
 | 
						|
        for option in optimization_options:
 | 
						|
            opts['cpp'][optimization_options[option]] = False
 | 
						|
            if option in flags['cxx_flags']:
 | 
						|
                opts['cpp'][optimization_options[option]] = True
 | 
						|
                self.remove_option(flags['cxx_flags'], option)
 | 
						|
            if option in flags['common_flags']:
 | 
						|
                opts['cpp'][optimization_options[option]] = True
 | 
						|
                self.remove_option(flags['common_flags'], option)
 | 
						|
 | 
						|
        warning_options = {
 | 
						|
            '-Wabi': 'warnabi',
 | 
						|
            '-Wctor-dtor-privacy': 'warnings.ctordtorprivacy',
 | 
						|
            '-Wnoexcept': 'warnings.noexcept',
 | 
						|
            '-Wnon-virtual-dtor': 'warnings.nonvirtualdtor',
 | 
						|
            '-Wstrict-null-sentinel': 'warnings.strictnullsentinel',
 | 
						|
            '-Wsign-promo': 'warnings.signpromo',
 | 
						|
            '-Weffc++': 'warneffc',
 | 
						|
        }
 | 
						|
 | 
						|
        for option in warning_options:
 | 
						|
            opts['cpp'][warning_options[option]] = False
 | 
						|
            if option in flags['cxx_flags']:
 | 
						|
                opts['cpp'][warning_options[option]] = True
 | 
						|
                self.remove_option(flags['cxx_flags'], option)
 | 
						|
            if option in flags['common_flags']:
 | 
						|
                opts['cpp'][warning_options[option]] = True
 | 
						|
                self.remove_option(flags['common_flags'], option)
 | 
						|
 | 
						|
        opts['cpp']['verbose'] = False
 | 
						|
        if '-v' in flags['cxx_flags']:
 | 
						|
            opts['cpp']['verbose'] = True
 | 
						|
            self.remove_option(flags['cxx_flags'], '-v')
 | 
						|
 | 
						|
        # Linker options.
 | 
						|
        linker_options = {
 | 
						|
            '-nostartfiles': 'nostart',
 | 
						|
            '-nodefaultlibs': 'nodeflibs',
 | 
						|
            '-nostdlib': 'nostdlibs',
 | 
						|
        }
 | 
						|
 | 
						|
        for option in linker_options:
 | 
						|
            opts['ld'][linker_options[option]] = False
 | 
						|
            if option in flags['ld_flags']:
 | 
						|
                opts['ld'][linker_options[option]] = True
 | 
						|
                self.remove_option(flags['ld_flags'], option)
 | 
						|
 | 
						|
        opts['ld']['gcsections'] = False
 | 
						|
        if '-Wl,--gc-sections' in flags['ld_flags']:
 | 
						|
            opts['ld']['gcsections'] = True
 | 
						|
            self.remove_option(flags['ld_flags'], '-Wl,--gc-sections')
 | 
						|
 | 
						|
        opts['ld']['flags'] = []
 | 
						|
        to_remove = []
 | 
						|
        for opt in flags['ld_flags']:
 | 
						|
            if opt.startswith('-Wl,--wrap,'):
 | 
						|
                opts['ld']['flags'].append(
 | 
						|
                    '--wrap=' + opt[len('-Wl,--wrap,'):])
 | 
						|
                to_remove.append(opt)
 | 
						|
        for opt in to_remove:
 | 
						|
            self.remove_option(flags['ld_flags'], opt)
 | 
						|
 | 
						|
        # Other tool remaining options are separated by category.
 | 
						|
        opts['as']['otherwarnings'] = self.find_options(
 | 
						|
            flags['asm_flags'], '-W')
 | 
						|
 | 
						|
        opts['c']['otherwarnings'] = self.find_options(
 | 
						|
            flags['c_flags'], '-W')
 | 
						|
        opts['c']['otheroptimizations'] = self.find_options(flags[
 | 
						|
            'c_flags'], '-f')
 | 
						|
 | 
						|
        opts['cpp']['otherwarnings'] = self.find_options(
 | 
						|
            flags['cxx_flags'], '-W')
 | 
						|
        opts['cpp']['otheroptimizations'] = self.find_options(
 | 
						|
            flags['cxx_flags'], '-f')
 | 
						|
 | 
						|
        # Other common remaining options are separated by category.
 | 
						|
        opts['common']['optimization.other'] = self.find_options(
 | 
						|
            flags['common_flags'], '-f')
 | 
						|
        opts['common']['warnings.other'] = self.find_options(
 | 
						|
            flags['common_flags'], '-W')
 | 
						|
 | 
						|
        # Remaining common flags are added to each tool.
 | 
						|
        opts['as']['other'] += ' ' + \
 | 
						|
            ' '.join(flags['common_flags']) + ' ' + \
 | 
						|
            ' '.join(flags['asm_flags'])
 | 
						|
        opts['c']['other'] += ' ' + \
 | 
						|
            ' '.join(flags['common_flags']) + ' ' + ' '.join(flags['c_flags'])
 | 
						|
        opts['cpp']['other'] += ' ' + \
 | 
						|
            ' '.join(flags['common_flags']) + ' ' + \
 | 
						|
            ' '.join(flags['cxx_flags'])
 | 
						|
        opts['ld']['other'] += ' ' + \
 | 
						|
            ' '.join(flags['common_flags']) + ' ' + ' '.join(flags['ld_flags'])
 | 
						|
 | 
						|
        if len(self.system_libraries) > 0:
 | 
						|
            opts['ld']['other'] += ' -Wl,--start-group '
 | 
						|
            opts['ld'][
 | 
						|
                'other'] += ' '.join('-l' + s for s in self.system_libraries)
 | 
						|
            opts['ld']['other'] += ' -Wl,--end-group '
 | 
						|
 | 
						|
        # Strip all 'other' flags, since they might have leading spaces.
 | 
						|
        opts['as']['other'] = opts['as']['other'].strip()
 | 
						|
        opts['c']['other'] = opts['c']['other'].strip()
 | 
						|
        opts['cpp']['other'] = opts['cpp']['other'].strip()
 | 
						|
        opts['ld']['other'] = opts['ld']['other'].strip()
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def find_options(lst, option):
 | 
						|
        tmp = [str for str in lst if str.startswith(option)]
 | 
						|
        if len(tmp) > 0:
 | 
						|
            return tmp[0]
 | 
						|
        else:
 | 
						|
            return None
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def find_options(lst, prefix):
 | 
						|
        other = ''
 | 
						|
        opts = [str for str in lst if str.startswith(prefix)]
 | 
						|
        if len(opts) > 0:
 | 
						|
            for opt in opts:
 | 
						|
                other += ' ' + opt
 | 
						|
                GNUARMEclipse.remove_option(lst, opt)
 | 
						|
        return other.strip()
 | 
						|
 | 
						|
    @staticmethod
 | 
						|
    def remove_option(lst, option):
 | 
						|
        if option in lst:
 | 
						|
            lst.remove(option)
 | 
						|
 | 
						|
# =============================================================================
 |