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 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")