diff options
| author | [email protected] <[email protected]> | 2012-12-18 08:59:21 +0000 |
|---|---|---|
| committer | [email protected] <[email protected]> | 2012-12-18 08:59:21 +0000 |
| commit | be73747fc45d8a6aaeb24d16d57c5f455b918146 (patch) | |
| tree | 2756aa92f757590157763ad356f6ce38ffbb0104 | |
| parent | eef72f68de9e6e2ddc7c150e30dc9b99729accfb (diff) | |
Add SConsUI tool.
git-svn-id: https://rt-thread.googlecode.com/svn/trunk@2494 bbd45198-f89e-11dd-88c7-29a3b14d5316
| -rw-r--r-- | tools/sconsui.py | 409 | ||||
| -rw-r--r-- | tools/win32spawn.py | 154 |
2 files changed, 563 insertions, 0 deletions
diff --git a/tools/sconsui.py b/tools/sconsui.py new file mode 100644 index 0000000000..e4f79a6ea5 --- /dev/null +++ b/tools/sconsui.py @@ -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()
diff --git a/tools/win32spawn.py b/tools/win32spawn.py new file mode 100644 index 0000000000..f513ec3ea4 --- /dev/null +++ b/tools/win32spawn.py @@ -0,0 +1,154 @@ +import os
+import threading
+import Queue
+
+# Windows import
+import win32file
+import win32pipe
+import win32api
+import win32con
+import win32security
+import win32process
+import win32event
+
+class Win32Spawn(object):
+ def __init__(self, cmd, shell=False):
+ self.queue = Queue.Queue()
+ self.is_terminated = False
+ self.wake_up_event = win32event.CreateEvent(None, 0, 0, None)
+
+ exec_dir = os.getcwd()
+ comspec = os.environ.get("COMSPEC", "cmd.exe")
+ cmd = comspec + ' /c ' + cmd
+
+ win32event.ResetEvent(self.wake_up_event)
+
+ currproc = win32api.GetCurrentProcess()
+
+ sa = win32security.SECURITY_ATTRIBUTES()
+ sa.bInheritHandle = 1
+
+ child_stdout_rd, child_stdout_wr = win32pipe.CreatePipe(sa, 0)
+ child_stdout_rd_dup = win32api.DuplicateHandle(currproc, child_stdout_rd, currproc, 0, 0, win32con.DUPLICATE_SAME_ACCESS)
+ win32file.CloseHandle(child_stdout_rd)
+
+ child_stderr_rd, child_stderr_wr = win32pipe.CreatePipe(sa, 0)
+ child_stderr_rd_dup = win32api.DuplicateHandle(currproc, child_stderr_rd, currproc, 0, 0, win32con.DUPLICATE_SAME_ACCESS)
+ win32file.CloseHandle(child_stderr_rd)
+
+ child_stdin_rd, child_stdin_wr = win32pipe.CreatePipe(sa, 0)
+ child_stdin_wr_dup = win32api.DuplicateHandle(currproc, child_stdin_wr, currproc, 0, 0, win32con.DUPLICATE_SAME_ACCESS)
+ win32file.CloseHandle(child_stdin_wr)
+
+ startup_info = win32process.STARTUPINFO()
+ startup_info.hStdInput = child_stdin_rd
+ startup_info.hStdOutput = child_stdout_wr
+ startup_info.hStdError = child_stderr_wr
+ startup_info.dwFlags = win32process.STARTF_USESTDHANDLES
+
+ cr_flags = 0
+ cr_flags = win32process.CREATE_NEW_PROCESS_GROUP
+
+ env = os.environ.copy()
+ self.h_process, h_thread, dw_pid, dw_tid = win32process.CreateProcess(None, cmd, None, None, 1,
+ cr_flags, env, os.path.abspath(exec_dir),
+ startup_info)
+
+ win32api.CloseHandle(h_thread)
+
+ win32file.CloseHandle(child_stdin_rd)
+ win32file.CloseHandle(child_stdout_wr)
+ win32file.CloseHandle(child_stderr_wr)
+
+ self.__child_stdout = child_stdout_rd_dup
+ self.__child_stderr = child_stderr_rd_dup
+ self.__child_stdin = child_stdin_wr_dup
+
+ self.exit_code = -1
+
+ def close(self):
+ win32file.CloseHandle(self.__child_stdout)
+ win32file.CloseHandle(self.__child_stderr)
+ win32file.CloseHandle(self.__child_stdin)
+ win32api.CloseHandle(self.h_process)
+ win32api.CloseHandle(self.wake_up_event)
+
+ def kill_subprocess():
+ win32event.SetEvent(self.wake_up_event)
+
+ def sleep(secs):
+ win32event.ResetEvent(self.wake_up_event)
+ timeout = int(1000 * secs)
+ val = win32event.WaitForSingleObject(self.wake_up_event, timeout)
+ if val == win32event.WAIT_TIMEOUT:
+ return True
+ else:
+ # The wake_up_event must have been signalled
+ return False
+
+ def get(self, block=True, timeout=None):
+ return self.queue.get(block=block, timeout=timeout)
+
+ def qsize(self):
+ return self.queue.qsize()
+
+ def __wait_for_child(self):
+ # kick off threads to read from stdout and stderr of the child process
+ threading.Thread(target=self.__do_read, args=(self.__child_stdout, )).start()
+ threading.Thread(target=self.__do_read, args=(self.__child_stderr, )).start()
+
+ while True:
+ # block waiting for the process to finish or the interrupt to happen
+ handles = (self.wake_up_event, self.h_process)
+ val = win32event.WaitForMultipleObjects(handles, 0, win32event.INFINITE)
+
+ if val >= win32event.WAIT_OBJECT_0 and val < win32event.WAIT_OBJECT_0 + len(handles):
+ handle = handles[val - win32event.WAIT_OBJECT_0]
+ if handle == self.wake_up_event:
+ win32api.TerminateProcess(self.h_process, 1)
+ win32event.ResetEvent(self.wake_up_event)
+ return False
+ elif handle == self.h_process:
+ # the process has ended naturally
+ return True
+ else:
+ assert False, "Unknown handle fired"
+ else:
+ assert False, "Unexpected return from WaitForMultipleObjects"
+
+ # Wait for job to finish. Since this method blocks, it can to be called from another thread.
+ # If the application wants to kill the process, it should call kill_subprocess().
+ def wait(self):
+ if not self.__wait_for_child():
+ # it's been killed
+ result = False
+ else:
+ # normal termination
+ self.exit_code = win32process.GetExitCodeProcess(self.h_process)
+ result = self.exit_code == 0
+ self.close()
+ self.is_terminated = True
+
+ return result
+
+ # This method gets called on a worker thread to read from either a stderr
+ # or stdout thread from the child process.
+ def __do_read(self, handle):
+ bytesToRead = 1024
+ while 1:
+ try:
+ finished = 0
+ hr, data = win32file.ReadFile(handle, bytesToRead, None)
+ self.queue.put_nowait(data)
+ except win32api.error:
+ finished = 1
+
+ if finished:
+ return
+
+ def start_pipe(self):
+ def worker(pipe):
+ return pipe.wait()
+
+ thrd = threading.Thread(target=worker, args=(self, ))
+ thrd.start()
|
