diff --git a/tools/make.py b/tools/make.py index d59c5badf8..c3bcacd6ab 100644 --- a/tools/make.py +++ b/tools/make.py @@ -21,11 +21,7 @@ TEST BUILD & RUN from __future__ import print_function from builtins import str import sys -import json -from time import sleep -from shutil import copy from os.path import join, abspath, dirname -from json import load, dump # Be sure that the tools directory is in the search path ROOT = abspath(join(dirname(__file__), "..")) @@ -41,7 +37,6 @@ from tools.paths import DSP_LIBRARIES 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.options import extract_profile from tools.options import extract_mcus @@ -54,51 +49,67 @@ from tools.build_api import merge_build_data from utils import argparse_filestring_type from utils import argparse_many from utils import argparse_dir_not_parent -from tools.toolchains import mbedToolchain, TOOLCHAIN_CLASSES, TOOLCHAIN_PATHS +from tools.toolchains import TOOLCHAIN_CLASSES, TOOLCHAIN_PATHS + + +def default_args_dict(options): + return dict( + linker_script=options.linker_script, + clean=options.clean, + macros=options.macros, + jobs=options.jobs, + name=options.artifact_name, + app_config=options.app_config, + stats_depth=options.stats_depth, + ignore=options.ignore + ) + + +def wrapped_build_project(src_dir, build_dir, mcu, *args, **kwargs): + try: + bin_file, update_file = build_project( + src_dir, build_dir, mcu, *args, **kwargs + ) + if update_file: + print('Update Image: %s' % update_file) + print('Image: %s' % bin_file) + except KeyboardInterrupt as e: + print("\n[CTRL+c] exit") + except NotSupportedException as e: + print("\nCould not compile for %s: %s" % (mcu, str(e))) + except Exception as e: + if options.verbose: + import traceback + traceback.print_exc(file=sys.stdout) + else: + print("[ERROR] %s" % str(e)) + sys.exit(1) + if __name__ == '__main__': # Parse Options parser = get_default_options_parser(add_app_config=True) + group = parser.add_mutually_exclusive_group(required=False) group.add_argument( "-p", type=argparse_many(test_known), dest="program", - help="The index of the desired test program: [0-%d]" % (len(TESTS)-1)) - + help="The index of the desired test program: [0-%d]" % (len(TESTS)-1) + ) group.add_argument( "-n", type=argparse_many(test_name_known), dest="program", - help="The name of the desired test program") - - 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_argument( - "-v", "--verbose", + help="The name of the desired test program" + ) + group.add_argument( + "-L", "--list-tests", action="store_true", - dest="verbose", + dest="list_tests", default=False, - help="Verbose diagnostic output") - - parser.add_argument( - "--silent", - action="store_true", - dest="silent", - default=False, - help="Silent diagnostic output (no copy, compile notification)") - - parser.add_argument( - "-D", - action="append", - dest="macros", - help="Add a macro definition") - + help="List available tests in order and exit" + ) group.add_argument( "-S", "--supported-toolchains", dest="supported_toolchains", @@ -106,239 +117,275 @@ if __name__ == '__main__': const="matrix", choices=["matrix", "toolchains", "targets"], nargs="?", - help="Displays supported matrix of MCUs and toolchains") + help="Displays supported matrix of MCUs and toolchains" + ) + 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_argument( + "-v", "--verbose", + action="store_true", + dest="verbose", + default=False, + help="Verbose diagnostic output" + ) + parser.add_argument( + "--silent", + action="store_true", + dest="silent", + default=False, + help="Silent diagnostic output (no copy, compile notification)" + ) + parser.add_argument( + "-D", + action="append", + dest="macros", + help="Add a macro definition" + ) parser.add_argument( '-f', '--filter', dest='general_filter_regex', default=None, - help='For some commands you can use filter to filter out results') - + help='For some commands you can use filter to filter out results' + ) parser.add_argument( "--stats-depth", type=int, dest="stats_depth", default=2, - help="Depth level for static memory report") - - # Local run - parser.add_argument("--automated", action="store_true", dest="automated", - default=False, help="Automated test") - parser.add_argument("--host", dest="host_test", - default=None, help="Host test") - parser.add_argument("--extra", dest="extra", - default=None, help="Extra files") - parser.add_argument("--peripherals", dest="peripherals", - default=None, help="Required peripherals") - parser.add_argument("--dep", dest="dependencies", - default=None, help="Dependencies") - parser.add_argument("--source", dest="source_dir", type=argparse_filestring_type, - default=None, help="The source (input) directory", action="append") - parser.add_argument("--duration", type=int, dest="duration", - default=None, help="Duration of the test") - parser.add_argument("--build", dest="build_dir", type=argparse_dir_not_parent(ROOT), - default=None, help="The build (output) directory") - parser.add_argument("-N", "--artifact-name", dest="artifact_name", - default=None, help="The built project's name") - parser.add_argument("--ignore", dest="ignore", type=argparse_many(str), - default=None, help="Comma separated list of patterns to add to mbedignore (eg. ./main.cpp)") - parser.add_argument("-d", "--disk", dest="disk", - default=None, help="The mbed disk") - parser.add_argument("-s", "--serial", dest="serial", - default=None, help="The mbed serial port") - parser.add_argument("-b", "--baud", type=int, dest="baud", - default=None, help="The mbed serial baud rate") - 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 usb, dsp - parser.add_argument("--rpc", - action="store_true", dest="rpc", - default=False, help="Link with RPC library") - - parser.add_argument("--usb", - action="store_true", - dest="usb", - default=False, - help="Link with USB Device library") - - parser.add_argument("--dsp", - action="store_true", - dest="dsp", - default=False, - help="Link with DSP library") - - parser.add_argument("--testlib", - action="store_true", - dest="testlib", - default=False, - help="Link with mbed test library") - - parser.add_argument("--build-data", - dest="build_data", - default=None, - help="Dump build_data to this file") - - # Specify a different linker script - parser.add_argument("-l", "--linker", dest="linker_script", - type=argparse_filestring_type, - default=None, help="use the specified linker script") - + help="Depth level for static memory report" + ) + parser.add_argument( + "--automated", + action="store_true", + dest="automated", + default=False, + help="Automated test" + ) + parser.add_argument( + "--host", + dest="host_test", + default=None, + help="Host test" + ) + parser.add_argument( + "--extra", + dest="extra", + default=None, + help="Extra files" + ) + parser.add_argument( + "--peripherals", + dest="peripherals", + default=None, + help="Required peripherals" + ) + parser.add_argument( + "--dep", + dest="dependencies", + default=None, + help="Dependencies" + ) + parser.add_argument( + "--source", + dest="source_dir", + type=argparse_filestring_type, + default=None, + action="append", + help="The source (input) directory" + ) + parser.add_argument( + "--duration", + type=int, + dest="duration", + default=None, + help="Duration of the test" + ) + parser.add_argument( + "--build", + dest="build_dir", + type=argparse_dir_not_parent(ROOT), + default=None, + help="The build (output) directory" + ) + parser.add_argument( + "-N", "--artifact-name", + dest="artifact_name", + default=None, + help="The built project's name" + ) + parser.add_argument( + "--ignore", + dest="ignore", + type=argparse_many(str), + default=None, + help="Comma separated list of patterns to add to mbedignore " + "(eg. ./main.cpp)" + ) + parser.add_argument( + "-b", "--baud", + type=int, + dest="baud", + default=None, + help="The mbed serial baud rate" + ) + parser.add_argument( + "--rpc", + action="store_true", + dest="rpc", + default=False, + help="Link with RPC library" + ) + parser.add_argument( + "--usb", + action="store_true", + dest="usb", + default=False, + help="Link with USB Device library" + ) + parser.add_argument( + "--dsp", + action="store_true", + dest="dsp", + default=False, + help="Link with DSP library" + ) + parser.add_argument( + "--testlib", + action="store_true", + dest="testlib", + default=False, + help="Link with mbed test library" + ) + parser.add_argument( + "--build-data", + dest="build_data", + default=None, + help="Dump build_data to this file" + ) + parser.add_argument( + "-l", "--linker", + dest="linker_script", + type=argparse_filestring_type, + default=None, + help="use the specified linker script" + ) options = parser.parse_args() - # Only prints matrix of supported toolchains if options.supported_toolchains: if options.supported_toolchains == "matrix": - print(mcu_toolchain_matrix(platform_filter=options.general_filter_regex, - release_version=None)) + print(mcu_toolchain_matrix( + platform_filter=options.general_filter_regex, + release_version=None + )) elif options.supported_toolchains == "toolchains": toolchain_list = mcu_toolchain_list() # Only print the lines that matter for line in toolchain_list.split("\n"): - if not "mbed" in line: + if "mbed" not in line: print(line) elif options.supported_toolchains == "targets": print(mcu_target_list()) - exit(0) - - # Print available tests in order and exit - if options.list_tests is True: + elif options.list_tests is True: print('\n'.join(map(str, sorted(TEST_MAP.values())))) - sys.exit() - - # force program to "0" if a source dir is specified - if options.source_dir is not None: - p = 0 else: - # Program Number or name - p = options.program + # Target + if options.mcu is None: + args_error(parser, "argument -m/--mcu is required") + mcu = extract_mcus(parser, options)[0] - # If 'p' was set via -n to list of numbers make this a single element integer list - if type(p) != type([]): - p = [p] + # Toolchain + if options.tool is None: + args_error(parser, "argument -t/--tool is required") + toolchain = options.tool[0] - # Target - if options.mcu is None : - args_error(parser, "argument -m/--mcu is required") - mcu = extract_mcus(parser, options)[0] + if (options.program is None) and (not options.source_dir): + args_error(parser, "one of -p, -n, or --source is required") - # Toolchain - if options.tool is None: - args_error(parser, "argument -t/--tool is required") - toolchain = options.tool[0] - - if (options.program is None) and (not options.source_dir): - args_error(parser, "one of -p, -n, or --source is required") - - if options.source_dir and not options.build_dir: - args_error(parser, "argument --build is required when argument --source is provided") + if options.source_dir and not options.build_dir: + args_error(parser, "argument --build is required when argument --source is provided") - notify = TerminalNotifier(options.verbose, options.silent, options.color) + notify = TerminalNotifier(options.verbose, options.silent, options.color) - if not TOOLCHAIN_CLASSES[toolchain].check_executable(): - search_path = TOOLCHAIN_PATHS[toolchain] or "No path set" - args_error(parser, "Could not find executable for %s.\n" - "Currently set search path: %s" - %(toolchain, search_path)) + if not TOOLCHAIN_CLASSES[toolchain].check_executable(): + search_path = TOOLCHAIN_PATHS[toolchain] or "No path set" + args_error(parser, "Could not find executable for %s.\n" + "Currently set search path: %s" + %(toolchain, search_path)) - # Test - build_data_blob = {} if options.build_data else None - for test_no in p: - test = Test(test_no) - if options.automated is not None: test.automated = options.automated - if options.dependencies is not None: test.dependencies = options.dependencies - if options.host_test is not None: test.host_test = options.host_test; - if options.peripherals is not None: test.peripherals = options.peripherals; - if options.duration is not None: test.duration = options.duration; - if options.extra is not None: test.extra_files = options.extra - - if not test.is_supported(mcu, toolchain): - print('The selected test is not supported on target %s with toolchain %s' % (mcu, toolchain)) - sys.exit() - - # Linking with extra libraries - if options.rpc: test.dependencies.append(RPC_LIBRARY) - if options.usb: test.dependencies.append(USB_LIBRARIES) - if options.dsp: test.dependencies.append(DSP_LIBRARIES) - if options.testlib: test.dependencies.append(TEST_MBED_LIB) - - build_dir = join(BUILD_DIR, "test", mcu, toolchain, test.id) if options.source_dir is not None: - test.source_dir = options.source_dir - build_dir = options.source_dir - - if options.build_dir is not None: - build_dir = options.build_dir - - try: - bin_file, update_file = build_project( - test.source_dir, - build_dir, + wrapped_build_project( + options.source_dir, + options.build_dir, mcu, toolchain, - set(test.dependencies), - linker_script=options.linker_script, - clean=options.clean, notify=notify, - report=build_data_blob, - macros=options.macros, - jobs=options.jobs, - name=options.artifact_name, - app_config=options.app_config, - inc_dirs=[dirname(MBED_LIBRARIES)], build_profile=extract_profile(parser, options, toolchain), - stats_depth=options.stats_depth, - ignore=options.ignore + **default_args_dict(options) ) - if update_file: - print('Update Image: %s' % update_file) - print('Image: %s' % bin_file) + else: + p = options.program - if options.disk: - # Simple copy to the mbed disk - copy(bin_file, options.disk) + # If 'p' was set via -n to list of numbers make this a single element + # integer list + if not isinstance(p, list): + p = [p] - if options.serial: - # Import pyserial: https://pypi.python.org/pypi/pyserial - from serial import Serial + build_data_blob = {} if options.build_data else None + for test_no in p: + test = Test(test_no) + if options.automated is not None: + test.automated = options.automated + if options.dependencies is not None: + test.dependencies = options.dependencies + if options.host_test is not None: + test.host_test = options.host_test + if options.peripherals is not None: + test.peripherals = options.peripherals + if options.duration is not None: + test.duration = options.duration + if options.extra is not None: + test.extra_files = options.extra - sleep(TARGET_MAP[mcu].program_cycle_s) + if not test.is_supported(mcu, toolchain): + print( + 'The selected test is not supported on target ' + '%s with toolchain %s' % (mcu, toolchain) + ) + sys.exit() - serial = Serial(options.serial, timeout = 1) - if options.baud: - serial.setBaudrate(options.baud) + # Linking with extra libraries + if options.rpc: + test.dependencies.append(RPC_LIBRARY) + if options.usb: + test.dependencies.append(USB_LIBRARIES) + if options.dsp: + test.dependencies.append(DSP_LIBRARIES) + if options.testlib: + test.dependencies.append(TEST_MBED_LIB) - serial.flushInput() - serial.flushOutput() + build_dir = join(BUILD_DIR, "test", mcu, toolchain, test.id) + if options.build_dir is not None: + build_dir = options.build_dir - try: - serial.sendBreak() - except: - # In linux a termios.error is raised in sendBreak and in setBreak. - # The following setBreak() is needed to release the reset signal on the target mcu. - try: - serial.setBreak(False) - except: - pass - - while True: - c = serial.read(512) - sys.stdout.write(c) - sys.stdout.flush() - - except KeyboardInterrupt as e: - print("\n[CTRL+c] exit") - except NotSupportedException as e: - print("\nCould not compile for %s: %s" % (mcu, str(e))) - except Exception as e: - if options.verbose: - import traceback - traceback.print_exc(file=sys.stdout) - else: - print("[ERROR] %s" % str(e)) - - sys.exit(1) - if options.build_data: - merge_build_data(options.build_data, build_data_blob, "application") + wrapped_build_project( + test.source_dir, + build_dir, + mcu, + toolchain, + set(test.dependencies), + notify=notify, + report=build_data_blob, + inc_dirs=[dirname(MBED_LIBRARIES)], + build_profile=extract_profile(parser, options, toolchain), + **default_args_dict(options) + ) + if options.build_data: + merge_build_data(options.build_data, build_data_blob, "application")