]> begriffs open source - cmsis/blob - CMSIS/CoreValidation/Tests/build.py
CoreValidation: Enhanced build script to support long term maintenance (LTM) version...
[cmsis] / CMSIS / CoreValidation / Tests / build.py
1 #! python
2
3 import sys
4 import os
5 from argparse import ArgumentParser
6 from datetime import datetime
7 from subprocess import call, Popen
8 from pathlib import Path
9
10 sys.path.append('buildutils') 
11
12 from rtecmd import RteCmd 
13 from uv4cmd import Uv4Cmd 
14 from dscmd import DsCmd 
15 from fvpcmd import FvpCmd 
16 from iarcmd import IarCmd 
17 from testresult import TestResult
18
19 try:
20   rtebuildhome = os.path.join(os.path.abspath(Path.home()), ".rtebuild")
21   sys.path.append(rtebuildhome)
22   import buildenv
23 except ModuleNotFoundError:
24   print("No custom buildenv.py found in "+rtebuildhome)
25   buildenv = None
26   pass
27
28 DEVICE_CM0     = 'Cortex-M0'
29 DEVICE_CM0PLUS = 'Cortex-M0plus'
30 DEVICE_CM3     = 'Cortex-M3'
31 DEVICE_CM4     = 'Cortex-M4'
32 DEVICE_CM4FP   = 'Cortex-M4FP'
33 DEVICE_CM7     = 'Cortex-M7'
34 DEVICE_CM7SP   = 'Cortex-M7SP'
35 DEVICE_CM7DP   = 'Cortex-M7DP'
36 DEVICE_CM23    = 'Cortex-M23'
37 DEVICE_CM33    = 'Cortex-M33'
38 DEVICE_CM23NS  = 'Cortex-M23NS'
39 DEVICE_CM33NS  = 'Cortex-M33NS'
40 DEVICE_CM23S   = 'Cortex-M23S'
41 DEVICE_CM33S   = 'Cortex-M33S'
42 DEVICE_CA5     = 'Cortex-A5'
43 DEVICE_CA7     = 'Cortex-A7'
44 DEVICE_CA9     = 'Cortex-A9'
45 DEVICE_CA5NEON = 'Cortex-A5neon'
46 DEVICE_CA7NEON = 'Cortex-A7neon'
47 DEVICE_CA9NEON = 'Cortex-A9neon'
48
49 CC_AC6    = 'AC6'
50 CC_AC6LTM = 'AC6LTM'
51 CC_AC5    = 'AC5'
52 CC_GCC    = 'GCC'
53 CC_IAR    = 'IAR'
54
55 TARGET_FVP = 'FVP'
56
57 ADEVICES = {
58     DEVICE_CM0     : 'CM0',
59     DEVICE_CM0PLUS : 'CM0plus',
60     DEVICE_CM3     : 'CM3',
61     DEVICE_CM4     : 'CM4',
62     DEVICE_CM4FP   : 'CM4FP',
63     DEVICE_CM7     : 'CM7',
64     DEVICE_CM7SP   : 'CM7SP',
65     DEVICE_CM7DP   : 'CM7DP',
66     DEVICE_CM23    : 'CM23',
67     DEVICE_CM33    : 'CM33',
68     DEVICE_CM23S   : 'CM23S',
69     DEVICE_CM33S   : 'CM33S',
70     DEVICE_CM33NS  : 'CM33NS',
71     DEVICE_CM23NS  : 'CM23NS',
72     DEVICE_CA5     : 'CA5',
73     DEVICE_CA7     : 'CA7',
74     DEVICE_CA9     : 'CA9',
75     DEVICE_CA5NEON : 'CA5neon',
76     DEVICE_CA7NEON : 'CA7neon',
77     DEVICE_CA9NEON : 'CA9neon'
78   }
79
80 DEVICES = [ DEVICE_CM0, DEVICE_CM0PLUS, DEVICE_CM3, DEVICE_CM4, DEVICE_CM4FP, DEVICE_CM7, DEVICE_CM7SP, DEVICE_CM7DP, DEVICE_CM23, DEVICE_CM33, DEVICE_CM23NS, DEVICE_CM33NS, DEVICE_CM23S, DEVICE_CM33S, DEVICE_CA5, DEVICE_CA7, DEVICE_CA9, DEVICE_CA5NEON, DEVICE_CA7NEON, DEVICE_CA9NEON ]
81 COMPILERS = [ CC_AC5, CC_AC6, CC_AC6LTM, CC_GCC, CC_IAR ]
82 TARGETS = [ TARGET_FVP ]
83
84 SKIP = [ 
85     [ DEVICE_CM23,    CC_AC5,    None ],
86     [ DEVICE_CM33,    CC_AC5,    None ],
87     [ DEVICE_CM23NS,  CC_AC5,    None ],
88     [ DEVICE_CM33NS,  CC_AC5,    None ],
89     [ DEVICE_CM23S,   CC_AC5,    None ],
90     [ DEVICE_CM33S,   CC_AC5,    None ],
91     [ DEVICE_CM0,     CC_AC6LTM, None ],
92     [ DEVICE_CM0PLUS, CC_AC6LTM, None ],
93     [ DEVICE_CM23,    CC_AC6LTM, None ],
94     [ DEVICE_CM33,    CC_AC6LTM, None ],
95     [ DEVICE_CM23NS,  CC_AC6LTM, None ],
96     [ DEVICE_CM33NS,  CC_AC6LTM, None ],
97     [ DEVICE_CM23S,   CC_AC6LTM, None ],
98     [ DEVICE_CM33S,   CC_AC6LTM, None ],
99   ]
100   
101 FVP_MODELS = { 
102     DEVICE_CM0      : { 'cmd': "FVP_MPS2_Cortex-M0_MDK.exe",      'args': { 'limit': "50000000", 'config': "ARMCM0_config.txt" } },
103     DEVICE_CM0PLUS  : { 'cmd': "FVP_MPS2_Cortex-M0plus_MDK.exe",  'args': { 'limit': "50000000", 'config': "ARMCM0plus_config.txt" } },
104     DEVICE_CM3      : { 'cmd': "FVP_MPS2_Cortex-M3_MDK.exe",      'args': { 'limit': "50000000", 'config': "ARMCM3_config.txt" } },
105     DEVICE_CM4      : { 'cmd': "FVP_MPS2_Cortex-M4_MDK.exe",      'args': { 'limit': "50000000", 'config': "ARMCM4_config.txt" } },
106     DEVICE_CM4FP    : { 'cmd': "FVP_MPS2_Cortex-M4_MDK.exe",      'args': { 'limit': "50000000", 'config': "ARMCM4FP_config.txt" } },
107     DEVICE_CM7      : { 'cmd': "FVP_MPS2_Cortex-M7_MDK.exe",      'args': { 'limit': "50000000", 'config': "ARMCM7_config.txt" } },
108     DEVICE_CM7SP    : { 'cmd': "FVP_MPS2_Cortex-M7_MDK.exe",      'args': { 'limit': "50000000", 'config': "ARMCM7SP_config.txt" } },
109     DEVICE_CM7DP    : { 'cmd': "FVP_MPS2_Cortex-M7_MDK.exe",      'args': { 'limit': "50000000", 'config': "ARMCM7DP_config.txt" } },
110     DEVICE_CM23     : { 'cmd': "FVP_MPS2_Cortex-M23_MDK.exe",     'args': { 'limit': "50000000", 'config': "ARMCM23_config.txt",           'target': "cpu0" } },
111     DEVICE_CM33     : { 'cmd': "FVP_MPS2_Cortex-M33_MDK.exe",     'args': { 'limit': "50000000", 'config': "ARMCM33_config.txt",           'target': "cpu0" } },
112     DEVICE_CM23NS   : { 'cmd': "FVP_MPS2_Cortex-M23_MDK.exe",     'args': { 'limit': "50000000", 'config': "ARMCM23_TZ_config.txt",        'target': "cpu0" } },
113     DEVICE_CM33NS   : { 'cmd': "FVP_MPS2_Cortex-M33_MDK.exe",     'args': { 'limit': "50000000", 'config': "ARMCM33_DSP_FP_TZ_config.txt", 'target': "cpu0" } },
114     DEVICE_CM23S    : { 'cmd': "FVP_MPS2_Cortex-M23_MDK.exe",     'args': { 'limit': "50000000", 'config': "ARMCM23_TZ_config.txt",        'target': "cpu0" } },
115     DEVICE_CM33S    : { 'cmd': "FVP_MPS2_Cortex-M33_MDK.exe",     'args': { 'limit': "50000000", 'config': "ARMCM33_DSP_FP_TZ_config.txt", 'target': "cpu0" } },
116     DEVICE_CA5      : { 'cmd': "fvp_ve_cortex-a5x1.exe",          'args': { 'limit': "70000000", 'config': "ARMCA5_config.txt" } },
117     DEVICE_CA7      : { 'cmd': "fvp_ve_cortex-a7x1.exe",          'args': { 'limit': "170000000", 'config': "ARMCA7_config.txt" } },
118     DEVICE_CA9      : { 'cmd': "fvp_ve_cortex-a9x1.exe",          'args': { 'limit': "70000000", 'config': "ARMCA9_config.txt" } },
119     DEVICE_CA5NEON  : { 'cmd': "fvp_ve_cortex-a5x1.exe",          'args': { 'limit': "70000000", 'config': "ARMCA5neon_config.txt" } },
120     DEVICE_CA7NEON  : { 'cmd': "fvp_ve_cortex-a7x1.exe",          'args': { 'limit': "170000000", 'config': "ARMCA7neon_config.txt" } },
121     DEVICE_CA9NEON  : { 'cmd': "fvp_ve_cortex-a9x1.exe",          'args': { 'limit': "70000000", 'config': "ARMCA9neon_config.txt" } }
122   }
123
124 def isSkipped(dev, cc, target):
125   for skip in SKIP:
126     skipDev = (skip[0] == None or skip[0] == dev)
127     skipCc = (skip[1] == None or skip[1] == cc)
128     skipTarget = (skip[2] == None or skip[2] == target)
129     if skipDev and skipCc and skipTarget:
130       return True
131   return False
132   
133 def testProject(dev, cc, target):
134   rtebuild = "{dev}/{cc}/default.rtebuild".format(dev = dev, cc = cc, target=target)
135   if os.path.exists(rtebuild):
136     return [
137         rtebuild,
138         "{dev}/{cc}/build/{target}/{target}.elf".format(dev = dev, cc = cc, target=target)
139       ]
140   elif (cc == CC_AC5) or (cc == CC_AC6):
141     return [
142         "{dev}/{cc}/CMSIS_CV.uvprojx".format(dev = dev, cc = cc),
143         "{dev}/{cc}/Objects/CMSIS_CV.axf".format(dev = dev, cc = cc)
144       ]
145   elif (cc == CC_AC6LTM):
146     return [
147         "{dev}/{cc}/CMSIS_CV.uvprojx".format(dev = dev, cc = CC_AC6),
148         "{dev}/{cc}/Objects/CMSIS_CV.axf".format(dev = dev, cc = CC_AC6)
149       ]
150   elif (cc == CC_GCC):
151     return [
152         "{dev}/{cc}/CMSIS_CV.uvprojx".format(dev = dev, cc = cc),
153         "{dev}/{cc}/Objects/CMSIS_CV.elf".format(dev = dev, cc = cc)
154       ]
155   elif (cc == CC_IAR):
156     return [
157         "{dev}/{cc}/CMSIS_CV.ewp".format(dev = dev, cc = cc),
158         "{dev}/{cc}/{target}/Exe/CMSIS_CV.out".format(dev = dev, cc = cc, target = target)
159       ]
160   raise "Unknown compiler!"
161
162 def bootloaderProject(dev, cc, target):
163   rtebuild = "{dev}/{cc}/Bootloader/default.rtebuild".format(dev = dev, cc = cc, target=target)
164   if os.path.exists(rtebuild):
165     return [
166         rtebuild,
167         "{dev}/{cc}/Bootloader/build/{target}/{target}.elf".format(dev = dev, cc = cc, target=target)
168       ]
169   elif (cc == CC_AC5) or (cc == CC_AC6):
170     return [
171         "{dev}/{cc}/Bootloader/Bootloader.uvprojx".format(dev = dev, cc = cc),
172         "{dev}/{cc}/Bootloader/Objects/Bootloader.axf".format(dev = dev, cc = cc)
173       ] 
174   elif (cc == CC_AC6LTM):
175     return [
176         "{dev}/{cc}/Bootloader/Bootloader.uvprojx".format(dev = dev, cc = CC_AC6),
177         "{dev}/{cc}/Bootloader/Objects/Bootloader.axf".format(dev = dev, cc = CC_AC6)
178       ] 
179   elif (cc == CC_GCC):
180     return [
181         "{dev}/{cc}/Bootloader/Bootloader.uvprojx".format(dev = dev, cc = cc),
182         "{dev}/{cc}/Bootloader/Objects/Bootloader.elf".format(dev = dev, cc = cc)
183       ] 
184   elif (cc == CC_IAR):
185     return [
186         "{dev}/{cc}/Bootloader/Bootloader.ewp".format(dev = dev, cc = cc),
187         "{dev}/{cc}/Bootloader/{target}/Exe/Bootloader.out".format(dev = dev, cc = cc, target = target)
188       ]
189   raise "Unknown compiler!"
190   
191 def buildStep(dev, cc, target, project, env=os.environ):
192   STEP_TYPES = {
193     ".uvprojx"  : Uv4Cmd,
194     ".ewp"      : IarCmd,
195     ".rtebuild" : RteCmd
196   }
197   
198   projectfile, projectext = os.path.splitext(project)
199   
200   if not projectext in STEP_TYPES:
201     raise "Unknown project type '"+projectext+"'!"
202     
203   return STEP_TYPES[projectext](project, target, env)
204   
205 def prepare(steps, args):
206   for dev in args.devices:
207     for cc in args.compilers:
208       for target in args.targets:
209         if not isSkipped(dev, cc, target):
210           config = "{dev} ({cc}, {target})".format(dev = dev, cc = cc, target = target)
211           prefix = "{dev}_{cc}_{target}".format(dev = dev, cc = cc, target = target)
212           
213           env = os.environ
214           if hasattr(buildenv, "env_"+cc):
215             env = getattr(buildenv, "env_"+cc)()
216
217           rv = testProject(dev, cc, target)
218           build = [ buildStep(dev, cc, target, rv[0], env=env) ]
219           binary = [ rv[1] ]
220           
221           bl = bootloaderProject(dev, cc, target)
222           if os.path.isfile(bl[0]):
223             build = [ buildStep(dev, cc, target, bl[0], env=env) ] + build
224             binary = [ bl[1] ] + binary
225
226           if target == TARGET_FVP:
227             test = FvpCmd(FVP_MODELS[dev]['cmd'], binary, **FVP_MODELS[dev]['args'])
228           steps += [ { 'name': config, 'prefix': prefix, 'build': build, 'test': test } ]
229
230 def execute(steps, args):
231   for step in steps:
232     print(step['name'])
233     if step['build'] and not args.execute_only:
234       for b in step['build']:
235         b.run()
236     else:
237       print("Skipping build")
238       # step['build'].skip()
239       
240     if step['test'] and not args.build_only:
241       step['test'].run()
242       step['result'] = TestResult(step['test'].getOutput())
243       step['result'].saveXml("result_{0}_{1}.xml".format(step['prefix'], datetime.now().strftime("%Y%m%d%H%M%S")))
244     else:
245       print("Skipping test")
246       step['test'].skip()
247       
248 def printSummary(steps):
249   print("")
250   print("Test Summary")
251   print("============")
252   print()
253   print("Test run                       Total Exec  Pass  Fail  ")
254   print("-------------------------------------------------------")
255   for step in steps:
256     try:
257       print("{0:30} {1:>4}  {2:>4}  {3:>4}  {4:>4}".format(step['name'], *step['result'].getSummary()))
258     except:
259       print("{0:30} ------ NO RESULTS ------".format(step['name']))
260
261 def main(argv):
262   parser = ArgumentParser()
263   parser.add_argument('--genconfig', action='store_true')
264   parser.add_argument('-b', '--build-only', action='store_true')
265   parser.add_argument('-e', '--execute-only', action='store_true')
266   parser.add_argument('-d', '--devices', nargs='*', choices=(DEVICES+list(ADEVICES.values())), default=DEVICES, help = 'Devices to be considered.')
267   parser.add_argument('-c', '--compilers', nargs='*', choices=COMPILERS, default=COMPILERS, help = 'Compilers to be considered.')
268   parser.add_argument('-t', '--targets', nargs='*', choices=TARGETS, default=TARGETS, help = 'Targets to be considered.')
269   args = parser.parse_args()
270   
271   devices = set()
272   for d in args.devices:
273     if d in ADEVICES.values():
274       d = list(ADEVICES.keys())[list(ADEVICES.values()).index(d)]
275     devices.add(d)
276   
277   args.devices = list(devices)
278     
279   if args.genconfig:
280     for dev in args.devices:
281       model = FVP_MODELS[dev]
282       cmd = [ model['cmd'], '-l', '-o', model['args']['config'] ]
283       print(" ".join(cmd))
284       call(cmd)
285     return 1
286     
287   steps = []
288
289   prepare(steps, args)
290   
291   execute(steps, args)
292   
293   printSummary(steps)
294   
295 if __name__ == "__main__":
296   main(sys.argv[1:])