code_builder.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. #! /usr/bin/env python
  2. # -*- coding: UTF-8 -*-
  3. #——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
  4. import sys, os, subprocess, shutil, json
  5. #——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
  6. import makefile
  7. import common_definitions
  8. import download_and_install_gccarm
  9. import teensy_cli_loader_builder
  10. import dev_platform
  11. #——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
  12. # Run process and wait for termination *
  13. #——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
  14. def runProcess (command) :
  15. returncode = subprocess.call (command)
  16. if returncode != 0 :
  17. print (makefile.BOLD_RED () + "Error " + str (returncode) + makefile.ENDC ())
  18. sys.exit (returncode)
  19. #——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
  20. # Run process, get output and wait for termination *
  21. #——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
  22. def runProcessAndGetOutput (command) :
  23. result = ""
  24. childProcess = subprocess.Popen (command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
  25. while True:
  26. out = childProcess.stdout.read(1)
  27. if out == '' and childProcess.poll() != None:
  28. break
  29. if out != '':
  30. result += out
  31. #--- Wait for subprocess termination
  32. if childProcess.poll () == None :
  33. childProcess.wait ()
  34. if childProcess.returncode != 0 :
  35. print (makefile.BOLD_RED () + "Error " + str (childProcess.returncode) + makefile.ENDC ())
  36. sys.exit (childProcess.returncode)
  37. return result
  38. #——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
  39. # dictionaryFromJsonFile *
  40. #——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
  41. def dictionaryFromJsonFile (file) :
  42. result = {}
  43. if not os.path.exists (os.path.abspath (file)):
  44. print (makefile.BOLD_RED () + "The '" + file + "' file does not exist" + makefile.ENDC ())
  45. sys.exit (1)
  46. try:
  47. f = open (file, "r")
  48. result = json.loads (f.read ())
  49. f.close ()
  50. except:
  51. print (makefile.BOLD_RED () + "Syntax error in " + file + makefile.ENDC ())
  52. sys.exit (1)
  53. return result
  54. #——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
  55. # buildCode *
  56. #——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*
  57. def buildCode (GOAL, projectDir, maxConcurrentJobs, showCommand):
  58. #--------------------------------------------------------------------------- Prepare
  59. os.chdir (projectDir)
  60. make = makefile.Make (GOAL)
  61. make.mMacTextEditor = "TextWrangler" # "Atom"
  62. allGoal = []
  63. #--------------------------------------------------------------------------- Install Linux UDEV rules ?
  64. platform = dev_platform.getPlatform ()
  65. if (platform == "linux") or (platform == "linux32") :
  66. import udev_on_linux
  67. udev_on_linux.installUDEVrulesOnLinux ()
  68. #--------------------------------------------------------------------------- Install compiler ?
  69. BASE_NAME = "arm-none-eabi"
  70. TOOL_DIR = download_and_install_gccarm.installGCCARMandGetToolDirectory ()
  71. AS_TOOL_WITH_OPTIONS = [TOOL_DIR + "/bin/" + BASE_NAME + "-as", "-mthumb", "-mcpu=cortex-m4"]
  72. COMPILER_TOOL_WITH_OPTIONS = [TOOL_DIR + "/bin/" + BASE_NAME + "-gcc", "-mthumb", "-mcpu=cortex-m4"]
  73. LD_TOOL_WITH_OPTIONS = [TOOL_DIR + "/bin/" + BASE_NAME + "-ld"]
  74. LD_TOOL_WITH_OPTIONS = COMPILER_TOOL_WITH_OPTIONS
  75. OBJCOPY_TOOL_WITH_OPTIONS = [TOOL_DIR + "/bin/" + BASE_NAME + "-objcopy"]
  76. DISPLAY_OBJ_SIZE_TOOL = [TOOL_DIR + "/bin/" + BASE_NAME + "-size"]
  77. OBJDUMP_TOOL = TOOL_DIR + "/bin/" + BASE_NAME + "-objdump"
  78. #--------------------------------------------------------------------------- Install Teensy loader CLI ?
  79. TEENSY_CLI_LOADER_PATH = teensy_cli_loader_builder.buildAndGetPath (TOOL_DIR + "/bin")
  80. #--------------------------------------------------------------------------- Analyze JSON file
  81. print (makefile.BOLD_GREEN () + "--- Making " + projectDir + makefile.ENDC ())
  82. dictionaire = dictionaryFromJsonFile (projectDir + "/makefile.json")
  83. #--- TEENSY
  84. linkerScript = ""
  85. teensyName = ""
  86. if dictionaire.has_key ("TEENSY") :
  87. TeensyKey = dictionaire ["TEENSY"]
  88. if (TeensyKey == "3.1") or (TeensyKey == "3.2") :
  89. teensyName = "TEENSY31"
  90. linkerScript = "teensy-3-1.ld"
  91. elif (TeensyKey == "3.5") :
  92. teensyName = "TEENSY35"
  93. linkerScript = "teensy-3-5.ld"
  94. elif (TeensyKey == "3.6") :
  95. teensyName = "TEENSY36"
  96. linkerScript = "teensy-3-6.ld"
  97. else:
  98. make.enterError ('In the makefile.json file, the "TEENSY" key value is invalid (possible values: "3.1", "3.2", "3.5" or "3.6").')
  99. else:
  100. make.enterError ('The makefile.json file does not have a "TEENSY" key (possible values: "3.1", "3.2", "3.5" or "3.6").')
  101. #--- ASSERTION_GENERATION
  102. ASSERTION_GENERATION = False
  103. if dictionaire.has_key ("ASSERTION-GENERATION") and dictionaire ["ASSERTION-GENERATION"] :
  104. ASSERTION_GENERATION = True
  105. #--- CPU_MHZ
  106. CPU_MHZ = 0
  107. if dictionaire.has_key ("CPU-MHZ") :
  108. CPU_MHZ = dictionaire ["CPU-MHZ"]
  109. #--- SOURCE_FILE_DIRECTORIES
  110. SOURCE_FILE_DIRECTORIES = []
  111. if dictionaire.has_key ("SOURCE-DIR") :
  112. SOURCE_FILE_DIRECTORIES = dictionaire ["SOURCE-DIR"]
  113. #--- GROUP_SOURCES
  114. GROUP_SOURCES = False
  115. if dictionaire.has_key ("GROUP-SOURCES") :
  116. GROUP_SOURCES = dictionaire ["GROUP-SOURCES"]
  117. #--- TASK_COUNT
  118. TASK_COUNT = "0" # Means TASK_COUNT is not defined by JSON file
  119. if dictionaire.has_key ("TASK-COUNT") :
  120. TASK_COUNT = str (dictionaire ["TASK-COUNT"])
  121. #--- LTO
  122. usesLTO = False
  123. if dictionaire.has_key ("LTO") and dictionaire ["LTO"] :
  124. usesLTO = True
  125. #--- SERVICE
  126. serviceScheme = ""
  127. if dictionaire.has_key ("SERVICE-SCHEME") :
  128. serviceScheme = dictionaire ["SERVICE-SCHEME"]
  129. #--- SECTION
  130. sectionScheme = ""
  131. if dictionaire.has_key ("SECTION-SCHEME") :
  132. sectionScheme = dictionaire ["SECTION-SCHEME"]
  133. #--------------------------------------------------------------------------- Directories
  134. BUILD_DIR = common_definitions.buildDirectory ()
  135. GENERATED_SOURCE_DIR = common_definitions.generatedSourceDirectory ()
  136. PRODUCT_DIR = common_definitions.productDirectory ()
  137. ASBUILD_DIR = common_definitions.asDirectory ()
  138. #--------------------------------------------------------------------------- Build source lists
  139. includeDirsInCompilerCommand = ["-I", GENERATED_SOURCE_DIR, "-I", projectDir]
  140. H_SOURCE_LIST = []
  141. CPP_SOURCE_LIST = []
  142. S_SOURCE_LIST = []
  143. for f in SOURCE_FILE_DIRECTORIES :
  144. for root, dirs, files in os.walk (f) :
  145. includeDirsInCompilerCommand += ["-I", root]
  146. for name in files:
  147. sourcePath = os.path.join (root, name)
  148. (b, extension) = os.path.splitext (sourcePath)
  149. if extension == ".cpp" :
  150. CPP_SOURCE_LIST.append (sourcePath)
  151. elif extension == ".h" :
  152. H_SOURCE_LIST.append (sourcePath)
  153. elif extension == ".s" :
  154. S_SOURCE_LIST.append (sourcePath)
  155. elif extension != "" : # Ceci permet d'ignorer les fichés cachés (dont les noms commencent par un point)
  156. print (makefile.MAGENTA () + makefile.BOLD () + "Note: unhandled file " + sourcePath + makefile.ENDC ())
  157. #--------------------------------------------------------------------------- Build base header file
  158. baseHeader_file = GENERATED_SOURCE_DIR + "/base.h"
  159. H_SOURCE_LIST.insert (0, baseHeader_file)
  160. rule = makefile.Rule ([baseHeader_file], "Build base header file")
  161. rule.mOpenSourceOnError = False
  162. rule.mDependences.append ("makefile.json")
  163. rule.mCommand += ["../dev-files/build_base_header_file.py", baseHeader_file, str (CPU_MHZ), TASK_COUNT, teensyName, "1" if ASSERTION_GENERATION else "0"]
  164. rule.mPriority = -1
  165. make.addRule (rule)
  166. #--------------------------------------------------------------------------- Build all header file
  167. allHeadersSecondaryDependenceFile = BUILD_DIR + "/all-headers.dep"
  168. allHeaders_file = GENERATED_SOURCE_DIR + "/all-headers.h"
  169. rule = makefile.Rule ([allHeaders_file, allHeadersSecondaryDependenceFile], "Build all headers file")
  170. rule.mOpenSourceOnError = False
  171. rule.mDependences.append ("makefile.json")
  172. rule.mDependences += H_SOURCE_LIST
  173. rule.mCommand += ["../dev-files/build_all_header_file.py", allHeaders_file, allHeadersSecondaryDependenceFile]
  174. rule.mCommand += H_SOURCE_LIST
  175. rule.enterSecondaryDependanceFile (allHeadersSecondaryDependenceFile, make)
  176. rule.mPriority = -1
  177. make.addRule (rule)
  178. #--------------------------------------------------------------------------- Build interrupt handler files
  179. interruptHandlerSFile = GENERATED_SOURCE_DIR + "/interrupt-handlers.s"
  180. interruptHandlerCppFile = GENERATED_SOURCE_DIR + "/interrupt-handler-helper.cpp"
  181. S_SOURCE_LIST.append (interruptHandlerSFile)
  182. CPP_SOURCE_LIST.append (interruptHandlerCppFile)
  183. rule = makefile.Rule ([interruptHandlerSFile, interruptHandlerCppFile], "Build interrupt files")
  184. rule.mOpenSourceOnError = False
  185. rule.mDependences += H_SOURCE_LIST
  186. rule.mDependences.append ("makefile.json")
  187. rule.mDependences.append ("../dev-files/build_interrupt_handlers.py")
  188. rule.mCommand += ["../dev-files/build_interrupt_handlers.py"]
  189. rule.mCommand += [interruptHandlerCppFile]
  190. rule.mCommand += [interruptHandlerSFile]
  191. rule.mCommand += [serviceScheme]
  192. rule.mCommand += [sectionScheme]
  193. rule.mCommand += H_SOURCE_LIST
  194. rule.mPriority = -1
  195. make.addRule (rule)
  196. #--------------------------------------------------------------------------- Group sources ?
  197. if GROUP_SOURCES :
  198. allSourceFile = GENERATED_SOURCE_DIR + "/all-sources.cpp"
  199. rule = makefile.Rule ([allSourceFile], "Group all sources")
  200. rule.mOpenSourceOnError = False
  201. rule.mDependences += CPP_SOURCE_LIST
  202. rule.mDependences.append ("makefile.json")
  203. rule.mCommand += ["../dev-files/build_grouped_sources.py", allSourceFile]
  204. rule.mCommand += CPP_SOURCE_LIST
  205. rule.mPriority = -1
  206. make.addRule (rule)
  207. CPP_SOURCE_LIST = [allSourceFile]
  208. #--------------------------------------------------------------------------- Build makefile rules
  209. objectFileList = []
  210. asObjectFileList = []
  211. #--- CPP source files
  212. for sourcePath in CPP_SOURCE_LIST :
  213. source = os.path.basename (sourcePath)
  214. objectFile = BUILD_DIR + "/" + source + ".o"
  215. objectFileForChecking = BUILD_DIR + "/" + source + ".check.o"
  216. asObjectFile = BUILD_DIR + "/" + source + ".s"
  217. #--- Checking source
  218. rule = makefile.Rule ([objectFileForChecking], "Checking " + source)
  219. rule.mOpenSourceOnError = False
  220. rule.mDependences.append (allHeaders_file)
  221. rule.mDependences.append (sourcePath)
  222. rule.mDependences.append ("makefile.json")
  223. rule.enterSecondaryDependanceFile (objectFileForChecking + ".dep", make)
  224. rule.mCommand += COMPILER_TOOL_WITH_OPTIONS
  225. rule.mCommand += common_definitions.checkModeOptions ()
  226. rule.mCommand += common_definitions.C_Cpp_optimizationOptions ()
  227. rule.mCommand += common_definitions.Cpp_actualOptions (False)
  228. rule.mCommand += ["-c", sourcePath]
  229. rule.mCommand += ["-o", objectFileForChecking]
  230. rule.mCommand += ["-DSTATIC="]
  231. rule.mCommand += includeDirsInCompilerCommand
  232. rule.mCommand += ["-MD", "-MP", "-MF", objectFileForChecking + ".dep"]
  233. make.addRule (rule)
  234. rule.mPriority = -1
  235. allGoal.append (objectFileForChecking)
  236. #--- Compile source
  237. rule = makefile.Rule ([objectFile], "Compiling " + source)
  238. rule.mOpenSourceOnError = False
  239. rule.mCommand += COMPILER_TOOL_WITH_OPTIONS
  240. rule.mCommand += common_definitions.C_Cpp_optimizationOptions ()
  241. rule.mCommand += common_definitions.Cpp_actualOptions (usesLTO)
  242. rule.mCommand += ["-g"]
  243. rule.mCommand += ["-c", sourcePath]
  244. rule.mCommand += ["-o", objectFile]
  245. rule.mCommand += ["-DSTATIC=static __attribute__((unused))"] if GROUP_SOURCES else ["-DSTATIC="]
  246. rule.mCommand += includeDirsInCompilerCommand
  247. rule.mCommand += ["-MD", "-MP", "-MF", objectFile + ".dep"]
  248. rule.mDependences.append (allHeaders_file)
  249. rule.mDependences.append (sourcePath)
  250. rule.mDependences.append ("makefile.json")
  251. rule.enterSecondaryDependanceFile (objectFile + ".dep", make)
  252. make.addRule (rule)
  253. objectFileList.append (objectFile)
  254. #--- objdump python source
  255. objdumpPythonFile = BUILD_DIR + "/" + source + ".objdump.py"
  256. rule = makefile.Rule ([objdumpPythonFile], "Building " + source + ".objdump.py")
  257. rule.mDependences.append (objectFile)
  258. rule.mDependences.append ("makefile.json")
  259. rule.mCommand += ["../dev-files/build_objdump.py", OBJDUMP_TOOL, source, objdumpPythonFile]
  260. rule.mPriority = -1
  261. make.addRule (rule)
  262. allGoal.append (objdumpPythonFile)
  263. #--- AS rule
  264. rule = makefile.Rule ([asObjectFile], "Compiling -> s " + source)
  265. rule.mOpenSourceOnError = False
  266. rule.mCommand += COMPILER_TOOL_WITH_OPTIONS
  267. rule.mCommand += common_definitions.C_Cpp_optimizationOptions ()
  268. rule.mCommand += common_definitions.Cpp_actualOptions (usesLTO)
  269. rule.mCommand += ["-S", sourcePath]
  270. rule.mCommand += ["-o", asObjectFile]
  271. rule.mCommand += ["-DSTATIC="]
  272. rule.mCommand += includeDirsInCompilerCommand
  273. rule.mCommand += ["-MD", "-MP", "-MF", asObjectFile + ".dep"]
  274. rule.mDependences.append (sourcePath)
  275. rule.mDependences.append (allHeaders_file)
  276. rule.mDependences.append ("makefile.json")
  277. rule.enterSecondaryDependanceFile (asObjectFile + ".dep", make)
  278. make.addRule (rule)
  279. #--- AS rule, getting output assembler file
  280. listingFile = ASBUILD_DIR + "/" + source + ".s.list"
  281. rule = makefile.Rule ([listingFile], "Assembling -> listing " + source)
  282. rule.mOpenSourceOnError = False
  283. rule.mCommand += AS_TOOL_WITH_OPTIONS
  284. rule.mCommand += [asObjectFile]
  285. rule.mCommand += ["-o", "/dev/null"]
  286. rule.mCommand += ["-aln=" + listingFile]
  287. rule.mDependences.append (asObjectFile)
  288. rule.mDependences.append (allHeaders_file)
  289. rule.mDependences.append ("makefile.json")
  290. make.addRule (rule)
  291. asObjectFileList.append (listingFile)
  292. #-- Add ARM S files
  293. for sourcePath in S_SOURCE_LIST :
  294. source = os.path.basename (sourcePath)
  295. objectFile = BUILD_DIR + "/" + source + ".o"
  296. objectFileForChecking = BUILD_DIR + "/" + source + ".check.o"
  297. asObjectFile = ASBUILD_DIR + "/" + source + ".s"
  298. if sourcePath != "" :
  299. rule = makefile.Rule ([objectFile], "Assembling " + source)
  300. rule.mOpenSourceOnError = False
  301. rule.mCommand += AS_TOOL_WITH_OPTIONS
  302. rule.mCommand += [sourcePath]
  303. rule.mCommand += ["-o", objectFile]
  304. rule.mCommand += includeDirsInCompilerCommand
  305. rule.mCommand += ["--MD", objectFile + ".dep"]
  306. rule.mDependences.append (sourcePath)
  307. rule.mDependences.append ("makefile.json")
  308. rule.enterSecondaryDependanceFile (objectFile + ".dep", make)
  309. make.addRule (rule)
  310. objectFileList.append (objectFile)
  311. #--- Add listing file
  312. listingFile = ASBUILD_DIR + "/" + source + ".list"
  313. rule = makefile.Rule ([listingFile], "Assembling -> listing " + source)
  314. rule.mOpenSourceOnError = False
  315. rule.mCommand += AS_TOOL_WITH_OPTIONS
  316. rule.mCommand += [sourcePath]
  317. rule.mCommand += ["-o", "/dev/null"]
  318. rule.mCommand += ["-aln=" + listingFile]
  319. rule.mDependences.append (sourcePath)
  320. rule.mDependences.append ("makefile.json")
  321. make.addRule (rule)
  322. asObjectFileList.append (listingFile)
  323. #--------------------------------------------------------------------------- Link for internal flash
  324. PRODUCT_INTERNAL_FLASH = PRODUCT_DIR + "/product"
  325. LINKER_SCRIPT_INTERNAL_FLASH = "../dev-files/" + linkerScript
  326. allGoal.append (PRODUCT_INTERNAL_FLASH + ".elf")
  327. #--- Add link rule
  328. rule = makefile.Rule ([PRODUCT_INTERNAL_FLASH + ".elf"], "Linking " + PRODUCT_INTERNAL_FLASH + ".elf")
  329. rule.mDependences += objectFileList
  330. rule.mDependences.append (LINKER_SCRIPT_INTERNAL_FLASH)
  331. rule.mDependences.append ("makefile.json")
  332. rule.mCommand += LD_TOOL_WITH_OPTIONS
  333. rule.mCommand += objectFileList
  334. rule.mCommand += ["-T" + LINKER_SCRIPT_INTERNAL_FLASH]
  335. rule.mCommand.append ("-Wl,-Map=" + PRODUCT_INTERNAL_FLASH + ".map")
  336. rule.mCommand += common_definitions.commonLinkerFlags (usesLTO)
  337. rule.mCommand += ["-o", PRODUCT_INTERNAL_FLASH + ".elf"]
  338. make.addRule (rule)
  339. #--- Add hex rule
  340. allGoal.append (PRODUCT_INTERNAL_FLASH + ".hex")
  341. rule = makefile.Rule ([PRODUCT_INTERNAL_FLASH + ".hex"], "Hexing " + PRODUCT_INTERNAL_FLASH + ".hex")
  342. rule.mDependences.append (PRODUCT_INTERNAL_FLASH + ".elf")
  343. rule.mDependences.append ("makefile.json")
  344. rule.mCommand += OBJCOPY_TOOL_WITH_OPTIONS
  345. rule.mCommand.append ("-O")
  346. rule.mCommand.append ("ihex")
  347. rule.mCommand.append (PRODUCT_INTERNAL_FLASH + ".elf")
  348. rule.mCommand.append (PRODUCT_INTERNAL_FLASH + ".hex")
  349. make.addRule (rule)
  350. #--------------------------------------------------------------------------- Goals
  351. make.addGoal ("all", allGoal, "Build all")
  352. make.addGoal ("run", allGoal, "Building all and run")
  353. make.addGoal ("view-hex", allGoal, "Building all and show hex")
  354. make.addGoal ("display-obj-size", allGoal, "Build binaries and display object sizes")
  355. make.addGoal ("as", asObjectFileList, "Compile C and C++ to assembly")
  356. #--------------------------------------------------------------------------- Run jobs
  357. #make.printRules ()
  358. #make.checkRules ()
  359. # make.writeRuleDependancesInDotFile ("dependances.dot")
  360. make.runGoal (maxConcurrentJobs, showCommand)
  361. #--------------------------------------------------------------------------- Ok ?
  362. make.printErrorCountAndExitOnError ()
  363. #---------------------------------------------------------------------------- "display-obj-size"
  364. if GOAL == "display-obj-size" :
  365. makefile.runCommand (DISPLAY_OBJ_SIZE_TOOL + objectFileList + ["-t"], "Display Object Size", False, showCommand)
  366. #---------------------------------------------------------------------------- "All" or "run"
  367. if (GOAL == "all") or (GOAL == "run") or (GOAL == "view-hex") :
  368. s = runProcessAndGetOutput (DISPLAY_OBJ_SIZE_TOOL + ["-t"] + [PRODUCT_INTERNAL_FLASH + ".elf"])
  369. secondLine = s.split('\n')[1]
  370. numbers = [int(s) for s in secondLine.split() if s.isdigit()]
  371. print (" ROM code: " + str (numbers [0]) + " bytes")
  372. print (" ROM data: " + str (numbers [1]) + " bytes")
  373. print (" RAM + STACK: " + str (numbers [2]) + " bytes")
  374. #----------------------------------------------- Run ?
  375. if GOAL == "run":
  376. FLASH_TEENSY = [TEENSY_CLI_LOADER_PATH, "-w", "-v", "-mmcu=TEENSY36"]
  377. print (makefile.BOLD_BLUE () + "Loading Teensy..." + makefile.ENDC ())
  378. runProcess (FLASH_TEENSY + [PRODUCT_INTERNAL_FLASH + ".hex"])
  379. print (makefile.BOLD_GREEN () + "Success" + makefile.ENDC ())
  380. elif GOAL == "view-hex":
  381. print (makefile.BOLD_GREEN () + "View hex..." + makefile.ENDC ())
  382. scriptDir = os.path.dirname (os.path.abspath (__file__))
  383. runProcess (["python", scriptDir+ "/view-hex.py", PRODUCT_INTERNAL_FLASH + ".hex"])
  384. #——————————————————————————————————————————————————————————————————————————————————————————————————————————————————————*