sconsui.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412
  1. #! /usr/bin/env python
  2. #coding=utf-8
  3. import sys
  4. py2 = py30 = py31 = False
  5. version = sys.hexversion
  6. if version >= 0x020600F0 and version < 0x03000000 :
  7. py2 = True # Python 2.6 or 2.7
  8. from Tkinter import *
  9. import ttk
  10. elif version >= 0x03000000 and version < 0x03010000 :
  11. py30 = True
  12. from tkinter import *
  13. import ttk
  14. elif version >= 0x03010000:
  15. py31 = True
  16. from tkinter import *
  17. import tkinter.ttk as ttk
  18. else:
  19. print ("""
  20. You do not have a version of python supporting ttk widgets..
  21. You need a version >= 2.6 to execute PAGE modules.
  22. """)
  23. sys.exit()
  24. import ScrolledText
  25. import tkFileDialog
  26. import tkMessageBox
  27. import os
  28. import threading
  29. import platform
  30. builder = None
  31. executor = None
  32. lock = None
  33. class CmdExecutor(threading.Thread):
  34. def __init__(self, cmd, output):
  35. threading.Thread.__init__(self)
  36. self.cmd = cmd
  37. self.child = None
  38. def run(self):
  39. global executor, builder, lock
  40. if platform.system() == 'Windows':
  41. from win32spawn import Win32Spawn
  42. subprocess = Win32Spawn(self.cmd)
  43. subprocess.start_pipe()
  44. builder.progressbar.start()
  45. while not subprocess.is_terminated or subprocess.qsize() > 0:
  46. try:
  47. line = subprocess.get(timeout=1)
  48. line = line.replace('\r', '')
  49. if line:
  50. lock.acquire()
  51. builder.output.see(END)
  52. builder.output.insert(END, line)
  53. lock.release()
  54. except:
  55. pass
  56. builder.progressbar.stop()
  57. executor = None
  58. def ExecCmd(cmd):
  59. global executor
  60. if executor:
  61. print 'cmd not exit, return'
  62. return
  63. executor = CmdExecutor(cmd, builder)
  64. executor.start()
  65. class DirSelectBox(ttk.Frame):
  66. def __init__(self, master=None, **kw):
  67. ttk.Frame.__init__(self, master, **kw)
  68. self.dir_var = StringVar()
  69. self.entry = ttk.Entry(self, textvariable = self.dir_var)
  70. self.entry.pack(fill=BOTH, expand=1,side=LEFT)
  71. self.entry.configure(width = 50)
  72. self.browser_button = ttk.Button(self, text="Browser", command=self.browser)
  73. self.browser_button.pack(side=RIGHT)
  74. def browser(self):
  75. dir = tkFileDialog.askdirectory(parent=self, title='Open directory', initialdir=self.dir_var.get())
  76. if dir != '':
  77. self.dir_var.set(dir)
  78. def set_path(self, path):
  79. path = path.replace('\\', '/')
  80. self.dir_var.set(path)
  81. def get_path(self):
  82. return self.dir_var.get()
  83. COMPILER = [
  84. ("GNU GCC", "GCC"),
  85. ("Keil ARMCC", "ARMCC"),
  86. ("IAR Compiler", "IAR"),
  87. ]
  88. IDE = [
  89. ('Keil MDK4', 'mdk4'),
  90. ('Keil MDK', 'mdk'),
  91. ('IAR Compiler', 'iar')
  92. ]
  93. class SconsUI():
  94. def __init__(self, master=None):
  95. style = ttk.Style()
  96. theme = style.theme_use()
  97. default = style.lookup(theme, 'background')
  98. master.configure(background=default)
  99. notebook = ttk.Notebook(master)
  100. notebook.pack(fill=BOTH, padx=5, pady=5)
  101. # building page
  102. page_building = ttk.Frame(notebook)
  103. notebook.add(page_building, padding=3)
  104. notebook.tab(0, text='Build', underline="-1")
  105. self.setup_building_ui(page_building)
  106. # make project page
  107. page_project = ttk.Frame(notebook)
  108. notebook.add(page_project, padding = 3)
  109. notebook.tab(1, text = 'Project', underline = '-1')
  110. self.setup_project_ui(page_project)
  111. # setting page
  112. page_setting = ttk.Frame(notebook)
  113. notebook.add(page_setting, padding = 3)
  114. notebook.tab(2, text = 'Setting', underline = '-1')
  115. self.setup_setting_ui(page_setting)
  116. padding = ttk.Frame(master)
  117. padding.pack(fill=X)
  118. quit = ttk.Button(padding, text='Quit', command = self.quit)
  119. quit.pack(side=RIGHT)
  120. # read setting
  121. self.read_setting()
  122. def read_setting(self):
  123. import platform
  124. import os
  125. home = ''
  126. if platform.system() == 'Windows':
  127. driver = os.environ['HOMEDRIVE']
  128. home = os.environ['HOMEPATH']
  129. home = os.path.join(driver, home)
  130. else:
  131. home = os.environ['HOME']
  132. setting_path = os.path.join(home, '.rtt_scons')
  133. if os.path.exists(setting_path):
  134. setting = file(os.path.join(home, '.rtt_scons'))
  135. for line in setting:
  136. line = line.replace('\n', '')
  137. line = line.replace('\r', '')
  138. if line.find('=') != -1:
  139. items = line.split('=')
  140. if items[0] == 'RTTRoot':
  141. self.RTTRoot.set_path(items[1])
  142. elif items[0] == 'BSPRoot':
  143. self.BSPRoot.set_path(items[1])
  144. elif items[0] == 'compiler':
  145. compiler = items[1]
  146. else:
  147. self.CompilersPath[items[0]].set_path(items[1])
  148. setting.close()
  149. # set RT-Thread Root Directory according environ
  150. if os.environ.has_key('RTT_ROOT'):
  151. self.RTTRoot.set_path(os.environ['RTT_ROOT'])
  152. if self.RTTRoot.get_path() == '':
  153. rtt_root = ''
  154. # detect RT-Thread directory
  155. if os.path.exists(os.path.join('..', 'include', 'rtthread.h')):
  156. rtt_root = os.path.join('..')
  157. elif os.path.exists(os.path.join('..', '..', 'include', 'rtthread.h')):
  158. rtt_root = os.path.join('..', '..')
  159. if rtt_root:
  160. self.RTTRoot.set_path(os.path.abspath(rtt_root))
  161. # detect compiler path
  162. if platform.system() == 'Windows':
  163. # Keil MDK
  164. if not self.CompilersPath['ARMCC'].get_path():
  165. if os.path.exists('C:\\Keil'):
  166. self.CompilersPath['ARMCC'].set_path('C:\\Keil')
  167. elif os.path.exists('D:\\Keil'):
  168. self.CompilersPath['ARMCC'].set_path('D:\\Keil')
  169. elif os.path.exists('E:\\Keil'):
  170. self.CompilersPath['ARMCC'].set_path('E:\\Keil')
  171. elif os.path.exists('F:\\Keil'):
  172. self.CompilersPath['ARMCC'].set_path('F:\\Keil')
  173. elif os.path.exists('G:\\Keil'):
  174. self.CompilersPath['ARMCC'].set_path('G:\\Keil')
  175. # GNU GCC
  176. if not self.CompilersPath['GCC'].get_path():
  177. paths = os.environ['PATH']
  178. paths = paths.split(';')
  179. for path in paths:
  180. if path.find('CodeSourcery') != -1:
  181. self.CompilersPath['GCC'].set_path(path)
  182. break
  183. elif path.find('GNU Tools ARM Embedded') != -1:
  184. self.CompilersPath['GCC'].set_path(path)
  185. break
  186. def save_setting(self):
  187. import platform
  188. import os
  189. home = ''
  190. if platform.system() == 'Windows':
  191. driver = os.environ['HOMEDRIVE']
  192. home = os.environ['HOMEPATH']
  193. home = os.path.join(driver, home)
  194. else:
  195. home = os.environ['HOME']
  196. setting = file(os.path.join(home, '.rtt_scons'), 'wb+')
  197. # current comiler
  198. # line = '%s=%s\n' % ('compiler', self.compilers.get()))
  199. line = '%s=%s\n' % ('compiler', 'iar')
  200. setting.write(line)
  201. # RTT Root Folder
  202. if self.RTTRoot.get_path():
  203. line = '%s=%s\n' % ('RTTRoot', self.RTTRoot.get_path())
  204. setting.write(line)
  205. # BSP Root Folder
  206. if self.BSPRoot.get_path():
  207. line = '%s=%s\n' % ('BSPRoot', self.BSPRoot.get_path())
  208. setting.write(line)
  209. for (compiler, path) in self.CompilersPath.iteritems():
  210. if path.get_path():
  211. line = '%s=%s\n' % (compiler, path.get_path())
  212. setting.write(line)
  213. setting.close()
  214. tkMessageBox.showinfo("RT-Thread SCons UI",
  215. "Save setting sucessfully")
  216. def setup_building_ui(self, frame):
  217. padding = ttk.Frame(frame)
  218. padding.pack(fill=X)
  219. button = ttk.Button(padding, text='Clean', command=self.do_clean)
  220. button.pack(side=RIGHT)
  221. button = ttk.Button(padding, text='Build', command=self.do_build)
  222. button.pack(side=RIGHT)
  223. label = ttk.Label(padding, relief = 'flat', text = 'Click Build or Clean to build or clean system -->')
  224. label.pack(side=RIGHT, ipady = 5)
  225. self.progressbar = ttk.Progressbar(frame)
  226. self.progressbar.pack(fill=X)
  227. separator = ttk.Separator(frame)
  228. separator.pack(fill=X)
  229. self.output = ScrolledText.ScrolledText(frame)
  230. self.output.pack(fill=X)
  231. def setup_project_ui(self, frame):
  232. label = ttk.Label(frame, relief = 'flat', text = 'Choose Integrated Development Environment:')
  233. label.pack(fill=X, pady = 5)
  234. separator = ttk.Separator(frame)
  235. separator.pack(fill=X)
  236. self.ide = StringVar()
  237. self.ide.set("mdk4") # initialize
  238. for text,mode in IDE:
  239. radiobutton = ttk.Radiobutton(frame, text=text, variable = self.ide, value = mode)
  240. radiobutton.pack(fill=X, padx=10)
  241. bottom = ttk.Frame(frame)
  242. bottom.pack(side=BOTTOM, fill=X)
  243. button = ttk.Button(bottom, text="Make Project", command = self.do_make_project)
  244. button.pack(side=RIGHT, padx = 10, pady = 10)
  245. def setup_setting_ui(self, frame):
  246. row = 0
  247. label = ttk.Label (frame, relief = 'flat', text='RT-Thread Root Folder:')
  248. label.grid(row=row, column=0,ipadx=5, ipady=5, padx = 5)
  249. self.RTTRoot = DirSelectBox(frame)
  250. self.RTTRoot.grid(row=row, column=1, sticky=E+W)
  251. row = row + 1
  252. label = ttk.Label (frame, relief = 'flat', text='Board Support Folder:')
  253. label.grid(row=row, column=0,ipadx=5, ipady=5, padx = 5)
  254. self.BSPRoot = DirSelectBox(frame)
  255. self.BSPRoot.grid(row=row, column=1, sticky=E+W)
  256. row = row + 1
  257. label = ttk.Label (frame, relief='flat', text='Toolchain:')
  258. label.grid(row=row, column=0,ipadx=5, ipady=5, sticky=E+W)
  259. row = row + 1
  260. separator = ttk.Separator(frame)
  261. separator.grid(row = row, column = 0, columnspan = 2, sticky = E+W)
  262. row = row + 1
  263. self.compilers = StringVar()
  264. self.compilers.set("GCC") # initialize
  265. self.CompilersPath = {}
  266. for text,compiler in COMPILER:
  267. radiobutton = ttk.Radiobutton(frame, text=text, variable = self.compilers, value = compiler)
  268. radiobutton.grid(row=row, column = 0, sticky = W, ipadx = 5, ipady = 5, padx = 20)
  269. self.CompilersPath[compiler] = DirSelectBox(frame)
  270. self.CompilersPath[compiler].grid(row=row, column=1, sticky=E+W)
  271. row = row + 1
  272. button = ttk.Button(frame, text='Save Setting', command = self.save_setting)
  273. button.grid(row = row, column = 1, sticky = E)
  274. row = row + 1
  275. def prepare_build(self):
  276. # get compiler
  277. compiler = self.compilers.get()
  278. if compiler == 'GCC':
  279. compiler = 'gcc'
  280. elif compiler == 'ARMCC':
  281. compiler = 'keil'
  282. elif compiler == 'IAR':
  283. compiler = 'iar'
  284. # get RTT Root
  285. rtt_root = self.RTTRoot.get_path()
  286. # get Compiler path
  287. exec_path = self.CompilersPath[self.compilers.get()].get_path()
  288. command = ''
  289. os.environ['RTT_ROOT'] = rtt_root
  290. os.environ['RTT_CC'] = compiler
  291. os.environ['RTT_EXEC_PATH'] = exec_path
  292. return command
  293. def do_build(self):
  294. self.prepare_build()
  295. command = 'scons'
  296. bsp = self.BSPRoot.get_path()
  297. os.chdir(bsp)
  298. self.output.delete(1.0, END)
  299. self.output.insert(END, 'building project...\n')
  300. ExecCmd(command)
  301. def do_clean(self):
  302. self.prepare_build()
  303. command = 'scons -c'
  304. bsp = self.BSPRoot.get_path()
  305. os.chdir(bsp)
  306. self.output.delete(1.0, END)
  307. self.output.insert(END, 'clean project...\n')
  308. ExecCmd(command)
  309. def do_make_project(self):
  310. ide = self.ide.get()
  311. self.prepare_build()
  312. command = 'scons --target=%s -s' % ide
  313. bsp = self.BSPRoot.get_path()
  314. os.chdir(bsp)
  315. self.output.delete(1.0, END)
  316. self.output.insert(END, 'make project ...\n')
  317. ExecCmd(command)
  318. def quit(self):
  319. exit(0)
  320. def StartSConsUI(path=None):
  321. global val, root, builder, lock
  322. root = Tk()
  323. root.title('RT-Thread SCons UI')
  324. #root.geometrygeometry('590x510+50+50')
  325. lock = threading.RLock()
  326. builder = SconsUI(root)
  327. if path:
  328. builder.BSPRoot.set_path(path)
  329. root.mainloop()
  330. if __name__ == '__main__':
  331. StartSConsUI()