3434from .arm_pack_manager import Cache
3535from .utils import (mkdir , run_cmd , run_cmd_ext , NotSupportedException ,
3636 ToolException , InvalidReleaseTargetException ,
37- copy_when_different )
37+ copy_when_different , NoValidToolchainException )
3838from .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 ,
4444from .notifier .mock import MockNotifier
4545from .targets import TARGET_NAMES , TARGET_MAP , CORE_ARCH , Target
4646from .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
4849from .config import Config
4950
5051RELEASE_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+
123164def 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+
147251def 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
10661152def mcu_target_list (release_version = '5' ):
10671153 """ Shows target list
0 commit comments