示例#1
0
class EmBitz(Exporter):
    NAME = 'EmBitz'
    TOOLCHAIN = 'GCC_ARM'


    TARGETS = filter_supported("GCC_ARM", POST_BINARY_WHITELIST)

    MBED_CONFIG_HEADER_SUPPORTED = True

    FILE_TYPES = {
        'headers': 'h',
        'c_sources': 'c',
        's_sources': 'a',
        'cpp_sources': 'cpp'
    }


    @staticmethod
    def _remove_symbols(sym_list):
        return [s for s in sym_list if not s.startswith("-D")]

    def generate(self):
        self.resources.win_to_unix()
        source_files = []
        for r_type, n in self.FILE_TYPES.iteritems():
            for file in getattr(self.resources, r_type):
                source_files.append({
                    'name': file, 'type': n
                })

        libraries = []
        for lib in self.resources.libraries:
            l, _ = splitext(basename(lib))
            libraries.append(l[3:])


        if self.resources.linker_script is None:
            self.resources.linker_script = ''

        ctx = {
            'name': self.project_name,
            'target': self.target,
            'toolchain': self.toolchain.name,
            'source_files': source_files,
            'include_paths': self.resources.inc_dirs,
            'script_file': self.resources.linker_script,
            'library_paths': self.resources.lib_dirs,
            'libraries': libraries,
            'symbols': self.toolchain.get_symbols(),
            'object_files': self.resources.objects,
            'sys_libs': self.toolchain.sys_libs,
            'cc_org': (self.flags['common_flags'] +
                       self._remove_symbols(self.flags['c_flags'])),
            'ld_org': self.flags['ld_flags'],
            'cppc_org': (self.flags['common_flags'] +
                         self._remove_symbols(self.flags['cxx_flags']))
        }

        self.gen_file('embitz/eix.tmpl', ctx, '%s.eix' % self.project_name)
示例#2
0
文件: __init__.py 项目: INU-NMS/Node
class QtCreator(GccArm):
    NAME = 'QtCreator'
    TOOLCHAIN = 'GCC_ARM'

    TARGETS = filter_supported("GCC_ARM", set())

    MBED_CONFIG_HEADER_SUPPORTED = True

    def generate(self):
        self.resources.win_to_unix()

        defines = [
        ]  # list of tuples ('D'/'U', [key, value]) (value is optional)
        forced_includes = []  # list of strings
        sources = []  # list of strings
        include_paths = []  # list of strings

        next_is_include = False
        for f in self.flags['c_flags'] + self.flags['cxx_flags']:
            f = f.strip()
            if next_is_include:
                forced_includes.append(f)
                next_is_include = False
                continue
            if f.startswith('-D'):
                defines.append(('D', f[2:].split('=', 1)))
            elif f.startswith('-U'):
                defines.append(('U', [f[2:]]))
            elif f == "-include":
                next_is_include = True

        for r_type in ['headers', 'c_sources', 's_sources', 'cpp_sources']:
            sources.extend(getattr(self.resources, r_type))

        include_paths = self.resources.inc_dirs

        ctx = {
            'defines': defines,
            'forced_includes': forced_includes,
            'sources': sources,
            'include_paths': self.resources.inc_dirs
        }

        for ext in ['creator', 'files', 'includes', 'config']:
            self.gen_file('qtcreator/%s.tmpl' % ext, ctx,
                          "%s.%s" % (self.project_name, ext))

        # finally, generate the Makefile
        super(QtCreator, self).generate()
示例#3
0
class Armc5(Makefile):
    """ARM Compiler 5 specific makefile target"""
    TARGETS = filter_supported("ARM", Makefile.POST_BINARY_WHITELIST)
    NAME = 'Make-ARMc5'
    TEMPLATE = 'make-armc5'
    TOOLCHAIN = "ARM"
    LINK_SCRIPT_OPTION = "--scatter"
    USER_LIBRARY_FLAG = "--userlibpath "

    @staticmethod
    def prepare_lib(libname):
        return libname

    @staticmethod
    def prepare_sys_lib(libname):
        return libname
