1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
#!/bin/python3
import subprocess
import re
import tempfile
import shlex
import sys
import os
dietc_dir = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
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 main(argv):
argv = argv[1:]
def argument(flag): return argv[argv.index(flag) + 1]
CC = "gcc"
tmpdir = tempfile.TemporaryDirectory()
# get the arguments WITHOUT -c, -o, source files, etc.
stripped_args = []
i = 0
while i < len(argv):
if (argv[i] == "-c" or argv[i].endswith(".c") or argv[i].endswith(".a") or argv[i].endswith(".o")):
i += 1
elif argv[i] == "-o":
i += 2
else:
stripped_args.append(argv[i])
i += 1
# ====== HANDLE -c ======
if "-c" in argv:
c_file = next(a for a in argv if a.endswith(".c"))
o_file = c_file[:-2] + ".o"
if "-o" in argv: o_file = argument("-o")
# (1) RUN PREPROCESSOR
c = open(c_file, "r").read()
t_file = open(f"{tmpdir.name}/file.c", "wb")
t_file.write(f"#line 1 \"{c_file}\"\n".encode("utf-8"))
t_file.write(f"#include \"{dietc_dir}/scripts/stdincludes/dietc_defines.h\"\n".encode("utf-8"))
t_file.write(c.encode("utf-8"))
t_file.flush()
dirname = os.path.dirname(os.path.realpath(c_file))
argstr = list(map(shlex.quote, stripped_args))
argstr.insert(0, f"-I{dietc_dir}/scripts/stdincludes")
argstr = ' '.join(argstr)
preproc_c = check_result(
subprocess.run(f"{CC} -I{dirname} -E {argstr} {t_file.name}",
shell=True, capture_output=True), c)
# (2) STRIP GCC-SPECIFIC STUFF AFTER PREPROCESSING
preproc_c = re.sub(rb"\[\[[^\]]*\]\]", b"", preproc_c)
preproc_c = re.sub(rb"__asm__", b"", preproc_c)
# (3) RUN DIETC
preproc_c = preproc_c.replace(b"# ", b"#line ")
t_file = open(f"{tmpdir.name}/file.c", "wb")
t_file.write(preproc_c)
t_file.flush()
dirname = os.path.dirname(os.path.realpath(c_file))
# TODO: args = ' '.join(meta["dietc_args"])
args = "--type-builtins"
diet_c = check_result(
subprocess.run(f"timeout 5s {dietc_dir}/dietc {t_file.name} {args}",
shell=True, stdout=subprocess.PIPE, stderr=sys.stderr), preproc_c)
# (4) SAVE TO A .o
with open(o_file, "wb") as out:
argstr = list(map(shlex.quote, stripped_args))
argstr = ' '.join(argstr)
out.write(b"DIETC")
out.write(len(argstr).to_bytes(4, "little"))
out.write(argstr.encode("utf-8"))
out.write(diet_c)
return
# ======= If any .cs, first convert them to .os =======
for i in range(len(argv)):
if not argv[i].endswith(".c"): continue
o_file = f"{tmpdir.name}/arg_{i}.o"
main(["dietcc", *stripped_args, "-c", argv[i], "-o", o_file])
argv[i] = o_file
# ======= If any .as, first ar -x them into .os =======
all_os = []
for i in range(len(argv)):
if argv[i].endswith(".o"):
all_os.append(argv[i])
elif argv[i].endswith(".a"):
subprocess.run(["ar", "-x", argv[i], "--output", f"{tmpdir.name}/{i}.unar"])
for path in os.listdir(f"{tmpdir.name}/{i}.unar"):
all_os.append(f"{tmpdir.name}/{i}.unar/{path}")
# ======= Put all the .os together into an output folder with Makefile =======
out_path = "a.out"
if "-o" in argv: out_path = argument("-o")
assert out_path not in ("", "/")
subprocess.run(["rm", "-rf", out_path])
os.mkdir(out_path)
makefile = open(f"{out_path}/Makefile", "w")
makefile.write("a.out: " + ' '.join([f"{i}.o" for i in range(len(all_os))]) + " $(OTHER_OBJS)\n")
argstr = list(map(shlex.quote, stripped_args))
argstr = ' '.join(argstr)
makefile.write(f"\t$(CC) $(CFLAGS) $^ -o $@ {argstr}\n\n")
for i, o_file in enumerate(all_os):
f = open(o_file, "rb")
if f.read(5) == b"DIETC":
# dietc file!
argstr = f.read(int.from_bytes(f.read(4), "little")).decode("utf-8")
with open(f"{out_path}/{i}.c", "wb") as i_file:
i_file.write(f.read())
makefile.write(f"{i}.o: {i}.c\n")
makefile.write(f"\t$(CC) $(CFLAGS) -c $^ -o $@ {argstr} -Wno-builtin-declaration-mismatch\n\n")
# TODO: include a postprocessing pass ...
else:
# regular .o
shutil.copy(o_file, f"{out_path}/{i}.o")
makefile.close()
main(sys.argv.copy())
|