Newer
Older
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
#!/usr/bin/env python3
"""
Takes 2 args
qtc_assembler_preview.py <build_dir> <file.c/c++>
Currently GCC is assumed
"""
import sys
import os
import shlex
import subprocess
BUILD_DIR = sys.argv[-2]
SOURCE_FILE = sys.argv[-1]
# TODO, support other compilers
COMPILER_ID = 'GCC'
def find_arg(source, data):
source_base = os.path.basename(source)
for l in data:
# chances are high that we found the file
if source_base in l:
# check if this file is in the line
l_split = shlex.split(l)
for w in l_split:
if w.endswith(source_base):
if os.path.isabs(w):
if os.path.samefile(w, source):
# print(l)
return l
else:
# check trailing path (a/b/c/d/e.c == d/e.c)
w_sep = os.path.normpath(w).split(os.sep)
s_sep = os.path.normpath(source).split(os.sep)
m = min(len(w_sep), len(s_sep))
if w_sep[-m:] == s_sep[-m:]:
# print(l)
return l
def find_build_args_ninja(source):
make_exe = "ninja"
process = subprocess.Popen([make_exe, "-t", "commands"],
stdout=subprocess.PIPE,
Campbell Barton
committed
cwd=BUILD_DIR,
)
while process.poll():
time.sleep(1)
out = process.stdout.read()
process.stdout.close()
# print("done!", len(out), "bytes")
data = out.decode("utf-8", errors="ignore").split("\n")
return find_arg(source, data)
def find_build_args_make(source):
make_exe = "make"
process = subprocess.Popen([make_exe, "--always-make", "--dry-run", "--keep-going", "VERBOSE=1"],
stdout=subprocess.PIPE,
Campbell Barton
committed
cwd=BUILD_DIR,
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
)
while process.poll():
time.sleep(1)
out = process.stdout.read()
process.stdout.close()
# print("done!", len(out), "bytes")
data = out.decode("utf-8", errors="ignore").split("\n")
return find_arg(source, data)
def main():
# currently only supports ninja or makefiles
build_file_ninja = os.path.join(BUILD_DIR, "build.ninja")
build_file_make = os.path.join(BUILD_DIR, "Makefile")
if os.path.exists(build_file_ninja):
print("Using Ninja")
arg = find_build_args_ninja(SOURCE_FILE)
elif os.path.exists(build_file_make):
print("Using Make")
arg = find_build_args_make(SOURCE_FILE)
else:
sys.stderr.write("Can't find Ninja or Makefile (%r or %r), aborting" % (build_file_ninja, build_file_make))
return
if arg is None:
sys.stderr.write("Can't find file %r in build command output of %r, aborting" % (SOURCE_FILE, BUILD_DIR))
return
# now we need to get arg and modify it to produce assembler
arg_split = shlex.split(arg)
# get rid of: 'cd /a/b/c && ' prefix used by make (ninja doesn't need)
try:
i = arg_split.index("&&")
except ValueError:
i = -1
if i != -1:
del arg_split[:i + 1]
if COMPILER_ID == 'GCC':
# remove arg pairs
for arg, n in (("-o", 2), ("-MF", 2), ("-MT", 2), ("-MMD", 1)):
if arg in arg_split:
i = arg_split.index(arg)
del arg_split[i : i + n]
# --- Switch debug for optimized ---
for arg, n in (("-O0", 1),
("-g", 1), ("-g1", 1), ("-g2", 1), ("-g3", 1),
("-ggdb", 1), ("-ggdb", 1), ("-ggdb1", 1), ("-ggdb2", 1), ("-ggdb3", 1),
("-fno-inline", 1),
("-fsanitize=address", 1),
("-fsanitize=undefined", 1),
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
("-DDEBUG", 1), ("-D_DEBUG", 1),
):
if arg in arg_split:
i = arg_split.index(arg)
del arg_split[i : i + n]
# add optimized args
arg_split += ["-O3", "-fomit-frame-pointer", "-DNDEBUG", "-Wno-error"]
# not essential but interesting to know
arg_split += ["-ftree-vectorizer-verbose=1"]
arg_split += ["-S"]
# arg_split += ["-masm=intel"] # optional
# arg_split += ["-fverbose-asm"] # optional but handy
else:
sys.stderr.write("Compiler %r not supported" % COMPILER_ID)
return
source_asm = SOURCE_FILE + ".asm"
# Never overwrite existing files
i = 1
while os.path.exists(source_asm):
source_asm = SOURCE_FILE + ".asm.%d" % i
i += 1
arg_split += ["-o", source_asm]
# print("Executing:", arg_split)
subprocess.call(arg_split)
if not os.path.exists(source_asm):
sys.stderr.write("Did not create %r from calling %r" % (source_asm, " ".join(arg_split)))
return
print("Running: %r" % " ".join(arg_split))
print("Created: %r" % source_asm)
if __name__ == "__main__":
main()