Merge pull request #10193 from bridadan/arm_tc_with_fallback

Fallback to ARMC5 when ARMC6 is not configured
pull/10221/head
Nir Sonnenschein 2019-03-24 09:28:53 +02:00 committed by GitHub
commit b29b55ab5a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 269 additions and 123 deletions

View File

@ -2594,7 +2594,7 @@
}, },
"MTB_MXCHIP_EMW3166": { "MTB_MXCHIP_EMW3166": {
"inherits": ["FAMILY_STM32"], "inherits": ["FAMILY_STM32"],
"supported_toolchains": ["ARM", "GCC_ARM", "IAR"], "supported_toolchains": ["ARMC6", "GCC_ARM", "IAR"],
"core": "Cortex-M4F", "core": "Cortex-M4F",
"extra_labels_add": [ "extra_labels_add": [
"STM32F4", "STM32F4",
@ -2627,7 +2627,7 @@
}, },
"USI_WM_BN_BM_22": { "USI_WM_BN_BM_22": {
"inherits": ["FAMILY_STM32"], "inherits": ["FAMILY_STM32"],
"supported_toolchains": ["ARM", "GCC_ARM", "IAR"], "supported_toolchains": ["ARMC6", "GCC_ARM", "IAR"],
"components_add": ["SPIF", "FLASHIAP"], "components_add": ["SPIF", "FLASHIAP"],
"core": "Cortex-M4F", "core": "Cortex-M4F",
"extra_labels_add": [ "extra_labels_add": [
@ -5309,7 +5309,7 @@
"RZ_A1XX": { "RZ_A1XX": {
"inherits": ["Target"], "inherits": ["Target"],
"core": "Cortex-A9", "core": "Cortex-A9",
"supported_toolchains": ["ARM", "GCC_ARM", "IAR"], "supported_toolchains": ["ARMC6", "GCC_ARM", "IAR"],
"extra_labels": ["RENESAS", "RZ_A1XX"], "extra_labels": ["RENESAS", "RZ_A1XX"],
"device_has": [ "device_has": [
"SLEEP", "SLEEP",

View File

@ -29,24 +29,24 @@ ROOT = abspath(join(dirname(__file__), ".."))
sys.path.insert(0, ROOT) sys.path.insert(0, ROOT)
from tools.toolchains import TOOLCHAINS, TOOLCHAIN_CLASSES, TOOLCHAIN_PATHS from tools.toolchains import TOOLCHAINS
from tools.toolchains import mbedToolchain from tools.targets import TARGET_NAMES, Target
from tools.targets import TARGET_NAMES, TARGET_MAP, Target
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
from tools.build_api import build_library, build_mbed_libs, build_lib from tools.build_api import build_library, build_mbed_libs, build_lib
from tools.build_api import mcu_toolchain_matrix from tools.build_api import mcu_toolchain_matrix
from tools.build_api import print_build_results from tools.build_api import print_build_results
from tools.build_api import get_toolchain_name from tools.build_api import target_supports_toolchain
from tools.settings import CPPCHECK_CMD, CPPCHECK_MSG_FORMAT from tools.build_api import find_valid_toolchain
from tools.settings import CPPCHECK_CMD, CPPCHECK_MSG_FORMAT, CLI_COLOR_MAP
from tools.notifier.term import TerminalNotifier from tools.notifier.term import TerminalNotifier
from tools.utils import argparse_filestring_type, args_error, argparse_many from tools.utils import argparse_filestring_type, args_error, argparse_many
from tools.utils import argparse_filestring_type, argparse_dir_not_parent from tools.utils import argparse_dir_not_parent
from tools.utils import NoValidToolchainException
from tools.utils import print_end_warnings
from tools.paths import is_relative_to_root from tools.paths import is_relative_to_root
if __name__ == '__main__': def main():
start = time() start = time()
# Parse Options # Parse Options
@ -169,40 +169,37 @@ if __name__ == '__main__':
failures = [] failures = []
successes = [] successes = []
skipped = [] skipped = []
end_warnings = []
toolchain_names = set()
for toolchain in toolchains: for toolchain in toolchains:
for target_name in targets: for target_name in targets:
target = Target.get_target(target_name) target = Target.get_target(target_name)
toolchain_names.add(get_toolchain_name(target, toolchain))
for toolchain_name in toolchain_names: try:
if not TOOLCHAIN_CLASSES[toolchain_name].check_executable(): toolchain_name, internal_tc_name, end_warnings = find_valid_toolchain(
search_path = TOOLCHAIN_PATHS[toolchain_name] or "No path set" target, toolchain
args_error(parser, "Could not find executable for %s.\n" )
"Currently set search path: %s" except NoValidToolchainException as e:
% (toolchain_name, search_path)) print_end_warnings(e.end_warnings)
args_error(parser, str(e))
for toolchain in toolchains: tt_id = "%s::%s" % (internal_tc_name, target_name)
for target in targets: if not target_supports_toolchain(target, toolchain):
tt_id = "%s::%s" % (toolchain, target)
if toolchain not in TARGET_MAP[target].supported_toolchains:
# Log this later # Log this later
print("%s skipped: toolchain not supported" % tt_id) print("%s skipped: toolchain not supported" % tt_id)
skipped.append(tt_id) skipped.append(tt_id)
else: else:
try: try:
notifier = TerminalNotifier(options.verbose, options.silent) notifier = TerminalNotifier(options.verbose, options.silent)
mcu = TARGET_MAP[target] profile = extract_profile(parser, options, internal_tc_name)
profile = extract_profile(parser, options, toolchain)
if mcu.is_PSA_secure_target and \ if target.is_PSA_secure_target and \
not is_relative_to_root(options.source_dir): not is_relative_to_root(options.source_dir):
options.source_dir = ROOT options.source_dir = ROOT
if options.source_dir: if options.source_dir:
lib_build_res = build_library( lib_build_res = build_library(
options.source_dir, options.build_dir, mcu, toolchain, options.source_dir, options.build_dir, target, toolchain_name,
jobs=options.jobs, jobs=options.jobs,
clean=options.clean, clean=options.clean,
archive=(not options.no_archive), archive=(not options.no_archive),
@ -214,7 +211,7 @@ if __name__ == '__main__':
) )
else: else:
lib_build_res = build_mbed_libs( lib_build_res = build_mbed_libs(
mcu, toolchain, target, toolchain_name,
jobs=options.jobs, jobs=options.jobs,
clean=options.clean, clean=options.clean,
macros=options.macros, macros=options.macros,
@ -225,7 +222,7 @@ if __name__ == '__main__':
for lib_id in libraries: for lib_id in libraries:
build_lib( build_lib(
lib_id, mcu, toolchain, lib_id, target, toolchain_name,
clean=options.clean, clean=options.clean,
macros=options.macros, macros=options.macros,
jobs=options.jobs, jobs=options.jobs,
@ -236,10 +233,15 @@ if __name__ == '__main__':
successes.append(tt_id) successes.append(tt_id)
else: else:
skipped.append(tt_id) skipped.append(tt_id)
except KeyboardInterrupt as e:
print("\n[CTRL+c] exit")
print_end_warnings(end_warnings)
sys.exit(0)
except Exception as e: except Exception as e:
if options.verbose: if options.verbose:
import traceback import traceback
traceback.print_exc(file=sys.stdout) traceback.print_exc(file=sys.stdout)
print_end_warnings(end_warnings)
sys.exit(1) sys.exit(1)
failures.append(tt_id) failures.append(tt_id)
print(e) print(e)
@ -254,5 +256,10 @@ if __name__ == '__main__':
if report: if report:
print(print_build_results(report, report_name)) print(print_build_results(report, report_name))
print_end_warnings(end_warnings)
if failures: if failures:
sys.exit(1) sys.exit(1)
if __name__ == '__main__':
main()

View File

@ -34,7 +34,7 @@ from jinja2.environment import Environment
from .arm_pack_manager import Cache from .arm_pack_manager import Cache
from .utils import (mkdir, run_cmd, run_cmd_ext, NotSupportedException, from .utils import (mkdir, run_cmd, run_cmd_ext, NotSupportedException,
ToolException, InvalidReleaseTargetException, ToolException, InvalidReleaseTargetException,
copy_when_different) copy_when_different, NoValidToolchainException)
from .paths import (MBED_CMSIS_PATH, MBED_TARGETS_PATH, MBED_LIBRARIES, from .paths import (MBED_CMSIS_PATH, MBED_TARGETS_PATH, MBED_LIBRARIES,
MBED_HEADER, MBED_DRIVERS, MBED_PLATFORM, MBED_HAL, MBED_HEADER, MBED_DRIVERS, MBED_PLATFORM, MBED_HAL,
MBED_CONFIG_FILE, MBED_LIBRARIES_DRIVERS, MBED_CONFIG_FILE, MBED_LIBRARIES_DRIVERS,
@ -44,7 +44,8 @@ from .resources import Resources, FileType, FileRef
from .notifier.mock import MockNotifier from .notifier.mock import MockNotifier
from .targets import TARGET_NAMES, TARGET_MAP, CORE_ARCH, Target from .targets import TARGET_NAMES, TARGET_MAP, CORE_ARCH, Target
from .libraries import Library from .libraries import Library
from .toolchains import TOOLCHAIN_CLASSES from .toolchains import TOOLCHAIN_CLASSES, TOOLCHAIN_PATHS
from .toolchains.arm import ARMC5_MIGRATION_WARNING
from .config import Config from .config import Config
RELEASE_VERSIONS = ['2', '5'] RELEASE_VERSIONS = ['2', '5']
@ -120,18 +121,76 @@ def add_result_to_report(report, result):
result_wrap = {0: result} result_wrap = {0: result}
report[target][toolchain][id_name].append(result_wrap) report[target][toolchain][id_name].append(result_wrap)
def get_toolchain_name(target, toolchain_name): def get_valid_toolchain_names(target, toolchain_name):
"""Return the list of toolchains with which a build should be attempted. This
list usually contains one element, however there may be multiple entries if
a toolchain is expected to fallback to different versions depending on the
environment configuration. If an invalid supported_toolchain configuration
is detected, an Exception will be raised.
Positional arguments:
target - Target object (not the string name) of the device we are building for
toolchain_name - the string that identifies the build toolchain as supplied by
the front-end scripts
"""
if int(target.build_tools_metadata["version"]) > 0: if int(target.build_tools_metadata["version"]) > 0:
if toolchain_name == "ARM" or toolchain_name == "ARMC6" : all_arm_toolchain_names = ["ARMC6", "ARMC5", "ARM"]
if("ARM" in target.supported_toolchains or "ARMC6" in target.supported_toolchains): arm_st = set(target.supported_toolchains).intersection(
set(all_arm_toolchain_names)
)
if len(arm_st) > 1:
raise Exception(
"Targets may only specify one of the following in "
"supported_toolchains: {}\n"
"The following toolchains were present: {}".format(
", ".join(all_arm_toolchain_names),
", ".join(arm_st),
)
)
if toolchain_name == "ARM":
# The order matters here
all_arm_toolchain_names = ["ARMC6", "ARMC5"]
if "ARM" in target.supported_toolchains:
return all_arm_toolchain_names
result_list = []
for tc_name in all_arm_toolchain_names:
if tc_name in target.supported_toolchains:
result_list.append(tc_name)
return result_list
return [toolchain_name]
def get_toolchain_name(target, toolchain_name):
"""Get the internal toolchain name given the toolchain_name provided by
the front-end scripts (usually by the -t/--toolchain argument) and the target
Positional arguments:
target - Target object (not the string name) of the device we are building for
toolchain_name - the string that identifies the build toolchain as supplied by
the front-end scripts
Overview of what the current return values should be for the "ARM" family of
toolchains (since the behavior is fairly complex). Top row header represents
the argument "toolchain_name", Left column header represents the attribute
"supported_toolchains" of the "target" argument.
| supported_toolchains/toolchain_name |+| ARMC5 | ARMC6 | ARM |
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
| ARMC5 |+| ARM* | ARMC6 | ARM |
| ARMC6 |+| ARM* | ARMC6 | ARMC6* |
| ARM |+| ARM* | ARMC6 | ARMC6* |
* Denotes that the input "toolchain_name" changes in the return value
"""
if int(target.build_tools_metadata["version"]) > 0:
if toolchain_name == "ARMC5":
return "ARM"
elif toolchain_name == "ARM":
if set(target.supported_toolchains).intersection(set(["ARMC6", "ARM"])):
return "ARMC6" return "ARMC6"
elif ("ARMC5" in target.supported_toolchains):
if toolchain_name == "ARM":
return "ARM" #note that returning ARM here means, use ARMC5 toolchain
else:
return "ARMC6" #ARMC6 explicitly specified by user, try ARMC6 anyway although the target doesnt explicitly specify ARMC6, as ARMC6 is our default ARM toolchain
elif toolchain_name == "uARM": elif toolchain_name == "uARM":
if ("ARMC5" in target.supported_toolchains): if "ARMC5" in target.supported_toolchains:
return "uARM" #use ARM_MICRO to use AC5+microlib return "uARM" #use ARM_MICRO to use AC5+microlib
else: else:
return "ARMC6" #use AC6+microlib return "ARMC6" #use AC6+microlib
@ -144,6 +203,51 @@ def get_toolchain_name(target, toolchain_name):
return toolchain_name return toolchain_name
def find_valid_toolchain(target, toolchain):
"""Given a target and toolchain, get the names for the appropriate
toolchain to use. The environment is also checked to see if the corresponding
compiler is configured correctl. For the ARM compilers, there is an automatic
fallback behavior if "ARM" is the specified toolchain, if the latest compiler
(ARMC6) is not available, and the target supports building with both ARMC5
and ARMC6. In the case where the environment configuration triggers the fallback
to ARMC5, add a warning to the list that is returned in the results.
Returns:
toolchain_name - The name of the toolchain. When "ARM" is supplied as the
"toolchain", this be changed to either "ARMC5" or "ARMC6".
internal_tc_name - This corresponds to that name of the class that will be
used to actually complete the build. This is mostly used for accessing build
profiles and just general legacy sections within the code.
end_warnings - This is a list of warnings (strings) that were raised during
the process of finding toolchain. This is used to warn the user of the ARM
fallback mechanism mentioned above.
Positional arguments:
target - Target object (not the string name) of the device we are building for
toolchain_name - the string that identifies the build toolchain as supplied by
the front-end scripts
"""
end_warnings = []
toolchain_names = get_valid_toolchain_names(target, toolchain)
last_error = None
for index, toolchain_name in enumerate(toolchain_names):
internal_tc_name = get_toolchain_name(target, toolchain_name)
if toolchain == "ARM" and toolchain_name == "ARMC5" and index != 0:
end_warnings.append(ARMC5_MIGRATION_WARNING)
if not TOOLCHAIN_CLASSES[internal_tc_name].check_executable():
search_path = TOOLCHAIN_PATHS[internal_tc_name] or "No path set"
last_error = (
"Could not find executable for {}.\n"
"Currently set search path: {}"
).format(toolchain_name, search_path)
else:
return toolchain_name, internal_tc_name, end_warnings
else:
if last_error:
e = NoValidToolchainException(last_error)
e.end_warnings = end_warnings
raise e
def get_config(src_paths, target, toolchain_name=None, app_config=None): def get_config(src_paths, target, toolchain_name=None, app_config=None):
"""Get the configuration object for a target-toolchain combination """Get the configuration object for a target-toolchain combination
@ -261,12 +365,18 @@ def transform_release_toolchains(target, version):
""" """
if int(target.build_tools_metadata["version"]) > 0: if int(target.build_tools_metadata["version"]) > 0:
if version == '5': if version == '5':
non_arm_toolchains = set(["IAR", "GCC_ARM"])
if 'ARMC5' in target.supported_toolchains: if 'ARMC5' in target.supported_toolchains:
return ['ARMC5', 'GCC_ARM', 'IAR'] result = ["ARMC5"]
else: else:
return ['ARM', 'ARMC6', 'GCC_ARM', 'IAR'] result = ["ARM", "ARMC6"]
else: result.extend(
return target.supported_toolchains set(target.supported_toolchains).intersection(
non_arm_toolchains
)
)
return result
return target.supported_toolchains
else: else:
if version == '5': if version == '5':
return ['ARM', 'GCC_ARM', 'IAR'] return ['ARM', 'GCC_ARM', 'IAR']
@ -315,8 +425,8 @@ def target_supports_toolchain(target, toolchain_name):
if(toolchain_name == "ARM"): if(toolchain_name == "ARM"):
#we cant find ARM, see if one ARMC5, ARMC6 or uARM listed #we cant find ARM, see if one ARMC5, ARMC6 or uARM listed
return any(tc in target.supported_toolchains for tc in ("ARMC5","ARMC6","uARM")) return any(tc in target.supported_toolchains for tc in ("ARMC5","ARMC6","uARM"))
if(toolchain_name == "ARMC6"): if(toolchain_name == "ARMC6" or toolchain_name == "ARMC5"):
#we did not find ARMC6, but check for ARM is listed #we did not find ARMC6 or ARMC5, but check if ARM is listed
return "ARM" in target.supported_toolchains return "ARM" in target.supported_toolchains
#return False in other cases #return False in other cases
return False return False
@ -1038,30 +1148,6 @@ def _lowercase_release_version(release_version):
except AttributeError: except AttributeError:
return 'all' return 'all'
def mcu_toolchain_list(release_version='5'):
""" Shows list of toolchains
"""
release_version = _lowercase_release_version(release_version)
version_release_targets = {}
version_release_target_names = {}
for version in RELEASE_VERSIONS:
version_release_targets[version] = get_mbed_official_release(version)
version_release_target_names[version] = [x[0] for x in
version_release_targets[
version]]
if release_version in RELEASE_VERSIONS:
release_targets = version_release_targets[release_version]
else:
release_targets = None
unique_supported_toolchains = get_unique_supported_toolchains(
release_targets)
columns = ["mbed OS %s" % x for x in RELEASE_VERSIONS] + unique_supported_toolchains
return "\n".join(columns)
def mcu_target_list(release_version='5'): def mcu_target_list(release_version='5'):
""" Shows target list """ Shows target list

View File

@ -41,17 +41,18 @@ from tools.tests import test_known, test_name_known
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
from tools.options import get_toolchain_list
from tools.notifier.term import TerminalNotifier from tools.notifier.term import TerminalNotifier
from tools.build_api import build_project from tools.build_api import build_project
from tools.build_api import mcu_toolchain_matrix from tools.build_api import mcu_toolchain_matrix
from tools.build_api import mcu_toolchain_list
from tools.build_api import mcu_target_list from tools.build_api import mcu_target_list
from tools.build_api import merge_build_data from tools.build_api import merge_build_data
from tools.build_api import get_toolchain_name from tools.build_api import find_valid_toolchain
from utils import argparse_filestring_type from tools.utils import argparse_filestring_type
from utils import argparse_many from tools.utils import argparse_many
from utils import argparse_dir_not_parent from tools.utils import argparse_dir_not_parent
from tools.toolchains import TOOLCHAIN_CLASSES, TOOLCHAIN_PATHS from tools.utils import NoValidToolchainException
from tools.utils import print_end_warnings
from tools.settings import ROOT from tools.settings import ROOT
from tools.targets import Target from tools.targets import Target
@ -68,8 +69,8 @@ def default_args_dict(options):
ignore=options.ignore ignore=options.ignore
) )
def wrapped_build_project(src_dir, build_dir, mcu, end_warnings, options, *args, **kwargs):
def wrapped_build_project(src_dir, build_dir, mcu, *args, **kwargs): error = False
try: try:
bin_file, update_file = build_project( bin_file, update_file = build_project(
src_dir, build_dir, mcu, *args, **kwargs src_dir, build_dir, mcu, *args, **kwargs
@ -80,17 +81,22 @@ def wrapped_build_project(src_dir, build_dir, mcu, *args, **kwargs):
except KeyboardInterrupt as e: except KeyboardInterrupt as e:
print("\n[CTRL+c] exit") print("\n[CTRL+c] exit")
except NotSupportedException as e: except NotSupportedException as e:
print("\nCould not compile for %s: %s" % (mcu, str(e))) print("\nCould not compile for {}: {}".format(mcu, str(e)))
error = True
except Exception as e: except Exception as e:
if options.verbose: if options.verbose:
import traceback import traceback
traceback.print_exc(file=sys.stdout) traceback.print_exc(file=sys.stdout)
else: else:
print("[ERROR] %s" % str(e)) print("[ERROR] {}".format(str(e)))
error = True
print_end_warnings(end_warnings)
if error:
sys.exit(1) sys.exit(1)
def 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)
@ -282,6 +288,8 @@ if __name__ == '__main__':
) )
options = parser.parse_args() options = parser.parse_args()
end_warnings = []
if options.supported_toolchains: if options.supported_toolchains:
if options.supported_toolchains == "matrix": if options.supported_toolchains == "matrix":
print(mcu_toolchain_matrix( print(mcu_toolchain_matrix(
@ -289,11 +297,7 @@ if __name__ == '__main__':
release_version=None release_version=None
)) ))
elif options.supported_toolchains == "toolchains": elif options.supported_toolchains == "toolchains":
toolchain_list = mcu_toolchain_list() print('\n'.join(get_toolchain_list()))
# Only print the lines that matter
for line in toolchain_list.split("\n"):
if "mbed" not in line:
print(line)
elif options.supported_toolchains == "targets": elif options.supported_toolchains == "targets":
print(mcu_target_list()) print(mcu_target_list())
elif options.list_tests is True: elif options.list_tests is True:
@ -323,21 +327,24 @@ if __name__ == '__main__':
notify = TerminalNotifier(options.verbose, options.silent, options.color) notify = TerminalNotifier(options.verbose, options.silent, options.color)
toolchain_name = get_toolchain_name(target, toolchain) try:
if not TOOLCHAIN_CLASSES[toolchain_name].check_executable(): toolchain_name, internal_tc_name, end_warnings = find_valid_toolchain(
search_path = TOOLCHAIN_PATHS[toolchain_name] or "No path set" target, toolchain
args_error(parser, "Could not find executable for %s.\n" )
"Currently set search path: %s" except NoValidToolchainException as e:
%(toolchain_name, search_path)) print_end_warnings(e.end_warnings)
args_error(parser, str(e))
if options.source_dir is not None: if options.source_dir is not None:
wrapped_build_project( wrapped_build_project(
options.source_dir, options.source_dir,
options.build_dir, options.build_dir,
mcu, mcu,
toolchain, end_warnings,
options,
toolchain_name,
notify=notify, notify=notify,
build_profile=extract_profile(parser, options, toolchain), build_profile=extract_profile(parser, options, internal_tc_name),
**default_args_dict(options) **default_args_dict(options)
) )
else: else:
@ -389,13 +396,18 @@ if __name__ == '__main__':
test.source_dir, test.source_dir,
build_dir, build_dir,
mcu, mcu,
toolchain, end_warnings,
options,
toolchain_name,
set(test.dependencies), set(test.dependencies),
notify=notify, notify=notify,
report=build_data_blob, report=build_data_blob,
inc_dirs=[dirname(MBED_LIBRARIES)], inc_dirs=[dirname(MBED_LIBRARIES)],
build_profile=extract_profile(parser, options, toolchain), build_profile=extract_profile(parser, options, internal_tc_name),
**default_args_dict(options) **default_args_dict(options)
) )
if options.build_data: if options.build_data:
merge_build_data(options.build_data, build_data_blob, "application") merge_build_data(options.build_data, build_data_blob, "application")
if __name__ == '__main__':
main()

View File

@ -21,7 +21,7 @@ from os.path import join, dirname
from os import listdir from os import listdir
from argparse import ArgumentParser, ArgumentTypeError from argparse import ArgumentParser, ArgumentTypeError
from .toolchains import TOOLCHAINS from .toolchains import TOOLCHAINS, EXTRA_TOOLCHAIN_NAMES
from .targets import TARGET_NAMES, Target, update_target_data from .targets import TARGET_NAMES, Target, update_target_data
from .utils import (argparse_force_uppercase_type, argparse_deprecate, from .utils import (argparse_force_uppercase_type, argparse_deprecate,
argparse_lowercase_hyphen_type, argparse_many, argparse_lowercase_hyphen_type, argparse_many,
@ -32,6 +32,12 @@ FLAGS_DEPRECATION_MESSAGE = "Please use the --profile argument instead.\n"\
"Documentation may be found in "\ "Documentation may be found in "\
"docs/Toolchain_Profiles.md" "docs/Toolchain_Profiles.md"
def get_toolchain_list():
toolchainlist = list(TOOLCHAINS)
toolchainlist.extend(EXTRA_TOOLCHAIN_NAMES)
toolchainlist.sort()
return toolchainlist
def get_default_options_parser(add_clean=True, add_options=True, def get_default_options_parser(add_clean=True, add_options=True,
add_app_config=False): add_app_config=False):
"""Create a new options parser with the default compiler options added """Create a new options parser with the default compiler options added
@ -44,8 +50,7 @@ def get_default_options_parser(add_clean=True, add_options=True,
targetnames = TARGET_NAMES targetnames = TARGET_NAMES
targetnames.sort() targetnames.sort()
toolchainlist = list(TOOLCHAINS) toolchainlist = get_toolchain_list()
toolchainlist.sort()
parser.add_argument("-m", "--mcu", parser.add_argument("-m", "--mcu",
help=("build for the given MCU (%s)" % help=("build for the given MCU (%s)" %
@ -127,7 +132,7 @@ def extract_profile(parser, options, toolchain, fallback="develop"):
profiles.append(contents) profiles.append(contents)
return profiles return profiles
def extract_mcus(parser, options): def extract_mcus(parser, options):
try: try:
if options.custom_targets_directory: if options.custom_targets_directory:

View File

@ -28,27 +28,25 @@ sys.path.insert(0, ROOT)
from tools.config import ConfigException, Config from tools.config import ConfigException, Config
from tools.test_configs import get_default_config from tools.test_configs import get_default_config
from tools.config import ConfigException
from tools.test_api import find_tests, get_test_config, print_tests, build_tests, test_spec_from_test_builds from tools.test_api import find_tests, get_test_config, print_tests, build_tests, test_spec_from_test_builds
import tools.test_configs as TestConfig
from tools.options import get_default_options_parser, extract_profile, extract_mcus from tools.options import get_default_options_parser, extract_profile, extract_mcus
from tools.build_api import build_project, build_library from tools.build_api import build_library
from tools.build_api import print_build_memory_usage from tools.build_api import print_build_memory_usage
from tools.build_api import merge_build_data from tools.build_api import merge_build_data
from tools.build_api import get_toolchain_name from tools.build_api import find_valid_toolchain
from tools.targets import TARGET_MAP
from tools.notifier.term import TerminalNotifier from tools.notifier.term import TerminalNotifier
from tools.utils import mkdir, ToolException, NotSupportedException, args_error, write_json_to_file from tools.utils import ToolException, NotSupportedException, args_error, write_json_to_file
from tools.utils import NoValidToolchainException
from tools.test_exporters import ReportExporter, ResultExporterType from tools.test_exporters import ReportExporter, ResultExporterType
from tools.utils import argparse_filestring_type, argparse_lowercase_type, argparse_many from tools.utils import argparse_filestring_type, argparse_lowercase_type, argparse_many
from tools.utils import argparse_dir_not_parent from tools.utils import argparse_dir_not_parent
from tools.toolchains import mbedToolchain, TOOLCHAIN_PATHS, TOOLCHAIN_CLASSES from tools.utils import print_end_warnings
from tools.settings import CLI_COLOR_MAP
from tools.settings import ROOT from tools.settings import ROOT
from tools.targets import Target from tools.targets import Target
from tools.paths import is_relative_to_root from tools.paths import is_relative_to_root
if __name__ == '__main__': def main():
error = False
try: try:
# Parse Options # Parse Options
parser = get_default_options_parser(add_app_config=True) parser = get_default_options_parser(add_app_config=True)
@ -140,6 +138,7 @@ if __name__ == '__main__':
all_tests = {} all_tests = {}
tests = {} tests = {}
end_warnings = []
# As default both test tools are enabled # As default both test tools are enabled
if not (options.greentea or options.icetea): if not (options.greentea or options.icetea):
@ -158,12 +157,13 @@ if __name__ == '__main__':
args_error(parser, "argument -t/--tool is required") args_error(parser, "argument -t/--tool is required")
toolchain = options.tool[0] toolchain = options.tool[0]
toolchain_name = get_toolchain_name(target, toolchain) try:
if not TOOLCHAIN_CLASSES[toolchain_name].check_executable(): toolchain_name, internal_tc_name, end_warnings = find_valid_toolchain(
search_path = TOOLCHAIN_PATHS[toolchain_name] or "No path set" target, toolchain
args_error(parser, "Could not find executable for %s.\n" )
"Currently set search path: %s" except NoValidToolchainException as e:
% (toolchain_name, search_path)) print_end_warnings(e.end_warnings)
args_error(parser, str(e))
# Assign config file. Precedence: test_config>app_config # Assign config file. Precedence: test_config>app_config
# TODO: merge configs if both given # TODO: merge configs if both given
@ -185,7 +185,7 @@ if __name__ == '__main__':
all_tests.update(find_tests( all_tests.update(find_tests(
base_dir=path, base_dir=path,
target_name=mcu, target_name=mcu,
toolchain_name=toolchain, toolchain_name=toolchain_name,
icetea=options.icetea, icetea=options.icetea,
greentea=options.greentea, greentea=options.greentea,
app_config=config)) app_config=config))
@ -229,12 +229,12 @@ if __name__ == '__main__':
build_properties = {} build_properties = {}
library_build_success = False library_build_success = False
profile = extract_profile(parser, options, toolchain) profile = extract_profile(parser, options, internal_tc_name)
try: try:
# Build sources # Build sources
notify = TerminalNotifier(options.verbose) notify = TerminalNotifier(options.verbose)
build_library(base_source_paths, options.build_dir, mcu, build_library(base_source_paths, options.build_dir, mcu,
toolchain, jobs=options.jobs, toolchain_name, jobs=options.jobs,
clean=options.clean, report=build_report, clean=options.clean, report=build_report,
properties=build_properties, name="mbed-build", properties=build_properties, name="mbed-build",
macros=options.macros, macros=options.macros,
@ -267,7 +267,7 @@ if __name__ == '__main__':
[os.path.relpath(options.build_dir)], [os.path.relpath(options.build_dir)],
options.build_dir, options.build_dir,
mcu, mcu,
toolchain, toolchain_name,
clean=options.clean, clean=options.clean,
report=build_report, report=build_report,
properties=build_properties, properties=build_properties,
@ -310,8 +310,16 @@ if __name__ == '__main__':
except ConfigException as e: except ConfigException as e:
# Catching ConfigException here to prevent a traceback # Catching ConfigException here to prevent a traceback
print("[ERROR] %s" % str(e)) print("[ERROR] %s" % str(e))
error = True
except Exception as e: except Exception as e:
import traceback import traceback
traceback.print_exc(file=sys.stdout) traceback.print_exc(file=sys.stdout)
print("[ERROR] %s" % str(e)) print("[ERROR] %s" % str(e))
error = True
print_end_warnings(end_warnings)
if error:
sys.exit(1) sys.exit(1)
if __name__ == '__main__':
main()

View File

@ -26,6 +26,10 @@ TOOLCHAIN_CLASSES = {
u'IAR': iar.IAR u'IAR': iar.IAR
} }
EXTRA_TOOLCHAIN_NAMES = [
u"ARMC5"
]
TOOLCHAINS = set(TOOLCHAIN_CLASSES.keys()) TOOLCHAINS = set(TOOLCHAIN_CLASSES.keys())
# Top level re-exports # Top level re-exports

View File

@ -30,6 +30,13 @@ from tools.targets import CORE_ARCH
from tools.toolchains.mbed_toolchain import mbedToolchain, TOOLCHAIN_PATHS from tools.toolchains.mbed_toolchain import mbedToolchain, TOOLCHAIN_PATHS
from tools.utils import mkdir, NotSupportedException, ToolException, run_cmd from tools.utils import mkdir, NotSupportedException, ToolException, run_cmd
ARMC5_MIGRATION_WARNING = (
"Warning: We noticed that you are using Arm Compiler 5. "
"We are deprecating the use of Arm Compiler 5 soon. "
"Please upgrade your environment to Arm Compiler 6 "
"which is free to use with Mbed OS. For more information, "
"please visit https://os.mbed.com/docs/mbed-os/latest/tools/index.html"
)
class ARM(mbedToolchain): class ARM(mbedToolchain):
LINKER_EXT = '.sct' LINKER_EXT = '.sct'
@ -394,7 +401,7 @@ class ARM_STD(ARM):
if int(target.build_tools_metadata["version"]) > 0: if int(target.build_tools_metadata["version"]) > 0:
#check only for ARMC5 because ARM_STD means using ARMC5, and thus #check only for ARMC5 because ARM_STD means using ARMC5, and thus
# supported_toolchains must include ARMC5 # supported_toolchains must include ARMC5
if "ARMC5" not in target.supported_toolchains: if not set(target.supported_toolchains).intersection(set(("ARMC5", "ARM"))):
raise NotSupportedException( raise NotSupportedException(
"ARM compiler 5 support is required for ARM build" "ARM compiler 5 support is required for ARM build"
) )

View File

@ -296,6 +296,11 @@ class NotSupportedException(Exception):
class InvalidReleaseTargetException(Exception): class InvalidReleaseTargetException(Exception):
pass pass
class NoValidToolchainException(Exception):
"""A class representing no valid toolchain configurations found on
the system"""
pass
def split_path(path): def split_path(path):
"""spilt a file name into it's directory name, base name, and extension """spilt a file name into it's directory name, base name, and extension
@ -334,8 +339,7 @@ def args_error(parser, message):
parser - the ArgumentParser object that parsed the command line parser - the ArgumentParser object that parsed the command line
message - what went wrong message - what went wrong
""" """
parser.error(message) parser.exit(status=2, message=message+'\n')
sys.exit(2)
def construct_enum(**enums): def construct_enum(**enums):
@ -597,3 +601,16 @@ def generate_update_filename(name, target):
name, name,
getattr(target, "OUTPUT_EXT_UPDATE", "bin") getattr(target, "OUTPUT_EXT_UPDATE", "bin")
) )
def print_end_warnings(end_warnings):
""" Print a formatted list of warnings
Positional arguments:
end_warnings - A list of warnings (strings) to print
"""
if end_warnings:
warning_separator = "-" * 60
print(warning_separator)
for end_warning in end_warnings:
print(end_warning)
print(warning_separator)