Skip to content

Commit 986af0d

Browse files
committed
New export-build tests.
Allows command line workflow of: mbed import mbed export Also revises exporter supported target checks
1 parent 7829b2f commit 986af0d

File tree

10 files changed

+235
-98
lines changed

10 files changed

+235
-98
lines changed

tools/export/cmsis/__init__.py

Lines changed: 24 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -31,37 +31,39 @@ class DeviceCMSIS():
3131
3232
Encapsulates target information retrieved by arm-pack-manager"""
3333
def __init__(self, target):
34-
cache = Cache(True, False)
34+
target_info = self.check_supported(target)
35+
if not target_info:
36+
raise TargetNotSupportedException("Target not supported in CMSIS pack")
3537

38+
self.url = target_info['pdsc_file']
39+
self.pack_url, self.pack_id = ntpath.split(self.url)
40+
self.dname = target_info["_cpu_name"]
41+
self.core = target_info["_core"]
42+
self.dfpu = target_info['processor']['fpu']
43+
self.debug, self.dvendor = self.vendor_debug(target_info['vendor'])
44+
self.dendian = target_info['processor'].get('endianness','Little-endian')
45+
self.debug_svd = target_info.get('debug', '')
46+
self.compile_header = target_info['compile']['header']
47+
self.target_info = target_info
48+
49+
@staticmethod
50+
def check_supported(target):
51+
cache = Cache(True, False)
3652
t = TARGET_MAP[target]
37-
self.core = t.core
3853
try:
3954
cpu_name = t.device_name
4055
target_info = cache.index[cpu_name]
4156
# Target does not have device name or pdsc file
4257
except:
4358
try:
4459
# Try to find the core as a generic CMSIS target
45-
cpu_name = self.cpu_cmsis()
60+
cpu_name = DeviceCMSIS.cpu_cmsis(t.core)
4661
target_info = cache.index[cpu_name]
4762
except:
48-
raise TargetNotSupportedException("Target not in CMSIS packs")
49-
50-
self.target_info = target_info
51-
52-
self.url = target_info['pdsc_file']
53-
self.pack_url, self.pack_id = ntpath.split(self.url)
54-
self.dname = cpu_name
55-
self.dfpu = target_info['processor']['fpu']
56-
self.debug, self.dvendor = self.vendor_debug(target_info['vendor'])
57-
self.dendian = target_info['processor'].get('endianness','Little-endian')
58-
self.debug_svd = target_info.get('debug', '')
59-
self.compile_header = target_info['compile']['header']
60-
61-
def check_version(self, filename):
62-
with open(filename) as data_file:
63-
data = json.load(data_file)
64-
return data.get("version", "0") == "0.1.0"
63+
return False
64+
target_info["_cpu_name"] = cpu_name
65+
target_info["_core"] = t.core
66+
return target_info
6567

6668
def vendor_debug(self, vendor):
6769
reg = "([\w\s]+):?\d*?"
@@ -74,9 +76,9 @@ def vendor_debug(self, vendor):
7476
}
7577
return debug_map.get(vendor_match, "CMSIS-DAP"), vendor_match
7678

77-
def cpu_cmsis(self):
79+
@staticmethod
80+
def cpu_cmsis(cpu):
7881
#Cortex-M4F => ARMCM4_FP, Cortex-M0+ => ARMCM0P
79-
cpu = self.core
8082
cpu = cpu.replace("Cortex-","ARMC")
8183
cpu = cpu.replace("+","P")
8284
cpu = cpu.replace("F","_FP")

tools/export/exporters.py

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -119,13 +119,6 @@ def get_source_paths(self):
119119
source_files.extend(getattr(self.resources, key))
120120
return list(set([os.path.dirname(src) for src in source_files]))
121121

122-
def check_supported(self):
123-
"""Indicated if this combination of IDE and MCU is supported"""
124-
if self.target not in self.TARGETS or \
125-
self.TOOLCHAIN not in TARGET_MAP[self.target].supported_toolchains:
126-
raise TargetNotSupportedException()
127-
return True
128-
129122
def gen_file(self, template_file, data, target_file):
130123
"""Generates a project file from a template using jinja"""
131124
jinja_loader = FileSystemLoader(

tools/export/iar/__init__.py

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from os.path import sep, join, exists
33
from collections import namedtuple
44
from subprocess import Popen, PIPE
5-
from distutils.spawn import find_executable
5+
import shutil
66
import re
77
import sys
88

@@ -29,7 +29,8 @@ class IAR(Exporter):
2929
#iar_definitions.json
3030
TARGETS = [target for target, obj in TARGET_MAP.iteritems()
3131
if hasattr(obj, 'device_name') and
32-
obj.device_name in IAR_DEFS.keys()]
32+
obj.device_name in IAR_DEFS.keys() and "IAR" in obj.supported_toolchains
33+
and DeviceCMSIS.check_supported(target)]
3334

3435
SPECIAL_TEMPLATES = {
3536
'rz_a1h' : 'iar/iar_rz_a1h.ewp.tmpl',
@@ -120,22 +121,13 @@ def generate(self):
120121
self.gen_file('iar/ewd.tmpl', ctx, self.project_name + ".ewd")
121122
self.gen_file(self.get_ewp_template(), ctx, self.project_name + ".ewp")
122123

123-
def build(self):
124+
@staticmethod
125+
def build(project_name, clean=True):
124126
""" Build IAR project """
125127
# > IarBuild [project_path] -build [project_name]
126-
proj_file = join(self.export_dir, self.project_name + ".ewp")
127128

128-
if find_executable("IarBuild"):
129-
iar_exe = "IarBuild.exe"
130-
else:
131-
iar_exe = join('C:', sep,
132-
'Program Files (x86)', 'IAR Systems',
133-
'Embedded Workbench 7.5', 'common', 'bin',
134-
'IarBuild.exe')
135-
if not exists(iar_exe):
136-
raise Exception("IarBuild.exe not found. Add to path.")
137-
138-
cmd = [iar_exe, proj_file, '-build', self.project_name]
129+
proj_file = project_name + ".ewp"
130+
cmd = ["IarBuild.exe", proj_file, '-build', project_name]
139131

140132
# IAR does not support a '0' option to automatically use all
141133
# available CPUs, so we use Python's multiprocessing library
@@ -156,7 +148,14 @@ def build(self):
156148
m = re.match(error_re, line)
157149
if m is not None:
158150
num_errors = int(m.group(1))
151+
152+
if clean:
153+
os.remove(project_name + ".ewp")
154+
os.remove(project_name + ".ewd")
155+
os.remove(project_name + ".eww")
156+
shutil.rmtree('.build')
157+
159158
if num_errors !=0:
160159
# Seems like something went wrong.
161-
raise FailedBuildException("Project: %s build failed with %s erros" % (
162-
proj_file, num_errors))
160+
return -1
161+
return 0

tools/export/makefile/__init__.py

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@
1616
"""
1717
from os.path import splitext, basename, relpath, join, abspath, dirname,\
1818
exists
19-
from os import curdir, getcwd
19+
from os import remove
20+
import sys
21+
from subprocess import check_output, CalledProcessError, Popen, PIPE
22+
import shutil
2023
from jinja2.exceptions import TemplateNotFound
2124
from tools.export.exporters import Exporter
2225
from tools.utils import NotSupportedException
@@ -102,6 +105,38 @@ def generate(self):
102105
else:
103106
raise NotSupportedException("This make tool is in development")
104107

