Keyboard firmwares for Atmel AVR and Cortex-M
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

build_api.py 22KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  1. """
  2. mbed SDK
  3. Copyright (c) 2011-2013 ARM Limited
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.apache.org/licenses/LICENSE-2.0
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. """
  14. import re
  15. import tempfile
  16. import colorama
  17. from types import ListType
  18. from shutil import rmtree
  19. from os.path import join, exists, basename
  20. from workspace_tools.utils import mkdir, run_cmd, run_cmd_ext
  21. from workspace_tools.paths import MBED_TARGETS_PATH, MBED_LIBRARIES, MBED_API, MBED_HAL, MBED_COMMON
  22. from workspace_tools.targets import TARGET_NAMES, TARGET_MAP
  23. from workspace_tools.libraries import Library
  24. from workspace_tools.toolchains import TOOLCHAIN_CLASSES
  25. from jinja2 import FileSystemLoader
  26. from jinja2.environment import Environment
  27. def build_project(src_path, build_path, target, toolchain_name,
  28. libraries_paths=None, options=None, linker_script=None,
  29. clean=False, notify=None, verbose=False, name=None, macros=None, inc_dirs=None, jobs=1, silent=False):
  30. """ This function builds project. Project can be for example one test / UT
  31. """
  32. # Toolchain instance
  33. toolchain = TOOLCHAIN_CLASSES[toolchain_name](target, options, notify, macros, silent)
  34. toolchain.VERBOSE = verbose
  35. toolchain.jobs = jobs
  36. toolchain.build_all = clean
  37. src_paths = [src_path] if type(src_path) != ListType else src_path
  38. # We need to remove all paths which are repeated to avoid
  39. # multiple compilations and linking with the same objects
  40. src_paths = [src_paths[0]] + list(set(src_paths[1:]))
  41. PROJECT_BASENAME = basename(src_paths[0])
  42. if name is None:
  43. # We will use default project name based on project folder name
  44. name = PROJECT_BASENAME
  45. toolchain.info("Building project %s (%s, %s)" % (PROJECT_BASENAME.upper(), target.name, toolchain_name))
  46. else:
  47. # User used custom global project name to have the same name for the
  48. toolchain.info("Building project %s to %s (%s, %s)" % (PROJECT_BASENAME.upper(), name, target.name, toolchain_name))
  49. # Scan src_path and libraries_paths for resources
  50. resources = toolchain.scan_resources(src_paths[0])
  51. for path in src_paths[1:]:
  52. resources.add(toolchain.scan_resources(path))
  53. if libraries_paths is not None:
  54. src_paths.extend(libraries_paths)
  55. for path in libraries_paths:
  56. resources.add(toolchain.scan_resources(path))
  57. if linker_script is not None:
  58. resources.linker_script = linker_script
  59. # Build Directory
  60. if clean:
  61. if exists(build_path):
  62. rmtree(build_path)
  63. mkdir(build_path)
  64. # We need to add if necessary additional include directories
  65. if inc_dirs:
  66. if type(inc_dirs) == ListType:
  67. resources.inc_dirs.extend(inc_dirs)
  68. else:
  69. resources.inc_dirs.append(inc_dirs)
  70. # Compile Sources
  71. for path in src_paths:
  72. src = toolchain.scan_resources(path)
  73. objects = toolchain.compile_sources(src, build_path, resources.inc_dirs)
  74. resources.objects.extend(objects)
  75. # Link Program
  76. return toolchain.link_program(resources, build_path, name)
  77. def build_library(src_paths, build_path, target, toolchain_name,
  78. dependencies_paths=None, options=None, name=None, clean=False,
  79. notify=None, verbose=False, macros=None, inc_dirs=None, inc_dirs_ext=None, jobs=1, silent=False):
  80. """ src_path: the path of the source directory
  81. build_path: the path of the build directory
  82. target: ['LPC1768', 'LPC11U24', 'LPC2368']
  83. toolchain: ['ARM', 'uARM', 'GCC_ARM', 'GCC_CS', 'GCC_CR']
  84. library_paths: List of paths to additional libraries
  85. clean: Rebuild everything if True
  86. notify: Notify function for logs
  87. verbose: Write the actual tools command lines if True
  88. inc_dirs: additional include directories which should be included in build
  89. inc_dirs_ext: additional include directories which should be copied to library directory
  90. """
  91. if type(src_paths) != ListType:
  92. src_paths = [src_paths]
  93. for src_path in src_paths:
  94. if not exists(src_path):
  95. raise Exception("The library source folder does not exist: %s", src_path)
  96. # Toolchain instance
  97. toolchain = TOOLCHAIN_CLASSES[toolchain_name](target, options, macros=macros, notify=notify, silent=silent)
  98. toolchain.VERBOSE = verbose
  99. toolchain.jobs = jobs
  100. toolchain.build_all = clean
  101. # The first path will give the name to the library
  102. name = basename(src_paths[0])
  103. toolchain.info("Building library %s (%s, %s)" % (name.upper(), target.name, toolchain_name))
  104. # Scan Resources
  105. resources = []
  106. for src_path in src_paths:
  107. resources.append(toolchain.scan_resources(src_path))
  108. # Add extra include directories / files which are required by library
  109. # This files usually are not in the same directory as source files so
  110. # previous scan will not include them
  111. if inc_dirs_ext is not None:
  112. for inc_ext in inc_dirs_ext:
  113. resources.append(toolchain.scan_resources(inc_ext))
  114. # Dependencies Include Paths
  115. dependencies_include_dir = []
  116. if dependencies_paths is not None:
  117. for path in dependencies_paths:
  118. lib_resources = toolchain.scan_resources(path)
  119. dependencies_include_dir.extend(lib_resources.inc_dirs)
  120. if inc_dirs:
  121. dependencies_include_dir.extend(inc_dirs)
  122. # Create the desired build directory structure
  123. bin_path = join(build_path, toolchain.obj_path)
  124. mkdir(bin_path)
  125. tmp_path = join(build_path, '.temp', toolchain.obj_path)
  126. mkdir(tmp_path)
  127. # Copy Headers
  128. for resource in resources:
  129. toolchain.copy_files(resource.headers, build_path, rel_path=resource.base_path)
  130. dependencies_include_dir.extend(toolchain.scan_resources(build_path).inc_dirs)
  131. # Compile Sources
  132. objects = []
  133. for resource in resources:
  134. objects.extend(toolchain.compile_sources(resource, tmp_path, dependencies_include_dir))
  135. toolchain.build_library(objects, bin_path, name)
  136. def build_lib(lib_id, target, toolchain, options=None, verbose=False, clean=False, macros=None, notify=None, jobs=1, silent=False):
  137. """ Wrapper for build_library function.
  138. Function builds library in proper directory using all dependencies and macros defined by user.
  139. """
  140. lib = Library(lib_id)
  141. if lib.is_supported(target, toolchain):
  142. # We need to combine macros from parameter list with macros from library definition
  143. MACROS = lib.macros if lib.macros else []
  144. if macros:
  145. MACROS.extend(macros)
  146. build_library(lib.source_dir, lib.build_dir, target, toolchain, lib.dependencies, options,
  147. verbose=verbose,
  148. silent=silent,
  149. clean=clean,
  150. macros=MACROS,
  151. notify=notify,
  152. inc_dirs=lib.inc_dirs,
  153. inc_dirs_ext=lib.inc_dirs_ext,
  154. jobs=jobs)
  155. else:
  156. print 'Library "%s" is not yet supported on target %s with toolchain %s' % (lib_id, target.name, toolchain)
  157. # We do have unique legacy conventions about how we build and package the mbed library
  158. def build_mbed_libs(target, toolchain_name, options=None, verbose=False, clean=False, macros=None, notify=None, jobs=1, silent=False):
  159. """ Function returns True is library was built and false if building was skipped """
  160. # Check toolchain support
  161. if toolchain_name not in target.supported_toolchains:
  162. supported_toolchains_text = ", ".join(target.supported_toolchains)
  163. print '%s target is not yet supported by toolchain %s' % (target.name, toolchain_name)
  164. print '%s target supports %s toolchain%s' % (target.name, supported_toolchains_text, 's' if len(target.supported_toolchains) > 1 else '')
  165. return False
  166. # Toolchain
  167. toolchain = TOOLCHAIN_CLASSES[toolchain_name](target, options, macros=macros, notify=notify, silent=silent)
  168. toolchain.VERBOSE = verbose
  169. toolchain.jobs = jobs
  170. toolchain.build_all = clean
  171. # Source and Build Paths
  172. BUILD_TARGET = join(MBED_LIBRARIES, "TARGET_" + target.name)
  173. BUILD_TOOLCHAIN = join(BUILD_TARGET, "TOOLCHAIN_" + toolchain.name)
  174. mkdir(BUILD_TOOLCHAIN)
  175. TMP_PATH = join(MBED_LIBRARIES, '.temp', toolchain.obj_path)
  176. mkdir(TMP_PATH)
  177. # CMSIS
  178. toolchain.info("Building library %s (%s, %s)"% ('CMSIS', target.name, toolchain_name))
  179. cmsis_src = join(MBED_TARGETS_PATH, "cmsis")
  180. resources = toolchain.scan_resources(cmsis_src)
  181. toolchain.copy_files(resources.headers, BUILD_TARGET)
  182. toolchain.copy_files(resources.linker_script, BUILD_TOOLCHAIN)
  183. toolchain.copy_files(resources.bin_files, BUILD_TOOLCHAIN)
  184. objects = toolchain.compile_sources(resources, TMP_PATH)
  185. toolchain.copy_files(objects, BUILD_TOOLCHAIN)
  186. # mbed
  187. toolchain.info("Building library %s (%s, %s)" % ('MBED', target.name, toolchain_name))
  188. # Common Headers
  189. toolchain.copy_files(toolchain.scan_resources(MBED_API).headers, MBED_LIBRARIES)
  190. toolchain.copy_files(toolchain.scan_resources(MBED_HAL).headers, MBED_LIBRARIES)
  191. # Target specific sources
  192. HAL_SRC = join(MBED_TARGETS_PATH, "hal")
  193. hal_implementation = toolchain.scan_resources(HAL_SRC)
  194. toolchain.copy_files(hal_implementation.headers + hal_implementation.hex_files + hal_implementation.libraries, BUILD_TARGET, HAL_SRC)
  195. incdirs = toolchain.scan_resources(BUILD_TARGET).inc_dirs
  196. objects = toolchain.compile_sources(hal_implementation, TMP_PATH, [MBED_LIBRARIES] + incdirs)
  197. # Common Sources
  198. mbed_resources = toolchain.scan_resources(MBED_COMMON)
  199. objects += toolchain.compile_sources(mbed_resources, TMP_PATH, [MBED_LIBRARIES] + incdirs)
  200. # A number of compiled files need to be copied as objects as opposed to
  201. # being part of the mbed library, for reasons that have to do with the way
  202. # the linker search for symbols in archives. These are:
  203. # - retarget.o: to make sure that the C standard lib symbols get overridden
  204. # - board.o: mbed_die is weak
  205. # - mbed_overrides.o: this contains platform overrides of various weak SDK functions
  206. separate_names, separate_objects = ['retarget.o', 'board.o', 'mbed_overrides.o'], []
  207. for o in objects:
  208. for name in separate_names:
  209. if o.endswith(name):
  210. separate_objects.append(o)
  211. for o in separate_objects:
  212. objects.remove(o)
  213. toolchain.build_library(objects, BUILD_TOOLCHAIN, "mbed")
  214. for o in separate_objects:
  215. toolchain.copy_files(o, BUILD_TOOLCHAIN)
  216. return True
  217. def get_unique_supported_toolchains():
  218. """ Get list of all unique toolchains supported by targets """
  219. unique_supported_toolchains = []
  220. for target in TARGET_NAMES:
  221. for toolchain in TARGET_MAP[target].supported_toolchains:
  222. if toolchain not in unique_supported_toolchains:
  223. unique_supported_toolchains.append(toolchain)
  224. return unique_supported_toolchains
  225. def mcu_toolchain_matrix(verbose_html=False, platform_filter=None):
  226. """ Shows target map using prettytable """
  227. unique_supported_toolchains = get_unique_supported_toolchains()
  228. from prettytable import PrettyTable # Only use it in this function so building works without extra modules
  229. # All tests status table print
  230. columns = ["Platform"] + unique_supported_toolchains
  231. pt = PrettyTable(["Platform"] + unique_supported_toolchains)
  232. # Align table
  233. for col in columns:
  234. pt.align[col] = "c"
  235. pt.align["Platform"] = "l"
  236. perm_counter = 0
  237. target_counter = 0
  238. for target in sorted(TARGET_NAMES):
  239. if platform_filter is not None:
  240. # FIlter out platforms using regex
  241. if re.search(platform_filter, target) is None:
  242. continue
  243. target_counter += 1
  244. row = [target] # First column is platform name
  245. default_toolchain = TARGET_MAP[target].default_toolchain
  246. for unique_toolchain in unique_supported_toolchains:
  247. text = "-"
  248. if default_toolchain == unique_toolchain:
  249. text = "Default"
  250. perm_counter += 1
  251. elif unique_toolchain in TARGET_MAP[target].supported_toolchains:
  252. text = "Supported"
  253. perm_counter += 1
  254. row.append(text)
  255. pt.add_row(row)
  256. result = pt.get_html_string() if verbose_html else pt.get_string()
  257. result += "\n"
  258. result += "*Default - default on-line compiler\n"
  259. result += "*Supported - supported off-line compiler\n"
  260. result += "\n"
  261. result += "Total platforms: %d\n"% (target_counter)
  262. result += "Total permutations: %d"% (perm_counter)
  263. return result
  264. def get_target_supported_toolchains(target):
  265. """ Returns target supported toolchains list """
  266. return TARGET_MAP[target].supported_toolchains if target in TARGET_MAP else None
  267. def static_analysis_scan(target, toolchain_name, CPPCHECK_CMD, CPPCHECK_MSG_FORMAT, options=None, verbose=False, clean=False, macros=None, notify=None, jobs=1):
  268. # Toolchain
  269. toolchain = TOOLCHAIN_CLASSES[toolchain_name](target, options, macros=macros, notify=notify)
  270. toolchain.VERBOSE = verbose
  271. toolchain.jobs = jobs
  272. toolchain.build_all = clean
  273. # Source and Build Paths
  274. BUILD_TARGET = join(MBED_LIBRARIES, "TARGET_" + target.name)
  275. BUILD_TOOLCHAIN = join(BUILD_TARGET, "TOOLCHAIN_" + toolchain.name)
  276. mkdir(BUILD_TOOLCHAIN)
  277. TMP_PATH = join(MBED_LIBRARIES, '.temp', toolchain.obj_path)
  278. mkdir(TMP_PATH)
  279. # CMSIS
  280. toolchain.info("Static analysis for %s (%s, %s)" % ('CMSIS', target.name, toolchain_name))
  281. cmsis_src = join(MBED_TARGETS_PATH, "cmsis")
  282. resources = toolchain.scan_resources(cmsis_src)
  283. # Copy files before analysis
  284. toolchain.copy_files(resources.headers, BUILD_TARGET)
  285. toolchain.copy_files(resources.linker_script, BUILD_TOOLCHAIN)
  286. # Gather include paths, c, cpp sources and macros to transfer to cppcheck command line
  287. includes = ["-I%s"% i for i in resources.inc_dirs]
  288. includes.append("-I%s"% str(BUILD_TARGET))
  289. c_sources = " ".join(resources.c_sources)
  290. cpp_sources = " ".join(resources.cpp_sources)
  291. macros = ["-D%s"% s for s in toolchain.get_symbols() + toolchain.macros]
  292. includes = map(str.strip, includes)
  293. macros = map(str.strip, macros)
  294. check_cmd = CPPCHECK_CMD
  295. check_cmd += CPPCHECK_MSG_FORMAT
  296. check_cmd += includes
  297. check_cmd += macros
  298. # We need to pass some params via file to avoid "command line too long in some OSs"
  299. tmp_file = tempfile.NamedTemporaryFile(delete=False)
  300. tmp_file.writelines(line + '\n' for line in c_sources.split())
  301. tmp_file.writelines(line + '\n' for line in cpp_sources.split())
  302. tmp_file.close()
  303. check_cmd += ["--file-list=%s"% tmp_file.name]
  304. _stdout, _stderr, _rc = run_cmd(check_cmd)
  305. if verbose:
  306. print _stdout
  307. print _stderr
  308. # =========================================================================
  309. # MBED
  310. toolchain.info("Static analysis for %s (%s, %s)" % ('MBED', target.name, toolchain_name))
  311. # Common Headers
  312. toolchain.copy_files(toolchain.scan_resources(MBED_API).headers, MBED_LIBRARIES)
  313. toolchain.copy_files(toolchain.scan_resources(MBED_HAL).headers, MBED_LIBRARIES)
  314. # Target specific sources
  315. HAL_SRC = join(MBED_TARGETS_PATH, "hal")
  316. hal_implementation = toolchain.scan_resources(HAL_SRC)
  317. # Copy files before analysis
  318. toolchain.copy_files(hal_implementation.headers + hal_implementation.hex_files, BUILD_TARGET, HAL_SRC)
  319. incdirs = toolchain.scan_resources(BUILD_TARGET)
  320. target_includes = ["-I%s" % i for i in incdirs.inc_dirs]
  321. target_includes.append("-I%s"% str(BUILD_TARGET))
  322. target_includes.append("-I%s"% str(HAL_SRC))
  323. target_c_sources = " ".join(incdirs.c_sources)
  324. target_cpp_sources = " ".join(incdirs.cpp_sources)
  325. target_macros = ["-D%s"% s for s in toolchain.get_symbols() + toolchain.macros]
  326. # Common Sources
  327. mbed_resources = toolchain.scan_resources(MBED_COMMON)
  328. # Gather include paths, c, cpp sources and macros to transfer to cppcheck command line
  329. mbed_includes = ["-I%s" % i for i in mbed_resources.inc_dirs]
  330. mbed_includes.append("-I%s"% str(BUILD_TARGET))
  331. mbed_includes.append("-I%s"% str(MBED_COMMON))
  332. mbed_includes.append("-I%s"% str(MBED_API))
  333. mbed_includes.append("-I%s"% str(MBED_HAL))
  334. mbed_c_sources = " ".join(mbed_resources.c_sources)
  335. mbed_cpp_sources = " ".join(mbed_resources.cpp_sources)
  336. target_includes = map(str.strip, target_includes)
  337. mbed_includes = map(str.strip, mbed_includes)
  338. target_macros = map(str.strip, target_macros)
  339. check_cmd = CPPCHECK_CMD
  340. check_cmd += CPPCHECK_MSG_FORMAT
  341. check_cmd += target_includes
  342. check_cmd += mbed_includes
  343. check_cmd += target_macros
  344. # We need to pass some parames via file to avoid "command line too long in some OSs"
  345. tmp_file = tempfile.NamedTemporaryFile(delete=False)
  346. tmp_file.writelines(line + '\n' for line in target_c_sources.split())
  347. tmp_file.writelines(line + '\n' for line in target_cpp_sources.split())
  348. tmp_file.writelines(line + '\n' for line in mbed_c_sources.split())
  349. tmp_file.writelines(line + '\n' for line in mbed_cpp_sources.split())
  350. tmp_file.close()
  351. check_cmd += ["--file-list=%s"% tmp_file.name]
  352. _stdout, _stderr, _rc = run_cmd_ext(check_cmd)
  353. if verbose:
  354. print _stdout
  355. print _stderr
  356. def static_analysis_scan_lib(lib_id, target, toolchain, cppcheck_cmd, cppcheck_msg_format,
  357. options=None, verbose=False, clean=False, macros=None, notify=None, jobs=1):
  358. lib = Library(lib_id)
  359. if lib.is_supported(target, toolchain):
  360. static_analysis_scan_library(lib.source_dir, lib.build_dir, target, toolchain, cppcheck_cmd, cppcheck_msg_format,
  361. lib.dependencies, options,
  362. verbose=verbose, clean=clean, macros=macros, notify=notify, jobs=jobs)
  363. else:
  364. print 'Library "%s" is not yet supported on target %s with toolchain %s'% (lib_id, target.name, toolchain)
  365. def static_analysis_scan_library(src_paths, build_path, target, toolchain_name, cppcheck_cmd, cppcheck_msg_format,
  366. dependencies_paths=None, options=None, name=None, clean=False,
  367. notify=None, verbose=False, macros=None, jobs=1):
  368. """ Function scans library (or just some set of sources/headers) for staticly detectable defects """
  369. if type(src_paths) != ListType:
  370. src_paths = [src_paths]
  371. for src_path in src_paths:
  372. if not exists(src_path):
  373. raise Exception("The library source folder does not exist: %s", src_path)
  374. # Toolchain instance
  375. toolchain = TOOLCHAIN_CLASSES[toolchain_name](target, options, macros=macros, notify=notify)
  376. toolchain.VERBOSE = verbose
  377. toolchain.jobs = jobs
  378. # The first path will give the name to the library
  379. name = basename(src_paths[0])
  380. toolchain.info("Static analysis for library %s (%s, %s)" % (name.upper(), target.name, toolchain_name))
  381. # Scan Resources
  382. resources = []
  383. for src_path in src_paths:
  384. resources.append(toolchain.scan_resources(src_path))
  385. # Dependencies Include Paths
  386. dependencies_include_dir = []
  387. if dependencies_paths is not None:
  388. for path in dependencies_paths:
  389. lib_resources = toolchain.scan_resources(path)
  390. dependencies_include_dir.extend(lib_resources.inc_dirs)
  391. # Create the desired build directory structure
  392. bin_path = join(build_path, toolchain.obj_path)
  393. mkdir(bin_path)
  394. tmp_path = join(build_path, '.temp', toolchain.obj_path)
  395. mkdir(tmp_path)
  396. # Gather include paths, c, cpp sources and macros to transfer to cppcheck command line
  397. includes = ["-I%s" % i for i in dependencies_include_dir + src_paths]
  398. c_sources = " "
  399. cpp_sources = " "
  400. macros = ['-D%s' % s for s in toolchain.get_symbols() + toolchain.macros]
  401. # Copy Headers
  402. for resource in resources:
  403. toolchain.copy_files(resource.headers, build_path, rel_path=resource.base_path)
  404. includes += ["-I%s" % i for i in resource.inc_dirs]
  405. c_sources += " ".join(resource.c_sources) + " "
  406. cpp_sources += " ".join(resource.cpp_sources) + " "
  407. dependencies_include_dir.extend(toolchain.scan_resources(build_path).inc_dirs)
  408. includes = map(str.strip, includes)
  409. macros = map(str.strip, macros)
  410. check_cmd = cppcheck_cmd
  411. check_cmd += cppcheck_msg_format
  412. check_cmd += includes
  413. check_cmd += macros
  414. # We need to pass some parameters via file to avoid "command line too long in some OSs"
  415. # Temporary file is created to store e.g. cppcheck list of files for command line
  416. tmp_file = tempfile.NamedTemporaryFile(delete=False)
  417. tmp_file.writelines(line + '\n' for line in c_sources.split())
  418. tmp_file.writelines(line + '\n' for line in cpp_sources.split())
  419. tmp_file.close()
  420. check_cmd += ["--file-list=%s"% tmp_file.name]
  421. # This will allow us to grab result from both stdio and stderr outputs (so we can show them)
  422. # We assume static code analysis tool is outputting defects on STDERR
  423. _stdout, _stderr, _rc = run_cmd_ext(check_cmd)
  424. if verbose:
  425. print _stdout
  426. print _stderr
  427. def print_build_results(result_list, build_name):
  428. """ Generate result string for build results """
  429. result = ""
  430. if result_list:
  431. result += build_name + "\n"
  432. result += "\n".join([" * %s" % f for f in result_list])
  433. result += "\n"
  434. return result
  435. def write_build_report(build_report, template_filename, filename):
  436. build_report_failing = []
  437. build_report_passing = []
  438. for report in build_report:
  439. if len(report["failing"]) > 0:
  440. build_report_failing.append(report)
  441. else:
  442. build_report_passing.append(report)
  443. env = Environment(extensions=['jinja2.ext.with_'])
  444. env.loader = FileSystemLoader('ci_templates')
  445. template = env.get_template(template_filename)
  446. with open(filename, 'w+') as f:
  447. f.write(template.render(failing_builds=build_report_failing, passing_builds=build_report_passing))