From 9bb4a25b05a63b206f851a9944aa688476078e03 Mon Sep 17 00:00:00 2001 From: Matthew Sotoudeh Date: Sun, 30 Jul 2023 19:31:03 -0700 Subject: support for line tracking in dietcc --- scripts/dietcc | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 55 insertions(+), 8 deletions(-) (limited to 'scripts') diff --git a/scripts/dietcc b/scripts/dietcc index 540d168..e404397 100755 --- a/scripts/dietcc +++ b/scripts/dietcc @@ -21,23 +21,25 @@ if "-E" in sys.argv[1:]: # https://stackoverflow.com/questions/595305 dietc_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__))) -def check_result(spr): +def check_result(spr, debug): if not spr.returncode: return spr.stdout print("Failed to run gcc wrapper:", ' '.join(sys.argv), file=sys.stderr) if spr.stderr: print(spr.stderr.decode("utf-8"), file=sys.stderr) + open("/tmp/dietc.error.c", "wb").write(debug) assert False def preprocess_pass(c, meta): with tempfile.TemporaryDirectory() as tmpdir: t_file = open(f"{tmpdir}/file.c", "wb") + t_file.write(f"#line 1 \"{meta['c_path']}\"\n".encode("utf-8")) t_file.write(f"#include \"{dietc_dir}/scripts/stdincludes/dietc_defines.h\"\n".encode("utf-8")) t_file.write(c) t_file.flush() dirname = os.path.dirname(os.path.realpath(meta["c_path"])) return check_result( subprocess.run(f"{CC} -I{dirname} -E {meta['argstr']} {t_file.name}", - shell=True, capture_output=True)) + shell=True, capture_output=True), c) def strip_after_preprocess_pass(c, meta): c = re.sub(rb"\[\[[^\]]*\]\]", b"", c) @@ -45,14 +47,16 @@ def strip_after_preprocess_pass(c, meta): return c def dietc_pass(c, meta): + c = c.replace(b"# ", b"#line ") with tempfile.TemporaryDirectory() as tmpdir: t_file = open(f"{tmpdir}/file.c", "wb") t_file.write(c) t_file.flush() dirname = os.path.dirname(os.path.realpath(meta["c_path"])) + args = ' '.join(meta["dietc_args"]) return check_result( - subprocess.run(f"timeout 5s {dietc_dir}/dietc {t_file.name}", - shell=True, capture_output=True)) + subprocess.run(f"timeout 5s {dietc_dir}/dietc {t_file.name} {args}", + shell=True, stdout=subprocess.PIPE, stderr=sys.stderr), c) def final_cleanup_pass(dietc, meta): # (1) treat builtins as builtins @@ -134,13 +138,48 @@ def make_external_pass(command): t_file.write(dietc) t_file.flush() return check_result(subprocess.run(f"{command} {t_file.name}", - shell=True, capture_output=True)) + shell=True, stdout=subprocess.PIPE, stderr=sys.stderr), dietc) return pass_ +def strip_line_info(dietc, meta): + if "--line-numbers" not in meta["dietc_args"]: return dietc + lines = dietc.split(b"\n") + insert_after = dict() + insert_before = dict() + for i, line in enumerate(lines): + if not line.startswith(b"#line"): continue + before_line, after_line = lines[i-1], lines[i+1] + insert_after[before_line] = line + insert_before[after_line] = line + meta["lineinfo_insert_after"] = insert_after + meta["lineinfo_insert_before"] = insert_before + return b"\n".join(l for l in lines if not l.startswith(b"#line")) + +def reinsert_line_info(dietc, meta): + if "--line-numbers" not in meta["dietc_args"]: return dietc + lines = dietc.split(b"\n") + insert_after = meta["lineinfo_insert_after"] + insert_before = meta["lineinfo_insert_before"] + final_lines = [] + for line in lines: + if final_lines and final_lines[-1].startswith(b"#line"): + final_lines.append(line) + elif line in insert_before: + final_lines.append(insert_before[line]) + final_lines.append(line) + elif line in insert_after: + final_lines.append(line) + final_lines.append(insert_after[line]) + else: + final_lines.append(line) + return b"\n".join(final_lines) + PASSES = [preprocess_pass, strip_after_preprocess_pass, dietc_pass, - final_cleanup_pass] + strip_line_info, + final_cleanup_pass, + reinsert_line_info] def main(): args = list(map(shlex.quote, sys.argv[1:])) @@ -150,6 +189,11 @@ def main(): i = args.index("--dietc-pass") args.pop(i) PASSES.insert(-1, make_external_pass(args.pop(i))) + dietc_args = [] + while "--dietc-arg" in args: + i = args.index("--dietc-arg") + args.pop(i) + dietc_args.append(args.pop(i)) # then process all of the C files out_dir = tempfile.TemporaryDirectory() @@ -163,9 +207,12 @@ def main(): subargs.pop(i_) argstr = " ".join(subargs) + pass_history = [] last = open(c_file, "rb").read() + meta = {"c_path": c_file, "argstr": argstr, "dietc_args": dietc_args} for dietpass in PASSES: - last = dietpass(last, {"c_path": c_file, "argstr": argstr}) + last = dietpass(last, meta) + pass_history.append(last) diet_files.append(f"{out_dir.name}/file{i}.c") with open(diet_files[-1], "wb") as f: @@ -178,6 +225,6 @@ def main(): if "-c" in args: args += ["-o", c_files[0].replace(".c", ".o")] gcc = subprocess.run(f"{CC} {' '.join(args)} -Wno-int-to-pointer-cast -Wno-builtin-declaration-mismatch", shell=True) - check_result(gcc) + check_result(gcc, pass_history[-1] if c_files else b"") main() -- cgit v1.2.3