-
Notifications
You must be signed in to change notification settings - Fork 10
/
Copy pathrun.sh
executable file
·258 lines (205 loc) · 6.11 KB
/
run.sh
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
#!/bin/bash
#
# Usage:
# ./run.sh <function name>
set -o nounset
set -o pipefail
set -o errexit
# https://www.gnu.org/software/make/manual/html_node/Automatic-Prerequisites.html
clean() {
rm -v -f main.d main.d.mm main.o main
}
edit-files() {
#echo '#include "newdep.h"' >> defs.h
# Override it
#echo '#define EXIT_CODE 100' > newdep.h
sed -i 's|/\*HERE\*/|#include "defs.h"|g' main.c
}
run-main() {
set +o errexit
./main
echo "status: $?"
echo
}
show-file() {
local path=$1
echo "--- $path ---"
cat $path
echo
}
demo() {
clean
git checkout main.c defs.h newdep.h # revert it
show-file main.c
#show-file defs.h
#show-file newdep.h
make "$@"
run-main
show-file main.d.mm
show-file main.d
edit-files
show-file main.c
#show-file defs.h
#show-file newdep.h
make "$@"
run-main
show-file main.d.mm
show-file main.d
#clean
}
# Trying without the %.d rule. This seems wrong on two counts:
# https://news.ycombinator.com/item?id=15061615
#
# Hm but it works?
demo-short() {
demo -f short.mk
}
show-flag() {
local flag=$1
rm -f main.d
# -M writes to stdout
echo "... $flag ..."
gcc $flag main.c
echo
}
flags() {
show-flag -M
test -f main.d && { echo "Should not exist"; exit 1; }
# -MD is equivalent to -M -MF file, except that -E is not implied. -E means
show-flag -MD
show-file main.d
show-flag -MMD
show-file main.d
}
# Hm this doesn't seem to output a .d file if there's a compile error. But it's a simple case.
compile-error() {
rm -f compile-error.d
set +o errexit
gcc -MD compile-error.c
ls -l
}
# Invoke the preprocessor directly
preprocessor-deps() {
# How to write it to a file, but not preprocess?
cpp main.c -M -MF my_custom_name.d
show-file my_custom_name.d
# Doesn't generate .o file
gcc -c main.c -M -MF my_custom_name2.d
show-file my_custom_name2.d
#ls -l main.o
# TODO: I don't think there's way to compile and generate .d to a custom name? Two outputs?
}
trace-procs() {
local prefix=$1
shift
rm -f $prefix.*
strace -ff -e 'execve' -o $prefix -s 64 -- "$@" || true
#ls -l $prefix.*
head $prefix.*
}
_trace-one() {
local strsize=$1
shift
rm -f _tmp/sflag.*
strace -ff -e 'execve' -o _tmp/sflag -s $strsize -- /bin/echo "$@" || true
head _tmp/sflag.*
echo
}
# Conclusion: If a string is less than 32, it prints ... at the end the arg
# list, even if there are no more args!
test-s-flag() {
for strsize in 2 4 8 16; do
echo "--- strsize: $strsize ---"
_trace-one $strsize a b c
done
echo
echo
# See print_array in util.c in strace
# https://github.com/strace/strace.git
# const kernel_ulong_t abbrev_end =
# (abbrev(tcp) && max_strlen < nmemb) ?
# start_addr + elem_size * max_strlen : end_addr;
# kernel_ulong_t cur;
# this isn't what I'm observing!
readonly LIMITS=( 2 4 8 16 )
#readonly LIMITS=( 64 )
for strsize in "${LIMITS[@]}"; do
echo
echo "=== strsize: $strsize ==="
echo
local begin=$(( strsize / 2 - 1 ))
#local begin=0
for numargs in $(seq $begin $strsize); do
echo "--- strsize: $strsize --- numargs: $numargs ---"
_trace-one $strsize $(seq $((numargs - 1))) # -1 to account for /binm/echo
done
done
}
# TODO: Does Clang work the same way?
trace-gcc() {
# /usr/lib/gcc/x86_64-linux-gnu/5/cc1
# Hm -MD invokes cc1 with -MD main.d? It takes an arg?
# Forks assembler0
mkdir -p _tmp
local prefix=_tmp/gcc
trace-procs $prefix gcc -c main.c -MD
rm -f $prefix.*
# How many processes? FOUR.
# 1. cc1 main.d main.c -> tmp file with assembly
# 2. as -o main.o /tmp/ccoPSa4.s. (Also it does 4 execve() calls, instead of using evecvpe?)
# 3. cc1 foo.d foo.c -> tmp file with assembly
# 4. as -o foo.o /tmp/ccoPS5a4.s (same name?)
#
# Hm yes that is a lot of format juggling!
touch foo.c
trace-procs $prefix gcc -c main.c foo.c -MD
}
# Both of these invoke cc1. That is odd. They just pass flags straight
# through. -MD takes and argument though.
trace-cpp() {
trace-procs _tmp/cpp cpp main.c -M -MF my_custom_name3.d
rm _tmp/cpp*
trace-procs _tmp/cpp cpp main.c -MD my_custom_name4.d
}
# NOTES:
# - This feels wrong because we couldn't set up a sandbox with just deps. Deps
# should be known, even in a full build?
# - Is it specific to the C preprocessor? The logic is that if a new
# dependency was added, then an #include must have been added, so the timestamp
# must have changed.
# - It's focused on .c files and not .h files. .c files are translation units.
# Questions:
# - How should OPy 'import' integrate witih Makefile? How does Go do it?
# Their object format is different.
# Page from 2000, updated 4/2017.
# http://make.mad-scientist.net/papers/advanced-auto-dependency-generation/
# - They're using the "Combined method" that's different than the GNU Make Manual
# - Lots of other flags, not just -MD
# - They use "mv" for .Td to to .d ? Why?
# because gcc is incapable of generating two outputs! What a horrible
# syntax!
#
# I think this is for out of tree builds:
#
# -MT $@ set the name of the target in the generated dependency file
# -MD or -MMD : generate as a side effect of compilation, not INSTEAD of compilation
# -MP: adds a target for each prequisite, to avoid errors when deleting files
# -MF: write location to temporary file
#
# POSTCOMPILE:
# mv - so we don't have corrupted half-files (but doesn't this happen for all
# build rules? The build system should take care of it) But it says that
# compilation failures can leave a half-formed dependency file. Geez. gcc
# should fail to generate a dependency file if compilation fails, but maybe
# it doesn't. Could you check its exit code too?
# touch - so that the .o file and .d file are newer?
#
# This scheme is full of hacks to get around Make! mv is definitely one. This
# is "naive style vs. pedantic style".
#
# You can also just flags to CFLAGS instead of having DEPFLAGS
# Critiques:
# - gcc flags are horrible -- lots of gymnastics to to out of tree builds instead of -MD
# - gcc semantics are bad -- if it truly leaves a broken file (not able to reproduce this)
# - the protocol is bad: makefile snippets
"$@"