Hi all,
I’m trying to create a custom .sublime-build in order to make calls to Keil uVision IDE to compile, debug, and flash code.
The problem with Keil compiler is that it does not write to STDOUT. The only way to get the output is to use the -o switch and direct it to a file.
Is there a way to get the content of that output file to the output panel?
I’m using the following as a guide;
Build Systems
Along with the following Keil Command Line options;
UV4 Command Line Options
So far I have the following;
keil.sublime-build
{
"target": "keil_build",
"selector": "source.c, source.cpp, source.c++",
"variants": [
{
"name": "build",
"build": true
},
{
"name": "Build Clean",
"clean_build": true
{ },
{
"name": "Clean All",
"clean_all": true
},
"name": "Debug",
"debug": true
}
]
}
keil_build.py
import sublime
import sublime_plugin
import subprocess
import threading
import os
class KeilBuildCommand(sublime_plugin.WindowCommand):
encoding = 'utf-8'
killed = False
proc = None
panel = None
panel_lock = threading.Lock()
output_file = ""
def is_enabled(self, build=False, clean_build=False, clean_all=False, debug=False, kill=False):
# The Cancel build option should only be available
# when the process is still running
if kill:
return self.proc is not None and self.proc.poll() is None
return True
def run(self, build=False, clean_build=False, clean_all=False, debug=False, kill=False):
if kill:
if self.proc:
self.killed = True
self.proc.terminate()
return
vars = self.window.extract_variables()
print (vars)
working_dir = vars['file_path']
# A lock is used to ensure only one thread is
# touching the output panel at a time
with self.panel_lock:
# Creating the panel implicitly clears any previous contents
self.panel = self.window.create_output_panel('exec')
# Enable result navigation. The result_file_regex does
# the primary matching, but result_line_regex is used
# when build output includes some entries that only
# contain line/column info beneath a previous line
# listing the file info. The result_base_dir sets the
# path to resolve relative file names against.
settings = self.panel.settings()
settings.set(
'result_file_regex',
r'^File "([^"]+)" line (\d+) col (\d+)'
)
settings.set(
'result_line_regex',
r'^\s+line (\d+) col (\d+)'
)
settings.set('result_base_dir', working_dir)
self.window.run_command('show_panel', {'panel': 'output.exec'})
if self.proc is not None:
self.proc.terminate()
self.proc = None
args = ['C:\\Keil\\UV4\\UV4.exe']
if build:
args.append('-b')
elif clean_build:
args.append('-r')
elif clean_all:
args.append('-c')
elif debug:
args.append('-d')
args.append(vars['project_path'] + "\\TxProj\\keilproj.uvproj")
self.output_file = vars['project_path'] + "\\TxProj\\buildOutput.txt"
args.append("-o")
args.append("buildOutput.txt")
print(args)
self.proc = subprocess.Popen(
args,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
cwd=working_dir
)
self.killed = False
threading.Thread(
target=self.read_handle,
args=(self.proc.stdout,)
).start()
def read_handle(self, handle):
chunk_size = 2 ** 13
out = b''
while True:
try:
print("Reading output file")
print(self.output_file)
fd = os.open(self.output_file, os.O_RDWR)
data = os.read(fd, chunk_size)
print(data)
# If exactly the requested number of bytes was
# read, there may be more data, and the current
# data may contain part of a multibyte char
out += data
if len(data) == chunk_size:
continue
if data == b'' and out == b'':
raise IOError('EOF')
# We pass out to a function to ensure the
# timeout gets the value of out right now,
# rather than a future (mutated) version
self.queue_write(out.decode(self.encoding))
if data == b'':
raise IOError('EOF')
out = b''
except (UnicodeDecodeError) as e:
msg = 'Error decoding output using %s - %s'
self.queue_write(msg % (self.encoding, str(e)))
break
except (IOError):
if self.killed:
msg = 'Cancelled'
else:
msg = 'Finished'
self.queue_write('\n[%s]' % msg)
break
def queue_write(self, text):
sublime.set_timeout(lambda: self.do_write(text), 1)
def do_write(self, text):
with self.panel_lock:
self.panel.run_command('append', {'characters': text})
you will notice that in the def read_handle I have changed it to read the output file. This doesn’t work
Cheers,
Simon