class CMSIS(Exporter): NAME = 'cmsis' TOOLCHAIN = 'ARM' TARGETS = [ target for target, obj in TARGET_MAP.iteritems() if "ARM" in obj.supported_toolchains ] def make_key(self, src): """turn a source file into its group name""" key = src.name.split(sep)[0] if key == ".": key = os.path.basename(os.path.realpath(self.export_dir)) return key def group_project_files(self, sources, root_element): """Recursively group the source files by their encompassing directory""" data = sorted(sources, key=self.make_key) for group, files in groupby(data, self.make_key): new_srcs = [] for f in list(files): spl = f.name.split(sep) if len(spl) == 2: file_element = Element('file', attrib={ 'category': f.type, 'name': f.loc }) root_element.append(file_element) else: f.name = os.path.join(*spl[1:]) new_srcs.append(f) if new_srcs: group_element = Element('group', attrib={'name': group}) root_element.append( self.group_project_files(new_srcs, group_element)) return root_element def generate(self): srcs = self.resources.headers + self.resources.s_sources + \ self.resources.c_sources + self.resources.cpp_sources + \ self.resources.objects + self.resources.libraries + \ [self.resources.linker_script] srcs = [fileCMSIS(src, src) for src in srcs if src] ctx = { 'name': self.project_name, 'project_files': tostring(self.group_project_files(srcs, Element('files'))), 'device': DeviceCMSIS(self.target), 'date': '' } # TODO: find how to keep prettyxml from adding xml version to this blob #dom = parseString(ctx['project_files']) #ctx['project_files'] = dom.toprettyxml(indent="\t") self.gen_file('cmsis/cpdsc.tmpl', ctx, 'project.cpdsc')
class IAR(Makefile): """IAR specific makefile target""" TARGETS = [ target for target, obj in TARGET_MAP.iteritems() if "IAR" in obj.supported_toolchains ] NAME = 'Make-IAR' TOOLCHAIN = "IAR" LINK_SCRIPT_OPTION = "--config"
class Armc5(Makefile): """ARM Compiler 5 specific makefile target""" TARGETS = [ target for target, obj in TARGET_MAP.iteritems() if "ARM" in obj.supported_toolchains ] NAME = 'Make-ARMc5' TOOLCHAIN = "ARM" LINK_SCRIPT_OPTION = "--scatter"
class GccArm(Makefile): """GCC ARM specific makefile target""" TARGETS = [ target for target, obj in TARGET_MAP.iteritems() if "GCC_ARM" in obj.supported_toolchains ] NAME = 'Make-GCC-ARM' TOOLCHAIN = "GCC_ARM" LINK_SCRIPT_OPTION = "-T"
class Armc5(Makefile): """ARM Compiler 5 specific makefile target""" TARGETS = [ target for target, obj in TARGET_MAP.iteritems() if "ARM" in obj.supported_toolchains ] NAME = 'Make-ARMc5' TOOLCHAIN = "ARM" LINK_SCRIPT_OPTION = "--scatter" USER_LIBRARY_FLAG = "--userlibpath " @staticmethod def prepare_lib(libname): return libname
class GccArm(Makefile): """GCC ARM specific makefile target""" TARGETS = [ target for target, obj in TARGET_MAP.iteritems() if "GCC_ARM" in obj.supported_toolchains ] NAME = 'Make-GCC-ARM' TOOLCHAIN = "GCC_ARM" LINK_SCRIPT_OPTION = "-T" USER_LIBRARY_FLAG = "-L" @staticmethod def prepare_lib(libname): return "-l:" + libname
def filter_supported(compiler, whitelist): """Generate a list of supported targets for a given compiler and post-binary hook white-list.""" def supported_p(obj): """Internal inner function used for filtering""" if compiler not in obj.supported_toolchains: return False if not hasattr(obj, "post_binary_hook"): return True if obj.post_binary_hook['function'] in whitelist: return True else: return False return list(target for target, obj in TARGET_MAP.iteritems() if supported_p(obj))
class IAR(Makefile): """IAR specific makefile target""" TARGETS = [ target for target, obj in TARGET_MAP.iteritems() if "IAR" in obj.supported_toolchains ] NAME = '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]
class IAR(Exporter): NAME = 'iar' TOOLCHAIN = 'IAR' #iar_definitions.json location def_loc = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..', '..', 'tools', 'export', 'iar', 'iar_definitions.json') #create a dictionary of the definitions with open(def_loc, 'r') as f: IAR_DEFS = json.load(f) #supported targets have a device name and corresponding definition in #iar_definitions.json TARGETS = [ target for target, obj in TARGET_MAP.iteritems() if hasattr(obj, 'device_name') and obj.device_name in IAR_DEFS.keys() ] SPECIAL_TEMPLATES = { 'rz_a1h': 'iar/iar_rz_a1h.ewp.tmpl', 'nucleo_f746zg': 'iar/iar_nucleo_f746zg.ewp.tmpl' } def iar_groups(self, grouped_src): """Return a namedtuple of group info Positional Arguments: grouped_src: dictionary mapping a group(str) to sources within it (list of file names) Relevant part of IAR template {% for group in groups %} <group> <name>group.name</name> {% for file in group.files %} <file> <name>$PROJ_DIR${{file}}</name> </file> {% endfor %} </group> {% endfor %} """ IARgroup = namedtuple('IARgroup', ['name', 'files']) groups = [] for name, files in grouped_src.items(): groups.append(IARgroup(name, files)) return groups def iar_device(self): """Retrieve info from iar_definitions.json""" device_name = TARGET_MAP[self.target].device_name device_info = self.IAR_DEFS[device_name] iar_defaults = { "OGChipSelectEditMenu": "", "CoreVariant": '', "GFPUCoreSlave": '', "GFPUCoreSlave2": 40, "GBECoreSlave": 35 } iar_defaults.update(device_info) IARdevice = namedtuple('IARdevice', iar_defaults.keys()) return IARdevice(**iar_defaults) def format_file(self, file): """Make IAR compatible path""" return join('$PROJ_DIR$', file) def format_src(self, srcs): """Group source files""" grouped = self.group_project_files(srcs) for group, files in grouped.items(): grouped[group] = [self.format_file(src) for src in files] return grouped def get_ewp_template(self): return self.SPECIAL_TEMPLATES.get(self.target.lower(), 'iar/ewp.tmpl') def generate(self): """Generate the .eww, .ewd, and .ewp files""" srcs = self.resources.headers + self.resources.s_sources + \ self.resources.c_sources + self.resources.cpp_sources + \ self.resources.objects + self.resources.libraries flags = self.flags flags['c_flags'] = list( set(flags['common_flags'] + flags['c_flags'] + flags['cxx_flags'])) if '--vla' in flags['c_flags']: flags['c_flags'].remove('--vla') if '--no_static_destruction' in flags['c_flags']: flags['c_flags'].remove('--no_static_destruction') #Optimizations if '-Oh' in flags['c_flags']: flags['c_flags'].remove('-Oh') ctx = { 'name': self.project_name, 'groups': self.iar_groups(self.format_src(srcs)), 'linker_script': self.format_file(self.resources.linker_script), 'include_paths': [self.format_file(src) for src in self.resources.inc_dirs], 'device': self.iar_device(), 'ewp': sep + self.project_name + ".ewp", 'debugger': DeviceCMSIS(self.target).debug.replace('-', '').upper() } ctx.update(flags) self.gen_file('iar/eww.tmpl', ctx, self.project_name + ".eww") self.gen_file('iar/ewd.tmpl', ctx, self.project_name + ".ewd") self.gen_file(self.get_ewp_template(), ctx, self.project_name + ".ewp") def build(self): """ Build IAR project """ # > IarBuild [project_path] -build [project_name] proj_file = join(self.export_dir, self.project_name + ".ewp") if find_executable("IarBuild"): iar_exe = "IarBuild.exe" else: iar_exe = join('C:', sep, 'Program Files (x86)', 'IAR Systems', 'Embedded Workbench 7.5', 'common', 'bin', 'IarBuild.exe') if not exists(iar_exe): raise Exception("IarBuild.exe not found. Add to path.") cmd = [iar_exe, proj_file, '-build', self.project_name] p = Popen(cmd, stdout=PIPE, stderr=PIPE) num_errors = 0 #Parse the output for printing and errors for line in p.stdout.readlines(): sys.stdout.write(line) error_re = '\s*Total number of errors:\s*(\d+)\s*' m = re.match(error_re, line) if m is not None: num_errors = int(m.group(1)) if num_errors != 0: # Seems like something went wrong. raise FailedBuildException( "Project: %s build failed with %s erros" % (proj_file, num_errors))
class EmBitz(Exporter): NAME = 'EmBitz' TOOLCHAIN = 'GCC_ARM' TARGETS = [ target for target, obj in TARGET_MAP.iteritems() if "GCC_ARM" in obj.supported_toolchains ] 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)
if "IAR" not in mcu.supported_toolchains: return False if hasattr(mcu, 'device_name') and mcu.device_name in iar_targets: return True if mcu.name in iar_targets: return True return False _iar_defs = os.path.join( os.path.dirname(os.path.abspath(__file__)), 'iar_definitions.json') with open(_iar_defs, 'r') as f: _GUI_OPTIONS = json.load(f) _IAR_TARGETS = [target for target, obj in TARGET_MAP.iteritems() if _supported(obj, _GUI_OPTIONS.keys())] class IAR(Exporter): NAME = 'iar' TOOLCHAIN = 'IAR' TARGETS = _IAR_TARGETS def iar_groups(self, grouped_src): """Return a namedtuple of group info Positional Arguments: grouped_src: dictionary mapping a group(str) to sources within it (list of file names)
return False if hasattr(mcu, 'device_name') and mcu.device_name in iar_targets: return True if mcu.name in iar_targets: return True return False _iar_defs = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'iar_definitions.json') with open(_iar_defs, 'r') as f: _GUI_OPTIONS = json.load(f) _IAR_TARGETS = [ target for target, obj in TARGET_MAP.iteritems() if _supported(obj, _GUI_OPTIONS.keys()) ] class IAR(Exporter): NAME = 'iar' TOOLCHAIN = 'IAR' TARGETS = _IAR_TARGETS def iar_groups(self, grouped_src): """Return a namedtuple of group info Positional Arguments: grouped_src: dictionary mapping a group(str) to sources within it (list of file names)
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' TARGETS = [] for target, obj in TARGET_MAP.iteritems(): if not ("ARM" in obj.supported_toolchains and hasattr(obj, "device_name")): continue if not DeviceCMSIS.check_supported(target): continue TARGETS.append(target) #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_file(self, loc): """Return a namedtuple of information about project file Positional Arguments: loc - the file's location .uvprojx XML for project file: <File> <FileType>{{file.type}}</FileType> <FileName>{{file.name}}</FileName> <FilePath>{{file.loc}}</FilePath> </File> """ UVFile = namedtuple('UVFile', ['type', 'loc', 'name']) _, ext = os.path.splitext(loc) type = self.file_types[ext.lower()] name = ntpath.basename(normpath(loc)) return UVFile(type, loc, name) def format_flags(self): """Format toolchain flags for Uvision""" flags = copy.deepcopy(self.flags) asm_flag_string = '--cpreproc --cpreproc_opts=-D__ASSERT_MSG,' + \ ",".join(flags['asm_flags']) # asm flags only, common are not valid within uvision project, # they are armcc specific flags['asm_flags'] = asm_flag_string # cxx flags included, as uvision have them all in one tab flags['c_flags'] = list( set(['-D__ASSERT_MSG'] + flags['common_flags'] + flags['c_flags'] + flags['cxx_flags'])) # not compatible with c99 flag set in the template try: flags['c_flags'].remove("--c99") except ValueError: pass # cpp is not required as it's implicit for cpp files try: flags['c_flags'].remove("--cpp") except ValueError: pass # we want no-vla for only cxx, but it's also applied for C in IDE, # thus we remove it try: flags['c_flags'].remove("--no_vla") except ValueError: pass 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] = [self.uv_file(src) for src in files] return grouped 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': self.format_src(srcs), 'linker_script': self.resources.linker_script, 'include_paths': '; '.join(self.resources.inc_dirs).encode('utf-8'), 'device': DeviceUvision(self.target), } # Turn on FPU optimizations if the core has an FPU ctx['fpu_setting'] = 1 if 'f' not in ctx['device'].core.lower() \ or 'd' in ctx['device'].core.lower() else 2 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
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' TARGETS = [] for target, obj in TARGET_MAP.iteritems(): if not ("ARM" in obj.supported_toolchains and hasattr(obj, "device_name")): continue if not DeviceCMSIS.check_supported(target): continue TARGETS.append(target) #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 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") # Turn on FPU optimizations if the core has an FPU ctx['fpu_setting'] = 1 if 'F' not in core or 'D' in core else 2 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
class IAR(Exporter): NAME = 'iar' TOOLCHAIN = 'IAR' #iar_definitions.json location def_loc = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..', '..', 'tools', 'export', 'iar', 'iar_definitions.json') #create a dictionary of the definitions with open(def_loc, 'r') as f: IAR_DEFS = json.load(f) #supported targets have a device name and corresponding definition in #iar_definitions.json TARGETS = [ target for target, obj in TARGET_MAP.iteritems() if hasattr(obj, 'device_name') and obj.device_name in IAR_DEFS.keys() and "IAR" in obj.supported_toolchains and DeviceCMSIS.check_supported(target) ] SPECIAL_TEMPLATES = { 'rz_a1h': 'iar/iar_rz_a1h.ewp.tmpl', 'nucleo_f746zg': 'iar/iar_nucleo_f746zg.ewp.tmpl' } def iar_groups(self, grouped_src): """Return a namedtuple of group info Positional Arguments: grouped_src: dictionary mapping a group(str) to sources within it (list of file names) Relevant part of IAR template {% for group in groups %} <group> <name>group.name</name> {% for file in group.files %} <file> <name>$PROJ_DIR${{file}}</name> </file> {% endfor %} </group> {% endfor %} """ IARgroup = namedtuple('IARgroup', ['name', 'files']) groups = [] for name, files in grouped_src.items(): groups.append(IARgroup(name, files)) return groups def iar_device(self): """Retrieve info from iar_definitions.json""" device_name = TARGET_MAP[self.target].device_name device_info = self.IAR_DEFS[device_name] iar_defaults = { "OGChipSelectEditMenu": "", "CoreVariant": '', "GFPUCoreSlave": '', "GFPUCoreSlave2": 40, "GBECoreSlave": 35 } iar_defaults.update(device_info) IARdevice = namedtuple('IARdevice', iar_defaults.keys()) return IARdevice(**iar_defaults) def format_file(self, file): """Make IAR compatible path""" return join('$PROJ_DIR$', file) def format_src(self, srcs): """Group source files""" grouped = self.group_project_files(srcs) for group, files in grouped.items(): grouped[group] = [self.format_file(src) for src in files] return grouped def get_ewp_template(self): return self.SPECIAL_TEMPLATES.get(self.target.lower(), 'iar/ewp.tmpl') def generate(self): """Generate the .eww, .ewd, and .ewp files""" srcs = self.resources.headers + self.resources.s_sources + \ self.resources.c_sources + self.resources.cpp_sources + \ self.resources.objects + self.resources.libraries flags = self.flags flags['c_flags'] = list( set(flags['common_flags'] + flags['c_flags'] + flags['cxx_flags'])) if '--vla' in flags['c_flags']: flags['c_flags'].remove('--vla') if '--no_static_destruction' in flags['c_flags']: flags['c_flags'].remove('--no_static_destruction') #Optimizations if '-Oh' in flags['c_flags']: flags['c_flags'].remove('-Oh') ctx = { 'name': self.project_name, 'groups': self.iar_groups(self.format_src(srcs)), 'linker_script': self.format_file(self.resources.linker_script), 'include_paths': [self.format_file(src) for src in self.resources.inc_dirs], 'device': self.iar_device(), 'ewp': sep + self.project_name + ".ewp", 'debugger': DeviceCMSIS(self.target).debug.replace('-', '').upper() } ctx.update(flags) self.gen_file('iar/eww.tmpl', ctx, self.project_name + ".eww") self.gen_file('iar/ewd.tmpl', ctx, self.project_name + ".ewd") self.gen_file(self.get_ewp_template(), ctx, self.project_name + ".ewp") @staticmethod def build(project_name, log_name="build_log.txt", cleanup=True): """ Build IAR project """ # > IarBuild [project_path] -build [project_name] proj_file = project_name + ".ewp" cmd = ["IarBuild", proj_file, '-build', project_name] # IAR does not support a '0' option to automatically use all # available CPUs, so we use Python's multiprocessing library # to detect the number of CPUs available cpus_available = cpu_count() jobs = cpus_available if cpus_available else None # Only add the parallel flag if we're using more than one CPU if jobs: cmd += ['-parallel', str(jobs)] # Build the project p = Popen(cmd, stdout=PIPE, stderr=PIPE) out, err = p.communicate() ret_code = p.returncode out_string = "=" * 10 + "STDOUT" + "=" * 10 + "\n" out_string += out out_string += "=" * 10 + "STDERR" + "=" * 10 + "\n" out_string += err if ret_code == 0: out_string += "SUCCESS" else: out_string += "FAILURE" print out_string if log_name: # Write the output to the log file with open(log_name, 'w+') as f: f.write(out_string) # Cleanup the exported and built files if cleanup: os.remove(project_name + ".ewp") os.remove(project_name + ".ewd") os.remove(project_name + ".eww") # legacy output file location if exists('.build'): shutil.rmtree('.build') if exists('BUILD'): shutil.rmtree('BUILD') if ret_code != 0: # Seems like something went wrong. return -1 else: return 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 = 'cmsis' TOOLCHAIN = 'ARM' TARGETS = [ target for target, obj in TARGET_MAP.iteritems() if "ARM" in obj.supported_toolchains ] #File associations within .uvprojx file file_types = { '.cpp': 8, '.c': 1, '.s': 2, '.obj': 3, '.o': 3, '.lib': 4, '.ar': 4, '.h': 5, '.sct': 4 } def uv_file(self, loc): """Return a namedtuple of information about project file Positional Arguments: loc - the file's location .uvprojx XML for project file: <File> <FileType>{{file.type}}</FileType> <FileName>{{file.name}}</FileName> <FilePath>{{file.loc}}</FilePath> </File> """ UVFile = namedtuple('UVFile', ['type', 'loc', 'name']) _, ext = os.path.splitext(loc) type = self.file_types[ext.lower()] name = ntpath.basename(normpath(loc)) return UVFile(type, loc, name) def format_flags(self): """Format toolchain flags for Uvision""" flags = copy.deepcopy(self.flags) asm_flag_string = '--cpreproc --cpreproc_opts=-D__ASSERT_MSG,' + \ ",".join(flags['asm_flags']) # asm flags only, common are not valid within uvision project, # they are armcc specific flags['asm_flags'] = asm_flag_string # cxx flags included, as uvision have them all in one tab flags['c_flags'] = list( set(['-D__ASSERT_MSG'] + flags['common_flags'] + flags['c_flags'] + flags['cxx_flags'])) # not compatible with c99 flag set in the template try: flags['c_flags'].remove("--c99") except ValueError: pass # cpp is not required as it's implicit for cpp files try: flags['c_flags'].remove("--cpp") except ValueError: pass # we want no-vla for only cxx, but it's also applied for C in IDE, # thus we remove it try: flags['c_flags'].remove("--no_vla") except ValueError: pass 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] = [self.uv_file(src) for src in files] return grouped 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': self.format_src(srcs), 'linker_script': self.resources.linker_script, 'include_paths': '; '.join(self.resources.inc_dirs).encode('utf-8'), 'device': DeviceUvision(self.target), } # Turn on FPU optimizations if the core has an FPU ctx['fpu_setting'] = 1 if 'f' not in ctx['device'].core.lower() \ or 'd' in ctx['device'].core.lower() else 2 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") def build(self): ERRORLEVEL = { 0: 'success (0 warnings, 0 errors)', 1: 'warnings', 2: 'errors', 3: 'fatal errors', 11: 'cant write to project file', 12: 'device error', 13: 'error writing', 15: 'error reading xml file', } success = 0 warn = 1 if find_executable("UV4"): uv_exe = "UV4.exe" else: uv_exe = join('C:', sep, 'Keil_v5', 'UV4', 'UV4.exe') if not exists(uv_exe): raise Exception("UV4.exe not found. Add to path.") cmd = [ uv_exe, '-r', '-j0', '-o', join(self.export_dir, 'build_log.txt'), join(self.export_dir, self.project_name + ".uvprojx") ] ret_code = subprocess.call(cmd) with open(join(self.export_dir, 'build_log.txt'), 'r') as build_log: print build_log.read() if ret_code != success and ret_code != warn: # Seems like something went wrong. raise FailedBuildException( "Project: %s build failed with the status: %s" % (self.project_name, ERRORLEVEL.get(ret_code, "Unknown"))) else: return "Project: %s build succeeded with the status: %s" % ( self.project_name, ERRORLEVEL.get(ret_code, "Unknown"))
class IAR(Exporter): NAME = 'iar' TOOLCHAIN = 'IAR' #iar_definitions.json location def_loc = os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..', '..', 'tools', 'export', 'iar', 'iar_definitions.json') #create a dictionary of the definitions with open(def_loc, 'r') as f: IAR_DEFS = json.load(f) def _iar_support(tgt, iar_targets): if "IAR" not in tgt.supported_toolchains: return False if hasattr(tgt, 'device_name') and tgt.device_name in iar_targets: return True if tgt.name in iar_targets: return True return False #supported targets have a name or device_name which maps to a definition #in iar_definitions.json TARGETS = [ target for target, obj in TARGET_MAP.iteritems() if _iar_support(obj, IAR_DEFS.keys()) ] def iar_groups(self, grouped_src): """Return a namedtuple of group info Positional Arguments: grouped_src: dictionary mapping a group(str) to sources within it (list of file names) Relevant part of IAR template {% for group in groups %} <group> <name>group.name</name> {% for file in group.files %} <file> <name>$PROJ_DIR${{file}}</name> </file> {% endfor %} </group> {% endfor %} """ IARgroup = namedtuple('IARgroup', ['name', 'files']) groups = [] for name, files in grouped_src.items(): groups.append(IARgroup(name, files)) return groups def iar_device(self): """Retrieve info from iar_definitions.json""" tgt = TARGET_MAP[self.target] device_name = (tgt.device_name if hasattr(tgt, "device_name") else tgt.name) device_info = self.IAR_DEFS[device_name] iar_defaults = { "OGChipSelectEditMenu": "", "CoreVariant": '', "GFPUCoreSlave": '', "GFPUCoreSlave2": 40, "GBECoreSlave": 35, "GBECoreSlave2": '', "FPU2": 0, "NrRegs": 0, "NEON": '', "CExtraOptionsCheck": 0, "CExtraOptions": "", "CMSISDAPJtagSpeedList": 0, } iar_defaults.update(device_info) IARdevice = namedtuple('IARdevice', iar_defaults.keys()) return IARdevice(**iar_defaults) def format_file(self, file): """Make IAR compatible path""" return join('$PROJ_DIR$', file) def format_src(self, srcs): """Group source files""" grouped = self.group_project_files(srcs) for group, files in grouped.items(): grouped[group] = [self.format_file(src) for src in files] return grouped def generate(self): """Generate the .eww, .ewd, and .ewp files""" if not self.resources.linker_script: raise NotSupportedException("No linker script found.") srcs = self.resources.headers + self.resources.s_sources + \ self.resources.c_sources + self.resources.cpp_sources + \ self.resources.objects + self.resources.libraries flags = self.flags c_flags = list( set(flags['common_flags'] + flags['c_flags'] + flags['cxx_flags'])) # Flags set in template to be set by user in IDE template = ["--vla", "--no_static_destruction"] # Flag invalid if set in template # Optimizations are also set in template invalid_flag = lambda x: x in template or re.match("-O(\d|time|n)", x) flags['c_flags'] = [flag for flag in c_flags if not invalid_flag(flag)] try: debugger = DeviceCMSIS(self.target).debug.replace('-', '').upper() except TargetNotSupportedException: debugger = "CMSISDAP" ctx = { 'name': self.project_name, 'groups': self.iar_groups(self.format_src(srcs)), 'linker_script': self.format_file(self.resources.linker_script), 'include_paths': [self.format_file(src) for src in self.resources.inc_dirs], 'device': self.iar_device(), 'ewp': sep + self.project_name + ".ewp", 'debugger': debugger } ctx.update(flags) self.gen_file('iar/eww.tmpl', ctx, self.project_name + ".eww") self.gen_file('iar/ewd.tmpl', ctx, self.project_name + ".ewd") self.gen_file('iar/ewp.tmpl', ctx, self.project_name + ".ewp") @staticmethod def build(project_name, log_name="build_log.txt", cleanup=True): """ Build IAR project """ # > IarBuild [project_path] -build [project_name] proj_file = project_name + ".ewp" cmd = ["IarBuild", proj_file, '-build', project_name] # IAR does not support a '0' option to automatically use all # available CPUs, so we use Python's multiprocessing library # to detect the number of CPUs available cpus_available = cpu_count() jobs = cpus_available if cpus_available else None # Only add the parallel flag if we're using more than one CPU if jobs: cmd += ['-parallel', str(jobs)] # Build the project p = Popen(cmd, stdout=PIPE, stderr=PIPE) out, err = p.communicate() ret_code = p.returncode out_string = "=" * 10 + "STDOUT" + "=" * 10 + "\n" out_string += out out_string += "=" * 10 + "STDERR" + "=" * 10 + "\n" out_string += err if ret_code == 0: out_string += "SUCCESS" else: out_string += "FAILURE" print out_string if log_name: # Write the output to the log file with open(log_name, 'w+') as f: f.write(out_string) # Cleanup the exported and built files if cleanup: os.remove(project_name + ".ewp") os.remove(project_name + ".ewd") os.remove(project_name + ".eww") # legacy output file location if exists('.build'): shutil.rmtree('.build') if exists('BUILD'): shutil.rmtree('BUILD') if ret_code != 0: # Seems like something went wrong. return -1 else: return 0
class GNUARMEclipse(Exporter): NAME = 'GNU ARM Eclipse' TOOLCHAIN = 'GCC_ARM' # Indirectly support all GCC_ARM targets. TARGETS = [ target for target, obj in TARGET_MAP.iteritems() if 'GCC_ARM' in obj.supported_toolchains ] # 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'] = self.ld_script # 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, # 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, } # TODO: it would be good to have jinja stop if one of the # expected context values is not defined. 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) if not exists('.mbedignore'): print print 'Create .mbedignore' with open('.mbedignore', 'w') as f: for bf in build_folders: print bf + '/' f.write(bf + '/\n') 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)