|
@@ -0,0 +1,409 @@
|
|
|
+#! /usr/bin/env python
|
|
|
+#coding=utf-8
|
|
|
+
|
|
|
+import sys
|
|
|
+
|
|
|
+py2 = py30 = py31 = False
|
|
|
+version = sys.hexversion
|
|
|
+if version >= 0x020600F0 and version < 0x03000000 :
|
|
|
+ py2 = True # Python 2.6 or 2.7
|
|
|
+ from Tkinter import *
|
|
|
+ import ttk
|
|
|
+elif version >= 0x03000000 and version < 0x03010000 :
|
|
|
+ py30 = True
|
|
|
+ from tkinter import *
|
|
|
+ import ttk
|
|
|
+elif version >= 0x03010000:
|
|
|
+ py31 = True
|
|
|
+ from tkinter import *
|
|
|
+ import tkinter.ttk as ttk
|
|
|
+else:
|
|
|
+ print ("""
|
|
|
+ You do not have a version of python supporting ttk widgets..
|
|
|
+ You need a version >= 2.6 to execute PAGE modules.
|
|
|
+ """)
|
|
|
+ sys.exit()
|
|
|
+
|
|
|
+import ScrolledText
|
|
|
+import tkFileDialog
|
|
|
+import tkMessageBox
|
|
|
+
|
|
|
+import os
|
|
|
+import threading
|
|
|
+import platform
|
|
|
+
|
|
|
+builder = None
|
|
|
+executor = None
|
|
|
+lock = None
|
|
|
+
|
|
|
+class CmdExecutor(threading.Thread):
|
|
|
+ def __init__(self, cmd, output):
|
|
|
+ threading.Thread.__init__(self)
|
|
|
+ self.cmd = cmd
|
|
|
+ self.child = None
|
|
|
+
|
|
|
+ def run(self):
|
|
|
+ global executor
|
|
|
+
|
|
|
+ if platform.system() == 'Windows':
|
|
|
+ from win32spawn import Win32Spawn
|
|
|
+
|
|
|
+ subprocess = Win32Spawn(self.cmd)
|
|
|
+ subprocess.start_pipe()
|
|
|
+
|
|
|
+ builder.progressbar.start()
|
|
|
+ while not subprocess.is_terminated or subprocess.qsize() > 0:
|
|
|
+ try:
|
|
|
+ line = subprocess.get(timeout=1)
|
|
|
+ line = line.replace('\r', '')
|
|
|
+ if line:
|
|
|
+ lock.acquire()
|
|
|
+ builder.output.see(END)
|
|
|
+ builder.output.insert(END, line)
|
|
|
+ lock.release()
|
|
|
+ except:
|
|
|
+ pass
|
|
|
+
|
|
|
+ builder.progressbar.stop()
|
|
|
+
|
|
|
+ executor = None
|
|
|
+
|
|
|
+def ExecCmd(cmd):
|
|
|
+ global executor
|
|
|
+ if executor:
|
|
|
+ print 'cmd not exit, return'
|
|
|
+ return
|
|
|
+
|
|
|
+ executor = CmdExecutor(cmd, builder)
|
|
|
+ executor.start()
|
|
|
+
|
|
|
+class DirSelectBox(ttk.Frame):
|
|
|
+ def __init__(self, master=None, **kw):
|
|
|
+ ttk.Frame.__init__(self, master, **kw)
|
|
|
+ self.dir_var = StringVar()
|
|
|
+ self.entry = ttk.Entry(self, textvariable = self.dir_var)
|
|
|
+ self.entry.pack(fill=BOTH, expand=1,side=LEFT)
|
|
|
+ self.entry.configure(width = 50)
|
|
|
+
|
|
|
+ self.browser_button = ttk.Button(self, text="Browser", command=self.browser)
|
|
|
+ self.browser_button.pack(side=RIGHT)
|
|
|
+
|
|
|
+ def browser(self):
|
|
|
+ dir = tkFileDialog.askdirectory(parent=self, title='Open directory', initialdir=self.dir_var.get())
|
|
|
+ if dir != '':
|
|
|
+ self.dir_var.set(dir)
|
|
|
+
|
|
|
+ def set_path(self, path):
|
|
|
+ path = path.replace('\\', '/')
|
|
|
+ self.dir_var.set(path)
|
|
|
+
|
|
|
+ def get_path(self):
|
|
|
+ return self.dir_var.get()
|
|
|
+
|
|
|
+COMPILER = [
|
|
|
+ ("GNU GCC", "GCC"),
|
|
|
+ ("Keil ARMCC", "ARMCC"),
|
|
|
+ ("IAR Compiler", "IAR"),
|
|
|
+ ]
|
|
|
+
|
|
|
+IDE = [
|
|
|
+ ('Keil MDK4', 'mdk4'),
|
|
|
+ ('Keil MDK', 'mdk'),
|
|
|
+ ('IAR Compiler', 'iar')
|
|
|
+]
|
|
|
+
|
|
|
+class SconsUI():
|
|
|
+ def __init__(self, master=None):
|
|
|
+ style = ttk.Style()
|
|
|
+ theme = style.theme_use()
|
|
|
+ default = style.lookup(theme, 'background')
|
|
|
+ master.configure(background=default)
|
|
|
+
|
|
|
+ notebook = ttk.Notebook(master)
|
|
|
+ notebook.pack(fill=BOTH, padx=5, pady=5)
|
|
|
+
|
|
|
+ # building page
|
|
|
+ page_building = ttk.Frame(notebook)
|
|
|
+ notebook.add(page_building, padding=3)
|
|
|
+ notebook.tab(0, text='Build', underline="-1")
|
|
|
+ self.setup_building_ui(page_building)
|
|
|
+
|
|
|
+ # make project page
|
|
|
+ page_project = ttk.Frame(notebook)
|
|
|
+ notebook.add(page_project, padding = 3)
|
|
|
+ notebook.tab(1, text = 'Project', underline = '-1')
|
|
|
+ self.setup_project_ui(page_project)
|
|
|
+
|
|
|
+ # setting page
|
|
|
+ page_setting = ttk.Frame(notebook)
|
|
|
+ notebook.add(page_setting, padding = 3)
|
|
|
+ notebook.tab(2, text = 'Setting', underline = '-1')
|
|
|
+ self.setup_setting_ui(page_setting)
|
|
|
+
|
|
|
+ padding = ttk.Frame(master)
|
|
|
+ padding.pack(fill=X)
|
|
|
+ quit = ttk.Button(padding, text='Quit', command = self.quit)
|
|
|
+ quit.pack(side=RIGHT)
|
|
|
+
|
|
|
+ # read setting
|
|
|
+ self.read_setting()
|
|
|
+
|
|
|
+ def read_setting(self):
|
|
|
+ import platform
|
|
|
+ import os
|
|
|
+
|
|
|
+ home = ''
|
|
|
+ if platform.system() == 'Windows':
|
|
|
+ driver = os.environ['HOMEDRIVE']
|
|
|
+ home = os.environ['HOMEPATH']
|
|
|
+ home = os.path.join(driver, home)
|
|
|
+ else:
|
|
|
+ home = os.environ['HOME']
|
|
|
+
|
|
|
+ setting_path = os.path.join(home, '.rtt_scons')
|
|
|
+ if os.path.exists(setting_path):
|
|
|
+ setting = file(os.path.join(home, '.rtt_scons'))
|
|
|
+ for line in setting:
|
|
|
+ line = line.replace('\n', '')
|
|
|
+ line = line.replace('\r', '')
|
|
|
+ if line.find('=') != -1:
|
|
|
+ items = line.split('=')
|
|
|
+ if items[0] == 'RTTRoot':
|
|
|
+ self.RTTRoot.set_path(items[1])
|
|
|
+ elif items[0] == 'BSPRoot':
|
|
|
+ self.BSPRoot.set_path(items[1])
|
|
|
+ elif items[0] == 'compiler':
|
|
|
+ compiler = items[1]
|
|
|
+ else:
|
|
|
+ self.CompilersPath[items[0]].set_path(items[1])
|
|
|
+ setting.close()
|
|
|
+
|
|
|
+ # set RT-Thread Root Directory according environ
|
|
|
+ if os.environ.has_key('RTT_ROOT'):
|
|
|
+ self.RTTRoot.set_path(os.environ['RTT_ROOT'])
|
|
|
+
|
|
|
+ # detect compiler path
|
|
|
+ if platform.system() == 'Windows':
|
|
|
+ # Keil MDK
|
|
|
+ if not self.CompilersPath['ARMCC'].get_path():
|
|
|
+ if os.path.exists('C:\\Keil'):
|
|
|
+ self.CompilersPath['ARMCC'].set_path('C:\\Keil')
|
|
|
+ elif os.path.exists('D:\\Keil'):
|
|
|
+ self.CompilersPath['ARMCC'].set_path('D:\\Keil')
|
|
|
+ elif os.path.exists('E:\\Keil'):
|
|
|
+ self.CompilersPath['ARMCC'].set_path('E:\\Keil')
|
|
|
+ elif os.path.exists('F:\\Keil'):
|
|
|
+ self.CompilersPath['ARMCC'].set_path('F:\\Keil')
|
|
|
+ elif os.path.exists('G:\\Keil'):
|
|
|
+ self.CompilersPath['ARMCC'].set_path('G:\\Keil')
|
|
|
+
|
|
|
+ # GNU GCC
|
|
|
+ if not self.CompilersPath['GCC'].get_path():
|
|
|
+ paths = os.environ['PATH']
|
|
|
+ paths = paths.split(';')
|
|
|
+
|
|
|
+ for path in paths:
|
|
|
+ if path.find('CodeSourcery') != -1:
|
|
|
+ self.CompilersPath['GCC'].set_path(path)
|
|
|
+ break
|
|
|
+ elif path.find('GNU Tools ARM Embedded') != -1:
|
|
|
+ self.CompilersPath['GCC'].set_path(path)
|
|
|
+ break
|
|
|
+
|
|
|
+ def save_setting(self):
|
|
|
+ import platform
|
|
|
+ import os
|
|
|
+
|
|
|
+ home = ''
|
|
|
+ if platform.system() == 'Windows':
|
|
|
+ driver = os.environ['HOMEDRIVE']
|
|
|
+ home = os.environ['HOMEPATH']
|
|
|
+ home = os.path.join(driver, home)
|
|
|
+ else:
|
|
|
+ home = os.environ['HOME']
|
|
|
+
|
|
|
+ setting = file(os.path.join(home, '.rtt_scons'), 'wb+')
|
|
|
+ # current comiler
|
|
|
+ # line = '%s=%s\n' % ('compiler', self.compilers.get()))
|
|
|
+ line = '%s=%s\n' % ('compiler', 'iar')
|
|
|
+ setting.write(line)
|
|
|
+
|
|
|
+ # RTT Root Folder
|
|
|
+ if self.RTTRoot.get_path():
|
|
|
+ line = '%s=%s\n' % ('RTTRoot', self.RTTRoot.get_path())
|
|
|
+ setting.write(line)
|
|
|
+
|
|
|
+ # BSP Root Folder
|
|
|
+ if self.BSPRoot.get_path():
|
|
|
+ line = '%s=%s\n' % ('BSPRoot', self.BSPRoot.get_path())
|
|
|
+ setting.write(line)
|
|
|
+
|
|
|
+ for (compiler, path) in self.CompilersPath.iteritems():
|
|
|
+ if path.get_path():
|
|
|
+ line = '%s=%s\n' % (compiler, path.get_path())
|
|
|
+ setting.write(line)
|
|
|
+
|
|
|
+ setting.close()
|
|
|
+ tkMessageBox.showinfo("RT-Thread SCons UI",
|
|
|
+ "Save setting sucessfully")
|
|
|
+
|
|
|
+ def setup_building_ui(self, frame):
|
|
|
+ padding = ttk.Frame(frame)
|
|
|
+ padding.pack(fill=X)
|
|
|
+
|
|
|
+ button = ttk.Button(padding, text='Clean', command=self.do_clean)
|
|
|
+ button.pack(side=RIGHT)
|
|
|
+ button = ttk.Button(padding, text='Build', command=self.do_build)
|
|
|
+ button.pack(side=RIGHT)
|
|
|
+ label = ttk.Label(padding, relief = 'flat', text = 'Click Build or Clean to build or clean system -->')
|
|
|
+ label.pack(side=RIGHT, ipady = 5)
|
|
|
+
|
|
|
+ self.progressbar = ttk.Progressbar(frame)
|
|
|
+ self.progressbar.pack(fill=X)
|
|
|
+
|
|
|
+ separator = ttk.Separator(frame)
|
|
|
+ separator.pack(fill=X)
|
|
|
+
|
|
|
+ self.output = ScrolledText.ScrolledText(frame)
|
|
|
+ self.output.pack(fill=X)
|
|
|
+
|
|
|
+ def setup_project_ui(self, frame):
|
|
|
+ label = ttk.Label(frame, relief = 'flat', text = 'Choose Integrated Development Environment:')
|
|
|
+ label.pack(fill=X, pady = 5)
|
|
|
+
|
|
|
+ separator = ttk.Separator(frame)
|
|
|
+ separator.pack(fill=X)
|
|
|
+
|
|
|
+ self.ide = StringVar()
|
|
|
+ self.ide.set("mdk4") # initialize
|
|
|
+
|
|
|
+ for text,mode in IDE:
|
|
|
+ radiobutton = ttk.Radiobutton(frame, text=text, variable = self.ide, value = mode)
|
|
|
+ radiobutton.pack(fill=X, padx=10)
|
|
|
+
|
|
|
+ bottom = ttk.Frame(frame)
|
|
|
+ bottom.pack(side=BOTTOM, fill=X)
|
|
|
+ button = ttk.Button(bottom, text="Make Project", command = self.do_make_project)
|
|
|
+ button.pack(side=RIGHT, padx = 10, pady = 10)
|
|
|
+
|
|
|
+ def setup_setting_ui(self, frame):
|
|
|
+ row = 0
|
|
|
+ label = ttk.Label (frame, relief = 'flat', text='RT-Thread Root Folder:')
|
|
|
+ label.grid(row=row, column=0,ipadx=5, ipady=5, padx = 5)
|
|
|
+
|
|
|
+ self.RTTRoot = DirSelectBox(frame)
|
|
|
+ self.RTTRoot.grid(row=row, column=1, sticky=E+W)
|
|
|
+ row = row + 1
|
|
|
+
|
|
|
+ label = ttk.Label (frame, relief = 'flat', text='Board Support Folder:')
|
|
|
+ label.grid(row=row, column=0,ipadx=5, ipady=5, padx = 5)
|
|
|
+
|
|
|
+ self.BSPRoot = DirSelectBox(frame)
|
|
|
+ self.BSPRoot.grid(row=row, column=1, sticky=E+W)
|
|
|
+ row = row + 1
|
|
|
+
|
|
|
+ label = ttk.Label (frame, relief='flat', text='Toolchain:')
|
|
|
+ label.grid(row=row, column=0,ipadx=5, ipady=5, sticky=E+W)
|
|
|
+ row = row + 1
|
|
|
+
|
|
|
+ separator = ttk.Separator(frame)
|
|
|
+ separator.grid(row = row, column = 0, columnspan = 2, sticky = E+W)
|
|
|
+ row = row + 1
|
|
|
+
|
|
|
+ self.compilers = StringVar()
|
|
|
+ self.compilers.set("GCC") # initialize
|
|
|
+
|
|
|
+ self.CompilersPath = {}
|
|
|
+
|
|
|
+ for text,compiler in COMPILER:
|
|
|
+ radiobutton = ttk.Radiobutton(frame, text=text, variable = self.compilers, value = compiler)
|
|
|
+ radiobutton.grid(row=row, column = 0, sticky = W, ipadx = 5, ipady = 5, padx = 20)
|
|
|
+
|
|
|
+ self.CompilersPath[compiler] = DirSelectBox(frame)
|
|
|
+ self.CompilersPath[compiler].grid(row=row, column=1, sticky=E+W)
|
|
|
+ row = row + 1
|
|
|
+
|
|
|
+ button = ttk.Button(frame, text='Save Setting', command = self.save_setting)
|
|
|
+ button.grid(row = row, column = 1, sticky = E)
|
|
|
+ row = row + 1
|
|
|
+
|
|
|
+ def prepare_build(self):
|
|
|
+ # get compiler
|
|
|
+ compiler = self.compilers.get()
|
|
|
+ if compiler == 'GCC':
|
|
|
+ compiler = 'gcc'
|
|
|
+ elif compiler == 'ARMCC':
|
|
|
+ compiler = 'keil'
|
|
|
+ elif compiler == 'IAR':
|
|
|
+ compiler = 'iar'
|
|
|
+
|
|
|
+ # get RTT Root
|
|
|
+ rtt_root = self.RTTRoot.get_path()
|
|
|
+ # get Compiler path
|
|
|
+ exec_path = self.CompilersPath[self.compilers.get()].get_path()
|
|
|
+
|
|
|
+ command = ''
|
|
|
+
|
|
|
+ os.environ['RTT_ROOT'] = rtt_root
|
|
|
+ os.environ['RTT_CC'] = compiler
|
|
|
+ os.environ['RTT_EXEC_PATH'] = exec_path
|
|
|
+
|
|
|
+ return command
|
|
|
+
|
|
|
+ def do_build(self):
|
|
|
+ self.prepare_build()
|
|
|
+ command = 'scons'
|
|
|
+
|
|
|
+ bsp = self.BSPRoot.get_path()
|
|
|
+ os.chdir(bsp)
|
|
|
+
|
|
|
+ self.output.delete(1.0, END)
|
|
|
+ self.output.insert(END, 'building project...\n')
|
|
|
+ ExecCmd(command)
|
|
|
+
|
|
|
+ def do_clean(self):
|
|
|
+ self.prepare_build()
|
|
|
+ command = 'scons -c'
|
|
|
+
|
|
|
+ bsp = self.BSPRoot.get_path()
|
|
|
+ os.chdir(bsp)
|
|
|
+
|
|
|
+ self.output.delete(1.0, END)
|
|
|
+ self.output.insert(END, 'clean project...\n')
|
|
|
+ ExecCmd(command)
|
|
|
+
|
|
|
+ def do_make_project(self):
|
|
|
+ ide = self.ide.get()
|
|
|
+ self.prepare_build()
|
|
|
+ command = 'scons --target=%s -s' % ide
|
|
|
+
|
|
|
+ bsp = self.BSPRoot.get_path()
|
|
|
+ os.chdir(bsp)
|
|
|
+
|
|
|
+ self.output.delete(1.0, END)
|
|
|
+ self.output.insert(END, 'make project ...\n')
|
|
|
+ ExecCmd(command)
|
|
|
+
|
|
|
+ def quit(self):
|
|
|
+ exit(0)
|
|
|
+
|
|
|
+def StartSConsUI(path=None):
|
|
|
+ global val, root
|
|
|
+ root = Tk()
|
|
|
+ root.title('RT-Thread SCons UI')
|
|
|
+ root.geometrygeometry('590x510+50+50')
|
|
|
+ lock = threading.RLock()
|
|
|
+ builder = SconsUI(root)
|
|
|
+ if path:
|
|
|
+ builder.BSPRoot.set_path(path)
|
|
|
+ root.mainloop
|
|
|
+
|
|
|
+if __name__ == '__main__':
|
|
|
+ global val, root
|
|
|
+ root = Tk()
|
|
|
+ root.title('scons_builder')
|
|
|
+ root.geometry('590x510+50+50')
|
|
|
+ lock = threading.RLock()
|
|
|
+ scons_ui = SconsUI(root)
|
|
|
+ builder = scons_ui
|
|
|
+ root.mainloop()
|