108+
@staticmethod
109+
def build(project_name, build_log="build_log.txt", project_loc=None, clean=True):
110+
""" Build Make project """
111+
# > Make -C [project directory] -j
112+
cmd = ["make", "-j"]
113+
p = Popen(cmd, stdout=PIPE, stderr=PIPE)
114+
ret = p.communicate()
115+
out, err = ret[0], ret[1]
116+
ret_code = p.returncode
117+
with open(build_log, 'w+') as f:
118+
f.write("=" * 10 + "OUT" + "=" * 10 + "\n")
119+
f.write(out)
120+
f.write("=" * 10 + "ERR" + "=" * 10 + "\n")
121+
f.write(err)
122+
if ret_code == 0:
123+
f.write("SUCCESS")
124+
else:
125+
f.write("FAILURE")
126+
with open(build_log, 'r') as f:
127+
print "\n".join(f.readlines())
128+
sys.stdout.flush()
129+
130+
if clean:
131+
remove("Makefile")
132+
remove(build_log)
133+
if exists('.build'):
134+
shutil.rmtree('.build')
135+
if ret_code != 0:
136+
# Seems like something went wrong.
137+
return -1
138+
return 0
139+
105140

106141
class GccArm(Makefile):
107142
"""GCC ARM specific makefile target"""

tools/export/uvision/__init__.py