示例#4
0
class GccArm(Makefile):
    """GCC ARM specific makefile target"""
    TARGETS = filter_supported("GCC_ARM", Makefile.POST_BINARY_WHITELIST)
    NAME = 'Make-GCC-ARM'
    TEMPLATE = 'make-gcc-arm'
    TOOLCHAIN = "GCC_ARM"
    LINK_SCRIPT_OPTION = "-T"
    USER_LIBRARY_FLAG = "-L"

    @staticmethod
    def prepare_lib(libname):
        return "-l:" + libname

    @staticmethod
    def prepare_sys_lib(libname):
        return "-l" + libname
示例#5
0
class IAR(Makefile):
    """IAR specific makefile target"""
    TARGETS = filter_supported("IAR", Makefile.POST_BINARY_WHITELIST)
    NAME = 'Make-IAR'
    TEMPLATE = 'make-iar'
    TOOLCHAIN = "IAR"
    LINK_SCRIPT_OPTION = "--config"
    USER_LIBRARY_FLAG = "-L"

    @staticmethod
    def prepare_lib(libname):
        if "lib" == libname[:3]:
            libname = libname[3:]
        return "-l" + splitext(libname)[0]

    @staticmethod
    def prepare_sys_lib(libname):
        if "lib" == libname[:3]:
            libname = libname[3:]
        return "-l" + splitext(libname)[0]
