Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: MAX44000 PWM_Tone_Library nexpaq_mdk
Fork of LED_Demo by
build_api.py
00001 """ 00002 mbed SDK 00003 Copyright (c) 2011-2016 ARM Limited 00004 00005 Licensed under the Apache License, Version 2.0 (the "License"); 00006 you may not use this file except in compliance with the License. 00007 You may obtain a copy of the License at 00008 00009 http://www.apache.org/licenses/LICENSE-2.0 00010 00011 Unless required by applicable law or agreed to in writing, software 00012 distributed under the License is distributed on an "AS IS" BASIS, 00013 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00014 See the License for the specific language governing permissions and 00015 limitations under the License. 00016 """ 00017 00018 import re 00019 import tempfile 00020 from types import ListType 00021 from shutil import rmtree 00022 from os.path import join, exists, basename, abspath, normpath 00023 from os import linesep, remove 00024 from time import time 00025 00026 from tools.utils import mkdir, run_cmd, run_cmd_ext, NotSupportedException,\ 00027 ToolException, InvalidReleaseTargetException 00028 from tools.paths import MBED_TARGETS_PATH, MBED_LIBRARIES, MBED_API, MBED_HAL,\ 00029 MBED_COMMON, MBED_CONFIG_FILE 00030 from tools.targets import TARGET_NAMES, TARGET_MAP 00031 from tools.libraries import Library 00032 from tools.toolchains import TOOLCHAIN_CLASSES 00033 from jinja2 import FileSystemLoader 00034 from jinja2.environment import Environment 00035 from tools.config import Config 00036 00037 RELEASE_VERSIONS = ['2', '5'] 00038 00039 def prep_report (report, target_name, toolchain_name, id_name): 00040 """Setup report keys 00041 00042 Positional arguments: 00043 report - the report to fill 00044 target_name - the target being used 00045 toolchain_name - the toolchain being used 00046 id_name - the name of the executable or library being built 00047 """ 00048 if not target_name in report: 00049 report[target_name] = {} 00050 00051 if not toolchain_name in report[target_name]: 00052 report[target_name][toolchain_name] = {} 00053 00054 if not id_name in report[target_name][toolchain_name]: 00055 report[target_name][toolchain_name][id_name] = [] 00056 00057 def prep_properties (properties, target_name, toolchain_name, vendor_label): 00058 """Setup test properties 00059 00060 Positional arguments: 00061 properties - the dict to fill 00062 target_name - the target the test is targeting 00063 toolchain_name - the toolchain that will compile the test 00064 vendor_label - the vendor 00065 """ 00066 if not target_name in properties: 00067 properties[target_name] = {} 00068 00069 if not toolchain_name in properties[target_name]: 00070 properties[target_name][toolchain_name] = {} 00071 00072 properties[target_name][toolchain_name]["target"] = target_name 00073 properties[target_name][toolchain_name]["vendor"] = vendor_label 00074 properties[target_name][toolchain_name]["toolchain"] = toolchain_name 00075 00076 def create_result (target_name, toolchain_name, id_name, description): 00077 """Create a result dictionary 00078 00079 Positional arguments: 00080 target_name - the target being built for 00081 toolchain_name - the toolchain doing the building 00082 id_name - the name of the executable or library being built 00083 description - a human readable description of what's going on 00084 """ 00085 cur_result = {} 00086 cur_result["target_name"] = target_name 00087 cur_result["toolchain_name"] = toolchain_name 00088 cur_result["id"] = id_name 00089 cur_result["description"] = description 00090 cur_result["elapsed_time"] = 0 00091 cur_result["output"] = "" 00092 00093 return cur_result 00094 00095 def add_result_to_report (report, result): 00096 """Add a single result to a report dictionary 00097 00098 Positional arguments: 00099 report - the report to append to 00100 result - the result to append 00101 """ 00102 target = result["target_name"] 00103 toolchain = result["toolchain_name"] 00104 id_name = result['id'] 00105 result_wrap = {0: result} 00106 report[target][toolchain][id_name].append(result_wrap) 00107 00108 def get_config (src_paths, target, toolchain_name): 00109 """Get the configuration object for a target-toolchain combination 00110 00111 Positional arguments: 00112 src_paths - paths to scan for the configuration files 00113 target - the device we are building for 00114 toolchain_name - the string that identifies the build tools 00115 """ 00116 # Convert src_paths to a list if needed 00117 if type(src_paths) != ListType: 00118 src_paths = [src_paths] 00119 00120 # Pass all params to the unified prepare_resources() 00121 toolchain = prepare_toolchain(src_paths, target, toolchain_name) 00122 00123 # Scan src_path for config files 00124 resources = toolchain.scan_resources(src_paths[0]) 00125 for path in src_paths[1:]: 00126 resources.add(toolchain.scan_resources(path)) 00127 00128 # Update configuration files until added features creates no changes 00129 prev_features = set() 00130 while True: 00131 # Update the configuration with any .json files found while scanning 00132 toolchain.config.add_config_files(resources.json_files) 00133 00134 # Add features while we find new ones 00135 features = toolchain.config.get_features() 00136 if features == prev_features: 00137 break 00138 00139 for feature in features: 00140 if feature in resources.features: 00141 resources += resources.features[feature] 00142 00143 prev_features = features 00144 toolchain.config.validate_config() 00145 00146 cfg, macros = toolchain.config.get_config_data() 00147 features = toolchain.config.get_features() 00148 return cfg, macros, features 00149 00150 def is_official_target (target_name, version): 00151 """ Returns True, None if a target is part of the official release for the 00152 given version. Return False, 'reason' if a target is not part of the 00153 official release for the given version. 00154 00155 Positional arguments: 00156 target_name - Name if the target (ex. 'K64F') 00157 version - The release version string. Should be a string contained within 00158 RELEASE_VERSIONS 00159 """ 00160 00161 result = True 00162 reason = None 00163 target = TARGET_MAP[target_name] 00164 00165 if hasattr(target, 'release_versions') \ 00166 and version in target.release_versions: 00167 if version == '2': 00168 # For version 2, either ARM or uARM toolchain support is required 00169 required_toolchains = set(['ARM', 'uARM']) 00170 00171 if not len(required_toolchains.intersection( 00172 set(target.supported_toolchains))) > 0: 00173 result = False 00174 reason = ("Target '%s' must support " % target.name) + \ 00175 ("one of the folowing toolchains to be included in the") + \ 00176 ((" mbed 2.0 official release: %s" + linesep) % 00177 ", ".join(required_toolchains)) + \ 00178 ("Currently it is only configured to support the ") + \ 00179 ("following toolchains: %s" % 00180 ", ".join(target.supported_toolchains)) 00181 00182 elif version == '5': 00183 # For version 5, ARM, GCC_ARM, and IAR toolchain support is required 00184 required_toolchains = set(['ARM', 'GCC_ARM', 'IAR']) 00185 required_toolchains_sorted = list(required_toolchains) 00186 required_toolchains_sorted.sort() 00187 supported_toolchains = set(target.supported_toolchains) 00188 supported_toolchains_sorted = list(supported_toolchains) 00189 supported_toolchains_sorted.sort() 00190 00191 if not required_toolchains.issubset(supported_toolchains): 00192 result = False 00193 reason = ("Target '%s' must support " % target.name) + \ 00194 ("ALL of the folowing toolchains to be included in the") + \ 00195 ((" mbed OS 5.0 official release: %s" + linesep) % 00196 ", ".join(required_toolchains_sorted)) + \ 00197 ("Currently it is only configured to support the ") + \ 00198 ("following toolchains: %s" % 00199 ", ".join(supported_toolchains_sorted)) 00200 00201 elif not target.default_lib == 'std': 00202 result = False 00203 reason = ("Target '%s' must set the " % target.name) + \ 00204 ("'default_lib' to 'std' to be included in the ") + \ 00205 ("mbed OS 5.0 official release." + linesep) + \ 00206 ("Currently it is set to '%s'" % target.default_lib) 00207 00208 else: 00209 result = False 00210 reason = ("Target '%s' has set an invalid release version of '%s'" % 00211 version) + \ 00212 ("Please choose from the following release versions: %s" % 00213 ', '.join(RELEASE_VERSIONS)) 00214 00215 else: 00216 result = False 00217 if not hasattr(target, 'release_versions'): 00218 reason = "Target '%s' " % target.name 00219 reason += "does not have the 'release_versions' key set" 00220 elif not version in target.release_versions: 00221 reason = "Target '%s' does not contain the version '%s' " % \ 00222 (target.name, version) 00223 reason += "in its 'release_versions' key" 00224 00225 return result, reason 00226 00227 def transform_release_toolchains (toolchains, version): 00228 """ Given a list of toolchains and a release version, return a list of 00229 only the supported toolchains for that release 00230 00231 Positional arguments: 00232 toolchains - The list of toolchains 00233 version - The release version string. Should be a string contained within 00234 RELEASE_VERSIONS 00235 """ 00236 if version == '5': 00237 return ['ARM', 'GCC_ARM', 'IAR'] 00238 else: 00239 return toolchains 00240 00241 00242 def get_mbed_official_release (version): 00243 """ Given a release version string, return a tuple that contains a target 00244 and the supported toolchains for that release. 00245 Ex. Given '2', return (('LPC1768', ('ARM', 'GCC_ARM')), 00246 ('K64F', ('ARM', 'GCC_ARM')), ...) 00247 00248 Positional arguments: 00249 version - The version string. Should be a string contained within 00250 RELEASE_VERSIONS 00251 """ 00252 00253 mbed_official_release = ( 00254 tuple( 00255 tuple( 00256 [ 00257 TARGET_MAP[target].name, 00258 tuple(transform_release_toolchains( 00259 TARGET_MAP[target].supported_toolchains, version)) 00260 ] 00261 ) for target in TARGET_NAMES \ 00262 if (hasattr(TARGET_MAP[target], 'release_versions') 00263 and version in TARGET_MAP[target].release_versions) 00264 ) 00265 ) 00266 00267 for target in mbed_official_release: 00268 is_official, reason = is_official_target(target[0], version) 00269 00270 if not is_official: 00271 raise InvalidReleaseTargetException(reason) 00272 00273 return mbed_official_release 00274 00275 00276 def prepare_toolchain (src_paths, target, toolchain_name, 00277 macros=None, options=None, clean=False, jobs=1, 00278 notify=None, silent=False, verbose=False, 00279 extra_verbose=False, config=None, 00280 app_config=None): 00281 """ Prepares resource related objects - toolchain, target, config 00282 00283 Positional arguments: 00284 src_paths - the paths to source directories 00285 target - ['LPC1768', 'LPC11U24', 'LPC2368', etc.] 00286 toolchain_name - ['ARM', 'uARM', 'GCC_ARM', 'GCC_CR'] 00287 00288 Keyword arguments: 00289 macros - additional macros 00290 options - general compiler options like debug-symbols or small-build 00291 clean - Rebuild everything if True 00292 jobs - how many compilers we can run at once 00293 notify - Notify function for logs 00294 silent - suppress printing of progress indicators 00295 verbose - Write the actual tools command lines used if True 00296 extra_verbose - even more output! 00297 config - a Config object to use instead of creating one 00298 app_config - location of a chosen mbed_app.json file 00299 """ 00300 00301 # We need to remove all paths which are repeated to avoid 00302 # multiple compilations and linking with the same objects 00303 src_paths = [src_paths[0]] + list(set(src_paths[1:])) 00304 00305 # If the configuration object was not yet created, create it now 00306 config = config or Config(target, src_paths, app_config=app_config) 00307 00308 # If the 'target' argument is a string, convert it to a target instance 00309 if isinstance(target, basestring): 00310 try: 00311 target = TARGET_MAP[target] 00312 except KeyError: 00313 raise KeyError("Target '%s' not found" % target) 00314 00315 # Toolchain instance 00316 try: 00317 toolchain = TOOLCHAIN_CLASSES[toolchain_name]( 00318 target, options, notify, macros, silent, 00319 extra_verbose=extra_verbose) 00320 except KeyError: 00321 raise KeyError("Toolchain %s not supported" % toolchain_name) 00322 00323 toolchain.config = config 00324 toolchain.jobs = jobs 00325 toolchain.build_all = clean 00326 toolchain.VERBOSE = verbose 00327 00328 return toolchain 00329 00330 def scan_resources (src_paths, toolchain, dependencies_paths=None, 00331 inc_dirs=None, base_path=None): 00332 """ Scan resources using initialized toolcain 00333 00334 Positional arguments 00335 src_paths - the paths to source directories 00336 toolchain - valid toolchain object 00337 dependencies_paths - dependency paths that we should scan for include dirs 00338 inc_dirs - additional include directories which should be added to 00339 the scanner resources 00340 """ 00341 00342 # Scan src_path 00343 resources = toolchain.scan_resources(src_paths[0], base_path=base_path) 00344 for path in src_paths[1:]: 00345 resources.add(toolchain.scan_resources(path, base_path=base_path)) 00346 00347 # Scan dependency paths for include dirs 00348 if dependencies_paths is not None: 00349 for path in dependencies_paths: 00350 lib_resources = toolchain.scan_resources(path) 00351 resources.inc_dirs.extend(lib_resources.inc_dirs) 00352 00353 # Add additional include directories if passed 00354 if inc_dirs: 00355 if type(inc_dirs) == ListType: 00356 resources.inc_dirs.extend(inc_dirs) 00357 else: 00358 resources.inc_dirs.append(inc_dirs) 00359 00360 # Load resources into the config system which might expand/modify resources 00361 # based on config data 00362 resources = toolchain.config.load_resources(resources) 00363 00364 # Set the toolchain's configuration data 00365 toolchain.set_config_data(toolchain.config.get_config_data()) 00366 00367 return resources 00368 00369 def build_project (src_paths, build_path, target, toolchain_name, 00370 libraries_paths=None, options=None, linker_script=None, 00371 clean=False, notify=None, verbose=False, name=None, 00372 macros=None, inc_dirs=None, jobs=1, silent=False, 00373 report=None, properties=None, project_id=None, 00374 project_description=None, extra_verbose=False, config=None, 00375 app_config=None): 00376 """ Build a project. A project may be a test or a user program. 00377 00378 Positional arguments: 00379 src_paths - a path or list of paths that contain all files needed to build 00380 the project 00381 build_path - the directory where all of the object files will be placed 00382 target - the MCU or board that the project will compile for 00383 toolchain_name - the name of the build tools 00384 00385 Keyword arguments: 00386 libraries_paths - The location of libraries to include when linking 00387 options - general compiler options like debug-symbols or small-build 00388 linker_script - the file that drives the linker to do it's job 00389 clean - Rebuild everything if True 00390 notify - Notify function for logs 00391 verbose - Write the actual tools command lines used if True 00392 name - the name of the project 00393 macros - additional macros 00394 inc_dirs - additional directories where include files may be found 00395 jobs - how many compilers we can run at once 00396 silent - suppress printing of progress indicators 00397 report - a dict where a result may be appended 00398 properties - UUUUHHHHH beats me 00399 project_id - the name put in the report 00400 project_description - the human-readable version of what this thing does 00401 extra_verbose - even more output! 00402 config - a Config object to use instead of creating one 00403 app_config - location of a chosen mbed_app.json file 00404 """ 00405 00406 # Convert src_path to a list if needed 00407 if type(src_paths) != ListType: 00408 src_paths = [src_paths] 00409 # Extend src_paths wiht libraries_paths 00410 if libraries_paths is not None: 00411 src_paths.extend(libraries_paths) 00412 00413 # Build Directory 00414 if clean and exists(build_path): 00415 rmtree(build_path) 00416 mkdir(build_path) 00417 00418 # Pass all params to the unified prepare_toolchain() 00419 toolchain = prepare_toolchain( 00420 src_paths, target, toolchain_name, macros=macros, options=options, 00421 clean=clean, jobs=jobs, notify=notify, silent=silent, verbose=verbose, 00422 extra_verbose=extra_verbose, config=config, app_config=app_config) 00423 00424 # The first path will give the name to the library 00425 if name is None: 00426 name = basename(normpath(abspath(src_paths[0]))) 00427 toolchain.info("Building project %s (%s, %s)" % 00428 (name, toolchain.target.name, toolchain_name)) 00429 00430 # Initialize reporting 00431 if report != None: 00432 start = time() 00433 # If project_id is specified, use that over the default name 00434 id_name = project_id.upper() if project_id else name.upper() 00435 description = project_description if project_description else name 00436 vendor_label = toolchain.target.extra_labels[0] 00437 prep_report(report, toolchain.target.name, toolchain_name, id_name) 00438 cur_result = create_result(toolchain.target.name, toolchain_name, 00439 id_name, description) 00440 if properties != None: 00441 prep_properties(properties, toolchain.target.name, toolchain_name, 00442 vendor_label) 00443 00444 try: 00445 # Call unified scan_resources 00446 resources = scan_resources(src_paths, toolchain, inc_dirs=inc_dirs) 00447 00448 # Change linker script if specified 00449 if linker_script is not None: 00450 resources.linker_script = linker_script 00451 00452 # Compile Sources 00453 objects = toolchain.compile_sources(resources, build_path, 00454 resources.inc_dirs) 00455 resources.objects.extend(objects) 00456 00457 # Link Program 00458 res, _ = toolchain.link_program(resources, build_path, name) 00459 00460 if report != None: 00461 end = time() 00462 cur_result["elapsed_time"] = end - start 00463 cur_result["output"] = toolchain.get_output() 00464 cur_result["result"] = "OK" 00465 cur_result["memory_usage"] = toolchain.map_outputs 00466 00467 add_result_to_report(report, cur_result) 00468 00469 return res 00470 00471 except Exception as exc: 00472 if report != None: 00473 end = time() 00474 00475 if isinstance(exc, NotSupportedException): 00476 cur_result["result"] = "NOT_SUPPORTED" 00477 else: 00478 cur_result["result"] = "FAIL" 00479 00480 cur_result["elapsed_time"] = end - start 00481 00482 toolchain_output = toolchain.get_output() 00483 if toolchain_output: 00484 cur_result["output"] += toolchain_output 00485 00486 add_result_to_report(report, cur_result) 00487 00488 # Let Exception propagate 00489 raise 00490 00491 def build_library (src_paths, build_path, target, toolchain_name, 00492 dependencies_paths=None, options=None, name=None, clean=False, 00493 archive=True, notify=None, verbose=False, macros=None, 00494 inc_dirs=None, jobs=1, silent=False, report=None, 00495 properties=None, extra_verbose=False, project_id=None, 00496 remove_config_header_file=False, app_config=None): 00497 """ Build a library 00498 00499 Positional arguments: 00500 src_paths - a path or list of paths that contain all files needed to build 00501 the library 00502 build_path - the directory where all of the object files will be placed 00503 target - the MCU or board that the project will compile for 00504 toolchain_name - the name of the build tools 00505 00506 Keyword arguments: 00507 dependencies_paths - The location of libraries to include when linking 00508 options - general compiler options like debug-symbols or small-build 00509 name - the name of the library 00510 clean - Rebuild everything if True 00511 archive - whether the library will create an archive file 00512 notify - Notify function for logs 00513 verbose - Write the actual tools command lines used if True 00514 macros - additional macros 00515 inc_dirs - additional directories where include files may be found 00516 jobs - how many compilers we can run at once 00517 silent - suppress printing of progress indicators 00518 report - a dict where a result may be appended 00519 properties - UUUUHHHHH beats me 00520 extra_verbose - even more output! 00521 project_id - the name that goes in the report 00522 remove_config_header_file - delete config header file when done building 00523 app_config - location of a chosen mbed_app.json file 00524 """ 00525 00526 # Convert src_path to a list if needed 00527 if type(src_paths) != ListType: 00528 src_paths = [src_paths] 00529 00530 # Build path 00531 if archive: 00532 # Use temp path when building archive 00533 tmp_path = join(build_path, '.temp') 00534 mkdir(tmp_path) 00535 else: 00536 tmp_path = build_path 00537 00538 # Clean the build directory 00539 if clean and exists(tmp_path): 00540 rmtree(tmp_path) 00541 mkdir(tmp_path) 00542 00543 # Pass all params to the unified prepare_toolchain() 00544 toolchain = prepare_toolchain( 00545 src_paths, target, toolchain_name, macros=macros, options=options, 00546 clean=clean, jobs=jobs, notify=notify, silent=silent, verbose=verbose, 00547 extra_verbose=extra_verbose, app_config=app_config) 00548 00549 # The first path will give the name to the library 00550 if name is None: 00551 name = basename(normpath(abspath(src_paths[0]))) 00552 toolchain.info("Building library %s (%s, %s)" % 00553 (name, toolchain.target.name, toolchain_name)) 00554 00555 # Initialize reporting 00556 if report != None: 00557 start = time() 00558 # If project_id is specified, use that over the default name 00559 id_name = project_id.upper() if project_id else name.upper() 00560 description = name 00561 vendor_label = toolchain.target.extra_labels[0] 00562 prep_report(report, toolchain.target.name, toolchain_name, id_name) 00563 cur_result = create_result(toolchain.target.name, toolchain_name, 00564 id_name, description) 00565 if properties != None: 00566 prep_properties(properties, toolchain.target.name, toolchain_name, 00567 vendor_label) 00568 00569 for src_path in src_paths: 00570 if not exists(src_path): 00571 error_msg = "The library source folder does not exist: %s", src_path 00572 if report != None: 00573 cur_result["output"] = error_msg 00574 cur_result["result"] = "FAIL" 00575 add_result_to_report(report, cur_result) 00576 raise Exception(error_msg) 00577 00578 try: 00579 # Call unified scan_resources 00580 resources = scan_resources(src_paths, toolchain, 00581 dependencies_paths=dependencies_paths, 00582 inc_dirs=inc_dirs) 00583 00584 00585 # Copy headers, objects and static libraries - all files needed for 00586 # static lib 00587 toolchain.copy_files(resources.headers, build_path, resources=resources) 00588 toolchain.copy_files(resources.objects, build_path, resources=resources) 00589 toolchain.copy_files(resources.libraries, build_path, 00590 resources=resources) 00591 toolchain.copy_files(resources.json_files, build_path, 00592 resources=resources) 00593 if resources.linker_script: 00594 toolchain.copy_files(resources.linker_script, build_path, 00595 resources=resources) 00596 00597 if resources.hex_files: 00598 toolchain.copy_files(resources.hex_files, build_path, 00599 resources=resources) 00600 00601 # Compile Sources 00602 objects = toolchain.compile_sources(resources, abspath(tmp_path), 00603 resources.inc_dirs) 00604 resources.objects.extend(objects) 00605 00606 if archive: 00607 toolchain.build_library(objects, build_path, name) 00608 00609 if remove_config_header_file: 00610 config_header_path = toolchain.get_config_header() 00611 if config_header_path: 00612 remove(config_header_path) 00613 00614 if report != None: 00615 end = time() 00616 cur_result["elapsed_time"] = end - start 00617 cur_result["output"] = toolchain.get_output() 00618 cur_result["result"] = "OK" 00619 00620 00621 add_result_to_report(report, cur_result) 00622 return True 00623 00624 except Exception as exc: 00625 if report != None: 00626 end = time() 00627 00628 if isinstance(exc, ToolException): 00629 cur_result["result"] = "FAIL" 00630 elif isinstance(exc, NotSupportedException): 00631 cur_result["result"] = "NOT_SUPPORTED" 00632 00633 cur_result["elapsed_time"] = end - start 00634 00635 toolchain_output = toolchain.get_output() 00636 if toolchain_output: 00637 cur_result["output"] += toolchain_output 00638 00639 add_result_to_report(report, cur_result) 00640 00641 # Let Exception propagate 00642 raise 00643 00644 ###################### 00645 ### Legacy methods ### 00646 ###################### 00647 00648 def build_lib(lib_id, target, toolchain_name, options=None, verbose=False, 00649 clean=False, macros=None, notify=None, jobs=1, silent=False, 00650 report=None, properties=None, extra_verbose=False): 00651 """ Legacy method for building mbed libraries 00652 00653 Positional arguments: 00654 lib_id - the library's unique identifier 00655 target - the MCU or board that the project will compile for 00656 toolchain_name - the name of the build tools 00657 00658 Keyword arguments: 00659 options - general compiler options like debug-symbols or small-build 00660 clean - Rebuild everything if True 00661 verbose - Write the actual tools command lines used if True 00662 macros - additional macros 00663 notify - Notify function for logs 00664 jobs - how many compilers we can run at once 00665 silent - suppress printing of progress indicators 00666 report - a dict where a result may be appended 00667 properties - UUUUHHHHH beats me 00668 extra_verbose - even more output! 00669 """ 00670 lib = Library(lib_id) 00671 if not lib.is_supported(target, toolchain_name): 00672 print('Library "%s" is not yet supported on target %s with toolchain %s' 00673 % (lib_id, target.name, toolchain_name)) 00674 return False 00675 00676 # We need to combine macros from parameter list with macros from library 00677 # definition 00678 lib_macros = lib.macros if lib.macros else [] 00679 if macros: 00680 macros.extend(lib_macros) 00681 else: 00682 macros = lib_macros 00683 00684 src_paths = lib.source_dir 00685 build_path = lib.build_dir 00686 dependencies_paths = lib.dependencies 00687 inc_dirs = lib.inc_dirs 00688 inc_dirs_ext = lib.inc_dirs_ext 00689 00690 if type(src_paths) != ListType: 00691 src_paths = [src_paths] 00692 00693 # The first path will give the name to the library 00694 name = basename(src_paths[0]) 00695 00696 if report != None: 00697 start = time() 00698 id_name = name.upper() 00699 description = name 00700 vendor_label = target.extra_labels[0] 00701 cur_result = None 00702 prep_report(report, target.name, toolchain_name, id_name) 00703 cur_result = create_result(target.name, toolchain_name, id_name, 00704 description) 00705 00706 if properties != None: 00707 prep_properties(properties, target.name, toolchain_name, 00708 vendor_label) 00709 00710 for src_path in src_paths: 00711 if not exists(src_path): 00712 error_msg = "The library source folder does not exist: %s", src_path 00713 00714 if report != None: 00715 cur_result["output"] = error_msg 00716 cur_result["result"] = "FAIL" 00717 add_result_to_report(report, cur_result) 00718 00719 raise Exception(error_msg) 00720 00721 try: 00722 # Toolchain instance 00723 toolchain = TOOLCHAIN_CLASSES[toolchain_name]( 00724 target, options, macros=macros, notify=notify, silent=silent, 00725 extra_verbose=extra_verbose) 00726 toolchain.VERBOSE = verbose 00727 toolchain.jobs = jobs 00728 toolchain.build_all = clean 00729 00730 toolchain.info("Building library %s (%s, %s)" % 00731 (name.upper(), target.name, toolchain_name)) 00732 00733 # Take into account the library configuration (MBED_CONFIG_FILE) 00734 config = Config(target) 00735 toolchain.config = config 00736 config.add_config_files([MBED_CONFIG_FILE]) 00737 00738 # Scan Resources 00739 resources = [] 00740 for src_path in src_paths: 00741 resources.append(toolchain.scan_resources(src_path)) 00742 00743 # Add extra include directories / files which are required by library 00744 # This files usually are not in the same directory as source files so 00745 # previous scan will not include them 00746 if inc_dirs_ext is not None: 00747 for inc_ext in inc_dirs_ext: 00748 resources.append(toolchain.scan_resources(inc_ext)) 00749 00750 # Dependencies Include Paths 00751 dependencies_include_dir = [] 00752 if dependencies_paths is not None: 00753 for path in dependencies_paths: 00754 lib_resources = toolchain.scan_resources(path) 00755 dependencies_include_dir.extend(lib_resources.inc_dirs) 00756 00757 if inc_dirs: 00758 dependencies_include_dir.extend(inc_dirs) 00759 00760 # Add other discovered configuration data to the configuration object 00761 for res in resources: 00762 config.load_resources(res) 00763 toolchain.set_config_data(toolchain.config.get_config_data()) 00764 00765 # Create the desired build directory structure 00766 bin_path = join(build_path, toolchain.obj_path) 00767 mkdir(bin_path) 00768 tmp_path = join(build_path, '.temp', toolchain.obj_path) 00769 mkdir(tmp_path) 00770 00771 # Copy Headers 00772 for resource in resources: 00773 toolchain.copy_files(resource.headers, build_path, 00774 resources=resource) 00775 00776 dependencies_include_dir.extend( 00777 toolchain.scan_resources(build_path).inc_dirs) 00778 00779 # Compile Sources 00780 objects = [] 00781 for resource in resources: 00782 objects.extend(toolchain.compile_sources(resource, tmp_path, 00783 dependencies_include_dir)) 00784 00785 needed_update = toolchain.build_library(objects, bin_path, name) 00786 00787 if report != None and needed_update: 00788 end = time() 00789 cur_result["elapsed_time"] = end - start 00790 cur_result["output"] = toolchain.get_output() 00791 cur_result["result"] = "OK" 00792 00793 add_result_to_report(report, cur_result) 00794 return True 00795 00796 except Exception: 00797 if report != None: 00798 end = time() 00799 cur_result["result"] = "FAIL" 00800 cur_result["elapsed_time"] = end - start 00801 00802 toolchain_output = toolchain.get_output() 00803 if toolchain_output: 00804 cur_result["output"] += toolchain_output 00805 00806 add_result_to_report(report, cur_result) 00807 00808 # Let Exception propagate 00809 raise 00810 00811 # We do have unique legacy conventions about how we build and package the mbed 00812 # library 00813 def build_mbed_libs (target, toolchain_name, options=None, verbose=False, 00814 clean=False, macros=None, notify=None, jobs=1, silent=False, 00815 report=None, properties=None, extra_verbose=False): 00816 """ Function returns True is library was built and false if building was 00817 skipped 00818 00819 Positional arguments: 00820 target - the MCU or board that the project will compile for 00821 toolchain_name - the name of the build tools 00822 00823 Keyword arguments: 00824 options - general compiler options like debug-symbols or small-build 00825 verbose - Write the actual tools command lines used if True 00826 clean - Rebuild everything if True 00827 macros - additional macros 00828 notify - Notify function for logs 00829 jobs - how many compilers we can run at once 00830 silent - suppress printing of progress indicators 00831 report - a dict where a result may be appended 00832 properties - UUUUHHHHH beats me 00833 extra_verbose - even more output! 00834 """ 00835 00836 if report != None: 00837 start = time() 00838 id_name = "MBED" 00839 description = "mbed SDK" 00840 vendor_label = target.extra_labels[0] 00841 cur_result = None 00842 prep_report(report, target.name, toolchain_name, id_name) 00843 cur_result = create_result(target.name, toolchain_name, id_name, 00844 description) 00845 00846 if properties != None: 00847 prep_properties(properties, target.name, toolchain_name, 00848 vendor_label) 00849 00850 # Check toolchain support 00851 if toolchain_name not in target.supported_toolchains: 00852 supported_toolchains_text = ", ".join(target.supported_toolchains) 00853 print('%s target is not yet supported by toolchain %s' % 00854 (target.name, toolchain_name)) 00855 print('%s target supports %s toolchain%s' % 00856 (target.name, supported_toolchains_text, 's' 00857 if len(target.supported_toolchains) > 1 else '')) 00858 00859 if report != None: 00860 cur_result["result"] = "SKIP" 00861 add_result_to_report(report, cur_result) 00862 00863 return False 00864 00865 try: 00866 # Toolchain 00867 toolchain = TOOLCHAIN_CLASSES[toolchain_name]( 00868 target, options, macros=macros, notify=notify, silent=silent, 00869 extra_verbose=extra_verbose) 00870 toolchain.VERBOSE = verbose 00871 toolchain.jobs = jobs 00872 toolchain.build_all = clean 00873 00874 # Take into account the library configuration (MBED_CONFIG_FILE) 00875 config = Config(target) 00876 toolchain.config = config 00877 config.add_config_files([MBED_CONFIG_FILE]) 00878 toolchain.set_config_data(toolchain.config.get_config_data()) 00879 00880 # Source and Build Paths 00881 build_target = join(MBED_LIBRARIES, "TARGET_" + target.name) 00882 build_toolchain = join(build_target, "TOOLCHAIN_" + toolchain.name) 00883 mkdir(build_toolchain) 00884 00885 tmp_path = join(MBED_LIBRARIES, '.temp', toolchain.obj_path) 00886 mkdir(tmp_path) 00887 00888 # CMSIS 00889 toolchain.info("Building library %s (%s, %s)" % 00890 ('CMSIS', target.name, toolchain_name)) 00891 cmsis_src = join(MBED_TARGETS_PATH, "cmsis") 00892 resources = toolchain.scan_resources(cmsis_src) 00893 00894 toolchain.copy_files(resources.headers, build_target) 00895 toolchain.copy_files(resources.linker_script, build_toolchain) 00896 toolchain.copy_files(resources.bin_files, build_toolchain) 00897 00898 objects = toolchain.compile_sources(resources, tmp_path) 00899 toolchain.copy_files(objects, build_toolchain) 00900 00901 # mbed 00902 toolchain.info("Building library %s (%s, %s)" % 00903 ('MBED', target.name, toolchain_name)) 00904 00905 # Common Headers 00906 toolchain.copy_files(toolchain.scan_resources(MBED_API).headers, 00907 MBED_LIBRARIES) 00908 toolchain.copy_files(toolchain.scan_resources(MBED_HAL).headers, 00909 MBED_LIBRARIES) 00910 00911 # Target specific sources 00912 hal_src = join(MBED_TARGETS_PATH, "hal") 00913 hal_implementation = toolchain.scan_resources(hal_src) 00914 toolchain.copy_files(hal_implementation.headers + 00915 hal_implementation.hex_files + 00916 hal_implementation.libraries, 00917 build_target, resources=hal_implementation) 00918 incdirs = toolchain.scan_resources(build_target).inc_dirs 00919 objects = toolchain.compile_sources(hal_implementation, tmp_path, 00920 [MBED_LIBRARIES] + incdirs) 00921 00922 # Common Sources 00923 mbed_resources = toolchain.scan_resources(MBED_COMMON) 00924 objects += toolchain.compile_sources(mbed_resources, tmp_path, 00925 [MBED_LIBRARIES] + incdirs) 00926 00927 # A number of compiled files need to be copied as objects as opposed to 00928 # being part of the mbed library, for reasons that have to do with the 00929 # way the linker search for symbols in archives. These are: 00930 # - retarget.o: to make sure that the C standard lib symbols get 00931 # overridden 00932 # - board.o: mbed_die is weak 00933 # - mbed_overrides.o: this contains platform overrides of various 00934 # weak SDK functions 00935 separate_names, separate_objects = ['retarget.o', 'board.o', 00936 'mbed_overrides.o'], [] 00937 00938 for obj in objects: 00939 for name in separate_names: 00940 if obj.endswith(name): 00941 separate_objects.append(obj) 00942 00943 for obj in separate_objects: 00944 objects.remove(obj) 00945 00946 toolchain.build_library(objects, build_toolchain, "mbed") 00947 00948 for obj in separate_objects: 00949 toolchain.copy_files(obj, build_toolchain) 00950 00951 if report != None: 00952 end = time() 00953 cur_result["elapsed_time"] = end - start 00954 cur_result["output"] = toolchain.get_output() 00955 cur_result["result"] = "OK" 00956 00957 add_result_to_report(report, cur_result) 00958 00959 return True 00960 00961 except Exception as exc: 00962 if report != None: 00963 end = time() 00964 cur_result["result"] = "FAIL" 00965 cur_result["elapsed_time"] = end - start 00966 00967 toolchain_output = toolchain.get_output() 00968 if toolchain_output: 00969 cur_result["output"] += toolchain_output 00970 00971 cur_result["output"] += str(exc) 00972 00973 add_result_to_report(report, cur_result) 00974 00975 # Let Exception propagate 00976 raise 00977 00978 00979 def get_unique_supported_toolchains (release_targets=None): 00980 """ Get list of all unique toolchains supported by targets 00981 00982 Keyword arguments: 00983 release_targets - tuple structure returned from get_mbed_official_release(). 00984 If release_targets is not specified, then it queries all 00985 known targets 00986 """ 00987 unique_supported_toolchains = [] 00988 00989 if not release_targets: 00990 for target in TARGET_NAMES: 00991 for toolchain in TARGET_MAP[target].supported_toolchains: 00992 if toolchain not in unique_supported_toolchains: 00993 unique_supported_toolchains.append(toolchain) 00994 else: 00995 for target in release_targets: 00996 for toolchain in target[1]: 00997 if toolchain not in unique_supported_toolchains: 00998 unique_supported_toolchains.append(toolchain) 00999 01000 return unique_supported_toolchains 01001 01002 01003 def mcu_toolchain_matrix (verbose_html=False, platform_filter=None, 01004 release_version='5'): 01005 """ Shows target map using prettytable 01006 01007 Keyword arguments: 01008 verbose_html - emit html instead of a simple table 01009 platform_filter - remove results that match the string 01010 release_version - get the matrix for this major version number 01011 """ 01012 # Only use it in this function so building works without extra modules 01013 from prettytable import PrettyTable 01014 01015 if isinstance(release_version, basestring): 01016 # Force release_version to lowercase if it is a string 01017 release_version = release_version.lower() 01018 else: 01019 # Otherwise default to printing all known targets and toolchains 01020 release_version = 'all' 01021 01022 01023 version_release_targets = {} 01024 version_release_target_names = {} 01025 01026 for version in RELEASE_VERSIONS: 01027 version_release_targets[version] = get_mbed_official_release(version) 01028 version_release_target_names[version] = [x[0] for x in 01029 version_release_targets[ 01030 version]] 01031 01032 if release_version in RELEASE_VERSIONS: 01033 release_targets = version_release_targets[release_version] 01034 else: 01035 release_targets = None 01036 01037 unique_supported_toolchains = get_unique_supported_toolchains( 01038 release_targets) 01039 prepend_columns = ["Target"] + ["mbed OS %s" % x for x in RELEASE_VERSIONS] 01040 01041 # All tests status table print 01042 columns = prepend_columns + unique_supported_toolchains 01043 table_printer = PrettyTable(columns) 01044 # Align table 01045 for col in columns: 01046 table_printer.align[col] = "c" 01047 table_printer.align["Target"] = "l" 01048 01049 perm_counter = 0 01050 target_counter = 0 01051 01052 target_names = [] 01053 01054 if release_targets: 01055 target_names = [x[0] for x in release_targets] 01056 else: 01057 target_names = TARGET_NAMES 01058 01059 for target in sorted(target_names): 01060 if platform_filter is not None: 01061 # FIlter out platforms using regex 01062 if re.search(platform_filter, target) is None: 01063 continue 01064 target_counter += 1 01065 01066 row = [target] # First column is platform name 01067 01068 for version in RELEASE_VERSIONS: 01069 if target in version_release_target_names[version]: 01070 text = "Supported" 01071 else: 01072 text = "-" 01073 row.append(text) 01074 01075 for unique_toolchain in unique_supported_toolchains: 01076 if unique_toolchain in TARGET_MAP[target].supported_toolchains: 01077 text = "Supported" 01078 perm_counter += 1 01079 else: 01080 text = "-" 01081 01082 row.append(text) 01083 table_printer.add_row(row) 01084 01085 result = table_printer.get_html_string() if verbose_html \ 01086 else table_printer.get_string() 01087 result += "\n" 01088 result += "Supported targets: %d\n"% (target_counter) 01089 if target_counter == 1: 01090 result += "Supported toolchains: %d"% (perm_counter) 01091 return result 01092 01093 01094 def get_target_supported_toolchains (target): 01095 """ Returns target supported toolchains list 01096 01097 Positional arguments: 01098 target - the target to get the supported toolchains of 01099 """ 01100 return TARGET_MAP[target].supported_toolchains if target in TARGET_MAP \ 01101 else None 01102 01103 01104 def static_analysis_scan (target, toolchain_name, cppcheck_cmd, 01105 cppcheck_msg_format, options=None, verbose=False, 01106 clean=False, macros=None, notify=None, jobs=1, 01107 extra_verbose=False): 01108 """Perform static analysis on a target and toolchain combination 01109 01110 Positional arguments: 01111 target - the target to fake the build for 01112 toolchain_name - pretend you would compile with this toolchain 01113 cppcheck_cmd - the command used to do static analysis 01114 cppcheck_msg_format - the format of the check messages 01115 01116 Keyword arguments: 01117 options - things like debug-symbols, or small-build, etc. 01118 verbose - more printing! 01119 clean - start from a clean slate 01120 macros - extra macros to compile with 01121 notify - the notification event handling function 01122 jobs - number of commands to run at once 01123 extra_verbose - even moar printing 01124 """ 01125 # Toolchain 01126 toolchain = TOOLCHAIN_CLASSES[toolchain_name](target, options, 01127 macros=macros, notify=notify, 01128 extra_verbose=extra_verbose) 01129 toolchain.VERBOSE = verbose 01130 toolchain.jobs = jobs 01131 toolchain.build_all = clean 01132 01133 # Source and Build Paths 01134 build_target = join(MBED_LIBRARIES, "TARGET_" + target.name) 01135 build_toolchain = join(build_target, "TOOLCHAIN_" + toolchain.name) 01136 mkdir(build_toolchain) 01137 01138 tmp_path = join(MBED_LIBRARIES, '.temp', toolchain.obj_path) 01139 mkdir(tmp_path) 01140 01141 # CMSIS 01142 toolchain.info("Static analysis for %s (%s, %s)" % 01143 ('CMSIS', target.name, toolchain_name)) 01144 cmsis_src = join(MBED_TARGETS_PATH, "cmsis") 01145 resources = toolchain.scan_resources(cmsis_src) 01146 01147 # Copy files before analysis 01148 toolchain.copy_files(resources.headers, build_target) 01149 toolchain.copy_files(resources.linker_script, build_toolchain) 01150 01151 # Gather include paths, c, cpp sources and macros to transfer to cppcheck 01152 # command line 01153 includes = ["-I%s"% i for i in resources.inc_dirs] 01154 includes.append("-I%s"% str(build_target)) 01155 c_sources = " ".join(resources.c_sources) 01156 cpp_sources = " ".join(resources.cpp_sources) 01157 macros = ["-D%s"% s for s in toolchain.get_symbols() + toolchain.macros] 01158 01159 includes = [inc.strip() for inc in includes] 01160 macros = [mac.strip() for mac in macros] 01161 01162 check_cmd = cppcheck_cmd 01163 check_cmd += cppcheck_msg_format 01164 check_cmd += includes 01165 check_cmd += macros 01166 01167 # We need to pass some params via file to avoid "command line too long in 01168 # some OSs" 01169 tmp_file = tempfile.NamedTemporaryFile(delete=False) 01170 tmp_file.writelines(line + '\n' for line in c_sources.split()) 01171 tmp_file.writelines(line + '\n' for line in cpp_sources.split()) 01172 tmp_file.close() 01173 check_cmd += ["--file-list=%s"% tmp_file.name] 01174 01175 _stdout, _stderr, _ = run_cmd(check_cmd) 01176 if verbose: 01177 print _stdout 01178 print _stderr 01179 01180 # ========================================================================= 01181 01182 # MBED 01183 toolchain.info("Static analysis for %s (%s, %s)" % 01184 ('MBED', target.name, toolchain_name)) 01185 01186 # Common Headers 01187 toolchain.copy_files(toolchain.scan_resources(MBED_API).headers, 01188 MBED_LIBRARIES) 01189 toolchain.copy_files(toolchain.scan_resources(MBED_HAL).headers, 01190 MBED_LIBRARIES) 01191 01192 # Target specific sources 01193 hal_src = join(MBED_TARGETS_PATH, "hal") 01194 hal_implementation = toolchain.scan_resources(hal_src) 01195 01196 # Copy files before analysis 01197 toolchain.copy_files(hal_implementation.headers + 01198 hal_implementation.hex_files, build_target, 01199 resources=hal_implementation) 01200 incdirs = toolchain.scan_resources(build_target) 01201 01202 target_includes = ["-I%s" % i for i in incdirs.inc_dirs] 01203 target_includes.append("-I%s"% str(build_target)) 01204 target_includes.append("-I%s"% str(hal_src)) 01205 target_c_sources = " ".join(incdirs.c_sources) 01206 target_cpp_sources = " ".join(incdirs.cpp_sources) 01207 target_macros = ["-D%s"% s for s in 01208 toolchain.get_symbols() + toolchain.macros] 01209 01210 # Common Sources 01211 mbed_resources = toolchain.scan_resources(MBED_COMMON) 01212 01213 # Gather include paths, c, cpp sources and macros to transfer to cppcheck 01214 # command line 01215 mbed_includes = ["-I%s" % i for i in mbed_resources.inc_dirs] 01216 mbed_includes.append("-I%s"% str(build_target)) 01217 mbed_includes.append("-I%s"% str(MBED_COMMON)) 01218 mbed_includes.append("-I%s"% str(MBED_API)) 01219 mbed_includes.append("-I%s"% str(MBED_HAL)) 01220 mbed_c_sources = " ".join(mbed_resources.c_sources) 01221 mbed_cpp_sources = " ".join(mbed_resources.cpp_sources) 01222 01223 target_includes = [inc.strip() for inc in target_includes] 01224 mbed_includes = [inc.strip() for inc in mbed_includes] 01225 target_macros = [mac.strip() for mac in target_macros] 01226 01227 check_cmd = cppcheck_cmd 01228 check_cmd += cppcheck_msg_format 01229 check_cmd += target_includes 01230 check_cmd += mbed_includes 01231 check_cmd += target_macros 01232 01233 # We need to pass some parames via file to avoid "command line too long in 01234 # some OSs" 01235 tmp_file = tempfile.NamedTemporaryFile(delete=False) 01236 tmp_file.writelines(line + '\n' for line in target_c_sources.split()) 01237 tmp_file.writelines(line + '\n' for line in target_cpp_sources.split()) 01238 tmp_file.writelines(line + '\n' for line in mbed_c_sources.split()) 01239 tmp_file.writelines(line + '\n' for line in mbed_cpp_sources.split()) 01240 tmp_file.close() 01241 check_cmd += ["--file-list=%s"% tmp_file.name] 01242 01243 _stdout, _stderr, _ = run_cmd_ext(check_cmd) 01244 if verbose: 01245 print _stdout 01246 print _stderr 01247 01248 01249 def static_analysis_scan_lib (lib_id, target, toolchain, cppcheck_cmd, 01250 cppcheck_msg_format, options=None, verbose=False, 01251 clean=False, macros=None, notify=None, jobs=1, 01252 extra_verbose=False): 01253 """Perform static analysis on a library as if it were to be compiled for a 01254 particular target and toolchain combination 01255 """ 01256 lib = Library(lib_id) 01257 if lib.is_supported(target, toolchain): 01258 static_analysis_scan_library( 01259 lib.source_dir, lib.build_dir, target, toolchain, cppcheck_cmd, 01260 cppcheck_msg_format, lib.dependencies, options, verbose=verbose, 01261 clean=clean, macros=macros, notify=notify, jobs=jobs, 01262 extra_verbose=extra_verbose) 01263 else: 01264 print('Library "%s" is not yet supported on target %s with toolchain %s' 01265 % (lib_id, target.name, toolchain)) 01266 01267 01268 def static_analysis_scan_library (src_paths, build_path, target, toolchain_name, 01269 cppcheck_cmd, cppcheck_msg_format, 01270 dependencies_paths=None, options=None, 01271 name=None, clean=False, notify=None, 01272 verbose=False, macros=None, jobs=1, 01273 extra_verbose=False): 01274 """ Function scans library for statically detectable defects 01275 01276 Positional arguments: 01277 src_paths - the list of library paths to scan 01278 build_path - the location directory of result files 01279 target - the target to fake the build for 01280 toolchain_name - pretend you would compile with this toolchain 01281 cppcheck_cmd - the command used to do static analysis 01282 cppcheck_msg_format - the format of the check messages 01283 01284 Keyword arguments: 01285 dependencies_paths - the paths to sources that this library depends on 01286 options - things like debug-symbols, or small-build, etc. 01287 name - the name of this library 01288 clean - start from a clean slate 01289 notify - the notification event handling function 01290 verbose - more printing! 01291 macros - extra macros to compile with 01292 jobs - number of commands to run at once 01293 extra_verbose - even moar printing 01294 """ 01295 if type(src_paths) != ListType: 01296 src_paths = [src_paths] 01297 01298 for src_path in src_paths: 01299 if not exists(src_path): 01300 raise Exception("The library source folder does not exist: %s", 01301 src_path) 01302 01303 # Toolchain instance 01304 toolchain = TOOLCHAIN_CLASSES[toolchain_name](target, options, 01305 macros=macros, notify=notify, 01306 extra_verbose=extra_verbose) 01307 toolchain.VERBOSE = verbose 01308 toolchain.jobs = jobs 01309 01310 # The first path will give the name to the library 01311 name = basename(src_paths[0]) 01312 toolchain.info("Static analysis for library %s (%s, %s)" % 01313 (name.upper(), target.name, toolchain_name)) 01314 01315 # Scan Resources 01316 resources = [] 01317 for src_path in src_paths: 01318 resources.append(toolchain.scan_resources(src_path)) 01319 01320 # Dependencies Include Paths 01321 dependencies_include_dir = [] 01322 if dependencies_paths is not None: 01323 for path in dependencies_paths: 01324 lib_resources = toolchain.scan_resources(path) 01325 dependencies_include_dir.extend(lib_resources.inc_dirs) 01326 01327 # Create the desired build directory structure 01328 bin_path = join(build_path, toolchain.obj_path) 01329 mkdir(bin_path) 01330 tmp_path = join(build_path, '.temp', toolchain.obj_path) 01331 mkdir(tmp_path) 01332 01333 # Gather include paths, c, cpp sources and macros to transfer to cppcheck 01334 # command line 01335 includes = ["-I%s" % i for i in dependencies_include_dir + src_paths] 01336 c_sources = " " 01337 cpp_sources = " " 01338 macros = ['-D%s' % s for s in toolchain.get_symbols() + toolchain.macros] 01339 01340 # Copy Headers 01341 for resource in resources: 01342 toolchain.copy_files(resource.headers, build_path, resources=resource) 01343 includes += ["-I%s" % i for i in resource.inc_dirs] 01344 c_sources += " ".join(resource.c_sources) + " " 01345 cpp_sources += " ".join(resource.cpp_sources) + " " 01346 01347 dependencies_include_dir.extend( 01348 toolchain.scan_resources(build_path).inc_dirs) 01349 01350 includes = [inc.strip() for inc in includes] 01351 macros = [mac.strip() for mac in macros] 01352 01353 check_cmd = cppcheck_cmd 01354 check_cmd += cppcheck_msg_format 01355 check_cmd += includes 01356 check_cmd += macros 01357 01358 # We need to pass some parameters via file to avoid "command line too long 01359 # in some OSs". A temporary file is created to store e.g. cppcheck list of 01360 # files for command line 01361 tmp_file = tempfile.NamedTemporaryFile(delete=False) 01362 tmp_file.writelines(line + '\n' for line in c_sources.split()) 01363 tmp_file.writelines(line + '\n' for line in cpp_sources.split()) 01364 tmp_file.close() 01365 check_cmd += ["--file-list=%s"% tmp_file.name] 01366 01367 # This will allow us to grab result from both stdio and stderr outputs (so 01368 # we can show them) We assume static code analysis tool is outputting 01369 # defects on STDERR 01370 _stdout, _stderr, _ = run_cmd_ext(check_cmd) 01371 if verbose: 01372 print _stdout 01373 print _stderr 01374 01375 01376 def print_build_results (result_list, build_name): 01377 """ Generate result string for build results 01378 01379 Positional arguments: 01380 result_list - the list of results to print 01381 build_name - the name of the build we are printing result for 01382 """ 01383 result = "" 01384 if len(result_list) > 0: 01385 result += build_name + "\n" 01386 result += "\n".join([" * %s" % f for f in result_list]) 01387 result += "\n" 01388 return result 01389 01390 def print_build_memory_usage (report): 01391 """ Generate result table with memory usage values for build results 01392 Aggregates (puts together) reports obtained from self.get_memory_summary() 01393 01394 Positional arguments: 01395 report - Report generated during build procedure. 01396 """ 01397 from prettytable import PrettyTable 01398 columns_text = ['name', 'target', 'toolchain'] 01399 columns_int = ['static_ram', 'stack', 'heap', 'total_ram', 'total_flash'] 01400 table = PrettyTable(columns_text + columns_int) 01401 01402 for col in columns_text: 01403 table.align[col] = 'l' 01404 01405 for col in columns_int: 01406 table.align[col] = 'r' 01407 01408 for target in report: 01409 for toolchain in report[target]: 01410 for name in report[target][toolchain]: 01411 for dlist in report[target][toolchain][name]: 01412 for dlistelem in dlist: 01413 # Get 'memory_usage' record and build table with 01414 # statistics 01415 record = dlist[dlistelem] 01416 if 'memory_usage' in record and record['memory_usage']: 01417 # Note that summary should be in the last record of 01418 # 'memory_usage' section. This is why we are 01419 # grabbing last "[-1]" record. 01420 row = [ 01421 record['description'], 01422 record['target_name'], 01423 record['toolchain_name'], 01424 record['memory_usage'][-1]['summary'][ 01425 'static_ram'], 01426 record['memory_usage'][-1]['summary']['stack'], 01427 record['memory_usage'][-1]['summary']['heap'], 01428 record['memory_usage'][-1]['summary'][ 01429 'total_ram'], 01430 record['memory_usage'][-1]['summary'][ 01431 'total_flash'], 01432 ] 01433 table.add_row(row) 01434 01435 result = "Memory map breakdown for built projects (values in Bytes):\n" 01436 result += table.get_string(sortby='name') 01437 return result 01438 01439 def write_build_report (build_report, template_filename, filename): 01440 """Write a build report to disk using a template file 01441 01442 Positional arguments: 01443 build_report - a report generated by the build system 01444 template_filename - a file that contains the template for the style of build 01445 report 01446 filename - the location on disk to write the file to 01447 """ 01448 build_report_failing = [] 01449 build_report_passing = [] 01450 01451 for report in build_report: 01452 if len(report["failing"]) > 0: 01453 build_report_failing.append(report) 01454 else: 01455 build_report_passing.append(report) 01456 01457 env = Environment(extensions=['jinja2.ext.with_']) 01458 env.loader = FileSystemLoader('ci_templates') 01459 template = env.get_template(template_filename) 01460 01461 with open(filename, 'w+') as placeholder: 01462 placeholder.write(template.render( 01463 failing_builds=build_report_failing, 01464 passing_builds=build_report_passing))
Generated on Tue Jul 12 2022 12:28:26 by
