-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathruncpp
executable file
·257 lines (241 loc) · 7.52 KB
/
runcpp
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
#! /bin/bash
#set -x
printhelp()
{
I_AM=$(basename "$0")
cat >&2 <<EOF
$I_AM - run one source file as script >&2
usage
$I_AM -h | --help
$I_AM [-f | -c | -w | -o OPTIONS | -p POSTOPTIONS | -i | -l | -s SUFFIX]... ( PROGRAM | -- PROGRAM ) ARGS
PROGRAM one source file,
placed in current directory, or in directory which containing in \$PATH
(if does not find - return 2)
OPTIONS - options which are getting to compiler
POSTOPTIONS - arguments which are getting to compiler AFTER source name (use it for adding libraries)
OPTIONS must be one argument to this script, so if its several - put its in quotes
and its must not contain unresolved variables, so if its contain ones - put its in double quotes, to bash resolve ones
also if defined environment variable RUNCPP_OPTIONS or RUNCPP_POSTOPTIONS, it used as options (or post_options)
if -o OPTIONS is defined in command line - it added throw space to options defined in RUNCPP_OPTIONS
if -p POSTOPTIONS is defined in command line - it added throw space to options defined in RUNCPP_POSTOPTIONS
SUFFIX - will be added to EXENAME (and if default suffix exit, it replace it)
also if suffix is .i will be added option -E for stop after preprocessing
and if suffix is .s will be added option -S for stop after assembling
-f - force compile
-c - compile only, without execute
-w - which-mode - only print founded path/file, without compile and run
-r - for PROGRAM, which name starts from dash "-"
-i - for ignore RUNCPP_OPTION
-l - for using compiler clang++
This script create executable (throw g++ or clang++ ) near the source file and run it (throw exec).
If executable already exist - this script compare it change time (like make) and, if it necessary, (re)compile source.
if at compilation happens an errors - script explicitly message about it and print only <=40 lines (for g++) of error messages
and number of total lines of error messages (and return 99)
(if wrong syntax - return 1)
Thogh g++ invocation is: (g++|clang++) [OPTIONS] [path/]PROGRAM[.cpp|.c] -o PROGRAM
and program invocation is: exec [./|path/]PROGRAM ARGS
EOF
exit $1
}
#help message
[ $# == 0 -o "$1" == -h -o "$1" == --help ] && printhelp 0
#g++ options
if [ -n "$RUNCPP_OPTIONS" ]; then
options="$RUNCPP_OPTIONS"
fi
if [ -n "$RUNCPP_POSTOPTIONS" ]; then
post_options="$RUNCPP_POSTOPTIONS"
fi
force=0
onlycompile=0
whichonly=0
clang=0
suffix=""
echooption()
{
# echo option "$@"
:
}
while getopts fcwo:p:ils: opts ; do
case "$opts" in
i)
echooption i
options=
# shift
;;
o)
echooption o
# [ $# -lt 2 ] && printhelp 1
options="$options $OPTARG"
# shift; shift
;;
p)
echooption p
# [ $# -lt 2 ] && printhelp 1
post_options="$post_options $OPTARG"
# shift; shift
;;
s)
echooption s
# [ $# -lt 2 ] && printhelp 1
suffix="$OPTARG"
# shift; shift
;;
f)
echooption f
force=1
# shift
;;
c)
echooption c
onlycompile=1
# shift
;;
w)
echooption w
whichonly=1
# shift
;;
l)
echooption l
clang=1
# shift ;;
# -r)
# echo option -r
# [ $# -lt 2 ] && printhelp 1
# cppname="$1"
# shift; shift
;;
*)
echooption '*'
printhelp 1 ;;
#*)
#echo option cppname "$1"
#cppname="$1"
#shift ;;
esac
done
shift `expr $OPTIND - 1`
cppname="$1"
shift
[ -z "$cppname" ] && printhelp 1
#=== cpp are placed in path ===
findcpp()
{
if [ ! -e "$cppname" ] ; then
#echo search "$cppname"
while read -d : p; do
# echo check "$p"/"$cppname"
[ -e "$p/$cppname" ] && { cppname="$p/$cppname";
#echo found "$cppname";
break; }
done< <(echo "$PATH":)
fi
}
if [[ "$cppname" == *.cpp ]] || [[ "$cppname" == *.c ]] || [[ "$cppname" == *.s ]] || [[ "$cppname" == *.i ]]
then
findcpp
else
echo can not found exactly \'"$cppname"\' >&2
tmp="$cppname"
cppname="$tmp".cpp
findcpp
if [ ! -e "$cppname" ]
then
cppname="$tmp".c
findcpp
fi
fi
[ ! -e "$cppname" ] && { echo runcpp: "$cppname" does not found >&2 ; exit 2; }
[ $whichonly == 1 ] && { echo "$cppname"; exit 0; }
#=== evaluate exename ===
if [[ "$cppname" == *.cpp ]] ; then exename="${cppname%.cpp}"
else if [[ "$cppname" == *.c ]] ; then exename="${cppname%.c}"
else if [[ "$cppname" == *.i ]] ; then exename="${cppname%.i}"
else if [[ "$cppname" == *.s ]] ; then exename="${cppname%.s}"
else echo 'runcpp: name of source shold be *.c or *.cpp or *.i or *.s' >&2
fi; fi; fi; fi;
if [ "$suffix" == ".s" ]; then
options="$options -S";
exename="$(dirname "$exename")/$(basename "$exename")$suffix"
else if [ "$suffix" == ".i" ]; then
options="$options -E";
exename="$(dirname "$exename")/$(basename "$exename")$suffix"
else
exename="$(dirname "$exename")/.$(basename "$exename")$suffix"
fi; fi
#если не указано .exe то оно не только запускается, но и на существование и на определение времени работает правильно
if [ $(uname -o) == "Cygwin" -a -z "$suffix" ]; then exename="$exename".exe; fi
#echo exename = $exename
#=== compile function ===
mygcc(){
g++ -fdiagnostics-color $options "$cppname" -o "$exename" $post_options 2>&1 |
awk 'NR<=40; END {print "runcpp: compile messages lines " NR;}'
echo "$PIPESTATUS"
}
myclang(){
clang++ $options "$cppname" -o "$exename" $post_options
echo "$PIPESTATUS"
}
compile()
{
# ????? почему вывод в stdout не работает, если вывод g++ не перенаправлять в stdout ???
if [ $clang == 1 ] ;then
echo "runcpp: clang++ $cppname (options = $options)" >&2
mess="$(myclang)"
echo "$mess" | head -n -1 >&2
else
echo "runcpp: g++ $cppname (options = $options)" >&2
mess="$(mygcc)"
echo "$mess" | head -n -1 >&2
# g++ -I"$YADISK_PATH"/_programming/_src/include/ "$cppname" -o "$exename" 2>&1 | tee >(sleep 1; wc -l >&2; echo \^ total lines >&2) | cat | head -n 40
#нужно больше котиков
fi
if [ "$(echo "$mess" | tail -n 1)" != 0 ]
then
# ????? почему вывод в stdout не работает, если вывод g++ не перенаправлять в stdout ???
echo '***** ОШИБКА КОМПИЛЯЦИИ *****' >&2
exit 99;
else
if [ "$(echo -n "$mess" | wc -l)" -gt 1 ]; then
echo '***** БЕЗ ОШИБОК *****' >&2
fi
fi
}
#=== debug information ===
if false; then
if [ -e "$exename" ] ;
then echo true: exename \("$exename"\) exist
else echo false: exename \("$exename"\) not exist
fi
if [ $(stat --format=%Y "$cppname") -lt $(stat --format=%Y "$exename") ]
then echo true: exe \($(stat --format=%Y "$exename")\) created later then cpp\($(stat --format=%Y "$cppname")\)
else echo false: cpp\($(stat --format=%Y "$cppname")\) created later then exe \($(stat --format=%Y "$exename")\)
fi
fi
#=== compile conditions ===
if [ $force == 1 -o $onlycompile == 1 ]; then
compile
else
if [ -e "$exename" ] && [ "$cppname" -ot "$exename" ]; then
:
else
compile
fi
fi
[ $onlycompile == 1 ] && exit 0
#=== echo now execute: ===
#echo exename = "$exename"
if [[ "$exename" == *.i ]] || [[ "$exename" == *.s ]]; then
echo in "$exename" $(wc -l <"$exename" ) lines
if [[ "$exename" == *.s ]]; then
sed -i 's/\t\./\t\t\t\./' "$exename"
fi
else
if [[ "$exename" == /* ]]
then
exec "$exename" "$@"
else
exec "./$exename" "$@"
fi
fi