Lines changed: 21 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
import ntpath
44
import copy
55
from collections import namedtuple
6-
from distutils.spawn import find_executable
6+
import shutil
77
import subprocess
88
import re
99

@@ -117,10 +117,15 @@ class Uvision(Exporter):
117117
project file (.uvprojx).
118118
The needed information can be viewed in uvision.tmpl
119119
"""
120-
NAME = 'cmsis'
120+
NAME = 'uvision5'
121121
TOOLCHAIN = 'ARM'
122-
TARGETS = [target for target, obj in TARGET_MAP.iteritems()
123-
if "ARM" in obj.supported_toolchains]
122+
TARGETS = []
123+
for target, obj in TARGET_MAP.iteritems():
124+
if not ("ARM" in obj.supported_toolchains and hasattr(obj, "device_name")):
125+
continue
126+
if not DeviceCMSIS.check_supported(target):
127+
continue
128+
TARGETS.append(target)
124129
#File associations within .uvprojx file
125130
file_types = {'.cpp': 8, '.c': 1, '.s': 2,
126131
'.obj': 3, '.o': 3, '.lib': 4,
@@ -200,35 +205,22 @@ def generate(self):
200205
self.gen_file('uvision/uvision.tmpl', ctx, self.project_name+".uvprojx")
201206
self.gen_file('uvision/uvision_debug.tmpl', ctx, self.project_name + ".uvoptx")
202207

203-
def build(self):
204-
ERRORLEVEL = {
205-
0: 'success (0 warnings, 0 errors)',
206-
1: 'warnings',
207-
2: 'errors',
208-
3: 'fatal errors',
209-
11: 'cant write to project file',
210-
12: 'device error',
211-
13: 'error writing',
212-
15: 'error reading xml file',
213-
}
208+
@staticmethod
209+
def build(project_name, log_name='build_log.txt', clean=True):
214210
success = 0
215211
warn = 1
216-
if find_executable("UV4"):
217-
uv_exe = "UV4.exe"
218-
else:
219-
uv_exe = join('C:', sep,
220-
'Keil_v5', 'UV4', 'UV4.exe')
221-
if not exists(uv_exe):
222-
raise Exception("UV4.exe not found. Add to path.")
223-
cmd = [uv_exe, '-r', '-j0', '-o', join(self.export_dir,'build_log.txt'), join(self.export_dir,self.project_name+".uvprojx")]
212+
cmd = ["UV4.exe", '-r', '-j0', '-o', log_name, project_name+".uvprojx"]
224213
ret_code = subprocess.call(cmd)
225-
with open(join(self.export_dir, 'build_log.txt'), 'r') as build_log:
214+
with open(log_name, 'r') as build_log:
226215
print build_log.read()
216+
if clean:
217+
os.remove(log_name)
218+
os.remove(project_name+".uvprojx")
219+
os.remove(project_name+".uvoptx")
220+
shutil.rmtree(".build")
221+
227222

228223
if ret_code != success and ret_code != warn:
229224
# Seems like something went wrong.
230-
raise FailedBuildException("Project: %s build failed with the status: %s" % (
231-
self.project_name, ERRORLEVEL.get(ret_code, "Unknown")))
232-
else:
233-
return "Project: %s build succeeded with the status: %s" % (
234-
self.project_name, ERRORLEVEL.get(ret_code, "Unknown"))
225+
return -1
226+
return 0

tools/project.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,9 @@ def main():
232232
if (options.program is None) and (not options.source_dir):
233233
args_error(parser, "one of -p, -n, or --source is required")
234234
# Export to selected toolchain
235-
_, toolchain_name = get_exporter_toolchain(options.ide)
235+
exporter, toolchain_name = get_exporter_toolchain(options.ide)
236+
if options.mcu not in exporter.TARGETS:
237+
args_error(parser, "%s not supported by %s")
236238
profile = extract_profile(parser, options, toolchain_name)
237239
export(options.mcu, options.ide, build=options.build,
238240
src=options.source_dir, macros=options.macros,

tools/project_api.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,6 @@ def generate_project_files(resources, export_path, target, name, toolchain, ide,
8686
exporter_cls, _ = get_exporter_toolchain(ide)
8787
exporter = exporter_cls(target, export_path, name, toolchain,
8888
extra_symbols=macros, resources=resources)
89-
exporter.check_supported()
9089
exporter.generate()
9190
files = exporter.generated_files
9291
return files, exporter

0 commit comments

Comments
 (0)