34
34
from .arm_pack_manager import Cache
35
35
from .utils import (mkdir , run_cmd , run_cmd_ext , NotSupportedException ,
36
36
ToolException , InvalidReleaseTargetException ,
37
- copy_when_different )
37
+ copy_when_different , NoValidToolchainException )
38
38
from .paths import (MBED_CMSIS_PATH , MBED_TARGETS_PATH , MBED_LIBRARIES ,
39
39
MBED_HEADER , MBED_DRIVERS , MBED_PLATFORM , MBED_HAL ,
40
40
MBED_CONFIG_FILE , MBED_LIBRARIES_DRIVERS ,
44
44
from .notifier .mock import MockNotifier
45
45
from .targets import TARGET_NAMES , TARGET_MAP , CORE_ARCH , Target
46
46
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
48
49
from .config import Config
49
50
50
51
RELEASE_VERSIONS = ['2' , '5' ]
@@ -120,18 +121,76 @@ def add_result_to_report(report, result):
120
121
result_wrap = {0 : result }
121
122
report [target ][toolchain ][id_name ].append (result_wrap )
122
123
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
+
123
164
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
+ """
124
186
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" ])):
127
191
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
133
192
elif toolchain_name == "uARM" :
134
- if ( "ARMC5" in target .supported_toolchains ) :
193
+ if "ARMC5" in target .supported_toolchains :
135
194
return "uARM" #use ARM_MICRO to use AC5+microlib
136
195
else :
137
196
return "ARMC6" #use AC6+microlib
@@ -144,6 +203,51 @@ def get_toolchain_name(target, toolchain_name):
144
203
145
204
return toolchain_name
146
205
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
+
147
251
def get_config (src_paths , target , toolchain_name = None , app_config = None ):
148
252
"""Get the configuration object for a target-toolchain combination
149
253
@@ -261,12 +365,18 @@ def transform_release_toolchains(target, version):
261
365
"""
262
366
if int (target .build_tools_metadata ["version" ]) > 0 :
263
367
if version == '5' :
368
+ non_arm_toolchains = set (["IAR" , "GCC_ARM" ])
264
369
if 'ARMC5' in target .supported_toolchains :
265
- return [ ' ARMC5' , 'GCC_ARM' , 'IAR' ]
370
+ result = [ " ARMC5" ]
266
371
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
270
380
else :
271
381
if version == '5' :
272
382
return ['ARM' , 'GCC_ARM' , 'IAR' ]
@@ -315,8 +425,8 @@ def target_supports_toolchain(target, toolchain_name):
315
425
if (toolchain_name == "ARM" ):
316
426
#we cant find ARM, see if one ARMC5, ARMC6 or uARM listed
317
427
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
320
430
return "ARM" in target .supported_toolchains
321
431
#return False in other cases
322
432
return False
@@ -1038,30 +1148,6 @@ def _lowercase_release_version(release_version):
1038
1148
except AttributeError :
1039
1149
return 'all'
1040
1150
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
-
1065
1151
1066
1152
def mcu_target_list (release_version = '5' ):
1067
1153
""" Shows target list
0 commit comments