-
Notifications
You must be signed in to change notification settings - Fork 0
/
bm
executable file
·142 lines (135 loc) · 3.62 KB
/
bm
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
130
131
132
133
134
135
136
137
138
139
140
141
#!/bin/env python3
# Bullshit make
from os import listdir, path, remove, stat, system, rename, makedirs
import re
from sys import argv
from json import load, dump
FLAG_DEBUG = 0
VERBOSE = True
CC = "g++"
SRC_PATH = "src"
CFLAGS = f"-I {SRC_PATH} -g -Werror=switch-enum" + ("" if not FLAG_DEBUG else " -D DEBUG")
LFLAGS = ""
OBJ_PATH = "temp"
BIN = "bin/my_incredible_program" # Bin path is deduced from this.
CONFIG = "config/bm.json" # Same here
EXT = ".cpp"
def rls(path_, filter = lambda x: True):
for target in listdir(path_):
target = f"{path_}/{target}"
if path.isdir(target):
for ret in rls(target, filter):
yield ret
else:
if filter(target):
yield target
def last_ch(path: str):
return stat(path).st_mtime
def load_opt():
global opt
try:
with open(CONFIG, "r") as f:
opt = load(f)
except FileNotFoundError:
print("[bm] Failed to open options.")
opt = {}
def save_opt():
global opt
with open(CONFIG, "w") as f:
dump(opt, f)
def yeet(code: int):
save_opt()
print(f"Exited with code {(code>>8)&0xff}")
quit(code)
def fixmissing_files_opt():
for path_ in rls(
SRC_PATH,
lambda p:
p[-len(EXT):] == EXT
and p not in opt
):
# Iter through all source .cpp files and check if there are any missing in the options
if path_ not in opt:
opt[path_] = last_ch(path_)
def compile_all(check_ch_time = True, cflags = ""):
for path_ in rls(
SRC_PATH,
lambda p:
p[-len(EXT):] == EXT
):
# Iter through all source .cpp files
if (not check_ch_time) or opt[path_] < last_ch(path_):
compile_to_obj(path_, cflags)
def compile_to_obj(p: str, cflags=""):
""" cflags are additional flags to the setting CFLAGS """
out_path = f"{OBJ_PATH}/{path.basename(p)}"[:-len(EXT)] + '.o'
if code := shell(f"{CC} -c {p} -o {out_path} {CFLAGS} {cflags}"):
yeet(code)
else:
opt[p] = last_ch(p)
def link_all(cflags = ""):
""" cflags are additional flags to the setting CFLAGS """
j = " ".join(rls(OBJ_PATH, lambda x: x[-2:] == ".o"))
if not j:
raise Exception("Wtf ???")
if code := shell(f"{CC} {j} -o {BIN} {CFLAGS} {cflags} {LFLAGS}"):
yeet(code)
def run_example():
if code := shell(EXAMPLE):
yeet(code)
def debugging(tool: str):
match tool:
case "valgrind" | "mem" | "v":
if code := shell(f"valgrind --leak-check=full --show-leak-kinds=all --track-origins=yes -s -- {BIN} examples/test.da"):
yeet(code)
# add more tools here
case _:
if code := shell(f"gdb {BIN}"):
yeet(code)
if VERBOSE:
def shell(cmd: str) -> int:
print(cmd)
return system(cmd)
else:
shell = system
if not path.exists(OBJ_PATH):
makedirs(OBJ_PATH, exist_ok=True)
BIN_PATH = BIN.rsplit('/', 1)[0]
if not path.exists(BIN_PATH):
makedirs(BIN_PATH, exist_ok=True)
CONFIG_PATH = CONFIG.rsplit('/', 1)[0]
if not path.exists(CONFIG_PATH):
makedirs(CONFIG_PATH, exist_ok=True)
load_opt()
fixmissing_files_opt()
if __name__ == "__main__":
if len(argv) == 1:
compile_all(cflags="-O0") # Avoid any optimization for a simple test run
link_all()
run_example()
yeet(0)
match argv[1]:
case "all":
compile_all(check_ch_time=False, cflags="-O0")
yeet(0)
case "production":
compile_all(check_ch_time=False, cflags="-O3")
link_all()
yeet(0)
case "dbg" | "gdb" | "debug" | "d" | "fd":
# 'fd' is fast debug (won't recompile everything)
if argv[1] != "fd":
shell("./bm all")
link_all(cflags="-O0")
debugging("" if len(argv) == 2 else argv[2])
yeet(0)
case "clear" | "clean":
shell("rm temp/*")
yeet(0)
case "copy":
if err := shell(f"cp {__file__} ."):
yeet(err)
yeet(0)
case _:
print("Syntax: bm [arg]")
print("\targ can either be 'c', 'all', 'dbg', 'clean', 'copy', or 'production'")