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.
Fork of mbed-tools by
build_api.py
00001 """ 00002 mbed SDK 00003 Copyright (c) 2011-2013 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 import colorama 00021 00022 00023 from types import ListType 00024 from shutil import rmtree 00025 from os.path import join, exists, basename 00026 from time import time 00027 00028 from tools.utils import mkdir, run_cmd, run_cmd_ext, NotSupportedException 00029 from tools.paths import MBED_TARGETS_PATH, MBED_LIBRARIES, MBED_API, MBED_HAL, MBED_COMMON 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 00036 00037 def prep_report(report, target_name, toolchain_name, id_name): 00038 # Setup report keys 00039 if not target_name in report: 00040 report[target_name] = {} 00041 00042 if not toolchain_name in report[target_name]: 00043 report[target_name][toolchain_name] = {} 00044 00045 if not id_name in report[target_name][toolchain_name]: 00046 report[target_name][toolchain_name][id_name] = [] 00047 00048 def prep_properties(properties, target_name, toolchain_name, vendor_label): 00049 # Setup test properties 00050 if not target_name in properties: 00051 properties[target_name] = {} 00052 00053 if not toolchain_name in properties[target_name]: 00054 properties[target_name][toolchain_name] = {} 00055 00056 properties[target_name][toolchain_name]["target"] = target_name 00057 properties[target_name][toolchain_name]["vendor"] = vendor_label 00058 properties[target_name][toolchain_name]["toolchain"] = toolchain_name 00059 00060 def create_result(target_name, toolchain_name, id_name, description): 00061 cur_result = {} 00062 cur_result["target_name"] = target_name 00063 cur_result["toolchain_name"] = toolchain_name 00064 cur_result["id"] = id_name 00065 cur_result["description"] = description 00066 cur_result["elapsed_time"] = 0 00067 cur_result["output"] = "" 00068 00069 return cur_result 00070 00071 def add_result_to_report(report, result): 00072 target = result["target_name"] 00073 toolchain = result["toolchain_name"] 00074 id_name = result['id'] 00075 result_wrap = { 0: result } 00076 report[target][toolchain][id_name].append(result_wrap) 00077 00078 def build_project (src_path, build_path, target, toolchain_name, 00079 libraries_paths=None, options=None, linker_script=None, 00080 clean=False, notify=None, verbose=False, name=None, macros=None, inc_dirs=None, 00081 jobs=1, silent=False, report=None, properties=None, project_id=None, project_description=None, extra_verbose=False): 00082 """ This function builds project. Project can be for example one test / UT 00083 """ 00084 # Toolchain instance 00085 toolchain = TOOLCHAIN_CLASSES[toolchain_name](target, options, notify, macros, silent, extra_verbose=extra_verbose) 00086 toolchain.VERBOSE = verbose 00087 toolchain.jobs = jobs 00088 toolchain.build_all = clean 00089 src_paths = [src_path] if type(src_path) != ListType else src_path 00090 00091 # We need to remove all paths which are repeated to avoid 00092 # multiple compilations and linking with the same objects 00093 src_paths = [src_paths[0]] + list(set(src_paths[1:])) 00094 PROJECT_BASENAME = basename(src_paths[0]) 00095 00096 if name is None: 00097 # We will use default project name based on project folder name 00098 name = PROJECT_BASENAME 00099 toolchain.info("Building project %s (%s, %s)" % (PROJECT_BASENAME.upper(), target.name, toolchain_name)) 00100 else: 00101 # User used custom global project name to have the same name for the 00102 toolchain.info("Building project %s to %s (%s, %s)" % (PROJECT_BASENAME.upper(), name, target.name, toolchain_name)) 00103 00104 00105 if report != None: 00106 start = time() 00107 id_name = project_id.upper() 00108 description = project_description 00109 vendor_label = target.extra_labels[0] 00110 cur_result = None 00111 prep_report(report, target.name, toolchain_name, id_name) 00112 cur_result = create_result(target.name, toolchain_name, id_name, description) 00113 00114 if properties != None: 00115 prep_properties(properties, target.name, toolchain_name, vendor_label) 00116 00117 try: 00118 # Scan src_path and libraries_paths for resources 00119 resources = toolchain.scan_resources(src_paths[0]) 00120 for path in src_paths[1:]: 00121 resources.add(toolchain.scan_resources(path)) 00122 if libraries_paths is not None: 00123 src_paths.extend(libraries_paths) 00124 for path in libraries_paths: 00125 resources.add(toolchain.scan_resources(path)) 00126 00127 if linker_script is not None: 00128 resources.linker_script = linker_script 00129 00130 # Build Directory 00131 if clean: 00132 if exists(build_path): 00133 rmtree(build_path) 00134 mkdir(build_path) 00135 00136 # We need to add if necessary additional include directories 00137 if inc_dirs: 00138 if type(inc_dirs) == ListType: 00139 resources.inc_dirs.extend(inc_dirs) 00140 else: 00141 resources.inc_dirs.append(inc_dirs) 00142 # Compile Sources 00143 for path in src_paths: 00144 src = toolchain.scan_resources(path) 00145 objects = toolchain.compile_sources(src, build_path, resources.inc_dirs) 00146 resources.objects.extend(objects) 00147 00148 00149 # Link Program 00150 res, needed_update = toolchain.link_program(resources, build_path, name) 00151 00152 if report != None and needed_update: 00153 end = time() 00154 cur_result["elapsed_time"] = end - start 00155 cur_result["output"] = toolchain.get_output() 00156 cur_result["result"] = "OK" 00157 00158 add_result_to_report(report, cur_result) 00159 00160 return res 00161 00162 except Exception, e: 00163 if report != None: 00164 end = time() 00165 00166 if isinstance(e, NotSupportedException): 00167 cur_result["result"] = "NOT_SUPPORTED" 00168 else: 00169 cur_result["result"] = "FAIL" 00170 00171 cur_result["elapsed_time"] = end - start 00172 00173 toolchain_output = toolchain.get_output() 00174 if toolchain_output: 00175 cur_result["output"] += toolchain_output 00176 00177 cur_result["output"] += str(e) 00178 00179 add_result_to_report(report, cur_result) 00180 00181 # Let Exception propagate 00182 raise e 00183 00184 00185 def build_library (src_paths, build_path, target, toolchain_name, 00186 dependencies_paths=None, options=None, name=None, clean=False, 00187 notify=None, verbose=False, macros=None, inc_dirs=None, inc_dirs_ext=None, 00188 jobs=1, silent=False, report=None, properties=None, extra_verbose=False): 00189 """ src_path: the path of the source directory 00190 build_path: the path of the build directory 00191 target: ['LPC1768', 'LPC11U24', 'LPC2368'] 00192 toolchain: ['ARM', 'uARM', 'GCC_ARM', 'GCC_CR'] 00193 library_paths: List of paths to additional libraries 00194 clean: Rebuild everything if True 00195 notify: Notify function for logs 00196 verbose: Write the actual tools command lines if True 00197 inc_dirs: additional include directories which should be included in build 00198 inc_dirs_ext: additional include directories which should be copied to library directory 00199 """ 00200 if type(src_paths) != ListType: 00201 src_paths = [src_paths] 00202 00203 # The first path will give the name to the library 00204 name = basename(src_paths[0]) 00205 00206 if report != None: 00207 start = time() 00208 id_name = name.upper() 00209 description = name 00210 vendor_label = target.extra_labels[0] 00211 cur_result = None 00212 prep_report(report, target.name, toolchain_name, id_name) 00213 cur_result = create_result(target.name, toolchain_name, id_name, description) 00214 00215 if properties != None: 00216 prep_properties(properties, target.name, toolchain_name, vendor_label) 00217 00218 for src_path in src_paths: 00219 if not exists(src_path): 00220 error_msg = "The library source folder does not exist: %s", src_path 00221 00222 if report != None: 00223 cur_result["output"] = error_msg 00224 cur_result["result"] = "FAIL" 00225 add_result_to_report(report, cur_result) 00226 00227 raise Exception(error_msg) 00228 00229 try: 00230 # Toolchain instance 00231 toolchain = TOOLCHAIN_CLASSES[toolchain_name](target, options, macros=macros, notify=notify, silent=silent, extra_verbose=extra_verbose) 00232 toolchain.VERBOSE = verbose 00233 toolchain.jobs = jobs 00234 toolchain.build_all = clean 00235 00236 toolchain.info("Building library %s (%s, %s)" % (name.upper(), target.name, toolchain_name)) 00237 00238 # Scan Resources 00239 resources = [] 00240 for src_path in src_paths: 00241 resources.append(toolchain.scan_resources(src_path)) 00242 00243 # Add extra include directories / files which are required by library 00244 # This files usually are not in the same directory as source files so 00245 # previous scan will not include them 00246 if inc_dirs_ext is not None: 00247 for inc_ext in inc_dirs_ext: 00248 resources.append(toolchain.scan_resources(inc_ext)) 00249 00250 # Dependencies Include Paths 00251 dependencies_include_dir = [] 00252 if dependencies_paths is not None: 00253 for path in dependencies_paths: 00254 lib_resources = toolchain.scan_resources(path) 00255 dependencies_include_dir.extend(lib_resources.inc_dirs) 00256 00257 if inc_dirs: 00258 dependencies_include_dir.extend(inc_dirs) 00259 00260 # Create the desired build directory structure 00261 bin_path = join(build_path, toolchain.obj_path) 00262 mkdir(bin_path) 00263 tmp_path = join(build_path, '.temp', toolchain.obj_path) 00264 mkdir(tmp_path) 00265 00266 # Copy Headers 00267 for resource in resources: 00268 toolchain.copy_files(resource.headers, build_path, rel_path=resource.base_path) 00269 dependencies_include_dir.extend(toolchain.scan_resources(build_path).inc_dirs) 00270 00271 # Compile Sources 00272 objects = [] 00273 for resource in resources: 00274 objects.extend(toolchain.compile_sources(resource, tmp_path, dependencies_include_dir)) 00275 00276 needed_update = toolchain.build_library(objects, bin_path, name) 00277 00278 if report != None and needed_update: 00279 end = time() 00280 cur_result["elapsed_time"] = end - start 00281 cur_result["output"] = toolchain.get_output() 00282 cur_result["result"] = "OK" 00283 00284 add_result_to_report(report, cur_result) 00285 00286 except Exception, e: 00287 if report != None: 00288 end = time() 00289 cur_result["result"] = "FAIL" 00290 cur_result["elapsed_time"] = end - start 00291 00292 toolchain_output = toolchain.get_output() 00293 if toolchain_output: 00294 cur_result["output"] += toolchain_output 00295 00296 cur_result["output"] += str(e) 00297 00298 add_result_to_report(report, cur_result) 00299 00300 # Let Exception propagate 00301 raise e 00302 00303 def build_lib (lib_id, target, toolchain, options=None, verbose=False, clean=False, macros=None, notify=None, jobs=1, silent=False, report=None, properties=None, extra_verbose=False): 00304 """ Wrapper for build_library function. 00305 Function builds library in proper directory using all dependencies and macros defined by user. 00306 """ 00307 lib = Library(lib_id) 00308 if lib.is_supported(target, toolchain): 00309 # We need to combine macros from parameter list with macros from library definition 00310 MACROS = lib.macros if lib.macros else [] 00311 if macros: 00312 MACROS.extend(macros) 00313 00314 return build_library(lib.source_dir, lib.build_dir, target, toolchain, lib.dependencies, options, 00315 verbose=verbose, 00316 silent=silent, 00317 clean=clean, 00318 macros=MACROS, 00319 notify=notify, 00320 inc_dirs=lib.inc_dirs, 00321 inc_dirs_ext=lib.inc_dirs_ext, 00322 jobs=jobs, 00323 report=report, 00324 properties=properties, 00325 extra_verbose=extra_verbose) 00326 else: 00327 print 'Library "%s" is not yet supported on target %s with toolchain %s' % (lib_id, target.name, toolchain) 00328 return False 00329 00330 00331 # We do have unique legacy conventions about how we build and package the mbed library 00332 def build_mbed_libs (target, toolchain_name, options=None, verbose=False, clean=False, macros=None, notify=None, jobs=1, silent=False, report=None, properties=None, extra_verbose=False): 00333 """ Function returns True is library was built and false if building was skipped """ 00334 00335 if report != None: 00336 start = time() 00337 id_name = "MBED" 00338 description = "mbed SDK" 00339 vendor_label = target.extra_labels[0] 00340 cur_result = None 00341 prep_report(report, target.name, toolchain_name, id_name) 00342 cur_result = create_result(target.name, toolchain_name, id_name, description) 00343 00344 if properties != None: 00345 prep_properties(properties, target.name, toolchain_name, vendor_label) 00346 00347 # Check toolchain support 00348 if toolchain_name not in target.supported_toolchains: 00349 supported_toolchains_text = ", ".join(target.supported_toolchains) 00350 print '%s target is not yet supported by toolchain %s' % (target.name, toolchain_name) 00351 print '%s target supports %s toolchain%s' % (target.name, supported_toolchains_text, 's' if len(target.supported_toolchains) > 1 else '') 00352 00353 if report != None: 00354 cur_result["result"] = "SKIP" 00355 add_result_to_report(report, cur_result) 00356 00357 return False 00358 00359 try: 00360 # Toolchain 00361 toolchain = TOOLCHAIN_CLASSES[toolchain_name](target, options, macros=macros, notify=notify, silent=silent, extra_verbose=extra_verbose) 00362 toolchain.VERBOSE = verbose 00363 toolchain.jobs = jobs 00364 toolchain.build_all = clean 00365 00366 # Source and Build Paths 00367 BUILD_TARGET = join(MBED_LIBRARIES, "TARGET_" + target.name) 00368 BUILD_TOOLCHAIN = join(BUILD_TARGET, "TOOLCHAIN_" + toolchain.name) 00369 mkdir(BUILD_TOOLCHAIN) 00370 00371 TMP_PATH = join(MBED_LIBRARIES, '.temp', toolchain.obj_path) 00372 mkdir(TMP_PATH) 00373 00374 # CMSIS 00375 toolchain.info("Building library %s (%s, %s)"% ('CMSIS', target.name, toolchain_name)) 00376 cmsis_src = join(MBED_TARGETS_PATH, "cmsis") 00377 resources = toolchain.scan_resources(cmsis_src) 00378 00379 toolchain.copy_files(resources.headers, BUILD_TARGET) 00380 toolchain.copy_files(resources.linker_script, BUILD_TOOLCHAIN) 00381 toolchain.copy_files(resources.bin_files, BUILD_TOOLCHAIN) 00382 00383 objects = toolchain.compile_sources(resources, TMP_PATH) 00384 toolchain.copy_files(objects, BUILD_TOOLCHAIN) 00385 00386 # mbed 00387 toolchain.info("Building library %s (%s, %s)" % ('MBED', target.name, toolchain_name)) 00388 00389 # Common Headers 00390 toolchain.copy_files(toolchain.scan_resources(MBED_API).headers, MBED_LIBRARIES) 00391 toolchain.copy_files(toolchain.scan_resources(MBED_HAL).headers, MBED_LIBRARIES) 00392 00393 # Target specific sources 00394 HAL_SRC = join(MBED_TARGETS_PATH, "hal") 00395 hal_implementation = toolchain.scan_resources(HAL_SRC) 00396 toolchain.copy_files(hal_implementation.headers + hal_implementation.hex_files + hal_implementation.libraries, BUILD_TARGET, HAL_SRC) 00397 incdirs = toolchain.scan_resources(BUILD_TARGET).inc_dirs 00398 objects = toolchain.compile_sources(hal_implementation, TMP_PATH, [MBED_LIBRARIES] + incdirs) 00399 00400 # Common Sources 00401 mbed_resources = toolchain.scan_resources(MBED_COMMON) 00402 objects += toolchain.compile_sources(mbed_resources, TMP_PATH, [MBED_LIBRARIES] + incdirs) 00403 00404 # A number of compiled files need to be copied as objects as opposed to 00405 # being part of the mbed library, for reasons that have to do with the way 00406 # the linker search for symbols in archives. These are: 00407 # - retarget.o: to make sure that the C standard lib symbols get overridden 00408 # - board.o: mbed_die is weak 00409 # - mbed_overrides.o: this contains platform overrides of various weak SDK functions 00410 separate_names, separate_objects = ['retarget.o', 'board.o', 'mbed_overrides.o'], [] 00411 00412 for o in objects: 00413 for name in separate_names: 00414 if o.endswith(name): 00415 separate_objects.append(o) 00416 00417 for o in separate_objects: 00418 objects.remove(o) 00419 00420 needed_update = toolchain.build_library(objects, BUILD_TOOLCHAIN, "mbed") 00421 00422 for o in separate_objects: 00423 toolchain.copy_files(o, BUILD_TOOLCHAIN) 00424 00425 if report != None and needed_update: 00426 end = time() 00427 cur_result["elapsed_time"] = end - start 00428 cur_result["output"] = toolchain.get_output() 00429 cur_result["result"] = "OK" 00430 00431 add_result_to_report(report, cur_result) 00432 00433 return True 00434 00435 except Exception, e: 00436 if report != None: 00437 end = time() 00438 cur_result["result"] = "FAIL" 00439 cur_result["elapsed_time"] = end - start 00440 00441 toolchain_output = toolchain.get_output() 00442 if toolchain_output: 00443 cur_result["output"] += toolchain_output 00444 00445 cur_result["output"] += str(e) 00446 00447 add_result_to_report(report, cur_result) 00448 00449 # Let Exception propagate 00450 raise e 00451 00452 def get_unique_supported_toolchains (): 00453 """ Get list of all unique toolchains supported by targets """ 00454 unique_supported_toolchains = [] 00455 for target in TARGET_NAMES: 00456 for toolchain in TARGET_MAP[target].supported_toolchains: 00457 if toolchain not in unique_supported_toolchains: 00458 unique_supported_toolchains.append(toolchain) 00459 return unique_supported_toolchains 00460 00461 00462 def mcu_toolchain_matrix (verbose_html=False, platform_filter=None): 00463 """ Shows target map using prettytable """ 00464 unique_supported_toolchains = get_unique_supported_toolchains() 00465 from prettytable import PrettyTable # Only use it in this function so building works without extra modules 00466 00467 # All tests status table print 00468 columns = ["Platform"] + unique_supported_toolchains 00469 pt = PrettyTable(["Platform"] + unique_supported_toolchains) 00470 # Align table 00471 for col in columns: 00472 pt.align[col] = "c" 00473 pt.align["Platform"] = "l" 00474 00475 perm_counter = 0 00476 target_counter = 0 00477 for target in sorted(TARGET_NAMES): 00478 if platform_filter is not None: 00479 # FIlter out platforms using regex 00480 if re.search(platform_filter, target) is None: 00481 continue 00482 target_counter += 1 00483 00484 row = [target] # First column is platform name 00485 default_toolchain = TARGET_MAP[target].default_toolchain 00486 for unique_toolchain in unique_supported_toolchains: 00487 text = "-" 00488 if default_toolchain == unique_toolchain: 00489 text = "Default" 00490 perm_counter += 1 00491 elif unique_toolchain in TARGET_MAP[target].supported_toolchains: 00492 text = "Supported" 00493 perm_counter += 1 00494 row.append(text) 00495 pt.add_row(row) 00496 00497 result = pt.get_html_string() if verbose_html else pt.get_string() 00498 result += "\n" 00499 result += "*Default - default on-line compiler\n" 00500 result += "*Supported - supported off-line compiler\n" 00501 result += "\n" 00502 result += "Total platforms: %d\n"% (target_counter) 00503 result += "Total permutations: %d"% (perm_counter) 00504 return result 00505 00506 00507 def get_target_supported_toolchains (target): 00508 """ Returns target supported toolchains list """ 00509 return TARGET_MAP[target].supported_toolchains if target in TARGET_MAP else None 00510 00511 00512 def static_analysis_scan(target, toolchain_name, CPPCHECK_CMD, CPPCHECK_MSG_FORMAT, options=None, verbose=False, clean=False, macros=None, notify=None, jobs=1, extra_verbose=False): 00513 # Toolchain 00514 toolchain = TOOLCHAIN_CLASSES[toolchain_name](target, options, macros=macros, notify=notify, extra_verbose=extra_verbose) 00515 toolchain.VERBOSE = verbose 00516 toolchain.jobs = jobs 00517 toolchain.build_all = clean 00518 00519 # Source and Build Paths 00520 BUILD_TARGET = join(MBED_LIBRARIES, "TARGET_" + target.name) 00521 BUILD_TOOLCHAIN = join(BUILD_TARGET, "TOOLCHAIN_" + toolchain.name) 00522 mkdir(BUILD_TOOLCHAIN) 00523 00524 TMP_PATH = join(MBED_LIBRARIES, '.temp', toolchain.obj_path) 00525 mkdir(TMP_PATH) 00526 00527 # CMSIS 00528 toolchain.info("Static analysis for %s (%s, %s)" % ('CMSIS', target.name, toolchain_name)) 00529 cmsis_src = join(MBED_TARGETS_PATH, "cmsis") 00530 resources = toolchain.scan_resources(cmsis_src) 00531 00532 # Copy files before analysis 00533 toolchain.copy_files(resources.headers, BUILD_TARGET) 00534 toolchain.copy_files(resources.linker_script, BUILD_TOOLCHAIN) 00535 00536 # Gather include paths, c, cpp sources and macros to transfer to cppcheck command line 00537 includes = ["-I%s"% i for i in resources.inc_dirs] 00538 includes.append("-I%s"% str(BUILD_TARGET)) 00539 c_sources = " ".join(resources.c_sources) 00540 cpp_sources = " ".join(resources.cpp_sources) 00541 macros = ["-D%s"% s for s in toolchain.get_symbols() + toolchain.macros] 00542 00543 includes = map(str.strip, includes) 00544 macros = map(str.strip, macros) 00545 00546 check_cmd = CPPCHECK_CMD 00547 check_cmd += CPPCHECK_MSG_FORMAT 00548 check_cmd += includes 00549 check_cmd += macros 00550 00551 # We need to pass some params via file to avoid "command line too long in some OSs" 00552 tmp_file = tempfile.NamedTemporaryFile(delete=False) 00553 tmp_file.writelines(line + '\n' for line in c_sources.split()) 00554 tmp_file.writelines(line + '\n' for line in cpp_sources.split()) 00555 tmp_file.close() 00556 check_cmd += ["--file-list=%s"% tmp_file.name] 00557 00558 _stdout, _stderr, _rc = run_cmd(check_cmd) 00559 if verbose: 00560 print _stdout 00561 print _stderr 00562 00563 # ========================================================================= 00564 00565 # MBED 00566 toolchain.info("Static analysis for %s (%s, %s)" % ('MBED', target.name, toolchain_name)) 00567 00568 # Common Headers 00569 toolchain.copy_files(toolchain.scan_resources(MBED_API).headers, MBED_LIBRARIES) 00570 toolchain.copy_files(toolchain.scan_resources(MBED_HAL).headers, MBED_LIBRARIES) 00571 00572 # Target specific sources 00573 HAL_SRC = join(MBED_TARGETS_PATH, "hal") 00574 hal_implementation = toolchain.scan_resources(HAL_SRC) 00575 00576 # Copy files before analysis 00577 toolchain.copy_files(hal_implementation.headers + hal_implementation.hex_files, BUILD_TARGET, HAL_SRC) 00578 incdirs = toolchain.scan_resources(BUILD_TARGET) 00579 00580 target_includes = ["-I%s" % i for i in incdirs.inc_dirs] 00581 target_includes.append("-I%s"% str(BUILD_TARGET)) 00582 target_includes.append("-I%s"% str(HAL_SRC)) 00583 target_c_sources = " ".join(incdirs.c_sources) 00584 target_cpp_sources = " ".join(incdirs.cpp_sources) 00585 target_macros = ["-D%s"% s for s in toolchain.get_symbols() + toolchain.macros] 00586 00587 # Common Sources 00588 mbed_resources = toolchain.scan_resources(MBED_COMMON) 00589 00590 # Gather include paths, c, cpp sources and macros to transfer to cppcheck command line 00591 mbed_includes = ["-I%s" % i for i in mbed_resources.inc_dirs] 00592 mbed_includes.append("-I%s"% str(BUILD_TARGET)) 00593 mbed_includes.append("-I%s"% str(MBED_COMMON)) 00594 mbed_includes.append("-I%s"% str(MBED_API)) 00595 mbed_includes.append("-I%s"% str(MBED_HAL)) 00596 mbed_c_sources = " ".join(mbed_resources.c_sources) 00597 mbed_cpp_sources = " ".join(mbed_resources.cpp_sources) 00598 00599 target_includes = map(str.strip, target_includes) 00600 mbed_includes = map(str.strip, mbed_includes) 00601 target_macros = map(str.strip, target_macros) 00602 00603 check_cmd = CPPCHECK_CMD 00604 check_cmd += CPPCHECK_MSG_FORMAT 00605 check_cmd += target_includes 00606 check_cmd += mbed_includes 00607 check_cmd += target_macros 00608 00609 # We need to pass some parames via file to avoid "command line too long in some OSs" 00610 tmp_file = tempfile.NamedTemporaryFile(delete=False) 00611 tmp_file.writelines(line + '\n' for line in target_c_sources.split()) 00612 tmp_file.writelines(line + '\n' for line in target_cpp_sources.split()) 00613 tmp_file.writelines(line + '\n' for line in mbed_c_sources.split()) 00614 tmp_file.writelines(line + '\n' for line in mbed_cpp_sources.split()) 00615 tmp_file.close() 00616 check_cmd += ["--file-list=%s"% tmp_file.name] 00617 00618 _stdout, _stderr, _rc = run_cmd_ext(check_cmd) 00619 if verbose: 00620 print _stdout 00621 print _stderr 00622 00623 00624 def static_analysis_scan_lib(lib_id, target, toolchain, cppcheck_cmd, cppcheck_msg_format, 00625 options=None, verbose=False, clean=False, macros=None, notify=None, jobs=1, extra_verbose=False): 00626 lib = Library(lib_id) 00627 if lib.is_supported(target, toolchain): 00628 static_analysis_scan_library(lib.source_dir, lib.build_dir, target, toolchain, cppcheck_cmd, cppcheck_msg_format, 00629 lib.dependencies, options, 00630 verbose=verbose, clean=clean, macros=macros, notify=notify, jobs=jobs, extra_verbose=extra_verbose) 00631 else: 00632 print 'Library "%s" is not yet supported on target %s with toolchain %s'% (lib_id, target.name, toolchain) 00633 00634 00635 def static_analysis_scan_library (src_paths, build_path, target, toolchain_name, cppcheck_cmd, cppcheck_msg_format, 00636 dependencies_paths=None, options=None, name=None, clean=False, 00637 notify=None, verbose=False, macros=None, jobs=1, extra_verbose=False): 00638 """ Function scans library (or just some set of sources/headers) for staticly detectable defects """ 00639 if type(src_paths) != ListType: 00640 src_paths = [src_paths] 00641 00642 for src_path in src_paths: 00643 if not exists(src_path): 00644 raise Exception("The library source folder does not exist: %s", src_path) 00645 00646 # Toolchain instance 00647 toolchain = TOOLCHAIN_CLASSES[toolchain_name](target, options, macros=macros, notify=notify, extra_verbose=extra_verbose) 00648 toolchain.VERBOSE = verbose 00649 toolchain.jobs = jobs 00650 00651 # The first path will give the name to the library 00652 name = basename(src_paths[0]) 00653 toolchain.info("Static analysis for library %s (%s, %s)" % (name.upper(), target.name, toolchain_name)) 00654 00655 # Scan Resources 00656 resources = [] 00657 for src_path in src_paths: 00658 resources.append(toolchain.scan_resources(src_path)) 00659 00660 # Dependencies Include Paths 00661 dependencies_include_dir = [] 00662 if dependencies_paths is not None: 00663 for path in dependencies_paths: 00664 lib_resources = toolchain.scan_resources(path) 00665 dependencies_include_dir.extend(lib_resources.inc_dirs) 00666 00667 # Create the desired build directory structure 00668 bin_path = join(build_path, toolchain.obj_path) 00669 mkdir(bin_path) 00670 tmp_path = join(build_path, '.temp', toolchain.obj_path) 00671 mkdir(tmp_path) 00672 00673 # Gather include paths, c, cpp sources and macros to transfer to cppcheck command line 00674 includes = ["-I%s" % i for i in dependencies_include_dir + src_paths] 00675 c_sources = " " 00676 cpp_sources = " " 00677 macros = ['-D%s' % s for s in toolchain.get_symbols() + toolchain.macros] 00678 00679 # Copy Headers 00680 for resource in resources: 00681 toolchain.copy_files(resource.headers, build_path, rel_path=resource.base_path) 00682 includes += ["-I%s" % i for i in resource.inc_dirs] 00683 c_sources += " ".join(resource.c_sources) + " " 00684 cpp_sources += " ".join(resource.cpp_sources) + " " 00685 00686 dependencies_include_dir.extend(toolchain.scan_resources(build_path).inc_dirs) 00687 00688 includes = map(str.strip, includes) 00689 macros = map(str.strip, macros) 00690 00691 check_cmd = cppcheck_cmd 00692 check_cmd += cppcheck_msg_format 00693 check_cmd += includes 00694 check_cmd += macros 00695 00696 # We need to pass some parameters via file to avoid "command line too long in some OSs" 00697 # Temporary file is created to store e.g. cppcheck list of files for command line 00698 tmp_file = tempfile.NamedTemporaryFile(delete=False) 00699 tmp_file.writelines(line + '\n' for line in c_sources.split()) 00700 tmp_file.writelines(line + '\n' for line in cpp_sources.split()) 00701 tmp_file.close() 00702 check_cmd += ["--file-list=%s"% tmp_file.name] 00703 00704 # This will allow us to grab result from both stdio and stderr outputs (so we can show them) 00705 # We assume static code analysis tool is outputting defects on STDERR 00706 _stdout, _stderr, _rc = run_cmd_ext(check_cmd) 00707 if verbose: 00708 print _stdout 00709 print _stderr 00710 00711 00712 def print_build_results (result_list, build_name): 00713 """ Generate result string for build results """ 00714 result = "" 00715 if len(result_list) > 0: 00716 result += build_name + "\n" 00717 result += "\n".join([" * %s" % f for f in result_list]) 00718 result += "\n" 00719 return result 00720 00721 def write_build_report(build_report, template_filename, filename): 00722 build_report_failing = [] 00723 build_report_passing = [] 00724 00725 for report in build_report: 00726 if len(report["failing"]) > 0: 00727 build_report_failing.append(report) 00728 else: 00729 build_report_passing.append(report) 00730 00731 env = Environment(extensions=['jinja2.ext.with_']) 00732 env.loader = FileSystemLoader('ci_templates') 00733 template = env.get_template(template_filename) 00734 00735 with open(filename, 'w+') as f: 00736 f.write(template.render(failing_builds=build_report_failing, passing_builds=build_report_passing))
Generated on Thu Jun 15 2023 14:54:59 by
