Skip to content

Commit 4e1ac4d

Browse files
authored
Merge pull request #2179 from sarahmarshy/progen_build_tests_v2
IDE build tests with progen
2 parents 7251a8c + b969fa5 commit 4e1ac4d

File tree

9 files changed

+336
-73
lines changed

9 files changed

+336
-73
lines changed

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ PySerial>=2.7
33
PrettyTable>=0.7.2
44
Jinja2>=2.7.3
55
IntelHex>=1.3
6-
project-generator>=0.9.3,<0.10.0
6+
project-generator>=0.9.7,<0.10.0
77
project_generator_definitions>=0.2.26,<0.3.0
88
junit-xml
99
pyYAML

tools/export/__init__.py

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
from tools.utils import mkdir
2323
from tools.export import uvision4, uvision5, codered, gccarm, ds5_5, iar, emblocks, coide, kds, zip, simplicityv3, atmelstudio, sw4stm32, e2studio
24-
from tools.export.exporters import zip_working_directory_and_clean_up, OldLibrariesException
24+
from tools.export.exporters import zip_working_directory_and_clean_up, OldLibrariesException, FailedBuildException
2525
from tools.targets import TARGET_NAMES, EXPORT_MAP, TARGET_MAP
2626

2727
from project_generator_definitions.definitions import ProGenDef
@@ -58,7 +58,8 @@ def online_build_url_resolver(url):
5858

5959

