Skip to content

Commit b29b55a

Browse files
author
Nir Sonnenschein
authored
Merge pull request #10193 from bridadan/arm_tc_with_fallback
Fallback to ARMC5 when ARMC6 is not configured
2 parents 4e514ae + b95732a commit b29b55a

File tree

9 files changed

+268
-122
lines changed

9 files changed

+268
-122
lines changed

targets/targets.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2594,7 +2594,7 @@
25942594
},
25952595
"MTB_MXCHIP_EMW3166": {
25962596
"inherits": ["FAMILY_STM32"],
2597-
"supported_toolchains": ["ARM", "GCC_ARM", "IAR"],
2597+
"supported_toolchains": ["ARMC6", "GCC_ARM", "IAR"],
25982598
"core": "Cortex-M4F",
25992599
"extra_labels_add": [
26002600
"STM32F4",
@@ -2627,7 +2627,7 @@
26272627
},
26282628
"USI_WM_BN_BM_22": {
26292629
"inherits": ["FAMILY_STM32"],
2630-
"supported_toolchains": ["ARM", "GCC_ARM", "IAR"],
2630+
"supported_toolchains": ["ARMC6", "GCC_ARM", "IAR"],
26312631
"components_add": ["SPIF", "FLASHIAP"],
26322632
"core": "Cortex-M4F",
26332633
"extra_labels_add": [
@@ -5309,7 +5309,7 @@
53095309
"RZ_A1XX": {
53105310
"inherits": ["Target"],
53115311
"core": "Cortex-A9",
5312-
"supported_toolchains": ["ARM", "GCC_ARM", "IAR"],
5312+
"supported_toolchains": ["ARMC6", "GCC_ARM", "IAR"],
53135313
"extra_labels": ["RENESAS", "RZ_A1XX"],
53145314
"device_has": [
53155315
"SLEEP",

tools/build.py

Lines changed: 33 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -29,24 +29,24 @@
2929
sys.path.insert(0, ROOT)
3030

3131

32-
from tools.toolchains import TOOLCHAINS, TOOLCHAIN_CLASSES, TOOLCHAIN_PATHS
33-
from tools.toolchains import mbedToolchain
34-
from tools.targets import TARGET_NAMES, TARGET_MAP, Target
32+
from tools.toolchains import TOOLCHAINS
33+
from tools.targets import TARGET_NAMES, Target
3534
from tools.options import get_default_options_parser
3635
from tools.options import extract_profile
3736
from tools.options import extract_mcus
3837
from tools.build_api import build_library, build_mbed_libs, build_lib
3938
from tools.build_api import mcu_toolchain_matrix
4039
from tools.build_api import print_build_results
41-
from tools.build_api import get_toolchain_name
42-
from tools.settings import CPPCHECK_CMD, CPPCHECK_MSG_FORMAT
43-
from tools.settings import CPPCHECK_CMD, CPPCHECK_MSG_FORMAT, CLI_COLOR_MAP
40+
from tools.build_api import target_supports_toolchain
41+
from tools.build_api import find_valid_toolchain
4442
from tools.notifier.term import TerminalNotifier
4543
from tools.utils import argparse_filestring_type, args_error, argparse_many
46-
from tools.utils import argparse_filestring_type, argparse_dir_not_parent
44+
from tools.utils import argparse_dir_not_parent
45+
from tools.utils import NoValidToolchainException
46+
from tools.utils import print_end_warnings
4747
from tools.paths import is_relative_to_root
4848

49-
if __name__ == '__main__':
49+
def main():
5050
start = time()
5151

5252
# Parse Options
@@ -169,40 +169,37 @@
169169
failures = []
170170
successes = []
171171
skipped = []
172+
end_warnings = []
172173

173-
toolchain_names = set()
174174
for toolchain in toolchains:
175175
for target_name in targets:
176176
target = Target.get_target(target_name)
177-
toolchain_names.add(get_toolchain_name(target, toolchain))
178177

179-
for toolchain_name in toolchain_names:
180-
if not TOOLCHAIN_CLASSES[toolchain_name].check_executable():
181-
search_path = TOOLCHAIN_PATHS[toolchain_name] or "No path set"
182-
args_error(parser, "Could not find executable for %s.\n"
183-
"Currently set search path: %s"
184-
% (toolchain_name, search_path))
178+
try:
179+
toolchain_name, internal_tc_name, end_warnings = find_valid_toolchain(
180+
target, toolchain
181+
)
182+
except NoValidToolchainException as e:
183+
print_end_warnings(e.end_warnings)
184+
args_error(parser, str(e))
185185

186-
for toolchain in toolchains:
187-
for target in targets:
188-
tt_id = "%s::%s" % (toolchain, target)
189-
if toolchain not in TARGET_MAP[target].supported_toolchains:
186+
tt_id = "%s::%s" % (internal_tc_name, target_name)
187+
if not target_supports_toolchain(target, toolchain):
190188
# Log this later
191189
print("%s skipped: toolchain not supported" % tt_id)
192190
skipped.append(tt_id)
193191
else:
194192
try:
195193
notifier = TerminalNotifier(options.verbose, options.silent)
196-
mcu = TARGET_MAP[target]
197-
profile = extract_profile(parser, options, toolchain)
194+
profile = extract_profile(parser, options, internal_tc_name)
198195

199-
if mcu.is_PSA_secure_target and \
196+
if target.is_PSA_secure_target and \
200197
not is_relative_to_root(options.source_dir):
201198
options.source_dir = ROOT
202199

203200
if options.source_dir:
204201
lib_build_res = build_library(
205-
options.source_dir, options.build_dir, mcu, toolchain,
202+
options.source_dir, options.build_dir, target, toolchain_name,
206203
jobs=options.jobs,
207204
clean=options.clean,
208205
archive=(not options.no_archive),
@@ -214,7 +211,7 @@
214211
)
215212
else:
216213
lib_build_res = build_mbed_libs(
217-
mcu, toolchain,
214+
target, toolchain_name,
218215
jobs=options.jobs,
219216
clean=options.clean,
220217
macros=options.macros,
@@ -225,7 +222,7 @@
225222

226223
for lib_id in libraries:
227224
build_lib(
228-
lib_id, mcu, toolchain,
225+
lib_id, target, toolchain_name,
229226
clean=options.clean,
230227
macros=options.macros,
231228
jobs=options.jobs,
@@ -236,10 +233,15 @@
236233
successes.append(tt_id)
237234
else:
238235
skipped.append(tt_id)
236+
except KeyboardInterrupt as e:
237+
print("\n[CTRL+c] exit")
238+
print_end_warnings(end_warnings)
239+
sys.exit(0)
239240
except Exception as e:
240241
if options.verbose:
241242
import traceback
242243
traceback.print_exc(file=sys.stdout)
244+
print_end_warnings(end_warnings)
243245
sys.exit(1)
244246
failures.append(tt_id)
245247
print(e)
@@ -254,5 +256,10 @@
254256
if report:
255257
print(print_build_results(report, report_name))
256258

259+
print_end_warnings(end_warnings)
257260
if failures:
258261
sys.exit(1)
262+
263+
264+
if __name__ == '__main__':
265+
main()

tools/build_api.py

Lines changed: 126 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
from .arm_pack_manager import Cache
3535
from .utils import (mkdir, run_cmd, run_cmd_ext, NotSupportedException,
3636
ToolException, InvalidReleaseTargetException,
37-
copy_when_different)
37+
copy_when_different, NoValidToolchainException)
3838
from .paths import (MBED_CMSIS_PATH, MBED_TARGETS_PATH, MBED_LIBRARIES,
3939
MBED_HEADER, MBED_DRIVERS, MBED_PLATFORM, MBED_HAL,
4040
MBED_CONFIG_FILE, MBED_LIBRARIES_DRIVERS,
@@ -44,7 +44,8 @@
4444
from .notifier.mock import MockNotifier
4545
from .targets import TARGET_NAMES, TARGET_MAP, CORE_ARCH, Target
4646
from .libraries import Library
47-
from .toolchains import TOOLCHAIN_CLASSES
47+
from .toolchains import TOOLCHAIN_CLASSES, TOOLCHAIN_PATHS
48+
from .toolchains.arm import ARMC5_MIGRATION_WARNING
4849
from .config import Config
4950

5051
RELEASE_VERSIONS = ['2', '5']
@@ -120,18 +121,76 @@ def add_result_to_report(report, result):
120121
result_wrap = {0: result}
121122
report[target][toolchain][id_name].append(result_wrap)
122123

124+
def get_valid_toolchain_names(target, toolchain_name):
125+
"""Return the list of toolchains with which a build should be attempted. This
126+
list usually contains one element, however there may be multiple entries if
127+
a toolchain is expected to fallback to different versions depending on the
128+
environment configuration. If an invalid supported_toolchain configuration
129+
is detected, an Exception will be raised.
130+
131+
Positional arguments:
132+
target - Target object (not the string name) of the device we are building for
133+
toolchain_name - the string that identifies the build toolchain as supplied by
134+
the front-end scripts
135+
"""
136+
if int(target.build_tools_metadata["version"]) > 0:
137+
all_arm_toolchain_names = ["ARMC6", "ARMC5", "ARM"]
138+
arm_st = set(target.supported_toolchains).intersection(
139+
set(all_arm_toolchain_names)
140+
)
141+
if len(arm_st) > 1:
142+
raise Exception(
143+
"Targets may only specify one of the following in "
144+
"supported_toolchains: {}\n"
145+
"The following toolchains were present: {}".format(
146+
", ".join(all_arm_toolchain_names),
147+
", ".join(arm_st),
148+
)
149+
)
150+
if toolchain_name == "ARM":
151+
# The order matters here
152+
all_arm_toolchain_names = ["ARMC6", "ARMC5"]
153+
if "ARM" in target.supported_toolchains:
154+
return all_arm_toolchain_names
155+
156+
result_list = []
157+
for tc_name in all_arm_toolchain_names:
158+
if tc_name in target.supported_toolchains:
159+
result_list.append(tc_name)
160+
return result_list
161+
162+
return [toolchain_name]
163+
123164
def get_toolchain_name(target, toolchain_name):
165+
"""Get the internal toolchain name given the toolchain_name provided by
166+
the front-end scripts (usually by the -t/--toolchain argument) and the target
167+
168+
Positional arguments:
169+
target - Target object (not the string name) of the device we are building for
170+
toolchain_name - the string that identifies the build toolchain as supplied by
171+
the front-end scripts
172+
173+
Overview of what the current return values should be for the "ARM" family of
174+
toolchains (since the behavior is fairly complex). Top row header represents
175+
the argument "toolchain_name", Left column header represents the attribute
176+
"supported_toolchains" of the "target" argument.
177+
178+
| supported_toolchains/toolchain_name |+| ARMC5 | ARMC6 | ARM |
179+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
180+
| ARMC5 |+| ARM* | ARMC6 | ARM |
181+
| ARMC6 |+| ARM* | ARMC6 | ARMC6* |
182+
| ARM |+| ARM* | ARMC6 | ARMC6* |
183+
184+
* Denotes that the input "toolchain_name" changes in the return value
185+
"""
124186
if int(target.build_tools_metadata["version"]) > 0:
125-
if toolchain_name == "ARM" or toolchain_name == "ARMC6" :
126-
if("ARM" in target.supported_toolchains or "ARMC6" in target.supported_toolchains):
187+
if toolchain_name == "ARMC5":
188+
return "ARM"
189+
elif toolchain_name == "ARM":
190+
if set(target.supported_toolchains).intersection(set(["ARMC6", "ARM"])):
127191
return "ARMC6"
128-
elif ("ARMC5" in target.supported_toolchains):
129-
if toolchain_name == "ARM":
130-
return "ARM" #note that returning ARM here means, use ARMC5 toolchain
131-
else:
132-
return "ARMC6" #ARMC6 explicitly specified by user, try ARMC6 anyway although the target doesnt explicitly specify ARMC6, as ARMC6 is our default ARM toolchain
133192
elif toolchain_name == "uARM":
134-
if ("ARMC5" in target.supported_toolchains):
193+
if "ARMC5" in target.supported_toolchains:
135194
return "uARM" #use ARM_MICRO to use AC5+microlib
136195
else:
137196
return "ARMC6" #use AC6+microlib
@@ -144,6 +203,51 @@ def get_toolchain_name(target, toolchain_name):
144203

145204
return toolchain_name
146205

206+
def find_valid_toolchain(target, toolchain):
207+
"""Given a target and toolchain, get the names for the appropriate
208+
toolchain to use. The environment is also checked to see if the corresponding
209+
compiler is configured correctl. For the ARM compilers, there is an automatic
210+
fallback behavior if "ARM" is the specified toolchain, if the latest compiler
211+
(ARMC6) is not available, and the target supports building with both ARMC5
212+
and ARMC6. In the case where the environment configuration triggers the fallback
213+
to ARMC5, add a warning to the list that is returned in the results.
214+
215+
Returns:
216+
toolchain_name - The name of the toolchain. When "ARM" is supplied as the
217+
"toolchain", this be changed to either "ARMC5" or "ARMC6".
218+
internal_tc_name - This corresponds to that name of the class that will be
219+
used to actually complete the build. This is mostly used for accessing build
220+
profiles and just general legacy sections within the code.
221+
end_warnings - This is a list of warnings (strings) that were raised during
222+
the process of finding toolchain. This is used to warn the user of the ARM
223+
fallback mechanism mentioned above.
224+
225+
Positional arguments:
226+
target - Target object (not the string name) of the device we are building for
227+
toolchain_name - the string that identifies the build toolchain as supplied by
228+
the front-end scripts
229+
"""
230+
end_warnings = []
231+
toolchain_names = get_valid_toolchain_names(target, toolchain)
232+
last_error = None
233+
for index, toolchain_name in enumerate(toolchain_names):
234+
internal_tc_name = get_toolchain_name(target, toolchain_name)
235+
if toolchain == "ARM" and toolchain_name == "ARMC5" and index != 0:
236+
end_warnings.append(ARMC5_MIGRATION_WARNING)
237+
if not TOOLCHAIN_CLASSES[internal_tc_name].check_executable():
238+
search_path = TOOLCHAIN_PATHS[internal_tc_name] or "No path set"
239+
last_error = (
240+
"Could not find executable for {}.\n"
241+
"Currently set search path: {}"
242+
).format(toolchain_name, search_path)
243+
else:
244+
return toolchain_name, internal_tc_name, end_warnings
245+
else:
246+
if last_error:
247+
e = NoValidToolchainException(last_error)
248+
e.end_warnings = end_warnings
249+
raise e
250+
147251
def get_config(src_paths, target, toolchain_name=None, app_config=None):
148252
"""Get the configuration object for a target-toolchain combination
149253
@@ -261,12 +365,18 @@ def transform_release_toolchains(target, version):
261365
"""
262366
if int(target.build_tools_metadata["version"]) > 0:
263367
if version == '5':
368+
non_arm_toolchains = set(["IAR", "GCC_ARM"])
264369
if 'ARMC5' in target.supported_toolchains:
265-
return ['ARMC5', 'GCC_ARM', 'IAR']
370+
result = ["ARMC5"]
266371
else:
267-
return ['ARM', 'ARMC6', 'GCC_ARM', 'IAR']
268-
else:
269-
return target.supported_toolchains
372+
result = ["ARM", "ARMC6"]
373+
result.extend(
374+
set(target.supported_toolchains).intersection(
375+
non_arm_toolchains
376+
)
377+
)
378+
return result
379+
return target.supported_toolchains
270380
else:
271381
if version == '5':
272382
return ['ARM', 'GCC_ARM', 'IAR']
@@ -315,8 +425,8 @@ def target_supports_toolchain(target, toolchain_name):
315425
if(toolchain_name == "ARM"):
316426
#we cant find ARM, see if one ARMC5, ARMC6 or uARM listed
317427
return any(tc in target.supported_toolchains for tc in ("ARMC5","ARMC6","uARM"))
318-
if(toolchain_name == "ARMC6"):
319-
#we did not find ARMC6, but check for ARM is listed
428+
if(toolchain_name == "ARMC6" or toolchain_name == "ARMC5"):
429+
#we did not find ARMC6 or ARMC5, but check if ARM is listed
320430
return "ARM" in target.supported_toolchains
321431
#return False in other cases
322432
return False
@@ -1038,30 +1148,6 @@ def _lowercase_release_version(release_version):
10381148
except AttributeError:
10391149
return 'all'
10401150

1041-
def mcu_toolchain_list(release_version='5'):
1042-
""" Shows list of toolchains
1043-
1044-
"""
1045-
release_version = _lowercase_release_version(release_version)
1046-
version_release_targets = {}
1047-
version_release_target_names = {}
1048-
1049-
for version in RELEASE_VERSIONS:
1050-
version_release_targets[version] = get_mbed_official_release(version)
1051-
version_release_target_names[version] = [x[0] for x in
1052-
version_release_targets[
1053-
version]]
1054-
1055-
if release_version in RELEASE_VERSIONS:
1056-
release_targets = version_release_targets[release_version]
1057-
else:
1058-
release_targets = None
1059-
1060-
unique_supported_toolchains = get_unique_supported_toolchains(
1061-
release_targets)
1062-
columns = ["mbed OS %s" % x for x in RELEASE_VERSIONS] + unique_supported_toolchains
1063-
return "\n".join(columns)
1064-
10651151

10661152
def mcu_target_list(release_version='5'):
10671153
""" Shows target list

0 commit comments

Comments
 (0)