示例#6
0
文件: __init__.py 项目: INU-NMS/Node
class GNUARMEclipse(Exporter):
    NAME = 'GNU ARM Eclipse'
    TOOLCHAIN = 'GCC_ARM'

    TARGETS = filter_supported("GCC_ARM", POST_BINARY_WHITELIST)

    # override
    @property
    def flags(self):
        """Returns a dictionary of toolchain flags.
        Keys of the dictionary are:
        cxx_flags    - c++ flags
        c_flags      - c flags
        ld_flags     - linker flags
        asm_flags    - assembler flags
        common_flags - common options

        The difference from the parent function is that it does not
        add macro definitions, since they are passed separately.
        """

        config_header = self.toolchain.get_config_header()
        flags = {
            key + "_flags": copy.deepcopy(value)
            for key, value in self.toolchain.flags.iteritems()
        }
        if config_header:
            config_header = relpath(
                config_header, self.resources.file_basepath[config_header])
            flags['c_flags'] += self.toolchain.get_config_option(config_header)
            flags['cxx_flags'] += self.toolchain.get_config_option(
                config_header)
        return flags

    def toolchain_flags(self, toolchain):
        """Returns a dictionary of toolchain flags.
        Keys of the dictionary are:
        cxx_flags    - c++ flags
        c_flags      - c flags
        ld_flags     - linker flags
        asm_flags    - assembler flags
        common_flags - common options

        The difference from the above is that it takes a parameter.
        """

        # Note: use the config options from the currently selected toolchain.
        config_header = self.toolchain.get_config_header()

        flags = {
            key + "_flags": copy.deepcopy(value)
            for key, value in toolchain.flags.iteritems()
        }
        if config_header:
            config_header = relpath(
                config_header, self.resources.file_basepath[config_header])
            header_options = self.toolchain.get_config_option(config_header)
            flags['c_flags'] += header_options
            flags['cxx_flags'] += header_options
        return flags

    # override
    def generate(self):
        """
        Generate the .project and .cproject files.
        """
        if not self.resources.linker_script:
            raise NotSupportedException("No linker script found.")

        print
        print 'Create a GNU ARM Eclipse C++ managed project'
        print 'Project name: {0}'.format(self.project_name)
        print 'Target: {0}'.format(self.toolchain.target.name)
        print 'Toolchain: {0}'.format(self.TOOLCHAIN)

        self.resources.win_to_unix()

        # TODO: use some logger to display additional info if verbose

        libraries = []
        # print 'libraries'
        # print self.resources.libraries
        for lib in self.resources.libraries:
            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')
        # print build_folders

        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 + '/')]
        # print 'objects'
        # print objects

        self.compute_exclusions()

        self.include_path = [
            self.filter_dot(s) for s in self.resources.inc_dirs
        ]
        print 'Include folders: {0}'.format(len(self.include_path))

        self.as_defines = self.toolchain.get_symbols(True)
        self.c_defines = self.toolchain.get_symbols()
        self.cpp_defines = self.c_defines
        print 'Symbols: {0}'.format(len(self.c_defines))

        self.ld_script = self.filter_dot(self.resources.linker_script)
        print 'Linker script: {0}'.format(self.ld_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()

            print
            print 'Build configuration: {0}'.format(opts['name'])

            profile = profiles[id]
            profile_toolchain = profile[self.TOOLCHAIN]

            # 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_toolchain)

            # Hack to fill in build_dir
            toolchain.build_dir = self.toolchain.build_dir

            flags = self.toolchain_flags(toolchain)

            print 'Common flags:', ' '.join(flags['common_flags'])
            print 'C++ flags:', ' '.join(flags['cxx_flags'])
            print 'C flags:', ' '.join(flags['c_flags'])
            print 'ASM flags:', ' '.join(flags['asm_flags'])
            print 'Linker flags:', ' '.join(flags['ld_flags'])

            # 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']['system_libraries'] = self.system_libraries
            opts['ld']['script'] = join(id.capitalize(),
                                        "linker-script-%s.ld" % id)
            opts['cpp_cmd'] = " ".join(toolchain.preproc)

            # 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,
        }

        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('gnuarmeclipse/mbedignore.tmpl', jinja_ctx,
                      '.mbedignore')

        print
        print 'Done. Import the \'{0}\' project in Eclipse.'.format(
            self.project_name)

    # 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)
            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')

        # 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")
        ]

        # print file_names

        profile_names = [
            basename(fn).replace(".json", "") for fn in file_names
        ]
        # print profile_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
        """
        source_folders = [
            self.filter_dot(s) for s in set(
                dirname(src) for src in self.resources.c_sources +
                self.resources.cpp_sources + self.resources.s_sources)
        ]
        if '.' in source_folders:
            source_folders.remove('.')

        # print 'source folders'
        # print source_folders

        # Source folders were converted before and are guaranteed to
        # use the POSIX separator.
        top_folders = [f for f in set(s.split('/')[0] for s in source_folders)]
        # print 'top folders'
        # print top_folders

        self.source_tree = {}
        for top_folder in top_folders:
            for root, dirs, files in os.walk(top_folder, topdown=True):
                # print root, dirs, files

                # Paths returned by os.walk() must be split with os.dep
                # to accomodate Windows weirdness.
                parts = root.split(os.sep)

                # Ignore paths that include parts starting with dot.
                skip = False
                for part in parts:
                    if part.startswith('.'):
                        skip = True
                        break
                if skip:
                    continue

                # Further process only leaf paths, (that do not have
                # sub-folders).
                if len(dirs) == 0:
                    # The path is reconstructed using POSIX separators.
                    self.add_source_folder_to_tree('/'.join(parts))

        for folder in source_folders:
            self.add_source_folder_to_tree(folder, True)

        # print
        # print self.source_tree
        # self.dump_paths(self.source_tree)
        # self.dump_tree(self.source_tree)

        # print 'excludings'
        self.excluded_folders = ['BUILD']
        self.recurse_excludings(self.source_tree)

        print 'Source folders: {0}, with {1} exclusions'.format(
            len(source_folders), len(self.excluded_folders))

    def add_source_folder_to_tree(self, path, is_used=False):
        """
        Decompose a path in an array of folder names and create the tree.
        On the second pass the nodes should be already there; mark them
        as used.
        """
        # print path, is_used

        # All paths arriving here are guaranteed to use the POSIX
        # separators, os.walk() paths were also explicitly converted.
        parts = path.split('/')
        # print parts
        node = self.source_tree
        prev = None
        for part in parts:
            if part not in node.keys():
                new_node = {}
                new_node['name'] = part
                new_node['children'] = {}
                if prev != None:
                    new_node['parent'] = prev
                node[part] = new_node
            node[part]['is_used'] = is_used
            prev = node[part]
            node = node[part]['children']

    def recurse_excludings(self, nodes):
        """
        Recurse the tree and collect all unused folders; descend
        the hierarchy only for used nodes.
        """
        for k in nodes.keys():
            node = nodes[k]
            if node['is_used'] == False:
                parts = []
                cnode = node
                while True:
                    parts.insert(0, cnode['name'])
                    if 'parent' not in cnode:
                        break
                    cnode = cnode['parent']

                # Compose a POSIX path.
                path = '/'.join(parts)
                # print path
                self.excluded_folders.append(path)
            else:
                self.recurse_excludings(node['children'])

    # -------------------------------------------------------------------------

    @staticmethod
    def filter_dot(str):
        """
        Remove the './' prefix, if present.
        This function assumes that resources.win_to_unix()
        replaced all windows backslashes with slashes.
        """
        if str == None:
            return None
        if str[:2] == './':
            return str[2:]
        return str

    # -------------------------------------------------------------------------

    def dump_tree(self, nodes, depth=0):
        for k in nodes.keys():
            node = nodes[k]
            parent_name = node['parent']['name'] if 'parent' in node.keys(
            ) else ''
            print '  ' * depth, node['name'], node['is_used'], parent_name
            if len(node['children'].keys()) != 0:
                self.dump_tree(node['children'], depth + 1)

    def dump_paths(self, nodes, depth=0):
        for k in nodes.keys():
            node = nodes[k]
            parts = []
            while True:
                parts.insert(0, node['name'])
                if 'parent' not in node:
                    break
                node = node['parent']
            path = '/'.join(parts)
            print path, nodes[k]['is_used']
            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)

        if False:
            print
            print 'common_flags', flags['common_flags']
            print 'asm_flags', flags['asm_flags']
            print 'c_flags', flags['c_flags']
            print 'cxx_flags', flags['cxx_flags']
            print 'ld_flags', flags['ld_flags']

        # 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()

        if False:
            print
            print opts

            print
            print 'common_flags', flags['common_flags']
            print 'asm_flags', flags['asm_flags']
            print 'c_flags', flags['c_flags']
            print 'cxx_flags', flags['cxx_flags']
            print 'ld_flags', flags['ld_flags']

    @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)
示例#7
0
class Uvision(Exporter):
    """Keil Uvision class

    This class encapsulates information to be contained in a Uvision
    project file (.uvprojx).
    The needed information can be viewed in uvision.tmpl
    """
    NAME = 'uvision5'
    TOOLCHAIN = 'ARM'

    POST_BINARY_WHITELIST = set([
        "MCU_NRF51Code.binary_hook",
        "TEENSY3_1Code.binary_hook",
        "LPCTargetCode.lpc_patch",
        "LPC4088Code.binary_hook",
        "MTSCode.combine_bins_mts_dot",
        "MTSCode.combine_bins_mts_dragonfly",
        "NCS36510TargetCode.ncs36510_addfib"
    ])
    TARGETS = [tgt for tgt in filter_supported("ARM", POST_BINARY_WHITELIST)
               if DeviceCMSIS.check_supported(tgt)]

    #File associations within .uvprojx file
    file_types = {'.cpp': 8, '.c': 1, '.s': 2,
                  '.obj': 3, '.o': 3, '.lib': 4,
                  '.ar': 4, '.h': 5, '.hpp': 5, '.sct': 4}

    def uv_files(self, files):
        """An generator containing Uvision specific information about project files
        Positional Arguments:
        files - the location of source files

        .uvprojx XML for project file:
        <File>
            <FileType>{{file.type}}</FileType>
            <FileName>{{file.name}}</FileName>
            <FilePath>{{file.loc}}</FilePath>
        </File>
        """
        for loc in files:
            #Encapsulates the information necessary for template entry above
            UVFile = namedtuple('UVFile', ['type','loc','name'])
            _, ext = os.path.splitext(loc)
            if ext.lower() in self.file_types:
                type = self.file_types[ext.lower()]
                name = ntpath.basename(normpath(loc))
                yield UVFile(type, loc, name)

    def format_flags(self):
        """Format toolchain flags for Uvision"""
        flags = copy.deepcopy(self.flags)
        # to be preprocessed with armcc
        asm_flag_string = '--cpreproc --cpreproc_opts=-D__ASSERT_MSG,' + \
                          ",".join(flags['asm_flags'])
        flags['asm_flags'] = asm_flag_string
        # All non-asm flags are in one template field
        c_flags = list(set(flags['c_flags'] + flags['cxx_flags'] +flags['common_flags']))
        # These flags are in template to be set by user i n IDE
        template = ["--no_vla", "--cpp", "--c99"]
        # Flag is invalid if set in template
        # Optimizations are also set in the template
        invalid_flag = lambda x: x in template or re.match("-O(\d|time)", x) 
        flags['c_flags'] = [flag.replace('"','\\"') for flag in c_flags if not invalid_flag(flag)]
        flags['c_flags'] = " ".join(flags['c_flags'])
        return flags

    def format_src(self, srcs):
        """Make sources into the named tuple for use in the template"""
        grouped = self.group_project_files(srcs)
        for group, files in grouped.items():
            grouped[group] = sorted(list(self.uv_files(files)),
                                    key=lambda (_, __, name): name.lower())
        return grouped

    @staticmethod
    def format_fpu(core):
        """Generate a core's FPU string"""
        if core.endswith("FD"):
            return "FPU3(DFPU)"
        elif core.endswith("F"):
            return "FPU2"
        else:
            return ""

    def generate(self):
        """Generate the .uvproj file"""
        cache = Cache(True, False)
        if cache_d:
            cache.cache_descriptors()

        srcs = self.resources.headers + self.resources.s_sources + \
               self.resources.c_sources + self.resources.cpp_sources + \
               self.resources.objects + self.resources.libraries
        ctx = {
            'name': self.project_name,
            # project_files => dict of generators - file group to generator of
            # UVFile tuples defined above
            'project_files': sorted(list(self.format_src(srcs).iteritems()),
                                    key=lambda (group, _): group.lower()),
            'linker_script':self.resources.linker_script,
            'include_paths': '; '.join(self.resources.inc_dirs).encode('utf-8'),
            'device': DeviceUvision(self.target),
        }
        core = ctx['device'].core
        ctx['cputype'] = core.rstrip("FD")
        if core.endswith("FD"):
            ctx['fpu_setting'] = 3
        elif core.endswith("F"):
            ctx['fpu_setting'] = 2
        else:
            ctx['fpu_setting'] = 1
        ctx['fputype'] = self.format_fpu(core)
        ctx.update(self.format_flags())
        self.gen_file('uvision/uvision.tmpl', ctx, self.project_name+".uvprojx")
        self.gen_file('uvision/uvision_debug.tmpl', ctx, self.project_name + ".uvoptx")

    @staticmethod
    def build(project_name, log_name='build_log.txt', cleanup=True):
        """ Build Uvision project """
        # > UV4 -r -j0 -o [log_name] [project_name].uvprojx
        proj_file = project_name + ".uvprojx"
        cmd = ['UV4', '-r', '-j0', '-o', log_name, proj_file]

        # Build the project
        p = Popen(cmd, stdout=PIPE, stderr=PIPE)
        out, err = p.communicate()
        ret_code = p.returncode

        # Print the log file to stdout
        with open(log_name, 'r') as f:
            print f.read()

        # Cleanup the exported and built files
        if cleanup:
            os.remove(log_name)
            os.remove(project_name+".uvprojx")
            os.remove(project_name+".uvoptx")
            # legacy .build directory cleaned if exists
            if exists('.build'):
                shutil.rmtree('.build')
            if exists('BUILD'):
                shutil.rmtree('BUILD')

        # Returns 0 upon success, 1 upon a warning, and neither upon an error
        if ret_code != 0 and ret_code != 1:
            # Seems like something went wrong.
            return -1
        else:
            return 0