Merge pull request #8538 from theotherjimmy/rework-make-cli

Rework make.py CLI to avoid treating apps as tests
pull/8624/head
Cruz Monrreal 2018-11-01 15:46:46 -05:00 committed by GitHub
commit 9c5fc7dc7c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 276 additions and 229 deletions

View File

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