Merge pull request #1976 from theotherjimmy/memap-args

Generalize flag handling
pull/2006/head
Sam Grove 2016-06-24 15:03:50 -05:00 committed by GitHub
commit 6dd11c76e4
13 changed files with 456 additions and 428 deletions

View File

@ -35,6 +35,7 @@ from tools.build_api import mcu_toolchain_matrix
from tools.build_api import static_analysis_scan, static_analysis_scan_lib, static_analysis_scan_library
from tools.build_api import print_build_results
from tools.settings import CPPCHECK_CMD, CPPCHECK_MSG_FORMAT
from utils import argparse_filestring_type
if __name__ == '__main__':
start = time()
@ -42,115 +43,115 @@ if __name__ == '__main__':
# Parse Options
parser = get_default_options_parser()
parser.add_option("--source", dest="source_dir",
default=None, help="The source (input) directory", action="append")
parser.add_argument("--source", dest="source_dir", type=argparse_filestring_type,
default=None, help="The source (input) directory", nargs="*")
parser.add_option("--build", dest="build_dir",
parser.add_argument("--build", dest="build_dir", type=argparse_filestring_type,
default=None, help="The build (output) directory")
parser.add_option("--no-archive", dest="no_archive", action="store_true",
parser.add_argument("--no-archive", dest="no_archive", action="store_true",
default=False, help="Do not produce archive (.ar) file, but rather .o")
# Extra libraries
parser.add_option("-r", "--rtos",
parser.add_argument("-r", "--rtos",
action="store_true",
dest="rtos",
default=False,
help="Compile the rtos")
parser.add_option("--rpc",
parser.add_argument("--rpc",
action="store_true",
dest="rpc",
default=False,
help="Compile the rpc library")
parser.add_option("-e", "--eth",
parser.add_argument("-e", "--eth",
action="store_true", dest="eth",
default=False,
help="Compile the ethernet library")
parser.add_option("-U", "--usb_host",
parser.add_argument("-U", "--usb_host",
action="store_true",
dest="usb_host",
default=False,
help="Compile the USB Host library")
parser.add_option("-u", "--usb",
parser.add_argument("-u", "--usb",
action="store_true",
dest="usb",
default=False,
help="Compile the USB Device library")
parser.add_option("-d", "--dsp",
parser.add_argument("-d", "--dsp",
action="store_true",
dest="dsp",
default=False,
help="Compile the DSP library")
parser.add_option("-F", "--fat",
parser.add_argument("-F", "--fat",
action="store_true",
dest="fat",
default=False,
help="Compile FS and SD card file system library")
parser.add_option("-b", "--ublox",
parser.add_argument("-b", "--ublox",
action="store_true",
dest="ublox",
default=False,
help="Compile the u-blox library")
parser.add_option("", "--cpputest",
parser.add_argument( "--cpputest",
action="store_true",
dest="cpputest_lib",
default=False,
help="Compiles 'cpputest' unit test library (library should be on the same directory level as mbed repository)")
parser.add_option("-D", "",
action="append",
parser.add_argument("-D",
nargs="*",
dest="macros",
help="Add a macro definition")
parser.add_option("-S", "--supported-toolchains",
parser.add_argument("-S", "--supported-toolchains",
action="store_true",
dest="supported_toolchains",
default=False,
help="Displays supported matrix of MCUs and toolchains")
parser.add_option('-f', '--filter',
parser.add_argument('-f', '--filter',
dest='general_filter_regex',
default=None,
help='For some commands you can use filter to filter out results')
parser.add_option("", "--cppcheck",
parser.add_argument("--cppcheck",
action="store_true",
dest="cppcheck_validation",
default=False,
help="Forces 'cppcheck' static code analysis")
parser.add_option("-j", "--jobs", type="int", dest="jobs",
parser.add_argument("-j", "--jobs", type=int, dest="jobs",
default=0, help="Number of concurrent jobs. Default: 0/auto (based on host machine's number of CPUs)")
parser.add_option("-N", "--artifact-name", dest="artifact_name",
parser.add_argument("-N", "--artifact-name", dest="artifact_name",
default=None, help="The built project's name")
parser.add_option("-v", "--verbose",
parser.add_argument("-v", "--verbose",
action="store_true",
dest="verbose",
default=False,
help="Verbose diagnostic output")
parser.add_option("--silent",
parser.add_argument("--silent",
action="store_true",
dest="silent",
default=False,
help="Silent diagnostic output (no copy, compile notification)")
parser.add_option("-x", "--extra-verbose-notifications",
parser.add_argument("-x", "--extra-verbose-notifications",
action="store_true",
dest="extra_verbose_notify",
default=False,
help="Makes compiler more verbose, CI friendly.")
(options, args) = parser.parse_args()
options = parser.parse_args()
# Only prints matrix of supported toolchains
if options.supported_toolchains:
@ -158,26 +159,10 @@ if __name__ == '__main__':
exit(0)
# Get target list
if options.mcu:
mcu_list = (options.mcu).split(",")
for mcu in mcu_list:
if mcu not in TARGET_NAMES:
print "Given MCU '%s' not into the supported list:\n%s" % (mcu, TARGET_NAMES)
sys.exit(1)
targets = mcu_list
else:
targets = TARGET_NAMES
targets = options.mcu if options.mcu else TARGET_NAMES
# Get toolchains list
if options.tool:
toolchain_list = (options.tool).split(",")
for tc in toolchain_list:
if tc not in TOOLCHAINS:
print "Given toolchain '%s' not into the supported list:\n%s" % (tc, TOOLCHAINS)
sys.exit(1)
toolchains = toolchain_list
else:
toolchains = TOOLCHAINS
toolchains = options.tool if options.tool else TOOLCHAINS
# Get libraries list
libraries = []

View File

@ -42,24 +42,24 @@ if __name__ == '__main__':
# Parse Options
parser = get_default_options_parser()
parser.add_option("-S", "--supported-toolchains",
parser.add_argument("-S", "--supported-toolchains",
action="store_true",
dest="supported_toolchains",
default=False,
help="Displays supported matrix of targets and toolchains")
parser.add_option('-f', '--filter',
parser.add_argument('-f', '--filter',
dest='general_filter_regex',
default=None,
help='Filter targets')
parser.add_option("-v", "--verbose",
parser.add_argument("-v", "--verbose",
action="store_true",
dest="verbose",
default=False,
help="Verbose diagnostic output")
(options, args) = parser.parse_args()
options = parser.parse_args()
# Only prints matrix of supported toolchains
if options.supported_toolchains:

View File

@ -28,6 +28,7 @@ from tools.utils import args_error
from tools.options import get_default_options_parser
from tools.build_api import get_config
from config import Config
from utils import argparse_filestring_type
try:
import tools.private_settings as ps
except:
@ -36,19 +37,15 @@ except:
if __name__ == '__main__':
# Parse Options
parser = get_default_options_parser(add_clean=False, add_options=False)
parser.add_option("--source", dest="source_dir",
default=None, help="The source (input) directory", action="append")
parser.add_option("--prefix", dest="prefix", action="append",
default=None, help="Restrict listing to parameters that have this prefix")
parser.add_option("-v", "--verbose", action="store_true", dest="verbose",
parser.add_argument("--source", dest="source_dir", type=argparse_filestring_type,
default=[], help="The source (input) directory", nargs="*")
parser.add_argument("--prefix", dest="prefix", nargs="*",
default=[], help="Restrict listing to parameters that have this prefix")
parser.add_argument("-v", "--verbose", action="store_true", dest="verbose",
default=False, help="Verbose diagnostic output")
(options, args) = parser.parse_args()
options = parser.parse_args()
for path in options.source_dir :
if not isdir(path) :
args_error(parser, "[ERROR] you passed \"{}\" to --source, which does not exist".
format(path))
# Target
if options.mcu is None :
args_error(parser, "[ERROR] You should specify an MCU")

View File

@ -38,157 +38,153 @@ from tools.paths import FS_LIBRARY
from tools.paths import UBLOX_LIBRARY
from tools.tests import TESTS, Test, TEST_MAP
from tools.tests import TEST_MBED_LIB
from tools.tests import test_known, test_name_known
from tools.targets import TARGET_MAP
from tools.options import get_default_options_parser
from tools.build_api import build_project
from tools.build_api import mcu_toolchain_matrix
try:
import tools.private_settings as ps
except:
ps = object()
from utils import argparse_filestring_type
from argparse import ArgumentTypeError
if __name__ == '__main__':
# Parse Options
parser = get_default_options_parser()
parser.add_option("-p",
type="int",
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument("-p",
type=test_known,
dest="program",
help="The index of the desired test program: [0-%d]" % (len(TESTS)-1))
parser.add_option("-n",
dest="program_name",
group.add_argument("-n",
type=test_name_known,
dest="program",
help="The name of the desired test program")
parser.add_option("-j", "--jobs",
type="int",
parser.add_argument("-j", "--jobs",
type=int,
dest="jobs",
default=0,
help="Number of concurrent jobs. Default: 0/auto (based on host machine's number of CPUs)")
parser.add_option("-v", "--verbose",
parser.add_argument("-v", "--verbose",
action="store_true",
dest="verbose",
default=False,
help="Verbose diagnostic output")
parser.add_option("--silent",
parser.add_argument("--silent",
action="store_true",
dest="silent",
default=False,
help="Silent diagnostic output (no copy, compile notification)")
parser.add_option("-D", "",
action="append",
parser.add_argument("-D",
nargs="*",
dest="macros",
help="Add a macro definition")
parser.add_option("-S", "--supported-toolchains",
group.add_argument("-S", "--supported-toolchains",
action="store_true",
dest="supported_toolchains",
default=False,
help="Displays supported matrix of MCUs and toolchains")
parser.add_option('-f', '--filter',
parser.add_argument('-f', '--filter',
dest='general_filter_regex',
default=None,
help='For some commands you can use filter to filter out results')
# Local run
parser.add_option("--automated", action="store_true", dest="automated",
parser.add_argument("--automated", action="store_true", dest="automated",
default=False, help="Automated test")
parser.add_option("--host", dest="host_test",
parser.add_argument("--host", dest="host_test",
default=None, help="Host test")
parser.add_option("--extra", dest="extra",
parser.add_argument("--extra", dest="extra",
default=None, help="Extra files")
parser.add_option("--peripherals", dest="peripherals",
parser.add_argument("--peripherals", dest="peripherals",
default=None, help="Required peripherals")
parser.add_option("--dep", dest="dependencies",
parser.add_argument("--dep", dest="dependencies",
default=None, help="Dependencies")
parser.add_option("--source", dest="source_dir",
default=None, help="The source (input) directory", action="append")
parser.add_option("--duration", type="int", dest="duration",
group.add_argument("--source", dest="source_dir", type=argparse_filestring_type,
default=None, help="The source (input) directory", nargs="*")
parser.add_argument("--duration", type=int, dest="duration",
default=None, help="Duration of the test")
parser.add_option("--build", dest="build_dir",
parser.add_argument("--build", dest="build_dir",
default=None, help="The build (output) directory")
parser.add_option("-N", "--artifact-name", dest="artifact_name",
parser.add_argument("-N", "--artifact-name", dest="artifact_name",
default=None, help="The built project's name")
parser.add_option("-d", "--disk", dest="disk",
parser.add_argument("-d", "--disk", dest="disk",
default=None, help="The mbed disk")
parser.add_option("-s", "--serial", dest="serial",
parser.add_argument("-s", "--serial", dest="serial",
default=None, help="The mbed serial port")
parser.add_option("-b", "--baud", type="int", dest="baud",
parser.add_argument("-b", "--baud", type=int, dest="baud",
default=None, help="The mbed serial baud rate")
parser.add_option("-L", "--list-tests", action="store_true", dest="list_tests",
group.add_argument("-L", "--list-tests", action="store_true", dest="list_tests",
default=False, help="List available tests in order and exit")
# Ideally, all the tests with a single "main" thread can be run with, or
# without the rtos, eth, usb_host, usb, dsp, fat, ublox
parser.add_option("--rtos",
parser.add_argument("--rtos",
action="store_true", dest="rtos",
default=False, help="Link with RTOS library")
parser.add_option("--rpc",
parser.add_argument("--rpc",
action="store_true", dest="rpc",
default=False, help="Link with RPC library")
parser.add_option("--eth",
parser.add_argument("--eth",
action="store_true", dest="eth",
default=False,
help="Link with Ethernet library")
parser.add_option("--usb_host",
parser.add_argument("--usb_host",
action="store_true",
dest="usb_host",
default=False,
help="Link with USB Host library")
parser.add_option("--usb",
parser.add_argument("--usb",
action="store_true",
dest="usb",
default=False,
help="Link with USB Device library")
parser.add_option("--dsp",
parser.add_argument("--dsp",
action="store_true",
dest="dsp",
default=False,
help="Link with DSP library")
parser.add_option("--fat",
parser.add_argument("--fat",
action="store_true",
dest="fat",
default=False,
help="Link with FS ad SD card file system library")
parser.add_option("--ublox",
parser.add_argument("--ublox",
action="store_true",
dest="ublox",
default=False,
help="Link with U-Blox library")
parser.add_option("--testlib",
parser.add_argument("--testlib",
action="store_true",
dest="testlib",
default=False,
help="Link with mbed test library")
# Specify a different linker script
parser.add_option("-l", "--linker", dest="linker_script",
parser.add_argument("-l", "--linker", dest="linker_script",
type=argparse_filestring_type,
default=None, help="use the specified linker script")
(options, args) = parser.parse_args()
options = parser.parse_args()
# Only prints matrix of supported toolchains
if options.supported_toolchains:
print mcu_toolchain_matrix(platform_filter=options.general_filter_regex)
exit(0)
if options.source_dir:
for path in options.source_dir :
if not isfile(path) and not isdir(path) :
args_error(parser, "[ERROR] you passed \"{}\" to --source, which does not exist".
format(path))
# Print available tests in order and exit
if options.list_tests is True:
print '\n'.join(map(str, sorted(TEST_MAP.values())))
@ -197,25 +193,9 @@ if __name__ == '__main__':
# force program to "0" if a source dir is specified
if options.source_dir is not None:
p = 0
n = None
else:
# Program Number or name
p, n = options.program, options.program_name
if n is not None and p is not None:
args_error(parser, "[ERROR] specify either '-n' or '-p', not both")
if n:
# We will transform 'n' to list of 'p' (integers which are test numbers)
nlist = n.split(',')
for test_id in nlist:
if test_id not in TEST_MAP.keys():
args_error(parser, "[ERROR] Program with name '%s' not found"% test_id)
p = [TEST_MAP[n].n for n in nlist]
elif p is None or (p < 0) or (p > (len(TESTS)-1)):
message = "[ERROR] You have to specify one of the following tests:\n"
message += '\n'.join(map(str, sorted(TEST_MAP.values())))
args_error(parser, message)
p = options.program
# If 'p' was set via -n to list of numbers make this a single element integer list
if type(p) != type([]):
@ -224,12 +204,12 @@ if __name__ == '__main__':
# Target
if options.mcu is None :
args_error(parser, "[ERROR] You should specify an MCU")
mcu = options.mcu
mcu = options.mcu[0]
# Toolchain
if options.tool is None:
args_error(parser, "[ERROR] You should specify a TOOLCHAIN")
toolchain = options.tool
toolchain = options.tool[0]
# Test
for test_no in p:

View File

@ -10,6 +10,7 @@ import re
import csv
import json
import argparse
from utils import argparse_uppercase_type, argparse_lowercase_hyphen_type
from prettytable import PrettyTable
debug = False
@ -336,6 +337,8 @@ class MemapParser(object):
else:
self.object_to_module.update({object_name:module_name})
export_formats = ["json", "csv-ci", "table"]
def generate_output(self, export_format, file_output=None):
"""
Generates summary of memory map data
@ -451,6 +454,8 @@ class MemapParser(object):
return True
toolchains = ["ARM", "ARM_STD", "ARM_MICRO", "GCC_ARM", "IAR"]
def parse(self, mapfile, toolchain):
"""
Parse and decode map file depending on the toolchain
@ -486,13 +491,13 @@ def main():
parser.add_argument('file', help='memory map file')
parser.add_argument('-t', '--toolchain', dest='toolchain', help='select a toolchain used to build the memory map file (ARM, GCC_ARM, IAR)',\
required=True)
parser.add_argument('-t', '--toolchain', dest='toolchain', help='select a toolchain used to build the memory map file (%s)' % ", ".join(MemapParser.toolchains),\
required=True, type=argparse_uppercase_type(MemapParser.toolchains, "toolchain"))
parser.add_argument('-o', '--output', help='output file name', required=False)
parser.add_argument('-e', '--export', dest='export', required=False,\
help="export format (examples: 'json', 'csv-ci', 'table': default)")
parser.add_argument('-e', '--export', dest='export', required=False, default='table', type=argparse_lowercase_hyphen_type(MemapParser.export_formats,'export format'),\
help="export format (examples: %s: default)" % ", ".join(MemapParser.export_formats))
parser.add_argument('-v', '--version', action='version', version=version)
@ -510,13 +515,8 @@ def main():
# Parse and decode a map file
if args.file and args.toolchain:
if memap.parse(args.file, args.toolchain) is False:
print "Unknown toolchain for memory statistics %s" % args.toolchain
sys.exit(0)
# default export format is table
if not args.export:
args.export = 'table'
# Write output in file
if args.output != None:
memap.generate_output(args.export, args.output)

View File

@ -14,33 +14,37 @@ 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 optparse import OptionParser
from argparse import ArgumentParser
from tools.toolchains import TOOLCHAINS
from tools.targets import TARGET_NAMES
from utils import argparse_uppercase_type, argparse_lowercase_hyphen_type, argparse_many
def get_default_options_parser(add_clean=True, add_options=True):
parser = OptionParser()
parser = ArgumentParser()
targetnames = TARGET_NAMES
targetnames.sort()
toolchainlist = list(TOOLCHAINS)
toolchainlist.sort()
parser.add_option("-m", "--mcu",
parser.add_argument("-m", "--mcu",
help="build for the given MCU (%s)" % ', '.join(targetnames),
metavar="MCU")
metavar="MCU",
type=argparse_many(argparse_uppercase_type(targetnames, "MCU")))
parser.add_option("-t", "--tool",
parser.add_argument("-t", "--tool",
help="build using the given TOOLCHAIN (%s)" % ', '.join(toolchainlist),
metavar="TOOLCHAIN")
metavar="TOOLCHAIN",
type=argparse_many(argparse_uppercase_type(toolchainlist, "toolchain")))
if add_clean:
parser.add_option("-c", "--clean", action="store_true", default=False,
parser.add_argument("-c", "--clean", action="store_true", default=False,
help="clean the build directory")
if add_options:
parser.add_option("-o", "--options", action="append",
help='Add a build option ("save-asm": save the asm generated by the compiler, "debug-info": generate debugging information, "analyze": run Goanna static code analyzer")')
parser.add_argument("-o", "--options", nargs="*",
help='Add a build argument ("save-asm": save the asm generated by the compiler, "debug-info": generate debugging information, "analyze": run Goanna static code analyzer")',
type=argparse_lowercase_hyphen_type(['save-asm', 'debug-info', 'analyze'], "build option"))
return parser

View File

@ -4,7 +4,7 @@ ROOT = abspath(join(dirname(__file__), ".."))
sys.path.insert(0, ROOT)
from shutil import move, rmtree
from optparse import OptionParser
from argparse import ArgumentParser
from os import path
from tools.paths import EXPORT_DIR, EXPORT_WORKSPACE, EXPORT_TMP
@ -12,84 +12,89 @@ from tools.paths import MBED_BASE, MBED_LIBRARIES
from tools.export import export, setup_user_prj, EXPORTERS, mcu_ide_matrix
from tools.utils import args_error, mkdir
from tools.tests import TESTS, Test, TEST_MAP
from tools.tests import test_known, test_name_known
from tools.targets import TARGET_NAMES
from tools.libraries import LIBRARIES
from utils import argparse_lowercase_type, argparse_uppercase_type, argparse_filestring_type, argparse_many
try:
import tools.private_settings as ps
except:
ps = object()
if __name__ == '__main__':
# Parse Options
parser = OptionParser()
parser = ArgumentParser()
targetnames = TARGET_NAMES
targetnames.sort()
toolchainlist = EXPORTERS.keys()
toolchainlist.sort()
parser.add_option("-m", "--mcu",
parser.add_argument("-m", "--mcu",
metavar="MCU",
default='LPC1768',
required=True,
type=argparse_many(argparse_uppercase_type(targetnames, "MCU")),
help="generate project for the given MCU (%s)"% ', '.join(targetnames))
parser.add_option("-i",
parser.add_argument("-i",
dest="ide",
default='uvision',
required=True,
type=argparse_many(argparse_lowercase_type(toolchainlist, "toolchain")),
help="The target IDE: %s"% str(toolchainlist))
parser.add_option("-c", "--clean",
parser.add_argument("-c", "--clean",
action="store_true",
default=False,
help="clean the export directory")
parser.add_option("-p",
type="int",
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument("-p",
type=test_known,
dest="program",
help="The index of the desired test program: [0-%d]"% (len(TESTS)-1))
parser.add_option("-n",
dest="program_name",
group.add_argument("-n",
type=test_name_known,
dest="program",
help="The name of the desired test program")
parser.add_option("-b",
parser.add_argument("-b",
dest="build",
action="store_true",
default=False,
help="use the mbed library build, instead of the sources")
parser.add_option("-L", "--list-tests",
group.add_argument("-L", "--list-tests",
action="store_true",
dest="list_tests",
default=False,
help="list available programs in order and exit")
parser.add_option("-S", "--list-matrix",
group.add_argument("-S", "--list-matrix",
action="store_true",
dest="supported_ides",
default=False,
help="displays supported matrix of MCUs and IDEs")
parser.add_option("-E",
parser.add_argument("-E",
action="store_true",
dest="supported_ides_html",
default=False,
help="writes tools/export/README.md")
parser.add_option("--source",
action="append",
group.add_argument("--source",
nargs="*",
type=argparse_filestring_type,
dest="source_dir",
default=None,
default=[],
help="The source (input) directory")
parser.add_option("-D", "",
action="append",
parser.add_argument("-D",
nargs="*",
dest="macros",
help="Add a macro definition")
(options, args) = parser.parse_args()
options = parser.parse_args()
# Print available tests in order and exit
if options.list_tests is True:
@ -122,16 +127,6 @@ if __name__ == '__main__':
if exists(EXPORT_DIR):
rmtree(EXPORT_DIR)
# Target
if options.mcu is None :
args_error(parser, "[ERROR] You should specify an MCU")
mcus = options.mcu
# IDE
if options.ide is None:
args_error(parser, "[ERROR] You should specify an IDE")
ide = options.ide
# Export results
successes = []
failures = []
@ -141,14 +136,14 @@ if __name__ == '__main__':
# source_dir = use relative paths, otherwise sources are copied
sources_relative = True if options.source_dir else False
for mcu in mcus.split(','):
for mcu in options.mcu:
# Program Number or name
p, n, src, ide = options.program, options.program_name, options.source_dir, options.ide
p, src, ides = options.program, options.source_dir, options.ide
if src is not None:
if src:
# --source is used to generate IDE files to toolchain directly in the source tree and doesn't generate zip file
project_dir = options.source_dir
project_name = n if n else "Unnamed_Project"
project_name = TESTS[p]
project_temp = path.join(options.source_dir[0], 'projectfiles', ide)
mkdir(project_temp)
lib_symbols = []
@ -157,31 +152,6 @@ if __name__ == '__main__':
zip = False # don't create zip
clean = False # don't cleanup because we use the actual source tree to generate IDE files
else:
if n is not None and p is not None:
args_error(parser, "[ERROR] specify either '-n' or '-p', not both")
if 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():
args_error(parser, "[ERROR] Program with name '%s' not found" % n)
else:
n = alias
else:
args_error(parser, "[ERROR] Program with name '%s' not found" % n)
p = TEST_MAP[n].n
if p is None or (p < 0) or (p > (len(TESTS)-1)):
message = "[ERROR] You have to specify one of the following tests:\n"
message += '\n'.join(map(str, sorted(TEST_MAP.values())))
args_error(parser, message)
# Project
if p is None or (p < 0) or (p > (len(TESTS)-1)):
message = "[ERROR] You have to specify one of the following tests:\n"
message += '\n'.join(map(str, sorted(TEST_MAP.values())))
args_error(parser, message)
test = Test(p)
# Some libraries have extra macros (called by exporter symbols) to we need to pass
@ -210,6 +180,7 @@ if __name__ == '__main__':
setup_user_prj(project_dir[0], test.source_dir, test.dependencies)
# Export to selected toolchain
for ide in ides:
tmp_path, report = export(project_dir, project_name, ide, mcu, project_dir[0], project_temp, clean=clean, zip=zip, extra_symbols=lib_symbols, relative=sources_relative)
if report['success']:
if not zip:

View File

@ -100,7 +100,7 @@ if __name__ == '__main__':
parser.description = """This script allows you to run mbed defined test cases for particular MCU(s) and corresponding toolchain(s)."""
parser.epilog = """Example: singletest.py -i test_spec.json -M muts_all.json"""
(opts, args) = parser.parse_args()
opts = parser.parse_args()
# Print scrip version
if opts.version:
@ -154,10 +154,10 @@ if __name__ == '__main__':
mut['disk'])
# Set up parameters for test specification filter function (we need to set toolchains per target here)
use_default_toolchain = 'default' in opts.toolchains_filter.split(',') if opts.toolchains_filter is not None else True
use_supported_toolchains = 'all' in opts.toolchains_filter.split(',') if opts.toolchains_filter is not None else False
use_default_toolchain = 'default' in opts.toolchains_filter if opts.toolchains_filter is not None else True
use_supported_toolchains = 'all' in opts.toolchains_filter if opts.toolchains_filter is not None else False
toolchain_filter = opts.toolchains_filter
platform_name_filter = opts.general_filter_regex.split(',') if opts.general_filter_regex is not None else opts.general_filter_regex
platform_name_filter = opts.general_filter_regex if opts.general_filter_regex is not None else opts.general_filter_regex
# Test specification with information about each target and associated toolchain
test_spec = get_autodetected_TEST_SPEC(MUTs.values(),
use_default_toolchain=use_default_toolchain,

View File

@ -32,64 +32,69 @@ from tools.build_api import build_project, build_library
from tools.targets import TARGET_MAP
from tools.utils import mkdir, ToolException, NotSupportedException
from tools.test_exporters import ReportExporter, ResultExporterType
from utils import argparse_filestring_type, argparse_lowercase_type, argparse_many
if __name__ == '__main__':
try:
# Parse Options
parser = get_default_options_parser()
parser.add_option("-D", "",
action="append",
parser.add_argument("-D",
nargs="*",
dest="macros",
help="Add a macro definition")
parser.add_option("-j", "--jobs",
type="int",
parser.add_argument("-j", "--jobs",
type=int,
dest="jobs",
default=0,
help="Number of concurrent jobs. Default: 0/auto (based on host machine's number of CPUs)")
parser.add_option("--source", dest="source_dir",
default=None, help="The source (input) directory (for sources other than tests). Defaults to current directory.", action="append")
parser.add_argument("--source", dest="source_dir",
type=argparse_filestring_type,
default=None, help="The source (input) directory (for sources other than tests). Defaults to current directory.", nargs="*")
parser.add_option("--build", dest="build_dir",
parser.add_argument("--build", dest="build_dir",
default=None, help="The build (output) directory")
parser.add_option("-l", "--list", action="store_true", dest="list",
parser.add_argument("-l", "--list", action="store_true", dest="list",
default=False, help="List (recursively) available tests in order and exit")
parser.add_option("-p", "--paths", dest="paths",
parser.add_argument("-p", "--paths", dest="paths",
type=argparse_many(argparse_filestring_type),
default=None, help="Limit the tests to those within the specified comma separated list of paths")
format_choices = ["list", "json"]
format_default_choice = "list"
format_help = "Change the format in which tests are listed. Choices include: %s. Default: %s" % (", ".join(format_choices), format_default_choice)
parser.add_option("-f", "--format", type="choice", dest="format",
choices=format_choices, default=format_default_choice, help=format_help)
parser.add_argument("-f", "--format", dest="format",
type=argparse_lowercase_type(format_choices, "format"),
default=format_default_choice, help=format_help)
parser.add_option("--continue-on-build-fail", action="store_true", dest="continue_on_build_fail",
parser.add_argument("--continue-on-build-fail", action="store_true", dest="continue_on_build_fail",
default=None, help="Continue trying to build all tests if a build failure occurs")
parser.add_option("-n", "--names", dest="names",
#TODO validate the names instead of just passing through str
parser.add_argument("-n", "--names", dest="names", type=argparse_many(str),
default=None, help="Limit the tests to a comma separated list of names")
parser.add_option("--test-spec", dest="test_spec",
parser.add_argument("--test-spec", dest="test_spec",
default=None, help="Destination path for a test spec file that can be used by the Greentea automated test tool")
parser.add_option("--build-report-junit", dest="build_report_junit",
parser.add_argument("--build-report-junit", dest="build_report_junit",
default=None, help="Destination path for a build report in the JUnit xml format")
parser.add_option("-v", "--verbose",
parser.add_argument("-v", "--verbose",
action="store_true",
dest="verbose",
default=False,
help="Verbose diagnostic output")
(options, args) = parser.parse_args()
options = parser.parse_args()
# Filter tests by path if specified
if options.paths:
all_paths = options.paths.split(",")
all_paths = options.paths
else:
all_paths = ["."]
@ -102,7 +107,7 @@ if __name__ == '__main__':
# Filter tests by name if specified
if options.names:
all_names = options.names.split(",")
all_names = options.names
all_names = [x.lower() for x in all_names]
for name in all_names:
@ -132,7 +137,7 @@ if __name__ == '__main__':
base_source_paths = ['.']
target = TARGET_MAP[options.mcu]
target = TARGET_MAP[options.mcu[0]]
build_report = {}
build_properties = {}
@ -140,7 +145,7 @@ if __name__ == '__main__':
library_build_success = False
try:
# Build sources
build_library(base_source_paths, options.build_dir, target, options.tool,
build_library(base_source_paths, options.build_dir, target, options.tool[0],
options=options.options,
jobs=options.jobs,
clean=options.clean,
@ -166,7 +171,7 @@ if __name__ == '__main__':
print "Failed to build library"
else:
# Build all the tests
test_build_success, test_build = build_tests(tests, [options.build_dir], options.build_dir, target, options.tool,
test_build_success, test_build = build_tests(tests, [options.build_dir], options.build_dir, target, options.tool[0],
options=options.options,
clean=options.clean,
report=build_report,

View File

@ -24,7 +24,7 @@ import json
import uuid
import pprint
import random
import optparse
import argparse
import datetime
import threading
import ctypes
@ -58,7 +58,12 @@ from tools.build_api import add_result_to_report
from tools.build_api import scan_for_source_paths
from tools.libraries import LIBRARIES, LIBRARY_MAP
from tools.toolchains import TOOLCHAIN_BIN_PATH
from tools.toolchains import TOOLCHAINS
from tools.test_exporters import ReportExporter, ResultExporterType
from tools.utils import argparse_filestring_type
from tools.utils import argparse_uppercase_type
from tools.utils import argparse_lowercase_type
from tools.utils import argparse_many
import tools.host_tests.host_tests_plugins as host_tests_plugins
@ -623,7 +628,7 @@ class SingleTestRunner(object):
for test_id in test_map_keys:
test = TEST_MAP[test_id]
if self.opts_test_by_names and test_id not in self.opts_test_by_names.split(','):
if self.opts_test_by_names and test_id not in self.opts_test_by_names:
continue
if test_ids and test_id not in test_ids:
@ -634,7 +639,7 @@ class SingleTestRunner(object):
print self.logger.log_line(self.logger.LogType.INFO, 'Common test skipped for target %s'% (target))
continue
if self.opts_peripheral_by_names and test.peripherals and not len([i for i in test.peripherals if i in self.opts_peripheral_by_names.split(',')]):
if self.opts_peripheral_by_names and test.peripherals and not len([i for i in test.peripherals if i in self.opts_peripheral_by_names]):
# We will skip tests not forced with -p option
if self.opts_verbose_skipped_tests:
print self.logger.log_line(self.logger.LogType.INFO, 'Common test skipped for target %s'% (target))
@ -655,7 +660,7 @@ class SingleTestRunner(object):
# When users are using 'build only flag' and test do not have
# specified peripherals we can allow test building by default
pass
elif self.opts_peripheral_by_names and test_id not in self.opts_peripheral_by_names.split(','):
elif self.opts_peripheral_by_names and test_id not in self.opts_peripheral_by_names:
# If we force peripheral with option -p we expect test
# to pass even if peripheral is not in MUTs file.
pass
@ -773,7 +778,7 @@ class SingleTestRunner(object):
"""
result = {}
if test_loops_str:
test_loops = test_loops_str.split(',')
test_loops = test_loops_str
for test_loop in test_loops:
test_loop_count = test_loop.split('=')
if len(test_loop_count) == 2:
@ -1713,7 +1718,7 @@ def get_autodetected_TEST_SPEC(mbeds_list,
toolchains += supported_toolchains
if toolchain_filter is not None:
all_toolchains = supported_toolchains + [default_toolchain]
for toolchain in toolchain_filter.split(','):
for toolchain in toolchain_filter:
if toolchain in all_toolchains:
toolchains.append(toolchain)
@ -1724,227 +1729,235 @@ def get_autodetected_TEST_SPEC(mbeds_list,
def get_default_test_options_parser():
""" Get common test script options used by CLI, web services etc.
"""
parser = optparse.OptionParser()
parser.add_option('-i', '--tests',
parser = argparse.ArgumentParser()
parser.add_argument('-i', '--tests',
dest='test_spec_filename',
metavar="FILE",
type=argparse_filestring_type,
help='Points to file with test specification')
parser.add_option('-M', '--MUTS',
parser.add_argument('-M', '--MUTS',
dest='muts_spec_filename',
metavar="FILE",
type=argparse_filestring_type,
help='Points to file with MUTs specification (overwrites settings.py and private_settings.py)')
parser.add_option("-j", "--jobs",
parser.add_argument("-j", "--jobs",
dest='jobs',
metavar="NUMBER",
type="int",
type=int,
help="Define number of compilation jobs. Default value is 1")
if get_module_avail('mbed_lstools'):
# Additional features available when mbed_lstools is installed on host and imported
# mbed_lstools allow users to detect connected to host mbed-enabled devices
parser.add_option('', '--auto',
parser.add_argument('--auto',
dest='auto_detect',
metavar=False,
action="store_true",
help='Use mbed-ls module to detect all connected mbed devices')
parser.add_option('', '--tc',
toolchain_list = list(TOOLCHAINS) + ["DEFAULT", "ALL"]
parser.add_argument('--tc',
dest='toolchains_filter',
help="Toolchain filter for --auto option. Use toolchains names separated by comma, 'default' or 'all' to select toolchains")
type=argparse_many(argparse_uppercase_type(toolchain_list, "toolchains")),
help="Toolchain filter for --auto argument. Use toolchains names separated by comma, 'default' or 'all' to select toolchains")
test_scopes = ','.join(["'%s'" % n for n in get_available_oper_test_scopes()])
parser.add_option('', '--oper',
parser.add_argument('--oper',
dest='operability_checks',
type=argparse_lowercase_type(get_available_oper_test_scopes(), "scopes"),
help='Perform interoperability tests between host and connected mbed devices. Available test scopes are: %s' % test_scopes)
parser.add_option('', '--clean',
parser.add_argument('--clean',
dest='clean',
metavar=False,
action="store_true",
help='Clean the build directory')
parser.add_option('-P', '--only-peripherals',
parser.add_argument('-P', '--only-peripherals',
dest='test_only_peripheral',
default=False,
action="store_true",
help='Test only peripheral declared for MUT and skip common tests')
parser.add_option('-C', '--only-commons',
parser.add_argument('-C', '--only-commons',
dest='test_only_common',
default=False,
action="store_true",
help='Test only board internals. Skip perpherials tests and perform common tests')
parser.add_option('-n', '--test-by-names',
parser.add_argument('-n', '--test-by-names',
dest='test_by_names',
type=argparse_many(str),
help='Runs only test enumerated it this switch. Use comma to separate test case names')
parser.add_option('-p', '--peripheral-by-names',
parser.add_argument('-p', '--peripheral-by-names',
dest='peripheral_by_names',
type=argparse_many(str),
help='Forces discovery of particular peripherals. Use comma to separate peripheral names')
copy_methods = host_tests_plugins.get_plugin_caps('CopyMethod')
copy_methods_str = "Plugin support: " + ', '.join(copy_methods)
parser.add_option('-c', '--copy-method',
parser.add_argument('-c', '--copy-method',
dest='copy_method',
type=argparse_uppercase_type(copy_methods, "flash method"),
help="Select binary copy (flash) method. Default is Python's shutil.copy() method. %s"% copy_methods_str)
reset_methods = host_tests_plugins.get_plugin_caps('ResetMethod')
reset_methods_str = "Plugin support: " + ', '.join(reset_methods)
parser.add_option('-r', '--reset-type',
parser.add_argument('-r', '--reset-type',
dest='mut_reset_type',
default=None,
type=argparse_uppercase_type(reset_methods, "reset method"),
help='Extra reset method used to reset MUT by host test script. %s'% reset_methods_str)
parser.add_option('-g', '--goanna-for-tests',
parser.add_argument('-g', '--goanna-for-tests',
dest='goanna_for_tests',
metavar=False,
action="store_true",
help='Run Goanna static analyse tool for tests. (Project will be rebuilded)')
parser.add_option('-G', '--goanna-for-sdk',
parser.add_argument('-G', '--goanna-for-sdk',
dest='goanna_for_mbed_sdk',
metavar=False,
action="store_true",
help='Run Goanna static analyse tool for mbed SDK (Project will be rebuilded)')
parser.add_option('-s', '--suppress-summary',
parser.add_argument('-s', '--suppress-summary',
dest='suppress_summary',
default=False,
action="store_true",
help='Suppresses display of wellformatted table with test results')
parser.add_option('-t', '--test-summary',
parser.add_argument('-t', '--test-summary',
dest='test_x_toolchain_summary',
default=False,
action="store_true",
help='Displays wellformatted table with test x toolchain test result per target')
parser.add_option('-A', '--test-automation-report',
parser.add_argument('-A', '--test-automation-report',
dest='test_automation_report',
default=False,
action="store_true",
help='Prints information about all tests and exits')
parser.add_option('-R', '--test-case-report',
parser.add_argument('-R', '--test-case-report',
dest='test_case_report',
default=False,
action="store_true",
help='Prints information about all test cases and exits')
parser.add_option("-S", "--supported-toolchains",
parser.add_argument("-S", "--supported-toolchains",
action="store_true",
dest="supported_toolchains",
default=False,
help="Displays supported matrix of MCUs and toolchains")
parser.add_option("-O", "--only-build",
parser.add_argument("-O", "--only-build",
action="store_true",
dest="only_build_tests",
default=False,
help="Only build tests, skips actual test procedures (flashing etc.)")
parser.add_option('', '--parallel',
parser.add_argument('--parallel',
dest='parallel_test_exec',
default=False,
action="store_true",
help='Experimental, you execute test runners for connected to your host MUTs in parallel (speeds up test result collection)')
parser.add_option('', '--config',
parser.add_argument('--config',
dest='verbose_test_configuration_only',
default=False,
action="store_true",
help='Displays full test specification and MUTs configration and exits')
parser.add_option('', '--loops',
parser.add_argument('--loops',
dest='test_loops_list',
type=argparse_many(str),
help='Set no. of loops per test. Format: TEST_1=1,TEST_2=2,TEST_3=3')
parser.add_option('', '--global-loops',
parser.add_argument('--global-loops',
dest='test_global_loops_value',
type=int,
help='Set global number of test loops per test. Default value is set 1')
parser.add_option('', '--consolidate-waterfall',
parser.add_argument('--consolidate-waterfall',
dest='consolidate_waterfall_test',
default=False,
action="store_true",
help='Used with --waterfall option. Adds only one test to report reflecting outcome of waterfall test.')
help='Used with --waterfall argument. Adds only one test to report reflecting outcome of waterfall test.')
parser.add_option('-W', '--waterfall',
parser.add_argument('-W', '--waterfall',
dest='waterfall_test',
default=False,
action="store_true",
help='Used with --loops or --global-loops options. Tests until OK result occurs and assumes test passed')
help='Used with --loops or --global-loops arguments. Tests until OK result occurs and assumes test passed')
parser.add_option('-N', '--firmware-name',
parser.add_argument('-N', '--firmware-name',
dest='firmware_global_name',
help='Set global name for all produced projects. Note, proper file extension will be added by buid scripts')
parser.add_option('-u', '--shuffle',
parser.add_argument('-u', '--shuffle',
dest='shuffle_test_order',
default=False,
action="store_true",
help='Shuffles test execution order')
parser.add_option('', '--shuffle-seed',
parser.add_argument('--shuffle-seed',
dest='shuffle_test_seed',
default=None,
help='Shuffle seed (If you want to reproduce your shuffle order please use seed provided in test summary)')
parser.add_option('-f', '--filter',
parser.add_argument('-f', '--filter',
dest='general_filter_regex',
type=argparse_many(str),
default=None,
help='For some commands you can use filter to filter out results')
parser.add_option('', '--inc-timeout',
parser.add_argument('--inc-timeout',
dest='extend_test_timeout',
metavar="NUMBER",
type="int",
type=int,
help='You can increase global timeout for each test by specifying additional test timeout in seconds')
parser.add_option('', '--db',
parser.add_argument('--db',
dest='db_url',
help='This specifies what database test suite uses to store its state. To pass DB connection info use database connection string. Example: \'mysql://username:password@127.0.0.1/db_name\'')
parser.add_option('-l', '--log',
parser.add_argument('-l', '--log',
dest='log_file_name',
help='Log events to external file (note not all console entries may be visible in log file)')
parser.add_option('', '--report-html',
parser.add_argument('--report-html',
dest='report_html_file_name',
help='You can log test suite results in form of HTML report')
parser.add_option('', '--report-junit',
parser.add_argument('--report-junit',
dest='report_junit_file_name',
help='You can log test suite results in form of JUnit compliant XML report')
parser.add_option("", "--report-build",
parser.add_argument("--report-build",
dest="report_build_file_name",
help="Output the build results to a junit xml file")
parser.add_option('', '--verbose-skipped',
parser.add_argument('--verbose-skipped',
dest='verbose_skipped_tests',
default=False,
action="store_true",
help='Prints some extra information about skipped tests')
parser.add_option('-V', '--verbose-test-result',
parser.add_argument('-V', '--verbose-test-result',
dest='verbose_test_result_only',
default=False,
action="store_true",
help='Prints test serial output')
parser.add_option('-v', '--verbose',
parser.add_argument('-v', '--verbose',
dest='verbose',
default=False,
action="store_true",
help='Verbose mode (prints some extra information)')
parser.add_option('', '--version',
parser.add_argument('--version',
dest='version',
default=False,
action="store_true",

View File

@ -106,14 +106,15 @@ def get_default_test_webservice_options_parser():
parser = get_default_test_options_parser()
# Things related to web services offered by test suite scripts
parser.add_option('', '--rest-api',
parser.add_argument('', '--rest-api',
dest='rest_api_enabled',
default=False,
action="store_true",
help='Enables REST API.')
parser.add_option('', '--rest-api-port',
parser.add_argument('', '--rest-api-port',
dest='rest_api_port_no',
type=int,
help='Sets port for REST API interface')
return parser

View File

@ -16,6 +16,13 @@ limitations under the License.
"""
from tools.paths import *
from tools.data.support import *
from argparse import ArgumentTypeError
from utils import columnate
try:
import tools.private_settings as ps
except:
ps = object()
TEST_CMSIS_LIB = join(TEST_DIR, "cmsis", "lib")
TEST_MBED_LIB = join(TEST_DIR, "mbed", "env")
@ -1212,3 +1219,19 @@ class Test:
return None
TEST_MAP = dict([(test['id'], Test(i)) for i, test in enumerate(TESTS)])
# parser helpers
def test_known(string):
i = int(string)
if i >= 0 and i < len(TESTS) : return i
else : raise ArgumentTypeError("{0} does not index a test. The accepted range is 0 to {1}\nThe test mapping is:\n{2}".format(i, len(TEST_MAP) - 1, columnate([str(i) + ":" + t['id'] for i,t in zip(range(len(TESTS)), TESTS)])))
def test_name_known(string):
nlist = string.split(',')
for test_id in nlist:
if test_id not in TEST_MAP.keys():
if getattr(ps, "test_alias", None) is None or \
ps.test_alias.get(test_id, "") not in TEST_MAP.keys():
raise ArgumentTypeError("Program with name '{0}' not found. Supported tests are: \n{1}".format(test_id, columnate([t['id'] for t in TESTS])))
return [TEST_MAP[n].n for n in nlist]

View File

@ -17,6 +17,8 @@ limitations under the License.
import sys
import inspect
import os
import argparse
import math
from os import listdir, remove, makedirs
from shutil import copyfile
from os.path import isdir, join, exists, split, relpath, splitext
@ -196,3 +198,50 @@ def dict_to_ascii(input):
def json_file_to_dict(fname):
with open(fname, "rt") as f:
return dict_to_ascii(json.load(f, object_pairs_hook=OrderedDict))
# Wowza, double closure
def argparse_type(casedness, prefer_hyphen=False) :
def middle(list, type_name):
def parse_type(string):
if prefer_hyphen: newstring = casedness(string).replace("_","-")
else: newstring = casedness(string).replace("-","_")
if string in list:
return string
elif string not in list and newstring in list:
raise argparse.ArgumentTypeError("{0} is not a supported {1}. Did you mean {2}?".format(string, type_name, newstring))
else:
raise argparse.ArgumentTypeError("{0} is not a supported {1}. Supported {1}s are:\n{2}".format(string, type_name, columnate(list)))
return parse_type
return middle
argparse_uppercase_type = argparse_type(str.upper, False)
argparse_lowercase_type = argparse_type(str.lower, False)
argparse_uppercase_hyphen_type = argparse_type(str.upper, True)
argparse_lowercase_hyphen_type = argparse_type(str.lower, True)
def argparse_many(fn):
def wrap(string):
return [fn(s) for s in string.split(",")]
return wrap
def argparse_filestring_type(string) :
if exists(string) :
return string
else :
raise argparse.ArgumentTypeError("{0}"" does not exist in the filesystem.".format(string))
def columnate(strings, seperator=", ", chars=80):
col_width = max(len(s) for s in strings)
total_width = col_width + len(seperator)
columns = math.floor(chars / total_width)
output = ""
for i, s in zip(range(len(strings)), strings):
append = s
if i != len(strings) - 1:
append += seperator
if i % columns == columns - 1:
append += "\n"
else:
append = append.ljust(total_width)
output += append
return output