1+ #!/usr/bin/env python3
12"""
23Copyright (c) 2017-2019 ARM Limited. All rights reserved.
34
1516See the License for the specific language governing permissions and
1617limitations
1718"""
19+ import json
1820import os
1921from os .path import dirname , abspath , basename , join , normpath
2022import os .path
3032
3133 """
3234
35+
36+ EXECUTABLE_ANALYSIS_TOOLS_PATH = join (
37+ os .path .dirname (__file__ ),
38+ "../../executable_analysis_tools/" ,
39+ )
40+ sys .path .append (EXECUTABLE_ANALYSIS_TOOLS_PATH )
41+ import elf_float_checker
42+
3343ROOT = abspath (dirname (dirname (dirname (dirname (__file__ )))))
34- sys .path .insert ( 0 , ROOT )
44+ sys .path .append ( ROOT )
3545
3646from tools .build_api import get_mbed_official_release
3747from tools .targets import TARGET_MAP
@@ -349,7 +359,7 @@ def status(message):
349359 return results
350360
351361
352- def compile_repos (config , toolchains , targets , profile , verbose , examples ):
362+ def compile_repos (config , toolchains , targets , profiles , verbose , examples , post_checks ):
353363 """Compiles combinations of example programs, targets and compile chains.
354364
355365 The results are returned in a [key: value] dictionary format:
@@ -388,6 +398,7 @@ def compile_repos(config, toolchains, targets, profile, verbose, examples):
388398 test_example = True
389399 else :
390400 test_example = False
401+
391402 if example ['compile' ]:
392403 for repo_info in get_repo_list (example ):
393404 name = basename (repo_info ['repo' ])
@@ -399,28 +410,54 @@ def compile_repos(config, toolchains, targets, profile, verbose, examples):
399410 example ['features' ]):
400411
401412 build_command = ["mbed-cli" , "compile" , "-t" , toolchain , "-m" , target ] + (['-vv' ] if verbose else [])
402- if profile :
403- build_command . append ( "-- profile" )
404- build_command .append ( profile )
413+ if profiles :
414+ for profile in profiles :
415+ build_command .extend ([ "-- profile" , profile ] )
405416
406417 print ("Compiling [%s] for [%s] with toolchain [%s]\n \n > %s" % (name , target , toolchain , " " .join (build_command )))
407418
408- proc = subprocess .Popen (build_command , stdout = subprocess .PIPE , stderr = subprocess .PIPE )
419+ if (
420+ post_checks
421+ and POST_BUILD_CHECK_FLOATS in post_checks
422+ and name not in POST_BUILD_CHECK_FLOATS_EXCLUDED_EXAMPLES
423+ ):
424+ # Disable floating point support for minimal-printf if
425+ # a post build check for minimal-printf is specified.
426+ has_float_support = "false"
427+ else :
428+ has_float_support = "true"
429+
430+ _set_minimal_printf_floats_status (has_float_support )
431+
432+ proc = subprocess .run (
433+ build_command ,
434+ stdin = None ,
435+ stdout = subprocess .PIPE ,
436+ stderr = subprocess .PIPE ,
437+ )
438+
439+ std_out = proc .stdout .decode ()
440+ std_err = proc .stderr .decode ()
409441
410- std_out , std_err = proc .communicate ()
411- std_out = std_out .decode ('utf-8' )
412442 print ("\n #### STDOUT ####\n %s\n #### STDERR ####\n %s\n #### End of STDOUT/STDERR ####\n " % (std_out ,std_err ))
413-
443+
414444 if test_example :
415445 log = example ['compare_log' ].pop (0 )
416446 # example['compare_log'] is a list of log file/files, which matches each examples/sub-examples from same repo.
417447 # pop the log file out of list regardless the compilation for each example pass of fail
418448 image = fetch_output_image (std_out )
419449 if image :
420450 image_info = [{"binary_type" : "bootable" ,"path" : normpath (join (name ,image )),"compare_log" :log }]
451+ if post_checks :
452+ try :
453+ _perform_post_build_checks (
454+ name , post_checks , dirname (image )
455+ )
456+ except PostBuildCheckFailureError as error :
457+ failures .append (str (error ))
421458 else :
422459 print ("Warning: could not find built image for example %s" % name )
423-
460+
424461 example_summary = "{} {} {}" .format (name , target , toolchain )
425462 if proc .returncode :
426463 failures .append (example_summary )
@@ -494,4 +531,81 @@ def fetch_output_image(output):
494531 image = lines [index ][7 :]
495532 if os .path .isfile (image ):
496533 return image
497- return False
534+ return False
535+
536+
537+ def _perform_post_build_checks (example_name , checks , elf_dir_path ):
538+ """
539+ Perform post build checks.
540+
541+ The function raises a PostBuildCheckFailureError exceptions if an error is
542+ encountered.
543+ """
544+ if not checks :
545+ raise PostBuildCheckFailureError ("No post build check specified" )
546+
547+ # Find the elf file
548+ elf_file = None
549+ for dirpath , _ , filenames in os .walk (elf_dir_path ):
550+ for filename in filenames :
551+ if filename .endswith (".elf" ):
552+ elf_file = os .path .join (dirpath , filename )
553+
554+ if not elf_file :
555+ raise PostBuildCheckFailureError (
556+ "Cannot find ELF file in {}" .format (elf_dir_path )
557+ )
558+
559+ for check in set (checks ):
560+ SUPPORTED_POST_BUILD_CHECKS [check ](example_name , elf_file )
561+
562+
563+ def _set_minimal_printf_floats_status (status ):
564+ """
565+ Enable or disable floating point support in minimal-printf.
566+
567+ Pass the string `true` or `false` to enable or disable floating point.
568+ """
569+ with open (
570+ os .path .join (ROOT , "platform" , "mbed_lib.json" ), "r"
571+ ) as platform_lib_file :
572+ data = json .load (platform_lib_file )
573+
574+ data ["config" ]["minimal-printf-enable-floating-point" ]["value" ] = status
575+
576+ with open (
577+ os .path .join (ROOT , "platform" , "mbed_lib.json" ), "w"
578+ ) as platform_lib_file :
579+ json .dump (data , platform_lib_file , indent = 4 )
580+
581+
582+ # Post-build check functions should be listed below and must raise a
583+ # a PostBuildCheckFailureError in case of failure
584+
585+ def _post_build_check_floating_point (example_name , elf_file ):
586+ """Check if there are floating points in the executable."""
587+
588+ if example_name in POST_BUILD_CHECK_FLOATS_EXCLUDED_EXAMPLES :
589+ return
590+
591+ float_symbols = elf_float_checker .check_float_symbols (elf_file )
592+
593+ if float_symbols :
594+ raise PostBuildCheckFailureError (
595+ "Floating point symbols found in executable: {}" .format (
596+ float_symbols
597+ )
598+ )
599+
600+ # Specify the example project that should not be checked for floating point because they will always fail
601+ POST_BUILD_CHECK_FLOATS_EXCLUDED_EXAMPLES = [
602+ "mbed-os-example-lorawan" , # The LoRaWAN is not actively worked on and we are consideing dropping LoRaWAN example from Mbed OS examples.
603+ "nanostack-border-router" , # nanostack-border-router example depends on ST changes to stm-spirit1-rf-driver library.
604+ ]
605+ POST_BUILD_CHECK_FLOATS = "FLOATS"
606+ SUPPORTED_POST_BUILD_CHECKS = {
607+ POST_BUILD_CHECK_FLOATS : _post_build_check_floating_point
608+ }
609+
610+ class PostBuildCheckFailureError (Exception ):
611+ """An exception to indicate that a post build check failed."""
0 commit comments