Merge pull request #2245 from theotherjimmy/exporter-refactor

Refactor export subsystem
pull/2645/head
Sam Grove 2016-09-07 23:16:44 +02:00 committed by GitHub
commit da3b07dbd1
23 changed files with 814 additions and 789 deletions

View File

@ -3,8 +3,8 @@ PySerial>=2.7
PrettyTable>=0.7.2
Jinja2>=2.7.3
IntelHex>=1.3
project-generator>=0.9.7,<0.10.0
project-generator-definitions>=0.2.26,<0.3.0
project-generator==0.9.10
project_generator_definitions>=0.2.26,<0.3.0
junit-xml
pyYAML
requests

View File

@ -1,6 +1,6 @@
"""
mbed SDK
Copyright (c) 2011-2013 ARM Limited
Copyright (c) 2011-2016 ARM Limited
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -326,7 +326,7 @@ def prepare_toolchain(src_paths, target, toolchain_name,
return toolchain
def scan_resources(src_paths, toolchain, dependencies_paths=None,
inc_dirs=None):
inc_dirs=None, base_path=None):
""" Scan resources using initialized toolcain
Positional arguments
@ -338,9 +338,9 @@ def scan_resources(src_paths, toolchain, dependencies_paths=None,
"""
# Scan src_path
resources = toolchain.scan_resources(src_paths[0])
resources = toolchain.scan_resources(src_paths[0], base_path=base_path)
for path in src_paths[1:]:
resources.add(toolchain.scan_resources(path))
resources.add(toolchain.scan_resources(path, base_path=base_path))
# Scan dependency paths for include dirs
if dependencies_paths is not None:

View File

@ -1,27 +1,28 @@
"""The generic interface for all exporters.
"""
mbed SDK
Copyright (c) 2011-2013 ARM Limited
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
# mbed SDK
# Copyright (c) 2011-2016 ARM Limited
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import os, tempfile
from os.path import join, exists, basename
from shutil import copytree, rmtree, copy
import yaml
from tools.utils import mkdir
from tools.export import uvision4, uvision5, codered, gccarm, ds5_5, iar, emblocks, coide, kds, zip, simplicityv3, atmelstudio, sw4stm32, e2studio
from tools.export.exporters import zip_working_directory_and_clean_up, OldLibrariesException, FailedBuildException
from tools.export import uvision4, uvision5, codered, gccarm, ds5_5, iar
from tools.export import emblocks, coide, kds, simplicityv3, atmelstudio
from tools.export import sw4stm32, e2studio, zip
from tools.export.exporters import OldLibrariesException, FailedBuildException
from tools.targets import TARGET_NAMES, EXPORT_MAP, TARGET_MAP
from project_generator_definitions.definitions import ProGenDef
@ -41,6 +42,7 @@ EXPORTERS = {
'atmelstudio' : atmelstudio.AtmelStudio,
'sw4stm32' : sw4stm32.Sw4STM32,
'e2studio' : e2studio.E2Studio,
'zip' : zip.ZIP,
}
ERROR_MESSAGE_UNSUPPORTED_TOOLCHAIN = """
@ -52,162 +54,25 @@ ERROR_MESSAGE_NOT_EXPORT_LIBS = """
To export this project please <a href='http://mbed.org/compiler/?import=http://mbed.org/users/mbed_official/code/mbed-export/k&mode=lib' target='_blank'>import the export version of the mbed library</a>.
"""
def online_build_url_resolver(url):
# TODO: Retrieve the path and name of an online library build URL
return {'path':'', 'name':''}
def mcu_ide_matrix(verbose_html=False):
"""Shows target map using prettytable
def export(project_path, project_name, ide, target, destination='/tmp/',
tempdir=None, pgen_build = False, clean=True, extra_symbols=None, make_zip=True, sources_relative=False,
build_url_resolver=online_build_url_resolver, progen_build=False):
# Convention: we are using capitals for toolchain and target names
if target is not None:
target = target.upper()
if tempdir is None:
tempdir = tempfile.mkdtemp()
use_progen = False
supported = True
report = {'success': False, 'errormsg':'', 'skip': False}
if ide is None or ide == "zip":
# Simple ZIP exporter
try:
ide = "zip"
exporter = zip.ZIP(target, tempdir, project_name, build_url_resolver, extra_symbols=extra_symbols)
exporter.scan_and_copy_resources(project_path, tempdir, sources_relative)
exporter.generate()
report['success'] = True
except OldLibrariesException, e:
report['errormsg'] = ERROR_MESSAGE_NOT_EXPORT_LIBS
else:
if ide not in EXPORTERS:
report['errormsg'] = ERROR_MESSAGE_UNSUPPORTED_TOOLCHAIN % (target, ide)
report['skip'] = True
else:
Exporter = EXPORTERS[ide]
target = EXPORT_MAP.get(target, target)
try:
if Exporter.PROGEN_ACTIVE:
use_progen = True
except AttributeError:
pass
if target not in Exporter.TARGETS or Exporter.TOOLCHAIN not in TARGET_MAP[target].supported_toolchains:
supported = False
if use_progen:
if not ProGenDef(ide).is_supported(TARGET_MAP[target].progen['target']):
supported = False
if supported:
# target checked, export
try:
exporter = Exporter(target, tempdir, project_name, build_url_resolver, extra_symbols=extra_symbols, sources_relative=sources_relative)
exporter.scan_and_copy_resources(project_path, tempdir, sources_relative)
if progen_build:
#try to build with pgen ide builders
try:
exporter.generate(progen_build=True)
report['success'] = True
except FailedBuildException, f:
report['errormsg'] = "Build Failed"
else:
exporter.generate()
report['success'] = True
except OldLibrariesException, e:
report['errormsg'] = ERROR_MESSAGE_NOT_EXPORT_LIBS
else:
report['errormsg'] = ERROR_MESSAGE_UNSUPPORTED_TOOLCHAIN % (target, ide)
report['skip'] = True
zip_path = None
if report['success']:
# readme.txt to contain more exported data
exporter_yaml = {
'project_generator': {
'active' : False,
}
}
if use_progen:
try:
import pkg_resources
version = pkg_resources.get_distribution('project_generator').version
exporter_yaml['project_generator']['version'] = version
exporter_yaml['project_generator']['active'] = True;
exporter_yaml['project_generator_definitions'] = {}
version = pkg_resources.get_distribution('project_generator_definitions').version
exporter_yaml['project_generator_definitions']['version'] = version
except ImportError:
pass
with open(os.path.join(tempdir, 'exporter.yaml'), 'w') as outfile:
yaml.dump(exporter_yaml, outfile, default_flow_style=False)
# add readme file to every offline export.
open(os.path.join(tempdir, 'GettingStarted.htm'),'w').write('<meta http-equiv="refresh" content="0; url=http://mbed.org/handbook/Getting-Started-mbed-Exporters#%s"/>'% (ide))
# copy .hgignore file to exported direcotry as well.
if exists(os.path.join(exporter.TEMPLATE_DIR,'.hgignore')):
copy(os.path.join(exporter.TEMPLATE_DIR,'.hgignore'), tempdir)
if make_zip:
zip_path = zip_working_directory_and_clean_up(tempdir, destination, project_name, clean)
else:
zip_path = destination
return zip_path, report
###############################################################################
# Generate project folders following the online conventions
###############################################################################
def copy_tree(src, dst, clean=True):
if exists(dst):
if clean:
rmtree(dst)
else:
return
copytree(src, dst)
def setup_user_prj(user_dir, prj_path, lib_paths=None):
Keyword argumets:
verbose_html - print the matrix in html format
"""
Setup a project with the same directory structure of the mbed online IDE
"""
mkdir(user_dir)
# Project Path
copy_tree(prj_path, join(user_dir, "src"))
# Project Libraries
user_lib = join(user_dir, "lib")
mkdir(user_lib)
if lib_paths is not None:
for lib_path in lib_paths:
copy_tree(lib_path, join(user_lib, basename(lib_path)))
def mcu_ide_matrix(verbose_html=False, platform_filter=None):
""" Shows target map using prettytable """
supported_ides = []
for key in EXPORTERS.iterkeys():
supported_ides.append(key)
supported_ides.sort()
from prettytable import PrettyTable, ALL # Only use it in this function so building works without extra modules
supported_ides = sorted(EXPORTERS.keys())
# Only use it in this function so building works without extra modules
from prettytable import PrettyTable, ALL
# All tests status table print
columns = ["Platform"] + supported_ides
pt = PrettyTable(columns)
table_printer = PrettyTable(["Platform"] + supported_ides)
# Align table
for col in columns:
pt.align[col] = "c"
pt.align["Platform"] = "l"
for col in supported_ides:
table_printer.align[col] = "c"
table_printer.align["Platform"] = "l"
perm_counter = 0
target_counter = 0
for target in sorted(TARGET_NAMES):
target_counter += 1
row = [target] # First column is platform name
for ide in supported_ides:
text = "-"
@ -218,20 +83,24 @@ def mcu_ide_matrix(verbose_html=False, platform_filter=None):
text = "x"
perm_counter += 1
row.append(text)
pt.add_row(row)
table_printer.add_row(row)
pt.border = True
pt.vrules = ALL
pt.hrules = ALL
# creates a html page suitable for a browser
# result = pt.get_html_string(format=True) if verbose_html else pt.get_string()
table_printer.border = True
table_printer.vrules = ALL
table_printer.hrules = ALL
# creates a html page in a shorter format suitable for readme.md
result = pt.get_html_string() if verbose_html else pt.get_string()
if verbose_html:
result = table_printer.get_html_string()
else:
result = table_printer.get_string()
result += "\n"
result += "Total IDEs: %d\n"% (len(supported_ides))
if verbose_html: result += "<br>"
result += "Total platforms: %d\n"% (target_counter)
if verbose_html: result += "<br>"
if verbose_html:
result += "<br>"
result += "Total platforms: %d\n"% (len(TARGET_NAMES))
if verbose_html:
result += "<br>"
result += "Total permutations: %d"% (perm_counter)
if verbose_html: result = result.replace("&amp;", "&")
if verbose_html:
result = result.replace("&amp;", "&")
return result

View File

@ -1,6 +1,6 @@
"""
mbed SDK
Copyright (c) 2011-2015 ARM Limited
Copyright (c) 2011-2016 ARM Limited
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -61,7 +61,7 @@ class AtmelStudio(Exporter):
ctx = {
'target': self.target,
'name': self.program_name,
'name': self.project_name,
'source_files': source_files,
'source_folders': source_folders,
'object_files': self.resources.objects,
@ -69,11 +69,11 @@ class AtmelStudio(Exporter):
'library_paths': self.resources.lib_dirs,
'linker_script': self.resources.linker_script,
'libraries': libraries,
'symbols': self.get_symbols(),
'symbols': self.toolchain.get_symbols(),
'solution_uuid': solution_uuid.upper(),
'project_uuid': project_uuid.upper()
}
ctx.update(self.progen_flags)
ctx.update(self.flags)
target = self.target.lower()
self.gen_file('atmelstudio6_2.atsln.tmpl', ctx, '%s.atsln' % self.program_name)
self.gen_file('atmelstudio6_2.cppproj.tmpl', ctx, '%s.cppproj' % self.program_name)
self.gen_file('atmelstudio6_2.atsln.tmpl', ctx, '%s.atsln' % self.project_name)
self.gen_file('atmelstudio6_2.cppproj.tmpl', ctx, '%s.cppproj' % self.project_name)

View File

@ -1,6 +1,6 @@
"""
mbed SDK
Copyright (c) 2011-2013 ARM Limited
Copyright (c) 2011-2016 ARM Limited
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -48,13 +48,13 @@ class CodeRed(Exporter):
libraries.append(l[3:])
ctx = {
'name': self.program_name,
'name': self.project_name,
'include_paths': self.resources.inc_dirs,
'linker_script': self.resources.linker_script,
'object_files': self.resources.objects,
'libraries': libraries,
'symbols': self.get_symbols()
'symbols': self.toolchain.get_symbols()
}
ctx.update(self.progen_flags)
ctx.update(self.flags)
self.gen_file('codered_%s_project.tmpl' % self.target.lower(), ctx, '.project')
self.gen_file('codered_%s_cproject.tmpl' % self.target.lower(), ctx, '.cproject')

View File

@ -1,6 +1,6 @@
"""
mbed SDK
Copyright (c) 2014 ARM Limited
Copyright (c) 2014-2016 ARM Limited
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -98,7 +98,7 @@ class CoIDE(Exporter):
self.resources.linker_script = ''
ctx = {
'name': self.program_name,
'name': self.project_name,
'source_files': source_files,
'header_files': header_files,
'include_paths': self.resources.inc_dirs,
@ -106,9 +106,9 @@ class CoIDE(Exporter):
'library_paths': self.resources.lib_dirs,
'object_files': self.resources.objects,
'libraries': libraries,
'symbols': self.get_symbols()
'symbols': self.toolchain.get_symbols()
}
target = self.target.lower()
# Project file
self.gen_file('coide_%s.coproj.tmpl' % target, ctx, '%s.coproj' % self.program_name)
self.gen_file('coide_%s.coproj.tmpl' % target, ctx, '%s.coproj' % self.project_name)

View File

@ -1,6 +1,6 @@
"""
mbed SDK
Copyright (c) 2011-2013 ARM Limited
Copyright (c) 2011-2016 ARM Limited
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -54,12 +54,12 @@ class DS5_5(Exporter):
})
ctx = {
'name': self.program_name,
'name': self.project_name,
'include_paths': self.resources.inc_dirs,
'scatter_file': self.resources.linker_script,
'object_files': self.resources.objects + self.resources.libraries,
'source_files': source_files,
'symbols': self.get_symbols()
'symbols': self.toolchain.get_symbols()
}
target = self.target.lower()

View File

@ -1,6 +1,6 @@
"""
mbed SDK
Copyright (c) 2011-2013 ARM Limited
Copyright (c) 2011-2016 ARM Limited
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -33,15 +33,15 @@ class E2Studio(Exporter):
libraries.append(l[3:])
ctx = {
'name': self.program_name,
'name': self.project_name,
'include_paths': self.resources.inc_dirs,
'linker_script': self.resources.linker_script,
'object_files': self.resources.objects,
'libraries': libraries,
'symbols': self.get_symbols()
'symbols': self.toolchain.get_symbols()
}
self.gen_file('e2studio_%s_project.tmpl' % self.target.lower(), ctx, '.project')
self.gen_file('e2studio_%s_cproject.tmpl' % self.target.lower(), ctx, '.cproject')
self.gen_file('e2studio_%s_gdbinit.tmpl' % self.target.lower(), ctx, '.gdbinit')
self.gen_file('e2studio_launch.tmpl', ctx, '%s OpenOCD.launch' % self.program_name)
self.gen_file('e2studio_launch.tmpl', ctx, '%s OpenOCD.launch' % self.project_name)

View File

@ -1,6 +1,6 @@
"""
mbed SDK
Copyright (c) 2014 ARM Limited
Copyright (c) 2014-2016 ARM Limited
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -60,7 +60,7 @@ class IntermediateFile(Exporter):
self.resources.linker_script = ''
ctx = {
'name': self.program_name,
'name': self.project_name,
'target': self.target,
'toolchain': self.toolchain.name,
'source_files': source_files,
@ -68,13 +68,13 @@ class IntermediateFile(Exporter):
'script_file': self.resources.linker_script,
'library_paths': self.resources.lib_dirs,
'libraries': libraries,
'symbols': self.get_symbols(),
'symbols': self.toolchain.get_symbols(),
'object_files': self.resources.objects,
'sys_libs': self.toolchain.sys_libs,
'cc_org': self.flags['common'] + self.flags['c'],
'ld_org': self.flags['common'] + self.flags['ld'],
'cppc_org': self.flags['common'] + self.flags['cxx']
'cc_org': self.flags['common_flags'] + self.flags['c_flags'],
'ld_org': self.flags['common_flags'] + self.flags['ld_flags'],
'cppc_org': self.flags['common_flags'] + self.flags['cxx_flags']
}
# EmBlocks intermediate file template
self.gen_file('emblocks.eix.tmpl', ctx, '%s.eix' % self.program_name)
self.gen_file('emblocks.eix.tmpl', ctx, '%s.eix' % self.project_name)

View File

@ -1,256 +1,219 @@
"""Just a template for subclassing"""
import uuid, shutil, os, logging, fnmatch
from os import walk, remove
from os.path import join, dirname, isdir, split
from copy import copy
from jinja2 import Template, FileSystemLoader
import os
import sys
import logging
from os.path import join, dirname, relpath
from itertools import groupby
from jinja2 import FileSystemLoader
from jinja2.environment import Environment
from contextlib import closing
from zipfile import ZipFile, ZIP_DEFLATED
from operator import add
from tools.utils import mkdir
from tools.toolchains import TOOLCHAIN_CLASSES
from tools.targets import TARGET_MAP
from project_generator.generate import Generator
from project_generator.project import Project
from project_generator.tools import tool
from project_generator.tools_supported import ToolsSupported
from project_generator.settings import ProjectSettings
from project_generator_definitions.definitions import ProGenDef
from tools.config import Config
class OldLibrariesException(Exception): pass
class OldLibrariesException(Exception):
"""Exception that indicates an export can not complete due to an out of date
library version.
"""
pass
class FailedBuildException(Exception) : pass
class FailedBuildException(Exception):
"""Exception that indicates that a build failed"""
pass
class TargetNotSupportedException(Exception):
"""Indicates that an IDE does not support a particular MCU"""
pass
# Exporter descriptor for TARGETS
# TARGETS as class attribute for backward compatibility (allows: if in Exporter.TARGETS)
class ExporterTargetsProperty(object):
""" Exporter descriptor for TARGETS
TARGETS as class attribute for backward compatibility
(allows: if in Exporter.TARGETS)
"""
def __init__(self, func):
self.func = func
def __get__(self, inst, cls):
return self.func(cls)
class Exporter(object):
"""Exporter base class
This class is meant to be extended by individual exporters, and provides a
few helper methods for implementing an exporter with either jinja2 or
progen.
"""
TEMPLATE_DIR = dirname(__file__)
DOT_IN_RELATIVE_PATH = False
NAME = None
TARGETS = None
TOOLCHAIN = None
def __init__(self, target, inputDir, program_name, build_url_resolver, extra_symbols=None, sources_relative=True):
self.inputDir = inputDir
def __init__(self, target, export_dir, project_name, toolchain,
extra_symbols=None, resources=None):
"""Initialize an instance of class exporter
Positional arguments:
target - the target mcu/board for this project
export_dir - the directory of the exported project files
project_name - the name of the project
toolchain - an instance of class toolchain
Keyword arguments:
extra_symbols - a list of extra macros for the toolchain
resources - an instance of class Resources
"""
self.export_dir = export_dir
self.target = target
self.program_name = program_name
self.toolchain = TOOLCHAIN_CLASSES[self.get_toolchain()](TARGET_MAP[target])
self.build_url_resolver = build_url_resolver
self.project_name = project_name
self.toolchain = toolchain
jinja_loader = FileSystemLoader(os.path.dirname(os.path.abspath(__file__)))
self.jinja_environment = Environment(loader=jinja_loader)
self.extra_symbols = extra_symbols if extra_symbols else []
self.config_macros = []
self.sources_relative = sources_relative
self.config_header = None
self.resources = resources
self.generated_files = []
self.builder_files_dict = {}
def get_toolchain(self):
"""A helper getter function that we should probably eliminate"""
return self.TOOLCHAIN
@property
def flags(self):
return self.toolchain.flags
"""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
"""
config_header = self.toolchain.get_config_header()
flags = {key + "_flags": value for key, value
in self.toolchain.flags.iteritems()}
asm_defines = ["-D" + symbol for symbol in self.toolchain.get_symbols(True)]
c_defines = ["-D" + symbol for symbol in self.toolchain.get_symbols()]
flags['asm_flags'] += asm_defines
flags['c_flags'] += c_defines
flags['cxx_flags'] += c_defines
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
@property
def progen_flags(self):
if not hasattr(self, "_progen_flag_cache") :
self._progen_flag_cache = dict([(key + "_flags", value) for key,value in self.flags.iteritems()])
asm_defines = ["-D"+symbol for symbol in self.toolchain.get_symbols(True)]
c_defines = ["-D" + symbol for symbol in self.toolchain.get_symbols()]
self._progen_flag_cache['asm_flags'] += asm_defines
self._progen_flag_cache['c_flags'] += c_defines
self._progen_flag_cache['cxx_flags'] += c_defines
if self.config_header:
self._progen_flag_cache['c_flags'] += self.toolchain.get_config_option(self.config_header)
self._progen_flag_cache['cxx_flags'] += self.toolchain.get_config_option(self.config_header)
return self._progen_flag_cache
def __scan_and_copy(self, src_path, trg_path):
resources = self.toolchain.scan_resources(src_path)
for r_type in ['headers', 's_sources', 'c_sources', 'cpp_sources',
'objects', 'libraries', 'linker_script',
'lib_builds', 'lib_refs', 'hex_files', 'bin_files']:
r = getattr(resources, r_type)
if r:
self.toolchain.copy_files(r, trg_path, resources=resources)
return resources
@staticmethod
def _get_dir_grouped_files(files):
""" Get grouped files based on the dirname """
files_grouped = {}
for file in files:
rel_path = os.path.relpath(file, os.getcwd())
dir_path = os.path.dirname(rel_path)
if dir_path == '':
# all files within the current dir go into Source_Files
dir_path = 'Source_Files'
if not dir_path in files_grouped.keys():
files_grouped[dir_path] = []
files_grouped[dir_path].append(file)
return files_grouped
def get_source_paths(self):
"""Returns a list of the directories where source files are contained"""
source_keys = ['s_sources', 'c_sources', 'cpp_sources', 'hex_files',
'objects', 'libraries']
source_files = []
for key in source_keys:
source_files.extend(getattr(self.resources, key))
return list(set([os.path.dirname(src) for src in source_files]))
def progen_get_project_data(self):
""" Get ProGen project data """
# provide default data, some tools don't require any additional
# tool specific settings
code_files = []
for r_type in ['c_sources', 'cpp_sources', 's_sources']:
for file in getattr(self.resources, r_type):
code_files.append(file)
sources_files = code_files + self.resources.hex_files + self.resources.objects + \
self.resources.libraries
sources_grouped = Exporter._get_dir_grouped_files(sources_files)
headers_grouped = Exporter._get_dir_grouped_files(self.resources.headers)
def make_key(src):
"""turn a source file into it's group name"""
key = os.path.basename(os.path.dirname(src))
if not key:
key = os.path.basename(os.path.normpath(self.export_dir))
return key
project_data = {
'common': {
'sources': sources_grouped,
'includes': headers_grouped,
'build_dir':'.build',
'target': [TARGET_MAP[self.target].progen['target']],
'macros': self.get_symbols(),
'export_dir': [self.inputDir],
'linker_file': [self.resources.linker_script],
}
}
def grouped(sources):
"""Group the source files by their encompassing directory"""
data = sorted(sources, key=make_key)
return {k: list(g) for k, g in groupby(data, make_key)}
if self.toolchain.get_config_header():
config_header = self.toolchain.get_config_header()
config_header = relpath(config_header,
self.resources.file_basepath[config_header])
else:
config_header = None
# we want to add this to our include dirs
config_dir = os.path.dirname(config_header) if config_header else []
project_data = tool.get_tool_template()
project_data['target'] = TARGET_MAP[self.target].progen['target']
project_data['source_paths'] = self.get_source_paths()
project_data['include_paths'] = self.resources.inc_dirs + [config_dir]
project_data['include_files'] = grouped(self.resources.headers)
project_data['source_files_s'] = grouped(self.resources.s_sources)
project_data['source_files_c'] = grouped(self.resources.c_sources)
project_data['source_files_cpp'] = grouped(self.resources.cpp_sources)
project_data['source_files_obj'] = grouped(self.resources.objects)
project_data['source_files_lib'] = grouped(self.resources.libraries)
project_data['output_dir']['path'] = self.export_dir
project_data['linker_file'] = self.resources.linker_script
project_data['macros'] = []
project_data['build_dir'] = 'build'
project_data['template'] = None
project_data['name'] = self.project_name
project_data['output_type'] = 'exe'
project_data['debugger'] = None
return project_data
def progen_gen_file(self, tool_name, project_data, progen_build=False):
""" Generate project using ProGen Project API """
def progen_gen_file(self, project_data):
""" Generate project using ProGen Project API
Positional arguments:
tool_name - the tool for which to generate project files
project_data - a dict whose base key, values are specified in
progen_get_project_data, the items will have been
modified by Exporter subclasses
Keyword arguments:
progen_build - A boolean that determines if the tool will build the
project
"""
if not self.check_supported(self.NAME):
raise TargetNotSupportedException("Target not supported")
settings = ProjectSettings()
project = Project(self.program_name, [project_data], settings)
# TODO: Fix this, the inc_dirs are not valid (our scripts copy files), therefore progen
# thinks it is not dict but a file, and adds them to workspace.
project.project['common']['include_paths'] = self.resources.inc_dirs
project.generate(tool_name, copied=not self.sources_relative)
if progen_build:
print("Project exported, building...")
result = project.build(tool_name)
if result == -1:
raise FailedBuildException("Build Failed")
exporter = ToolsSupported().get_tool(self.NAME)
self.builder_files_dict = {self.NAME:exporter(project_data, settings).export_project()}
for middle in self.builder_files_dict.values():
for field, thing in middle.iteritems():
if field == "files":
for filename in thing.values():
self.generated_files.append(filename)
def __scan_all(self, path):
resources = []
def progen_build(self):
"""Build a project that was already generated by progen"""
print("Project {} exported, building for {}...".format(
self.project_name, self.NAME))
sys.stdout.flush()
builder = ToolsSupported().get_tool(self.NAME)
result = builder(self.builder_files_dict[self.NAME], ProjectSettings()).build_project()
if result == -1:
raise FailedBuildException("Build Failed")
for root, dirs, files in walk(path):
for d in copy(dirs):
if d == '.' or d == '..':
dirs.remove(d)
for file in files:
file_path = join(root, file)
resources.append(file_path)
return resources
def scan_and_copy_resources(self, prj_paths, trg_path, relative=False):
# Copy only the file for the required target and toolchain
lib_builds = []
# Create the configuration object
if isinstance(prj_paths, basestring):
prj_paths = [prj_paths]
config = Config(self.target, prj_paths)
for src in ['lib', 'src']:
resources = self.__scan_and_copy(join(prj_paths[0], src), trg_path)
for path in prj_paths[1:]:
resources.add(self.__scan_and_copy(join(path, src), trg_path))
lib_builds.extend(resources.lib_builds)
# The repository files
#for repo_dir in resources.repo_dirs:
# repo_files = self.__scan_all(repo_dir)
# for path in prj_paths:
# self.toolchain.copy_files(repo_files, trg_path, rel_path=join(path, src))
# The libraries builds
for bld in lib_builds:
build_url = open(bld).read().strip()
lib_data = self.build_url_resolver(build_url)
lib_path = lib_data['path'].rstrip('\\/')
self.__scan_and_copy(lib_path, join(trg_path, lib_data['name']))
# Create .hg dir in mbed build dir so it's ignored when versioning
hgdir = join(trg_path, lib_data['name'], '.hg')
mkdir(hgdir)
fhandle = file(join(hgdir, 'keep.me'), 'a')
fhandle.close()
if not relative:
# Final scan of the actual exported resources
resources = self.toolchain.scan_resources(trg_path)
resources.relative_to(trg_path, self.DOT_IN_RELATIVE_PATH)
else:
# use the prj_dir (source, not destination)
resources = self.toolchain.scan_resources(prj_paths[0])
for path in prj_paths[1:]:
resources.add(toolchain.scan_resources(path))
# Loads the resources into the config system which might expand/modify resources based on config data
self.resources = config.load_resources(resources)
if hasattr(self, "MBED_CONFIG_HEADER_SUPPORTED") and self.MBED_CONFIG_HEADER_SUPPORTED :
# Add the configuration file to the target directory
self.config_header = self.toolchain.MBED_CONFIG_FILE_NAME
config.get_config_data_header(join(trg_path, self.config_header))
self.config_macros = []
self.resources.inc_dirs.append(".")
else:
# And add the configuration macros to the toolchain
self.config_macros = config.get_config_data_macros()
def check_supported(self, ide):
"""Indicated if this combination of IDE and MCU is supported"""
if self.target not in self.TARGETS or \
self.TOOLCHAIN not in TARGET_MAP[self.target].supported_toolchains:
return False
if not ProGenDef(ide).is_supported(
TARGET_MAP[self.target].progen['target']):
return False
return True
def gen_file(self, template_file, data, target_file):
template_path = join(Exporter.TEMPLATE_DIR, template_file)
template = self.jinja_environment.get_template(template_file)
"""Generates a project file from a template using jinja"""
jinja_loader = FileSystemLoader(
os.path.dirname(os.path.abspath(__file__)))
jinja_environment = Environment(loader=jinja_loader)
template = jinja_environment.get_template(template_file)
target_text = template.render(data)
target_path = join(self.inputDir, target_file)
logging.debug("Generating: %s" % target_path)
target_path = join(self.export_dir, target_file)
logging.debug("Generating: %s", target_path)
open(target_path, "w").write(target_text)
def get_symbols(self, add_extra_symbols=True):
""" This function returns symbols which must be exported.
Please add / overwrite symbols in each exporter separately
"""
# We have extra symbols from e.g. libraries, we want to have them also added to export
extra = self.extra_symbols if add_extra_symbols else []
if hasattr(self, "MBED_CONFIG_HEADER_SUPPORTED") and self.MBED_CONFIG_HEADER_SUPPORTED:
# If the config header is supported, we will preinclude it and do not not
# need the macros as preprocessor flags
return extra
symbols = self.toolchain.get_symbols(True) + self.toolchain.get_symbols() \
+ self.config_macros + extra
return symbols
def zip_working_directory_and_clean_up(tempdirectory=None, destination=None, program_name=None, clean=True):
uid = str(uuid.uuid4())
zipfilename = '%s.zip'%uid
logging.debug("Zipping up %s to %s" % (tempdirectory, join(destination, zipfilename)))
# make zip
def zipdir(basedir, archivename):
assert isdir(basedir)
fakeroot = program_name + '/'
with closing(ZipFile(archivename, "w", ZIP_DEFLATED)) as z:
for root, _, files in os.walk(basedir):
# NOTE: ignore empty directories
for fn in files:
absfn = join(root, fn)
zfn = fakeroot + '/' + absfn[len(basedir)+len(os.sep):]
z.write(absfn, zfn)
zipdir(tempdirectory, join(destination, zipfilename))
if clean:
shutil.rmtree(tempdirectory)
return join(destination, zipfilename)
self.generated_files += [target_path]

View File

@ -1,6 +1,6 @@
"""
mbed SDK
Copyright (c) 2011-2013 ARM Limited
Copyright (c) 2011-2016 ARM Limited
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -14,9 +14,9 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
"""
from exporters import Exporter
from os.path import splitext, basename, relpath, join, abspath
from os.path import splitext, basename, relpath, join, abspath, dirname
from os import curdir, getcwd
from tools.export.exporters import Exporter
class GccArm(Exporter):
@ -135,8 +135,6 @@ class GccArm(Exporter):
def generate(self):
# "make" wants Unix paths
if self.sources_relative:
self.resources.relative_to(self.prj_paths[0])
self.resources.win_to_unix()
to_be_compiled = []
@ -152,19 +150,20 @@ class GccArm(Exporter):
l, _ = splitext(basename(lib))
libraries.append(l[3:])
build_dir = abspath(join(self.inputDir, ".build"))
ctx = {
'name': self.program_name,
'name': self.project_name,
'to_be_compiled': to_be_compiled,
'object_files': self.resources.objects,
'include_paths': self.resources.inc_dirs,
'library_paths': self.resources.lib_dirs,
'linker_script': self.resources.linker_script,
'libraries': libraries,
'symbols': self.get_symbols(),
'symbols': self.toolchain.get_symbols(),
'cpu_flags': self.toolchain.cpu,
'vpath': [relpath(s, build_dir) for s in self.prj_paths] if self.sources_relative else [".."],
'hex_files': self.resources.hex_files
'hex_files': self.resources.hex_files,
'vpath': (["../../.."]
if basename(dirname(dirname(self.export_dir))) == "projectfiles"
else [".."])
}
for key in ['include_paths', 'library_paths', 'linker_script', 'hex_files']:
@ -174,9 +173,5 @@ class GccArm(Exporter):
ctx[key] = ctx['vpath'][0] + "/" + ctx[key]
if "../." not in ctx["include_paths"]:
ctx["include_paths"] += ['../.']
ctx.update(self.progen_flags)
ctx.update(self.flags)
self.gen_file('gcc_arm_%s.tmpl' % self.target.lower(), ctx, 'Makefile')
def scan_and_copy_resources(self, prj_paths, trg_path, relative=False):
self.prj_paths = prj_paths
Exporter.scan_and_copy_resources(self, prj_paths, trg_path, relative)

View File

@ -1,6 +1,6 @@
"""
mbed SDK
Copyright (c) 2011-2015 ARM Limited
Copyright (c) 2011-2016 ARM Limited
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -28,7 +28,7 @@ class IAREmbeddedWorkbench(Exporter):
Exporter class for IAR Systems. This class uses project generator.
"""
# These 2 are currently for exporters backward compatiblity
NAME = 'IAR'
NAME = 'iar_arm'
TOOLCHAIN = 'IAR'
# PROGEN_ACTIVE contains information for exporter scripts that this is using progen
PROGEN_ACTIVE = True
@ -50,39 +50,23 @@ class IAREmbeddedWorkbench(Exporter):
continue
return cls._targets_supported
def generate(self, progen_build=False):
def generate(self):
""" Generates the project files """
project_data = self.progen_get_project_data()
tool_specific = {}
# Expand tool specific settings by IAR specific settings which are required
try:
if TARGET_MAP[self.target].progen['iar']['template']:
tool_specific['iar'] = TARGET_MAP[self.target].progen['iar']
project_data['template']=TARGET_MAP[self.target].progen['iar']['template']
except KeyError:
# use default template
# by the mbed projects
tool_specific['iar'] = {
# We currently don't use misc, template sets those for us
# 'misc': {
# 'cxx_flags': ['--no_rtti', '--no_exceptions'],
# 'c_flags': ['--diag_suppress=Pa050,Pa084,Pa093,Pa082'],
# 'ld_flags': ['--skip_dynamic_initialization'],
# },
'template': [os.path.join(os.path.dirname(__file__), 'iar_template.ewp.tmpl')],
}
project_data['template']=[os.path.join(os.path.dirname(__file__), 'iar_template.ewp.tmpl')]
project_data['tool_specific'] = {}
project_data['tool_specific'].setdefault("iar", {})
project_data['tool_specific']['iar'].setdefault("misc", {})
project_data['tool_specific']['iar'].update(tool_specific['iar'])
project_data['tool_specific']['iar']['misc'].update(self.progen_flags)
project_data['misc'] = self.flags
# VLA is enabled via template IccAllowVLA
project_data['tool_specific']['iar']['misc']['c_flags'].remove("--vla")
project_data['common']['build_dir'] = os.path.join(project_data['common']['build_dir'], 'iar_arm')
if progen_build:
self.progen_gen_file('iar_arm', project_data, True)
else:
self.progen_gen_file('iar_arm', project_data)
project_data['misc']['c_flags'].remove("--vla")
project_data['misc']['asm_flags'] = list(set(project_data['misc']['asm_flags']))
project_data['build_dir'] = os.path.join(project_data['build_dir'], 'iar_arm')
self.progen_gen_file(project_data)
# Currently not used, we should reuse folder_name to create virtual folders
class IarFolder():

View File

@ -1,6 +1,6 @@
"""
mbed SDK
Copyright (c) 2011-2013 ARM Limited
Copyright (c) 2011-2016 ARM Limited
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -35,13 +35,13 @@ class KDS(Exporter):
libraries.append(l[3:])
ctx = {
'name': self.program_name,
'name': self.project_name,
'include_paths': self.resources.inc_dirs,
'linker_script': self.resources.linker_script,
'object_files': self.resources.objects,
'libraries': libraries,
'symbols': self.get_symbols()
'symbols': self.toolchain.get_symbols()
}
self.gen_file('kds_%s_project.tmpl' % self.target.lower(), ctx, '.project')
self.gen_file('kds_%s_cproject.tmpl' % self.target.lower(), ctx, '.cproject')
self.gen_file('kds_launch.tmpl', ctx, '%s.launch' % self.program_name)
self.gen_file('kds_launch.tmpl', ctx, '%s.launch' % self.project_name)

View File

@ -1,6 +1,6 @@
"""
mbed SDK
Copyright (c) 2014 ARM Limited
Copyright (c) 2014-2016 ARM Limited
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -147,7 +147,7 @@ class SimplicityV3(Exporter):
libraries.append(l[3:])
defines = []
for define in self.get_symbols():
for define in self.toolchain.get_symbols():
if '=' in define:
keyval = define.split('=')
defines.append( (keyval[0], keyval[1]) )
@ -157,7 +157,7 @@ class SimplicityV3(Exporter):
self.check_and_add_path(split(self.resources.linker_script)[0])
ctx = {
'name': self.program_name,
'name': self.project_name,
'main_files': main_files,
'recursiveFolders': self.orderedPaths,
'object_files': self.resources.objects,
@ -165,13 +165,12 @@ class SimplicityV3(Exporter):
'library_paths': self.resources.lib_dirs,
'linker_script': self.resources.linker_script,
'libraries': libraries,
'symbols': self.get_symbols(),
'defines': defines,
'part': self.PARTS[self.target],
'kit': self.KITS[self.target],
'loopcount': 0
}
ctx.update(self.progen_flags)
ctx.update(self.flags)
## Strip main folder from include paths because ssproj is not capable of handling it
if '.' in ctx['include_paths']:
@ -191,4 +190,4 @@ class SimplicityV3(Exporter):
print("\t" + bpath.name + "\n")
'''
self.gen_file('simplicityv3_slsproj.tmpl', ctx, '%s.slsproj' % self.program_name)
self.gen_file('simplicityv3_slsproj.tmpl', ctx, '%s.slsproj' % self.project_name)

View File

@ -65,7 +65,7 @@ class Sw4STM32(Exporter):
TARGETS = BOARDS.keys()
def __gen_dir(self, dirname):
settings = join(self.inputDir, dirname)
settings = join(self.export_dir, dirname)
mkdir(settings)
def __generate_uid(self):
@ -78,13 +78,13 @@ class Sw4STM32(Exporter):
libraries.append(l[3:])
ctx = {
'name': self.program_name,
'name': self.project_name,
'include_paths': self.resources.inc_dirs,
'linker_script': self.resources.linker_script,
'library_paths': self.resources.lib_dirs,
'object_files': self.resources.objects,
'libraries': libraries,
'symbols': self.get_symbols(),
'symbols': self.toolchain.get_symbols(),
'board_name': self.BOARDS[self.target.upper()]['name'],
'mcu_name': self.BOARDS[self.target.upper()]['mcuId'],
'debug_config_uid': self.__generate_uid(),

View File

@ -1,6 +1,6 @@
"""
mbed SDK
Copyright (c) 2011-2013 ARM Limited
Copyright (c) 2011-2016 ARM Limited
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -28,7 +28,7 @@ class Uvision4(Exporter):
Exporter class for uvision. This class uses project generator.
"""
# These 2 are currently for exporters backward compatiblity
NAME = 'uVision4'
NAME = 'uvision'
TOOLCHAIN = 'ARM'
# PROGEN_ACTIVE contains information for exporter scripts that this is using progen
PROGEN_ACTIVE = True
@ -53,7 +53,7 @@ class Uvision4(Exporter):
def get_toolchain(self):
return TARGET_MAP[self.target].default_toolchain
def generate(self, progen_build=False):
def generate(self):
""" Generates the project files """
project_data = self.progen_get_project_data()
tool_specific = {}
@ -72,25 +72,24 @@ class Uvision4(Exporter):
project_data['tool_specific'].update(tool_specific)
# get flags from toolchain and apply
project_data['tool_specific']['uvision']['misc'] = {}
project_data['misc'] = {}
# need to make this a string for progen. Only adds preprocessor when "macros" set
asm_flag_string = '--cpreproc --cpreproc_opts=-D__ASSERT_MSG,' + ",".join(
list(set(self.progen_flags['asm_flags'])))
project_data['tool_specific']['uvision']['misc']['asm_flags'] = [asm_flag_string]
list(set(self.flags['asm_flags'])))
# asm flags only, common are not valid within uvision project, they are armcc specific
project_data['misc']['asm_flags'] = [asm_flag_string]
# cxx flags included, as uvision have them all in one tab
project_data['tool_specific']['uvision']['misc']['c_flags'] = list(set(
['-D__ASSERT_MSG'] + self.progen_flags['common_flags'] + self.progen_flags['c_flags'] + self.progen_flags[
'cxx_flags']))
project_data['misc']['c_flags'] = list(set(['-D__ASSERT_MSG']
+ self.flags['common_flags']
+ self.flags['c_flags']
+ self.flags['cxx_flags']))
# not compatible with c99 flag set in the template
project_data['tool_specific']['uvision']['misc']['c_flags'].remove("--c99")
project_data['misc']['c_flags'].remove("--c99")
# cpp is not required as it's implicit for cpp files
project_data['tool_specific']['uvision']['misc']['c_flags'].remove("--cpp")
project_data['misc']['c_flags'].remove("--cpp")
# we want no-vla for only cxx, but it's also applied for C in IDE, thus we remove it
project_data['tool_specific']['uvision']['misc']['c_flags'].remove("--no_vla")
project_data['tool_specific']['uvision']['misc']['ld_flags'] = self.progen_flags['ld_flags']
project_data['misc']['c_flags'].remove("--no_vla")
project_data['misc']['ld_flags'] = self.flags['ld_flags']
project_data['common']['build_dir'] = project_data['common']['build_dir'] + '\\' + 'uvision4'
if progen_build:
self.progen_gen_file('uvision', project_data, True)
else:
self.progen_gen_file('uvision', project_data)
project_data['build_dir'] = project_data['build_dir'] + '\\' + 'uvision4'
self.progen_gen_file(project_data)

View File

@ -28,7 +28,7 @@ class Uvision5(Exporter):
Exporter class for uvision5. This class uses project generator.
"""
# These 2 are currently for exporters backward compatiblity
NAME = 'uVision5'
NAME = 'uvision5'
TOOLCHAIN = 'ARM'
# PROGEN_ACTIVE contains information for exporter scripts that this is using progen
PROGEN_ACTIVE = True
@ -53,7 +53,7 @@ class Uvision5(Exporter):
def get_toolchain(self):
return TARGET_MAP[self.target].default_toolchain
def generate(self, progen_build=False):
def generate(self):
""" Generates the project files """
project_data = self.progen_get_project_data()
tool_specific = {}
@ -68,27 +68,28 @@ class Uvision5(Exporter):
'template': [join(dirname(__file__), 'uvision.uvproj.tmpl')],
}
#project_data['template'] = [tool_specific['uvision5']['template']]
project_data['tool_specific'] = {}
project_data['tool_specific'].update(tool_specific)
# get flags from toolchain and apply
project_data['tool_specific']['uvision5']['misc'] = {}
# need to make this a string got progen. Only adds preprocessor when "macros" set
asm_flag_string = '--cpreproc --cpreproc_opts=-D__ASSERT_MSG,' + ",".join(list(set(self.progen_flags['asm_flags'])))
project_data['tool_specific']['uvision5']['misc']['asm_flags'] = [asm_flag_string]
project_data['misc'] = {}
asm_flag_string = '--cpreproc --cpreproc_opts=-D__ASSERT_MSG,' + ",".join(list(set(self.flags['asm_flags'])))
# asm flags only, common are not valid within uvision project, they are armcc specific
project_data['misc']['asm_flags'] = [asm_flag_string]
# cxx flags included, as uvision have them all in one tab
project_data['tool_specific']['uvision5']['misc']['c_flags'] = list(set(['-D__ASSERT_MSG']+self.progen_flags['common_flags'] + self.progen_flags['c_flags'] + self.progen_flags['cxx_flags']))
project_data['misc']['c_flags'] = list(set(['-D__ASSERT_MSG']
+ self.flags['common_flags']
+ self.flags['c_flags']
+ self.flags['cxx_flags']))
# not compatible with c99 flag set in the template
project_data['tool_specific']['uvision5']['misc']['c_flags'].remove("--c99")
project_data['misc']['c_flags'].remove("--c99")
# cpp is not required as it's implicit for cpp files
project_data['tool_specific']['uvision5']['misc']['c_flags'].remove("--cpp")
project_data['misc']['c_flags'].remove("--cpp")
# we want no-vla for only cxx, but it's also applied for C in IDE, thus we remove it
project_data['tool_specific']['uvision5']['misc']['c_flags'].remove("--no_vla")
project_data['tool_specific']['uvision5']['misc']['ld_flags'] = self.progen_flags['ld_flags']
project_data['misc']['c_flags'].remove("--no_vla")
project_data['misc']['ld_flags'] = self.flags['ld_flags']
project_data['common']['build_dir'] = project_data['common']['build_dir'] + '\\' + 'uvision5'
if progen_build:
self.progen_gen_file('uvision5', project_data, True)
else:
self.progen_gen_file('uvision5', project_data)
i = 0
project_data['build_dir'] = project_data['build_dir'] + '\\' + 'uvision5'
self.progen_gen_file(project_data)

View File

@ -33,9 +33,11 @@ class ZIP(Exporter):
's_sources':'2'
}
TOOLCHAIN = 'ARM'
def get_toolchain(self):
return 'uARM' if (self.target in self.USING_MICROLIB) else 'ARM'
def generate(self):
return True

View File

@ -1,3 +1,6 @@
""" The CLI entry point for exporting projects from the mbed tools to any of the
supported IDEs or project structures.
"""
import sys
from os.path import join, abspath, dirname, exists, basename
ROOT = abspath(join(dirname(__file__), ".."))
@ -5,21 +8,87 @@ sys.path.insert(0, ROOT)
from shutil import move, rmtree
from argparse import ArgumentParser
from os import path
from os.path import normpath, realpath
from tools.paths import EXPORT_DIR
from tools.export import export, EXPORTERS, mcu_ide_matrix
from tools.paths import EXPORT_DIR, MBED_BASE, MBED_LIBRARIES
from tools.export import EXPORTERS, mcu_ide_matrix
from tools.tests import TESTS, TEST_MAP
from tools.tests import test_known, test_name_known
from tools.tests import test_known, test_name_known, Test
from tools.targets import TARGET_NAMES
from tools.libraries import LIBRARIES
from utils import argparse_filestring_type, argparse_many, args_error
from utils import argparse_force_lowercase_type, argparse_force_uppercase_type, argparse_dir_not_parent
from project_api import setup_project, perform_export, print_results, get_lib_symbols
from tools.utils import argparse_filestring_type, argparse_many, args_error
from tools.utils import argparse_force_lowercase_type
from tools.utils import argparse_force_uppercase_type
from tools.project_api import export_project
def setup_project(ide, target, program=None, source_dir=None, build=None):
"""Generate a name, if not provided, and find dependencies
if __name__ == '__main__':
Positional arguments:
ide - IDE or project structure that will soon be exported to
target - MCU that the project will build for
Keyword arguments:
program - the index of a test program
source_dir - the directory, or directories that contain all of the sources
build - a directory that will contain the result of the export
"""
# Some libraries have extra macros (called by exporter symbols) to we need
# to pass them to maintain compilation macros integrity between compiled
# library and header files we might use with it
if source_dir:
# --source is used to generate IDE files to toolchain directly
# in the source tree and doesn't generate zip file
project_dir = source_dir[0]
if program:
project_name = TESTS[program]
else:
project_name = basename(normpath(realpath(source_dir[0])))
src_paths = source_dir
lib_paths = None
else:
test = Test(program)
if not build:
# Substitute the mbed library builds with their sources
if MBED_LIBRARIES in test.dependencies:
test.dependencies.remove(MBED_LIBRARIES)
test.dependencies.append(MBED_BASE)
src_paths = [test.source_dir]
lib_paths = test.dependencies
project_name = "_".join([test.id, ide, target])
project_dir = join(EXPORT_DIR, project_name)
return project_dir, project_name, src_paths, lib_paths
def export(target, ide, build=None, src=None, macros=None, project_id=None,
clean=False, zip_proj=False, options=None):
"""Do an export of a project.
Positional arguments:
target - MCU that the project will compile for
ide - the IDE or project structure to export to
Keyword arguments:
build - to use the compiled mbed libraries or not
src - directory or directories that contain the source to export
macros - extra macros to add to the project
project_id - the name of the project
clean - start from a clean state before exporting
zip_proj - create a zip file or not
"""
project_dir, name, src, lib = setup_project(ide, target, program=project_id,
source_dir=src, build=build)
zip_name = name+".zip" if zip_proj else None
export_project(src, project_dir, target, ide, clean=clean, name=name,
macros=macros, libraries_paths=lib, zip_proj=zip_name, options=options)
def main():
"""Entry point"""
# Parse Options
parser = ArgumentParser()
@ -29,32 +98,35 @@ if __name__ == '__main__':
toolchainlist.sort()
parser.add_argument("-m", "--mcu",
metavar="MCU",
default='LPC1768',
type=argparse_many(argparse_force_uppercase_type(targetnames, "MCU")),
help="generate project for the given MCU (%s)"% ', '.join(targetnames))
metavar="MCU",
default='LPC1768',
type=argparse_force_uppercase_type(targetnames, "MCU"),
help="generate project for the given MCU ({})".format(
', '.join(targetnames)))
parser.add_argument("-i",
dest="ide",
default='uvision',
type=argparse_force_lowercase_type(toolchainlist, "toolchain"),
help="The target IDE: %s"% str(toolchainlist))
dest="ide",
default='uvision',
type=argparse_force_lowercase_type(
toolchainlist, "toolchain"),
help="The target IDE: %s"% str(toolchainlist))
parser.add_argument("-c", "--clean",
action="store_true",
default=False,
help="clean the export directory")
action="store_true",
default=False,
help="clean the export directory")
group = parser.add_mutually_exclusive_group(required=False)
group.add_argument("-p",
type=test_known,
dest="program",
help="The index of the desired test program: [0-%d]"% (len(TESTS)-1))
group.add_argument(
"-p",
type=test_known,
dest="program",
help="The index of the desired test program: [0-%s]"% (len(TESTS)-1))
group.add_argument("-n",
type=test_name_known,
dest="program",
help="The name of the desired test program")
type=test_name_known,
dest="program",
help="The name of the desired test program")
parser.add_argument("-b",
dest="build",
@ -63,40 +135,46 @@ if __name__ == '__main__':
help="use the mbed library build, instead of the sources")
group.add_argument("-L", "--list-tests",
action="store_true",
dest="list_tests",
default=False,
help="list available programs in order and exit")
action="store_true",
dest="list_tests",
default=False,
help="list available programs in order and exit")
group.add_argument("-S", "--list-matrix",
action="store_true",
dest="supported_ides",
default=False,
help="displays supported matrix of MCUs and IDEs")
action="store_true",
dest="supported_ides",
default=False,
help="displays supported matrix of MCUs and IDEs")
parser.add_argument("-E",
action="store_true",
dest="supported_ides_html",
default=False,
help="writes tools/export/README.md")
action="store_true",
dest="supported_ides_html",
default=False,
help="writes tools/export/README.md")
parser.add_argument("--source",
action="append",
type=argparse_filestring_type,
dest="source_dir",
default=[],
help="The source (input) directory")
action="append",
type=argparse_filestring_type,
dest="source_dir",
default=[],
help="The source (input) directory")
parser.add_argument("-D",
action="append",
dest="macros",
help="Add a macro definition")
action="append",
dest="macros",
help="Add a macro definition")
parser.add_argument("-o",
type=argparse_many(str),
dest="opts",
default=["debug-info"],
help="Toolchain options")
options = parser.parse_args()
# Print available tests in order and exit
if options.list_tests is True:
print '\n'.join(map(str, sorted(TEST_MAP.values())))
print '\n'.join([str(test) for test in sorted(TEST_MAP.values())])
sys.exit()
# Only prints matrix of supported IDEs
@ -108,13 +186,13 @@ if __name__ == '__main__':
if options.supported_ides_html:
html = mcu_ide_matrix(verbose_html=True)
try:
with open("./export/README.md","w") as f:
f.write("Exporter IDE/Platform Support\n")
f.write("-----------------------------------\n")
f.write("\n")
f.write(html)
except IOError as e:
print "I/O error({0}): {1}".format(e.errno, e.strerror)
with open("./export/README.md", "w") as readme:
readme.write("Exporter IDE/Platform Support\n")
readme.write("-----------------------------------\n")
readme.write("\n")
readme.write(html)
except IOError as exc:
print "I/O error({0}): {1}".format(exc.errno, exc.strerror)
except:
print "Unexpected error:", sys.exc_info()[0]
raise
@ -125,12 +203,9 @@ if __name__ == '__main__':
if exists(EXPORT_DIR):
rmtree(EXPORT_DIR)
# Export results
successes = []
failures = []
for mcu in options.mcu:
zip_proj = not bool(options.source_dir)
# source_dir = use relative paths, otherwise sources are copied
sources_relative = True if options.source_dir else False
# Target
if not options.mcu:
args_error(parser, "argument -m/--mcu is required")
@ -141,32 +216,12 @@ if __name__ == '__main__':
if (options.program is None) and (not options.source_dir):
args_error(parser, "one of -p, -n, or --source is required")
# Export to selected toolchain
export(options.mcu, options.ide, build=options.build,
src=options.source_dir, macros=options.macros,
project_id=options.program, clean=options.clean,
zip_proj=zip_proj, options=options.opts)
for mcu in options.mcu:
# Program Number or name
p, src, ide = options.program, options.source_dir, options.ide
try:
project_dir, project_name, project_temp = setup_project(mcu, ide, p, src, options.build)
zip = not bool(src) # create zip when no src_dir provided
clean = not bool(src) # don't clean when source is provided, use acrual source tree for IDE files
# Export to selected toolchain
lib_symbols = get_lib_symbols(options.macros, src, p)
tmp_path, report = export(project_dir, project_name, ide, mcu, project_dir[0], project_temp, clean=clean, make_zip=zip, extra_symbols=lib_symbols, sources_relative=sources_relative)
except OSError as e:
if e.errno == 2:
report = dict(success=False, errormsg="Library path '%s' does not exist. Ensure that the library is built." % (e.filename))
else:
report = dict(success=False, errormsg="An OS error occured: errno #{}".format(e.errno))
if report['success']:
if not zip:
zip_path = join(project_temp, project_name)
else:
zip_path = join(EXPORT_DIR, "%s_%s_%s.zip" % (project_name, ide, mcu))
move(tmp_path, zip_path)
successes.append("%s::%s\t%s"% (mcu, ide, zip_path))
else:
failures.append("%s::%s\t%s"% (mcu, ide, report['errormsg']))
# Prints export results
print_results(successes, failures)
if __name__ == "__main__":
main()

View File

@ -1,110 +1,255 @@
""" The new way of doing exports """
import sys
from os.path import join, abspath, dirname, exists, basename
from os.path import join, abspath, dirname, exists
from os.path import basename, relpath, normpath
from os import makedirs, walk
ROOT = abspath(join(dirname(__file__), ".."))
sys.path.insert(0, ROOT)
import copy
from shutil import rmtree
import zipfile
from tools.paths import EXPORT_WORKSPACE, EXPORT_TMP
from tools.paths import MBED_BASE, MBED_LIBRARIES
from tools.export import export, setup_user_prj
from tools.utils import mkdir
from tools.tests import Test, TEST_MAP, TESTS
from tools.libraries import LIBRARIES
try:
import tools.private_settings as ps
except:
ps = object()
from tools.build_api import prepare_toolchain
from tools.build_api import scan_resources
from tools.export import EXPORTERS
from tools.toolchains import Resources
def get_program(n):
p = TEST_MAP[n].n
return p
def get_exporter_toolchain(ide):
""" Return the exporter class and the toolchain string as a tuple
Positional arguments:
ide - the ide name of an exporter
"""
return EXPORTERS[ide], EXPORTERS[ide].TOOLCHAIN
def get_test(p):
return Test(p)
def rewrite_basepath(file_name, resources, export_path, loc):
""" Replace the basepath of filename with export_path
Positional arguments:
file_name - the absolute path to a file
resources - the resources object that the file came from
export_path - the final destination of the file after export
"""
new_f = join(loc, relpath(file_name, resources.file_basepath[file_name]))
resources.file_basepath[join(export_path, new_f)] = export_path
return new_f
def get_test_from_name(n):
if not n in TEST_MAP.keys():
# Check if there is an alias for this in private_settings.py
if getattr(ps, "test_alias", None) is not None:
alias = ps.test_alias.get(n, "")
if not alias in TEST_MAP.keys():
return None
def subtract_basepath(resources, export_path, loc=""):
""" Rewrite all of the basepaths with the export_path
Positional arguments:
resources - the resource object to rewrite the basepaths of
export_path - the final destination of the resources with respect to the
generated project files
"""
keys = ['s_sources', 'c_sources', 'cpp_sources', 'hex_files',
'objects', 'libraries', 'inc_dirs', 'headers', 'linker_script',
'lib_dirs']
for key in keys:
vals = getattr(resources, key)
if isinstance(vals, set):
vals = list(vals)
if isinstance(vals, list):
new_vals = []
for val in vals:
new_vals.append(rewrite_basepath(val, resources, export_path,
loc))
if isinstance(getattr(resources, key), set):
setattr(resources, key, set(new_vals))
else:
n = alias
else:
return None
return get_program(n)
setattr(resources, key, new_vals)
elif vals:
setattr(resources, key, rewrite_basepath(vals, resources,
export_path, loc))
def get_lib_symbols(macros, src, program):
# Some libraries have extra macros (called by exporter symbols) to we need to pass
# them to maintain compilation macros integrity between compiled library and
# header files we might use with it
lib_symbols = []
if macros:
lib_symbols += macros
if src:
return lib_symbols
test = get_test(program)
for lib in LIBRARIES:
if lib['build_dir'] in test.dependencies:
lib_macros = lib.get('macros', None)
if lib_macros is not None:
lib_symbols.extend(lib_macros)
def generate_project_files(resources, export_path, target, name, toolchain, ide,
macros=None):
"""Generate the project files for a project
Positional arguments:
resources - a Resources object containing all of the files needed to build
this project
export_path - location to place project files
name - name of the project
toolchain - a toolchain class that corresponds to the toolchain used by the
IDE or makefile
ide - IDE name to export to
Optional arguments:
macros - additional macros that should be defined within the exported
project
"""
exporter_cls, _ = get_exporter_toolchain(ide)
exporter = exporter_cls(target, export_path, name, toolchain,
extra_symbols=macros, resources=resources)
exporter.generate()
files = exporter.generated_files
return files, exporter
def setup_project(mcu, ide, program=None, source_dir=None, build=None):
def zip_export(file_name, prefix, resources, project_files):
"""Create a zip file from an exported project.
# Some libraries have extra macros (called by exporter symbols) to we need to pass
# them to maintain compilation macros integrity between compiled library and
# header files we might use with it
if source_dir:
# --source is used to generate IDE files to toolchain directly in the source tree and doesn't generate zip file
project_dir = source_dir
project_name = TESTS[program] if program else "Unnamed_Project"
project_temp = join(source_dir[0], 'projectfiles', '%s_%s' % (ide, mcu))
mkdir(project_temp)
Positional Parameters:
file_name - the file name of the resulting zip file
prefix - a directory name that will prefix the entire zip file's contents
resources - a resources object with files that must be included in the zip
project_files - a list of extra files to be added to the root of the prefix
directory
"""
with zipfile.ZipFile(file_name, "w") as zip_file:
for prj_file in project_files:
zip_file.write(prj_file, join(prefix, basename(prj_file)))
for loc, resource in resources.iteritems():
print resource.features
for res in [resource] + resource.features.values():
extras = []
for directory in res.repo_dirs:
for root, _, files in walk(directory):
for repo_file in files:
source = join(root, repo_file)
extras.append(source)
res.file_basepath[source] = res.base_path
for source in \
res.headers + res.s_sources + res.c_sources +\
res.cpp_sources + res.libraries + res.hex_files + \
[res.linker_script] + res.bin_files + res.objects + \
res.json_files + res.lib_refs + res.lib_builds + \
res.repo_files + extras:
if source:
zip_file.write(
source,
join(prefix, loc,
relpath(source, res.file_basepath[source])))
def export_project(src_paths, export_path, target, ide,
libraries_paths=None, options=None, linker_script=None,
clean=False, notify=None, verbose=False, name=None,
inc_dirs=None, jobs=1, silent=False, extra_verbose=False,
config=None, macros=None, zip_proj=None):
"""Generates a project file and creates a zip archive if specified
Positional Arguments:
src_paths - a list of paths from which to find source files
export_path - a path specifying the location of generated project files
target - the mbed board/mcu for which to generate the executable
ide - the ide for which to generate the project fields
Keyword Arguments:
libraries_paths - paths to additional libraries
options - build options passed by -o flag
linker_script - path to the linker script for the specified target
clean - removes the export_path if it exists
notify - function is passed all events, and expected to handle notification
of the user, emit the events to a log, etc.
verbose - assigns the notify function to toolchains print_notify_verbose
name - project name
inc_dirs - additional include directories
jobs - number of threads
silent - silent build - no output
extra_verbose - assigns the notify function to toolchains
print_notify_verbose
config - toolchain's config object
macros - User-defined macros
zip_proj - string name of the zip archive you wish to creat (exclude arg
if you do not wish to create an archive
"""
# Convert src_path to a list if needed
if isinstance(src_paths, dict):
paths = sum(src_paths.values(), [])
elif isinstance(src_paths, list):
paths = src_paths[:]
else:
test = get_test(program)
if not build:
# Substitute the library builds with the sources
# TODO: Substitute also the other library build paths
if MBED_LIBRARIES in test.dependencies:
test.dependencies.remove(MBED_LIBRARIES)
test.dependencies.append(MBED_BASE)
paths = [src_paths]
# Build the project with the same directory structure of the mbed online IDE
project_name = test.id
project_dir = [join(EXPORT_WORKSPACE, project_name)]
project_temp = EXPORT_TMP
setup_user_prj(project_dir[0], test.source_dir, test.dependencies)
# Extend src_paths wit libraries_paths
if libraries_paths is not None:
paths.extend(libraries_paths)
return project_dir, project_name, project_temp
if not isinstance(src_paths, dict):
src_paths = {"": paths}
# Export Directory
if exists(export_path) and clean:
rmtree(export_path)
if not exists(export_path):
makedirs(export_path)
_, toolchain_name = get_exporter_toolchain(ide)
# Pass all params to the unified prepare_resources()
toolchain = prepare_toolchain(paths, target, toolchain_name,
macros=macros, options=options, clean=clean,
jobs=jobs, notify=notify, silent=silent,
verbose=verbose, extra_verbose=extra_verbose,
config=config)
# The first path will give the name to the library
if name is None:
name = basename(normpath(abspath(src_paths[0])))
# Call unified scan_resources
resource_dict = {loc: scan_resources(path, toolchain, inc_dirs=inc_dirs)
for loc, path in src_paths.iteritems()}
resources = Resources()
toolchain.build_dir = export_path
config_header = toolchain.get_config_header()
resources.headers.append(config_header)
resources.file_basepath[config_header] = dirname(config_header)
if zip_proj:
subtract_basepath(resources, export_path)
for loc, res in resource_dict.iteritems():
temp = copy.deepcopy(res)
subtract_basepath(temp, export_path, loc)
resources.add(temp)
else:
for _, res in resource_dict.iteritems():
resources.add(res)
# Change linker script if specified
if linker_script is not None:
resources.linker_script = linker_script
files, exporter = generate_project_files(resources, export_path,
target, name, toolchain, ide,
macros=macros)
files.append(config_header)
if zip_proj:
if isinstance(zip_proj, basestring):
zip_export(join(export_path, zip_proj), name, resource_dict, files)
else:
zip_export(zip_proj, name, resource_dict, files)
return exporter
def perform_export(dir, name, ide, mcu, temp, clean=False, zip=False, lib_symbols='',
sources_relative=False, progen_build=False):
def print_results(successes, failures, skips=None):
""" Print out the results of an export process
tmp_path, report = export(dir, name, ide, mcu, dir[0], temp, clean=clean,
make_zip=zip, extra_symbols=lib_symbols, sources_relative=sources_relative,
progen_build=progen_build)
return tmp_path, report
Positional arguments:
successes - The list of exports that succeeded
failures - The list of exports that failed
def print_results(successes, failures, skips = []):
Keyword arguments:
skips - The list of exports that were skipped
"""
print
if len(successes) > 0:
if successes:
print "Successful: "
for success in successes:
print " * %s" % success
if len(failures) > 0:
if failures:
print "Failed: "
for failure in failures:
print " * %s" % failure
if len(skips) > 0:
if skips:
print "Skipped: "
for skip in skips:
print " * %s" % skip

View File

@ -1,7 +1,7 @@
#!/usr/bin/env python
"""
mbed SDK
Copyright (c) 2011-2013 ARM Limited
Copyright (c) 2011-2016 ARM Limited
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@ -16,154 +16,166 @@ See the License for the specific language governing permissions and
limitations under the License.
"""
import sys
import argparse
import os
from os import path, remove, rename
import shutil
from os.path import join, abspath, dirname, exists, basename
r=dirname(__file__)
ROOT = abspath(join(r, "..","..",".."))
ROOT = path.abspath(path.join(path.dirname(__file__), "..", "..", ".."))
sys.path.insert(0, ROOT)
import argparse
from tools.export import EXPORTERS
from tools.targets import TARGET_NAMES, TARGET_MAP
from tools.project_api import setup_project, perform_export, print_results, get_test_from_name, get_lib_symbols
from project_generator_definitions.definitions import ProGenDef
from tools.utils import args_error
from tools.targets import TARGET_NAMES
from tools.tests import TESTS
from tools.project import setup_project
from tools.project_api import print_results, export_project
from tools.tests import test_name_known, Test
from tools.export.exporters import FailedBuildException, \
TargetNotSupportedException
from tools.utils import argparse_force_lowercase_type, \
argparse_force_uppercase_type, argparse_many
class ProgenBuildTest():
def __init__(self, desired_ides, targets):
#map of targets and the ides that can build programs for them
self.target_ides = {}
for target in targets:
self.target_ides[target] =[]
for ide in desired_ides:
if target in EXPORTERS[ide].TARGETS:
#target is supported by ide
self.target_ides[target].append(ide)
if len(self.target_ides[target]) == 0:
del self.target_ides[target]
class ProgenBuildTest(object):
"""Object to encapsulate logic for progen build testing"""
def __init__(self, desired_ides, mcus, tests):
"""
Initialize an instance of class ProgenBuildTest
Args:
desired_ides: the IDEs you wish to make/build project files for
mcus: the mcus to specify in project files
tests: the test projects to make/build project files from
"""
self.ides = desired_ides
self.mcus = mcus
self.tests = tests
@property
def mcu_ide_pairs(self):
"""Yields tuples of valid mcu, ide combinations"""
for mcu in self.mcus:
for ide in self.ides:
if mcu in EXPORTERS[ide].TARGETS:
yield mcu, ide
@staticmethod
def get_pgen_targets(ides):
#targets supported by pgen and desired ides for tests
targs = []
for ide in ides:
for target in TARGET_NAMES:
if target not in targs and hasattr(TARGET_MAP[target],'progen') \
and ProGenDef(ide).is_supported(TARGET_MAP[target].progen['target']):
targs.append(target)
return targs
@staticmethod
def handle_project_files(project_dir, mcu, test, tool, clean=False):
def handle_log_files(project_dir, tool, name):
"""
Renames/moves log files
Args:
project_dir: the directory that contains project files
tool: the ide that created the project files
name: the name of the project
clean: a boolean value determining whether to remove the
created project files
"""
log = ''
if tool == 'uvision' or tool == 'uvision5':
log = os.path.join(project_dir,"build","build_log.txt")
log = path.join(project_dir, "build", "build_log.txt")
elif tool == 'iar':
log = os.path.join(project_dir, 'build_log.txt')
log = path.join(project_dir, 'build_log.txt')
try:
with open(log, 'r') as f:
print f.read()
except:
return
with open(log, 'r') as in_log:
print in_log.read()
log_name = path.join(path.dirname(project_dir), name + "_log.txt")
prefix = "_".join([test, mcu, tool])
log_name = os.path.join(os.path.dirname(project_dir), prefix+"_log.txt")
# check if a log already exists for this platform+test+ide
if path.exists(log_name):
# delete it if so
remove(log_name)
rename(log, log_name)
except IOError:
pass
#check if a log already exists for this platform+test+ide
if os.path.exists(log_name):
#delete it if so
os.remove(log_name)
os.rename(log, log_name)
def generate_and_build(self, clean=False):
"""
Generate the project file and build the project
Args:
clean: a boolean value determining whether to remove the
created project files
if clean:
shutil.rmtree(project_dir, ignore_errors=True)
return
Returns:
successes: a list of strings that contain the mcu, ide, test
properties of a successful build test
skips: a list of strings that contain the mcu, ide, test properties
of a skipped test (if the ide does not support mcu)
failures: a list of strings that contain the mcu, ide, test
properties of a failed build test
def generate_and_build(self, tests, clean=False):
#build results
"""
successes = []
failures = []
skips = []
for mcu, ides in self.target_ides.items():
for test in tests:
#resolve name alias
test = get_test_from_name(test)
for ide in ides:
lib_symbols = get_lib_symbols(None, None, test)
project_dir, project_name, project_temp = setup_project(mcu, ide, test)
for mcu, ide in self.mcu_ide_pairs:
for test in self.tests:
export_location, name, src, lib = setup_project(ide, mcu,
program=test)
test_name = Test(test).id
try:
exporter = export_project(src, export_location, mcu, ide,
clean=clean, name=name,
libraries_paths=lib)
exporter.progen_build()
successes.append("%s::%s\t%s" % (mcu, ide, test_name))
except FailedBuildException:
failures.append("%s::%s\t%s" % (mcu, ide, test_name))
except TargetNotSupportedException:
skips.append("%s::%s\t%s" % (mcu, ide, test_name))
dest_dir = os.path.dirname(project_temp)
destination = os.path.join(dest_dir,"_".join([project_name, mcu, ide]))
tmp_path, report = perform_export(project_dir, project_name, ide, mcu, destination,
lib_symbols=lib_symbols, progen_build = True)
if report['success']:
successes.append("build for %s::%s\t%s" % (mcu, ide, project_name))
elif report['skip']:
skips.append("%s::%s\t%s" % (mcu, ide, project_name))
else:
failures.append("%s::%s\t%s for %s" % (mcu, ide, report['errormsg'], project_name))
ProgenBuildTest.handle_project_files(destination, mcu, project_name, ide, clean)
ProgenBuildTest.handle_log_files(export_location, ide, name)
if clean:
shutil.rmtree(export_location, ignore_errors=True)
return successes, failures, skips
if __name__ == '__main__':
accepted_ides = ["iar", "uvision", "uvision5"]
accepted_targets = sorted(ProgenBuildTest.get_pgen_targets(accepted_ides))
default_tests = ["MBED_BLINKY"]
def main():
"""Entry point"""
toolchainlist = ["iar", "uvision", "uvision5"]
default_tests = [test_name_known("MBED_BLINKY")]
targetnames = TARGET_NAMES
targetnames.sort()
parser = argparse.ArgumentParser(description = "Test progen builders. Leave any flag off to run with all possible options.")
parser.add_argument("-i", "--IDEs",
nargs = '+',
dest="ides",
help="tools you wish to perfrom build tests. (%s)" % ', '.join(accepted_ides),
default = accepted_ides)
parser = argparse.ArgumentParser(description=
"Test progen builders. Leave any flag off"
" to run with all possible options.")
parser.add_argument("-i",
dest="ides",
default=toolchainlist,
type=argparse_many(argparse_force_lowercase_type(
toolchainlist, "toolchain")),
help="The target IDE: %s"% str(toolchainlist))
parser.add_argument(
"-p",
type=argparse_many(test_name_known),
dest="programs",
help="The index of the desired test program: [0-%d]" % (len(TESTS) - 1),
default=default_tests)
parser.add_argument("-n",
nargs='+',
dest="tests",
help="names of desired test programs",
default = default_tests)
type=argparse_many(test_name_known),
dest="programs",
help="The name of the desired test program",
default=default_tests)
parser.add_argument("-m", "--mcus",
nargs='+',
dest ="targets",
help="generate project for the given MCUs (%s)" % '\n '.join(accepted_targets),
default = accepted_targets)
parser.add_argument(
"-m", "--mcu",
metavar="MCU",
default='LPC1768',
nargs="+",
type=argparse_force_uppercase_type(targetnames, "MCU"),
help="generate project for the given MCU (%s)" % ', '.join(targetnames))
parser.add_argument("-c", "--clean",
dest="clean",
action = "store_true",
action="store_true",
help="clean up the exported project files",
default=False)
options = parser.parse_args()
tests = options.tests
ides = [ide.lower() for ide in options.ides]
targets = [target.upper() for target in options.targets]
if any(get_test_from_name(test) is None for test in tests):
args_error(parser, "[ERROR] test name not recognized")
if any(target not in accepted_targets for target in targets):
args_error(parser, "[ERROR] mcu must be one of the following:\n %s" % '\n '.join(accepted_targets))
if any(ide not in accepted_ides for ide in ides):
args_error(parser, "[ERROR] ide must be in %s" % ', '.join(accepted_ides))
build_test = ProgenBuildTest(ides, targets)
successes, failures, skips = build_test.generate_and_build(tests, options.clean)
test = ProgenBuildTest(options.ides, options.mcu, options.programs)
successes, failures, skips = test.generate_and_build(clean=options.clean)
print_results(successes, failures, skips)
sys.exit(len(failures))
if __name__ == "__main__":
main()

View File

@ -1253,7 +1253,7 @@ def test_known(string):
def test_name_known(string):
if string not in TEST_MAP.keys() and \
(getattr(ps, "test_alias", None) is None or \
ps.test_alias.get(test_id, "") not in TEST_MAP.keys()):
ps.test_alias.get(string, "") not in TEST_MAP.keys()):
raise ArgumentTypeError("Program with name '{0}' not found. Supported tests are: \n{1}".format(string, columnate([t['id'] for t in TESTS])))
return TEST_MAP[string].n

View File

@ -564,6 +564,7 @@ class mbedToolchain:
# Add root to include paths
resources.inc_dirs.append(root)
resources.file_basepath[root] = base_path
for file in files:
file_path = join(root, file)