ASCII Serial Com
Serial communication library between computers, microcontrollers, FPGAs, etc. Uses only ASCII. Not the most efficient protocol, but meant to be easy to read
Loading...
Searching...
No Matches
make.py
1#!/usr/bin/env python3
2
3import argparse
4import os
5import os.path
6import subprocess
7import sys
8
9
10def run_make(platform, CC, build_type, args):
11 env = os.environ.copy()
12 env.update({"platform": platform, "CC": CC, "build_type": build_type})
13 exe_path = env["PATH"]
14 exe_path = os.path.abspath("tools/avr-install/bin") + ":" + exe_path
15 env["PATH"] = exe_path
16 if args.coverage and platform == "native" and build_type == "debug":
17 env["coverage"] = "TRUE"
18
19 outdir = "build/{}_{}_{}".format(platform, CC, build_type)
20 outdir = os.path.abspath(outdir)
21
22 try:
23 subprocess.run(["make", "clean"], env=env, check=True)
24 except subprocess.CalledProcessError as e:
25 sys.exit(1)
26 try:
27 subprocess.run(["make", "install"], env=env, check=True)
28 except subprocess.CalledProcessError as e:
29 sys.exit(1)
30 if args.unittest:
31 stdout = ""
32 success = True
33 print(outdir, flush=True)
34 for fn in os.listdir(outdir):
35 print(fn)
36 if "test_" == fn[:5]:
37 fnabs = os.path.join(outdir, fn)
38 print(fnabs)
39 cmpltProc = subprocess.run(
40 [fnabs],
41 env=env,
42 stdout=subprocess.PIPE,
43 stderr=subprocess.STDOUT,
44 text=True,
45 )
46 stdout += (
47 "\n==========================================================\n\n"
48 )
49 stdout += "build/{}_{}_{}/{}\n\n".format(platform, CC, build_type, fn)
50 stdout += cmpltProc.stdout
51 success = success and (cmpltProc.returncode == 0)
52 if args.coverage and platform == "native" and build_type == "debug":
53 coverage_dir = os.path.join(outdir, "coverage")
54 try:
55 os.mkdir(coverage_dir)
56 except FileExistsError:
57 pass
58 coverage_html_base = os.path.join(coverage_dir, "index.html")
59 coverage_text = os.path.join(coverage_dir, "coverage.txt")
60 subprocess.run(
61 ["gcovr", "-o", coverage_text, "-e", "src/externals/.*"],
62 env=env,
63 check=True,
64 )
65 subprocess.run(
66 [
67 "gcovr",
68 "--html-details",
69 "-o",
70 coverage_html_base,
71 "-e",
72 "src/externals/.*",
73 ],
74 env=env,
75 check=True,
76 )
77 return success, stdout
78 return None, None
79
80
81def run_integration_tests():
82 env = os.environ.copy()
83
84 test_dir = "integration_tests"
85 tests = os.listdir(test_dir)
86 success = True
87 print()
88 print("========== Integration Tests =============")
89 print()
90 stdout = ""
91 for test in tests:
92 if test[-3:] != ".py":
93 continue
94 testfn = os.path.join(test_dir, test)
95 cmpltProc = subprocess.run(
96 ["python3", "-m", "unittest", testfn],
97 env=env,
98 stdout=subprocess.PIPE,
99 stderr=subprocess.STDOUT,
100 text=True,
101 )
102 success = success and (cmpltProc.returncode == 0)
103 print(cmpltProc.stdout, flush=True)
104 stdout += cmpltProc.stdout
105 if success:
106 print("Integration Tests All Pass!")
107 else:
108 print("Integration Test Failure")
109 return success, stdout
110
111
112def print_FW_size(targets):
113 env = os.environ.copy()
114 exe_path = env["PATH"]
115 exe_path = os.path.abspath("tools/avr-install/bin") + ":" + exe_path
116 env["PATH"] = exe_path
117 avr_fwfiles = []
118 cortex_fwfiles = []
119 rv32_fwfiles = []
120 for target in sorted(targets):
121 for build_type in ["debug", "opt"]:
122 target_list = target.split("_")
123 assert len(target_list) == 2
124 platform = target_list[0]
125 if "avr" in platform:
126 CC = target_list[1]
127 outdir = "build/{}_{}_{}".format(platform, CC, build_type)
128 outdir = os.path.abspath(outdir)
129 outfiles = os.listdir(outdir)
130 fwfiles = [os.path.join(outdir, x) for x in outfiles if x[-2:] != ".a"]
131 avr_fwfiles += fwfiles
132 elif "cortex" in platform:
133 CC = target_list[1]
134 outdir = "build/{}_{}_{}".format(platform, CC, build_type)
135 outdir = os.path.abspath(outdir)
136 outfiles = os.listdir(outdir)
137 fwfiles = [os.path.join(outdir, x) for x in outfiles if x[-2:] != ".a"]
138 cortex_fwfiles += fwfiles
139 elif "rv32" in platform:
140 CC = target_list[1]
141 outdir = "build/{}_{}_{}".format(platform, CC, build_type)
142 outdir = os.path.abspath(outdir)
143 outfiles = os.listdir(outdir)
144 fwfiles = [os.path.join(outdir, x) for x in outfiles if x[-4:] == ".elf"]
145 rv32_fwfiles += fwfiles
146 if len(avr_fwfiles) + len(cortex_fwfiles) + len(rv32_fwfiles) == 0:
147 return
148 print("========= Firmware Size ==========")
149 cmpltProc = subprocess.run(["avr-size", "-G"] + avr_fwfiles, env=env, text=True,)
150 cmpltProc = subprocess.run(
151 ["arm-none-eabi-size", "-G"] + cortex_fwfiles, env=env, text=True,
152 )
153 cmpltProc = subprocess.run(
154 ["riscv32-unknown-elf-size", "-G"] + rv32_fwfiles, env=env, text=True,
155 )
156
157
158def run_doxygen():
159 cmpltProc = subprocess.run(["doxygen", "doc/Doxyfile"],)
160
161
162def main():
163
164 available_targets = [
165 "all",
166 "default",
167 "native_gcc",
168 "native_clang",
169 "avr5_gcc",
170 "avr6_gcc",
171 "avrxmega3_gcc",
172 "cortex-m0_gcc",
173 "cortex-m3_gcc",
174 "cortex-m4_gcc",
175 "cortex-m7_gcc",
176 "rv32i_gcc",
177 "rv32ic_gcc",
178 ]
179 default_targets = [
180 "native_gcc",
181 "native_clang",
182 "avr5_gcc",
183 "cortex-m0_gcc",
184 ]
185
186 parser = argparse.ArgumentParser(
187 description="Build tool for ASCII-Serial-Com. Will stop and exit with status 1 if build fails, but continue if tests fail."
188 )
189 parser.add_argument(
190 "targets",
191 help="Targets to build; defaults: {}".format(default_targets),
192 nargs="*",
193 default="default",
194 choices=available_targets,
195 )
196 parser.add_argument(
197 "--unittest", "-u", help="Perform unittests after building", action="store_true"
198 )
199 parser.add_argument(
200 "--coverage",
201 "-c",
202 help="Collect coverage info when unittests are performed (sets -u)",
203 action="store_true",
204 )
205 args = parser.parse_args()
206
207 targets = args.targets
208
209 print(targets)
210 if type(targets) == str:
211 targets = default_targets
212 elif "all" in targets:
213 targets = available_targets
214 targets.remove("all")
215 targets.remove("default")
216 elif "default" in targets:
217 targets += default_targets
218 targets.remove("default")
219 print(targets)
220
221 if args.coverage:
222 args.unittest = True
223
224 testOutBuffer = ""
225 testsAllPass = True
226 for target in targets:
227 target_list = target.split("_")
228 assert len(target_list) == 2
229 platform = target_list[0]
230 CC = target_list[1]
231 build_types = ["debug", "opt"]
232 if "native" in target:
233 build_types.append("profile")
234 for build_type in build_types:
235 testPass, testOutput = run_make(platform, CC, build_type, args)
236 if args.unittest:
237 testOutBuffer += testOutput
238 testsAllPass = testsAllPass and testPass
239
240 pythonTestsPass = False
241 if args.unittest:
242 print()
243 print("==========================================")
244 print("========== Unit Test Results =============")
245 print("==========================================")
246 print()
247 print(testOutBuffer)
248
249 if testsAllPass:
250 print("Unit Tests All Pass!")
251 else:
252 print("Unit Test Failure")
253
254 print_FW_size(targets)
255
256 if args.unittest:
257 print()
258 print("============= Test Summary ===============")
259 print()
260 if args.unittest:
261 if testsAllPass:
262 print("Unit Tests All Pass!")
263 else:
264 print("Unit Test Failure")
265 if args.unittest:
266 print()
267
268
269if __name__ == "__main__":
270 main()