6060
def export(project_path, project_name, ide, target, destination='/tmp/',
61-
tempdir=None, clean=True, extra_symbols=None, make_zip=True, sources_relative=False, build_url_resolver=online_build_url_resolver):
61+
tempdir=None, pgen_build = False, clean=True, extra_symbols=None, make_zip=True, sources_relative=False,
62+
build_url_resolver=online_build_url_resolver, progen_build=False):
6263
# Convention: we are using capitals for toolchain and target names
6364
if target is not None:
6465
target = target.upper()
@@ -68,8 +69,8 @@ def export(project_path, project_name, ide, target, destination='/tmp/',
6869

6970
use_progen = False
7071
supported = True
71-
report = {'success': False, 'errormsg':''}
72-
72+
report = {'success': False, 'errormsg':'', 'skip': False}
73+
7374
if ide is None or ide == "zip":
7475
# Simple ZIP exporter
7576
try:
@@ -83,6 +84,7 @@ def export(project_path, project_name, ide, target, destination='/tmp/',
8384
else:
8485
if ide not in EXPORTERS:
8586
report['errormsg'] = ERROR_MESSAGE_UNSUPPORTED_TOOLCHAIN % (target, ide)
87+
report['skip'] = True
8688
else:
8789
Exporter = EXPORTERS[ide]
8890
target = EXPORT_MAP.get(target, target)
@@ -91,24 +93,35 @@ def export(project_path, project_name, ide, target, destination='/tmp/',
9193
use_progen = True
9294
except AttributeError:
9395
pass
96+
97+
if target not in Exporter.TARGETS or Exporter.TOOLCHAIN not in TARGET_MAP[target].supported_toolchains:
98+
supported = False
99+
94100
if use_progen:
95101
if not ProGenDef(ide).is_supported(TARGET_MAP[target].progen['target']):
96102
supported = False
97-
else:
98-
if target not in Exporter.TARGETS:
99-
supported = False
100103

101104
if supported:
102105
# target checked, export
103106
try:
104107
exporter = Exporter(target, tempdir, project_name, build_url_resolver, extra_symbols=extra_symbols, sources_relative=sources_relative)
105108
exporter.scan_and_copy_resources(project_path, tempdir, sources_relative)
106-
exporter.generate()
107-
report['success'] = True
109+
if progen_build:
110+
#try to build with pgen ide builders
111+
try:
112+
exporter.generate(progen_build=True)
113+
report['success'] = True
114+
except FailedBuildException, f:
115+
report['errormsg'] = "Build Failed"
116+
else:
117+
exporter.generate()
118+
report['success'] = True
108119
except OldLibrariesException, e:
109120
report['errormsg'] = ERROR_MESSAGE_NOT_EXPORT_LIBS
121+
110122
else:
111123
report['errormsg'] = ERROR_MESSAGE_UNSUPPORTED_TOOLCHAIN % (target, ide)
124+
report['skip'] = True
112125

113126
zip_path = None
114127
if report['success']:

tools/export/exporters.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121

2222
class OldLibrariesException(Exception): pass
2323

24+
class FailedBuildException(Exception) : pass
25+
2426
class Exporter(object):
2527
TEMPLATE_DIR = dirname(__file__)
2628
DOT_IN_RELATIVE_PATH = False
@@ -107,14 +109,19 @@ def progen_get_project_data(self):
107109
}
108110
return project_data
109111

110-
def progen_gen_file(self, tool_name, project_data):
112+
def progen_gen_file(self, tool_name, project_data, progen_build=False):
111113
""" Generate project using ProGen Project API """
112114
settings = ProjectSettings()
113115
project = Project(self.program_name, [project_data], settings)
114116
# TODO: Fix this, the inc_dirs are not valid (our scripts copy files), therefore progen
115117
# thinks it is not dict but a file, and adds them to workspace.
116118
project.project['common']['include_paths'] = self.resources.inc_dirs
117119
project.generate(tool_name, copied=not self.sources_relative)
120+
if progen_build:
121+
print("Project exported, building...")
122+
result = project.build(tool_name)
123+
if result == -1:
124+
raise FailedBuildException("Build Failed")
118125

119126
def __scan_all(self, path):
120127
resources = []

tools/export/iar.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ def TARGETS(self):
4949
continue
5050
return self._targets_supported
5151

52-
def generate(self):
52+
def generate(self, progen_build=False):
5353
""" Generates the project files """
5454
project_data = self.progen_get_project_data()
5555
tool_specific = {}
@@ -78,7 +78,10 @@ def generate(self):
7878
# VLA is enabled via template IccAllowVLA
7979
project_data['tool_specific']['iar']['misc']['c_flags'].remove("--vla")
8080
project_data['common']['build_dir'] = os.path.join(project_data['common']['build_dir'], 'iar_arm')
81-
self.progen_gen_file('iar_arm', project_data)
81+
if progen_build:
82+
self.progen_gen_file('iar_arm', project_data, True)
83+
else:
84+
self.progen_gen_file('iar_arm', project_data)
8285

8386
# Currently not used, we should reuse folder_name to create virtual folders
8487
class IarFolder():

tools/export/uvision4.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ def TARGETS(self):
5353
def get_toolchain(self):
5454
return TARGET_MAP[self.target].default_toolchain
5555

56-
def generate(self):
56+
def generate(self, progen_build=False):
5757
""" Generates the project files """
5858
project_data = self.progen_get_project_data()
5959
tool_specific = {}
@@ -99,4 +99,7 @@ def generate(self):
9999
i += 1
100100
project_data['common']['macros'].append('__ASSERT_MSG')
101101
project_data['common']['build_dir'] = join(project_data['common']['build_dir'], 'uvision4')
102-
self.progen_gen_file('uvision', project_data)
102+
if progen_build:
103+
self.progen_gen_file('uvision', project_data, True)
104+
else:
105+
self.progen_gen_file('uvision', project_data)

tools/export/uvision5.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ def TARGETS(self):
5757
def get_toolchain(self):
5858
return TARGET_MAP[self.target].default_toolchain
5959

60-
def generate(self):
60+
def generate(self, progen_build=False):
6161
""" Generates the project files """
6262
project_data = self.progen_get_project_data()
6363
tool_specific = {}
@@ -102,4 +102,7 @@ def generate(self):
102102
project_data['common']['macros'].pop(i)
103103
i += 1
104104
project_data['common']['macros'].append('__ASSERT_MSG')
105-
self.progen_gen_file('uvision5', project_data)
105+
if progen_build:
106+
self.progen_gen_file('uvision5', project_data, True)
107+
else:
108+
self.progen_gen_file('uvision5', project_data)

tools/project.py

Lines changed: 10 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,14 @@
77
from argparse import ArgumentParser
88
from os import path
99

10-
from tools.paths import EXPORT_DIR, EXPORT_WORKSPACE, EXPORT_TMP
11-
from tools.paths import MBED_BASE, MBED_LIBRARIES
12-
from tools.export import export, setup_user_prj, EXPORTERS, mcu_ide_matrix
13-
from tools.utils import args_error, mkdir
14-
from tools.tests import TESTS, Test, TEST_MAP
10+
from tools.paths import EXPORT_DIR
11+
from tools.export import export, EXPORTERS, mcu_ide_matrix
12+
from tools.tests import TESTS, TEST_MAP
1513
from tools.tests import test_known, test_name_known
1614
from tools.targets import TARGET_NAMES
17-
from tools.libraries import LIBRARIES
18-
from utils import argparse_lowercase_type, argparse_uppercase_type, argparse_filestring_type, argparse_many
15+
from utils import argparse_filestring_type, argparse_many
1916
from utils import argparse_force_lowercase_type, argparse_force_uppercase_type
17+
from project_api import setup_project, perform_export, print_results, get_lib_symbols
2018

2119

2220

@@ -129,56 +127,20 @@
129127
# Export results
130128
successes = []
131129
failures = []
132-
zip = True
133-
clean = True
134130

135131
# source_dir = use relative paths, otherwise sources are copied
136132
sources_relative = True if options.source_dir else False
137133

138134
for mcu in options.mcu:
139135
# Program Number or name
140136
p, src, ide = options.program, options.source_dir, options.ide
137+
project_dir, project_name, project_temp = setup_project(mcu, ide, p, src, options.build)
141138

142-
if src:
143-
# --source is used to generate IDE files to toolchain directly in the source tree and doesn't generate zip file
144-
project_dir = options.source_dir
145-
project_name = TESTS[p] if p else "Unnamed_project"
146-
project_temp = path.join(options.source_dir[0], 'projectfiles', '%s_%s' % (ide, mcu))
147-
mkdir(project_temp)
148-
lib_symbols = []
149-
if options.macros:
150-
lib_symbols += options.macros
151-
zip = False # don't create zip
152-
clean = False # don't cleanup because we use the actual source tree to generate IDE files
153-
else:
154-
test = Test(p)
155-
156-
# Some libraries have extra macros (called by exporter symbols) to we need to pass
157-
# them to maintain compilation macros integrity between compiled library and
158-
# header files we might use with it
159-
lib_symbols = []
160-
if options.macros:
161-
lib_symbols += options.macros
162-
for lib in LIBRARIES:
163-
if lib['build_dir'] in test.dependencies:
164-
lib_macros = lib.get('macros', None)
165-
if lib_macros is not None:
166-
lib_symbols.extend(lib_macros)
167-
168-
if not options.build:
169-
# Substitute the library builds with the sources
170-
# TODO: Substitute also the other library build paths
171-
if MBED_LIBRARIES in test.dependencies:
172-
test.dependencies.remove(MBED_LIBRARIES)
173-
test.dependencies.append(MBED_BASE)
174-
175-
# Build the project with the same directory structure of the mbed online IDE
176-
project_name = test.id
177-
project_dir = [join(EXPORT_WORKSPACE, project_name)]
178-
project_temp = EXPORT_TMP
179-
setup_user_prj(project_dir[0], test.source_dir, test.dependencies)
139+
zip = src is [] # create zip when no src_dir provided
140+
clean = src is [] # don't clean when source is provided, use acrual source tree for IDE files
180141

181142
# Export to selected toolchain
143+
lib_symbols = get_lib_symbols(options.macros, src, p)
182144
tmp_path, report = export(project_dir, project_name, ide, mcu, project_dir[0], project_temp, clean=clean, make_zip=zip, extra_symbols=lib_symbols, sources_relative=sources_relative)
183145
if report['success']:
184146
if not zip:
@@ -191,12 +153,4 @@
191153
failures.append("%s::%s\t%s"% (mcu, ide, report['errormsg']))
192154

193155
# Prints export results
194-
print
195-
if len(successes) > 0:
196-
print "Successful exports:"
197-
for success in successes:
198-
print " * %s"% success
199-
if len(failures) > 0:
200-
print "Failed exports:"
201-
for failure in failures:
202-
print " * %s"% failure
156+
print_results(successes, failures)

tools/project_api.py

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import sys
2+
from os.path import join, abspath, dirname, exists, basename
3+
ROOT = abspath(join(dirname(__file__), ".."))
4+
sys.path.insert(0, ROOT)
5+
6+
from tools.paths import EXPORT_WORKSPACE, EXPORT_TMP
7+
from tools.paths import MBED_BASE, MBED_LIBRARIES
8+
from tools.export import export, setup_user_prj
9+
from tools.utils import mkdir
10+
from tools.tests import Test, TEST_MAP, TESTS
11+
from tools.libraries import LIBRARIES
12+
13+
try:
14+
import tools.private_settings as ps
15+
except:
16+
ps = object()
17+
18+
19+
def get_program(n):
20+
p = TEST_MAP[n].n
21+
return p
22+
23+
24+
def get_test(p):
25+
return Test(p)
26+
27+
28+
def get_test_from_name(n):
29+
if not n in TEST_MAP.keys():
30+
# Check if there is an alias for this in private_settings.py
31+
if getattr(ps, "test_alias", None) is not None:
32+
alias = ps.test_alias.get(n, "")
33+
if not alias in TEST_MAP.keys():
34+
return None
35+
else:
36+
n = alias
37+
else:
38+
return None
39+
return get_program(n)
40+
41+
42+
def get_lib_symbols(macros, src, program):
43+
# Some libraries have extra macros (called by exporter symbols) to we need to pass
44+
# them to maintain compilation macros integrity between compiled library and
45+
# header files we might use with it
46+
lib_symbols = []
47+
if macros:
48+
lib_symbols += macros
49+
if src:
50+
return lib_symbols
51+
test = get_test(program)
52+
for lib in LIBRARIES:
53+
if lib['build_dir'] in test.dependencies:
54+
lib_macros = lib.get('macros', None)
55+
if lib_macros is not None:
56+
lib_symbols.extend(lib_macros)
57+
58+
59+
def setup_project(mcu, ide, program=None, source_dir=None, build=None):
60+
61+
# Some libraries have extra macros (called by exporter symbols) to we need to pass
62+
# them to maintain compilation macros integrity between compiled library and
63+
# header files we might use with it
64+
if source_dir:
65+
# --source is used to generate IDE files to toolchain directly in the source tree and doesn't generate zip file
66+
project_dir = source_dir
67+
project_name = TESTS[program] if program else "Unnamed_Project"
68+
project_temp = join(source_dir[0], 'projectfiles', '%s_%s' % (ide, mcu))
69+
mkdir(project_temp)
70+
else:
71+
test = get_test(program)
72+
if not build:
73+
# Substitute the library builds with the sources
74+
# TODO: Substitute also the other library build paths
75+
if MBED_LIBRARIES in test.dependencies:
76+
test.dependencies.remove(MBED_LIBRARIES)
77+
test.dependencies.append(MBED_BASE)
78+
79+
# Build the project with the same directory structure of the mbed online IDE
80+
project_name = test.id
81+
project_dir = [join(EXPORT_WORKSPACE, project_name)]
82+
project_temp = EXPORT_TMP
83+
setup_user_prj(project_dir[0], test.source_dir, test.dependencies)
84+
85+
return project_dir, project_name, project_temp
86+
87+
88+
def perform_export(dir, name, ide, mcu, temp, clean=False, zip=False, lib_symbols='',
89+
sources_relative=False, progen_build=False):
90+
91+
tmp_path, report = export(dir, name, ide, mcu, dir[0], temp, clean=clean,
92+
make_zip=zip, extra_symbols=lib_symbols, sources_relative=sources_relative,
93+
progen_build=progen_build)
94+
return tmp_path, report
95+
96+
97+
def print_results(successes, failures, skips = []):
98+
print
99+
if len(successes) > 0:
100+
print "Successful: "
101+
for success in successes:
102+
print " * %s" % success
103+
if len(failures) > 0:
104+
print "Failed: "
105+
for failure in failures:
106+
print " * %s" % failure
107+
if len(skips) > 0:
108+
print "Skipped: "
109+
for skip in skips:
110+
print " * %s" % skip
111+

0 commit comments

Comments
 (0)