1
0

sconsui.py 14 KB

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