rakefile_helper.rb 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. # ==========================================
  2. # Unity Project - A Test Framework for C
  3. # Copyright (c) 2007 Mike Karlesky, Mark VanderVoord, Greg Williams
  4. # [Released under MIT License. Please refer to license.txt for details]
  5. # ==========================================
  6. require 'fileutils'
  7. require_relative '../../auto/unity_test_summary'
  8. require_relative '../../auto/generate_test_runner'
  9. require_relative '../../auto/colour_reporter'
  10. require_relative '../../auto/yaml_helper'
  11. C_EXTENSION = '.c'.freeze
  12. def load_configuration(config_file)
  13. $cfg_file = config_file
  14. $cfg = YamlHelper.load_file($cfg_file)
  15. end
  16. def configure_clean
  17. CLEAN.include("#{$cfg['compiler']['build_path']}*.*") unless $cfg['compiler']['build_path'].nil?
  18. end
  19. def configure_toolchain(config_file = DEFAULT_CONFIG_FILE)
  20. config_file += '.yml' unless config_file =~ /\.yml$/
  21. load_configuration(config_file)
  22. configure_clean
  23. end
  24. def unit_test_files
  25. path = "#{$cfg['compiler']['unit_tests_path']}Test*#{C_EXTENSION}"
  26. path.tr!('\\', '/')
  27. FileList.new(path)
  28. end
  29. def local_include_dirs
  30. include_dirs = $cfg['compiler']['includes']['items'].dup
  31. include_dirs.delete_if { |dir| dir.is_a?(Array) }
  32. include_dirs
  33. end
  34. def extract_headers(filename)
  35. includes = []
  36. lines = File.readlines(filename)
  37. lines.each do |line|
  38. m = line.match(/^\s*#include\s+"\s*(.+\.[hH])\s*"/)
  39. includes << m[1] unless m.nil?
  40. end
  41. includes
  42. end
  43. def find_source_file(header, paths)
  44. paths.each do |dir|
  45. src_file = dir + header.ext(C_EXTENSION)
  46. return src_file if File.exist?(src_file)
  47. end
  48. nil
  49. end
  50. def tackit(strings)
  51. if strings.is_a?(Array)
  52. "\"#{strings.join}\""
  53. else
  54. strings
  55. end
  56. end
  57. def squash(prefix, items)
  58. result = ''
  59. items.each { |item| result += " #{prefix}#{tackit(item)}" }
  60. result
  61. end
  62. def build_compiler_fields
  63. command = tackit($cfg['compiler']['path'])
  64. defines = if $cfg['compiler']['defines']['items'].nil?
  65. ''
  66. else
  67. squash($cfg['compiler']['defines']['prefix'], $cfg['compiler']['defines']['items'])
  68. end
  69. options = squash('', $cfg['compiler']['options'])
  70. includes = squash($cfg['compiler']['includes']['prefix'], $cfg['compiler']['includes']['items'])
  71. includes = includes.gsub(/\\ /, ' ').gsub(/\\"/, '"').gsub(/\\$/, '') # Remove trailing slashes (for IAR)
  72. { command: command, defines: defines, options: options, includes: includes }
  73. end
  74. def compile(file, _defines = [])
  75. compiler = build_compiler_fields
  76. cmd_str = "#{compiler[:command]}#{compiler[:defines]}#{compiler[:options]}#{compiler[:includes]} #{file} " \
  77. "#{$cfg['compiler']['object_files']['prefix']}#{$cfg['compiler']['object_files']['destination']}"
  78. obj_file = "#{File.basename(file, C_EXTENSION)}#{$cfg['compiler']['object_files']['extension']}"
  79. execute(cmd_str + obj_file)
  80. obj_file
  81. end
  82. def build_linker_fields
  83. command = tackit($cfg['linker']['path'])
  84. options = if $cfg['linker']['options'].nil?
  85. ''
  86. else
  87. squash('', $cfg['linker']['options'])
  88. end
  89. includes = if $cfg['linker']['includes'].nil? || $cfg['linker']['includes']['items'].nil?
  90. ''
  91. else
  92. squash($cfg['linker']['includes']['prefix'], $cfg['linker']['includes']['items'])
  93. end.gsub(/\\ /, ' ').gsub(/\\"/, '"').gsub(/\\$/, '') # Remove trailing slashes (for IAR)
  94. { command: command, options: options, includes: includes }
  95. end
  96. def link_it(exe_name, obj_list)
  97. linker = build_linker_fields
  98. cmd_str = "#{linker[:command]}#{linker[:options]}#{linker[:includes]}"
  99. cmd_str += " #{(obj_list.map { |obj| "#{$cfg['linker']['object_files']['path']}#{obj}" }).join(' ')}"
  100. cmd_str += " #{$cfg['linker']['bin_files']['prefix']} "
  101. cmd_str += $cfg['linker']['bin_files']['destination']
  102. cmd_str += exe_name + $cfg['linker']['bin_files']['extension']
  103. execute(cmd_str)
  104. end
  105. def build_simulator_fields
  106. return nil if $cfg['simulator'].nil?
  107. command = if $cfg['simulator']['path'].nil?
  108. ''
  109. else
  110. "#{tackit($cfg['simulator']['path'])} "
  111. end
  112. pre_support = if $cfg['simulator']['pre_support'].nil?
  113. ''
  114. else
  115. squash('', $cfg['simulator']['pre_support'])
  116. end
  117. post_support = if $cfg['simulator']['post_support'].nil?
  118. ''
  119. else
  120. squash('', $cfg['simulator']['post_support'])
  121. end
  122. { command: command, pre_support: pre_support, post_support: post_support }
  123. end
  124. def execute(command_string, verbose = true, raise_on_fail = true)
  125. report command_string
  126. output = `#{command_string}`.chomp
  127. report(output) if verbose && !output.nil? && !output.empty?
  128. if !$?.nil? && !$?.exitstatus.zero? && raise_on_fail
  129. raise "Command failed. (Returned #{$?.exitstatus})"
  130. end
  131. output
  132. end
  133. def report_summary
  134. summary = UnityTestSummary.new
  135. summary.root = __dir__
  136. results_glob = "#{$cfg['compiler']['build_path']}*.test*"
  137. results_glob.tr!('\\', '/')
  138. results = Dir[results_glob]
  139. summary.targets = results
  140. summary.run
  141. fail_out 'FAIL: There were failures' if summary.failures > 0
  142. end
  143. def run_tests(test_files)
  144. report 'Running system tests...'
  145. # Tack on TEST define for compiling unit tests
  146. load_configuration($cfg_file)
  147. test_defines = ['TEST']
  148. $cfg['compiler']['defines']['items'] = [] if $cfg['compiler']['defines']['items'].nil?
  149. $cfg['compiler']['defines']['items'] << 'TEST'
  150. include_dirs = local_include_dirs
  151. # Build and execute each unit test
  152. test_files.each do |test|
  153. obj_list = []
  154. # Detect dependencies and build required required modules
  155. extract_headers(test).each do |header|
  156. # Compile corresponding source file if it exists
  157. src_file = find_source_file(header, include_dirs)
  158. obj_list << compile(src_file, test_defines) unless src_file.nil?
  159. end
  160. # Build the test runner (generate if configured to do so)
  161. test_base = File.basename(test, C_EXTENSION)
  162. runner_name = "#{test_base}_Runner.c"
  163. if $cfg['compiler']['runner_path'].nil?
  164. runner_path = $cfg['compiler']['build_path'] + runner_name
  165. test_gen = UnityTestRunnerGenerator.new($cfg_file)
  166. test_gen.run(test, runner_path)
  167. else
  168. runner_path = $cfg['compiler']['runner_path'] + runner_name
  169. end
  170. obj_list << compile(runner_path, test_defines)
  171. # Build the test module
  172. obj_list << compile(test, test_defines)
  173. # Link the test executable
  174. link_it(test_base, obj_list)
  175. # Execute unit test and generate results file
  176. simulator = build_simulator_fields
  177. executable = $cfg['linker']['bin_files']['destination'] + test_base + $cfg['linker']['bin_files']['extension']
  178. cmd_str = if simulator.nil?
  179. executable
  180. else
  181. "#{simulator[:command]} #{simulator[:pre_support]} #{executable} #{simulator[:post_support]}"
  182. end
  183. output = execute(cmd_str, true, false)
  184. test_results = $cfg['compiler']['build_path'] + test_base
  185. test_results += if output.match(/OK$/m).nil?
  186. '.testfail'
  187. else
  188. '.testpass'
  189. end
  190. File.open(test_results, 'w') { |f| f.print output }
  191. end
  192. end
  193. def build_application(main)
  194. report 'Building application...'
  195. obj_list = []
  196. load_configuration($cfg_file)
  197. main_path = $cfg['compiler']['source_path'] + main + C_EXTENSION
  198. # Detect dependencies and build required required modules
  199. include_dirs = get_local_include_dirs
  200. extract_headers(main_path).each do |header|
  201. src_file = find_source_file(header, include_dirs)
  202. obj_list << compile(src_file) unless src_file.nil?
  203. end
  204. # Build the main source file
  205. main_base = File.basename(main_path, C_EXTENSION)
  206. obj_list << compile(main_path)
  207. # Create the executable
  208. link_it(main_base, obj_list)
  209. end
  210. def fail_out(msg)
  211. puts msg
  212. puts 'Not returning exit code so continuous integration can pass'
  213. # exit(-1) # Only removed to pass example_3, which has failing tests on purpose.
  214. # Still fail if the build fails for any other reason.
  215. end