1 | #!/usr/bin/env bash
|
2 | #
|
3 | # Actions invoked by build.ninja, which is generated by ./NINJA-config.sh.
|
4 | #
|
5 | # It's distributed with the tarball and invoked by _build/oils.sh, so
|
6 | # it's written in a /bin/sh style. But we're not using /bin/sh yet.
|
7 | #
|
8 | # And some non-Ninja wrappers.
|
9 | #
|
10 | # Usage:
|
11 | # build/ninja-rules-cpp.sh <function name>
|
12 | #
|
13 | # Env variables:
|
14 | # BASE_CXXFLAGS= default flags passed to all compiler invocations
|
15 | # CXXFLAGS= additional flags
|
16 | # OILS_CXX_VERBOSE=1 show compiler command lines
|
17 | # TIME_TSV_OUT=file compile_one and link output rows to this TSV file
|
18 |
|
19 | set -o nounset
|
20 | set -o errexit
|
21 | # For /bin/sh portability
|
22 | #eval 'set -o pipefail'
|
23 |
|
24 | REPO_ROOT=$(cd "$(dirname $0)/.."; pwd)
|
25 |
|
26 | . build/common.sh # for $BASE_CXXFLAGS
|
27 | . build/dev-shell.sh # python2 in $PATH
|
28 |
|
29 | # for HAVE_READLINE, READLINE_DIR, and STRIP_FLAGS
|
30 | if ! . _build/detected-config.sh; then
|
31 | die "Can't find _build/detected-config.sh. Run './configure'"
|
32 | fi
|
33 |
|
34 | line_count() {
|
35 | local out=$1
|
36 | shift # rest are inputs
|
37 | wc -l "$@" | sort -n | tee $out
|
38 | }
|
39 |
|
40 | #
|
41 | # Mutable GLOBALS
|
42 | #
|
43 |
|
44 | cxx='' # compiler
|
45 | flags='' # compile flags
|
46 | link_flags='' # link flags
|
47 |
|
48 | #
|
49 | # Functions to set them
|
50 | #
|
51 |
|
52 | setglobal_cxx() {
|
53 | local compiler=$1
|
54 |
|
55 | case $compiler in
|
56 | (clang) cxx=$CLANGXX ;;
|
57 | # Note: we could get rid of this "alias", and use 'c++' everywhere
|
58 | (cxx) cxx='c++' ;;
|
59 |
|
60 | # e.g. could be cosmoc++
|
61 | (*) cxx=$compiler ;;
|
62 | esac
|
63 | }
|
64 |
|
65 | setglobal_compile_flags() {
|
66 | ### Set flags based on $variant $more_cxx_flags and $dotd
|
67 |
|
68 | local variant=$1
|
69 | local more_cxx_flags=$2
|
70 | local dotd=${3:-}
|
71 |
|
72 | # flags from Ninja/shell respected
|
73 | flags="$BASE_CXXFLAGS -I $REPO_ROOT $more_cxx_flags"
|
74 |
|
75 | # Flags from env
|
76 | # Similar to
|
77 | # - GNU make - https://www.gnu.org/software/make/manual/html_node/Implicit-Variables.html
|
78 | # CXXFLAGS "Extra flags to give to the C++ compiler"
|
79 | # - CMake - https://cmake.org/cmake/help/latest/envvar/CXXFLAGS.html
|
80 | # "Add default compilation flags to be used when compiling CXX (C++) files."
|
81 |
|
82 | local env_flags=${CXXFLAGS:-}
|
83 | if test -n "$env_flags"; then
|
84 | flags="$flags $env_flags"
|
85 | fi
|
86 |
|
87 | if test -n "$READLINE_DIR"; then
|
88 | flags="$flags -I${READLINE_DIR}/include"
|
89 | fi
|
90 |
|
91 | case $variant in
|
92 | *+bumpleak|*+bumproot)
|
93 | ;;
|
94 | *)
|
95 | flags="$flags -D MARK_SWEEP"
|
96 | ;;
|
97 | esac
|
98 |
|
99 | # First half of variant: what affects ALL translation units
|
100 |
|
101 | case $variant in
|
102 | dbg*)
|
103 | flags="$flags -O0 -g"
|
104 | ;;
|
105 |
|
106 | asan*)
|
107 | # CLEAN_PROCESS_EXIT avoids spurious memory leaks
|
108 | flags="$flags -O0 -g -fsanitize=address -D CLEAN_PROCESS_EXIT"
|
109 | ;;
|
110 |
|
111 | tsan*)
|
112 | flags="$flags -O0 -g -fsanitize=thread"
|
113 | ;;
|
114 |
|
115 | ubsan*)
|
116 | # Extra flag to make it fatal
|
117 | # https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html
|
118 |
|
119 | flags="$flags -O0 -g -fsanitize=undefined -fno-sanitize-recover=null"
|
120 | ;;
|
121 |
|
122 | opt*)
|
123 | flags="$flags -O2 -g -D OPTIMIZED"
|
124 | ;;
|
125 |
|
126 | coverage*)
|
127 | # source-based coverage is more precise than say sanitizer-based
|
128 | # https://clang.llvm.org/docs/SourceBasedCodeCoverage.html
|
129 | flags="$flags -O0 -g -fprofile-instr-generate -fcoverage-mapping"
|
130 | ;;
|
131 |
|
132 | uftrace*)
|
133 | # -O0 creates a A LOT more data. But sometimes we want to see the
|
134 | # structure of the code.
|
135 | # NewStr(), OverAllocatedStr(), StrFromC() etc. are not inlined
|
136 | # Ditto vector::size(), std::forward, len(), etc.
|
137 |
|
138 | local opt='-O0'
|
139 | #local opt='-O2'
|
140 | flags="$flags $opt -g -pg"
|
141 | ;;
|
142 |
|
143 | (*)
|
144 | die "Invalid variant $variant"
|
145 | ;;
|
146 | esac
|
147 |
|
148 | # for cxx-dbg32, cxx-opt32+bumpleak, etc.
|
149 | case $variant in
|
150 | *32*)
|
151 | flags="$flags -m32"
|
152 | ;;
|
153 | esac
|
154 |
|
155 | # OPTIONAL second half of variant: for the application
|
156 |
|
157 | case $variant in
|
158 | *+gcalways)
|
159 | flags="$flags -D GC_ALWAYS"
|
160 | ;;
|
161 |
|
162 | *+tcmalloc)
|
163 | flags="$flags -D TCMALLOC"
|
164 | ;;
|
165 |
|
166 | *+bumpleak)
|
167 | flags="$flags -D BUMP_LEAK"
|
168 | ;;
|
169 | *+bumproot)
|
170 | flags="$flags -D BUMP_LEAK -D BUMP_ROOT"
|
171 | ;;
|
172 |
|
173 | *+bumpsmall)
|
174 | # the pool allocator should approximate opt+bumpsmall (which doesn't support GC)
|
175 | flags="$flags -D BUMP_ROOT -D BUMP_SMALL -D NO_POOL_ALLOC"
|
176 | ;;
|
177 |
|
178 | *+nopool)
|
179 | flags="$flags -D NO_POOL_ALLOC"
|
180 | ;;
|
181 | esac
|
182 |
|
183 | # needed to strip unused symbols
|
184 | # https://stackoverflow.com/questions/6687630/how-to-remove-unused-c-c-symbols-with-gcc-and-ld
|
185 |
|
186 | # Note: -ftlo doesn't do anything for size?
|
187 |
|
188 | flags="$flags -fdata-sections -ffunction-sections"
|
189 |
|
190 | # https://ninja-build.org/manual.html#ref_headers
|
191 | if test -n "$dotd"; then
|
192 | flags="$flags -MD -MF $dotd"
|
193 | fi
|
194 | }
|
195 |
|
196 | setglobal_link_flags() {
|
197 | local variant=$1
|
198 |
|
199 | case $variant in
|
200 | # Must REPEAT these flags, otherwise we lose sanitizers / coverage
|
201 | asan*)
|
202 | link_flags='-fsanitize=address'
|
203 | ;;
|
204 |
|
205 | tcmalloc)
|
206 | # Need to tell the dynamic loader where to find tcmalloc
|
207 | link_flags='-ltcmalloc -Wl,-rpath,/usr/local/lib'
|
208 | ;;
|
209 |
|
210 | tsan)
|
211 | link_flags='-fsanitize=thread'
|
212 | ;;
|
213 | ubsan*)
|
214 | link_flags='-fsanitize=undefined'
|
215 | ;;
|
216 | coverage*)
|
217 | link_flags='-fprofile-instr-generate -fcoverage-mapping'
|
218 | ;;
|
219 | esac
|
220 |
|
221 | case $variant in
|
222 | # TODO: 32-bit variants can't handle -l readline right now.
|
223 | *32*)
|
224 | link_flags="$link_flags -m32"
|
225 | ;;
|
226 |
|
227 | *)
|
228 | if test "$HAVE_READLINE" = 1; then
|
229 | link_flags="$link_flags -lreadline"
|
230 | fi
|
231 | if test -n "$READLINE_DIR"; then
|
232 | link_flags="$link_flags -L${READLINE_DIR}/lib"
|
233 | fi
|
234 | ;;
|
235 | esac
|
236 |
|
237 | if test -n "${STRIP_FLAGS:-}"; then
|
238 | link_flags="$link_flags -Wl,$STRIP_FLAGS"
|
239 | fi
|
240 | }
|
241 |
|
242 | compile_one() {
|
243 | ### Compile one translation unit. Invoked by build.ninja
|
244 |
|
245 | local compiler=$1
|
246 | local variant=$2
|
247 | local more_cxx_flags=$3
|
248 | local in=$4
|
249 | local out=$5
|
250 | local dotd=${6:-} # optional .d file
|
251 |
|
252 | setglobal_compile_flags "$variant" "$more_cxx_flags" "$dotd"
|
253 |
|
254 | case $out in
|
255 | (_build/preprocessed/*)
|
256 | flags="$flags -E"
|
257 | ;;
|
258 |
|
259 | # DISABLE spew for mycpp-generated code. mycpp/pea could flag this at the
|
260 | # PYTHON level, rather than doing it at the C++ level.
|
261 | (_build/obj/*/_gen/bin/oils_for_unix.mycpp.o)
|
262 | flags="$flags -Wno-unused-variable -Wno-unused-but-set-variable"
|
263 | ;;
|
264 | esac
|
265 |
|
266 | # TODO: exactly when is -fPIC needed? Clang needs it sometimes?
|
267 | if test $compiler = 'clang' && test $variant != 'opt'; then
|
268 | flags="$flags -fPIC"
|
269 | fi
|
270 |
|
271 | # this flag is only valid in Clang, doesn't work in continuous build
|
272 | if test "$compiler" = 'clang'; then
|
273 | flags="$flags -ferror-limit=10"
|
274 | fi
|
275 |
|
276 | setglobal_cxx $compiler
|
277 |
|
278 | if test -n "${OILS_CXX_VERBOSE:-}"; then
|
279 | echo '__' "$cxx" $flags -o "$out" -c "$in" >&2
|
280 | fi
|
281 |
|
282 | # Not using arrays because this is POSIX shell
|
283 | local prefix=''
|
284 | if test -n "${TIME_TSV_OUT:-}"; then
|
285 | prefix="benchmarks/time_.py --tsv --out $TIME_TSV_OUT --append --rusage --field compile_one --field $out --"
|
286 | fi
|
287 |
|
288 | $prefix "$cxx" $flags -o "$out" -c "$in"
|
289 | }
|
290 |
|
291 | link() {
|
292 | ### Link a binary. Invoked by build.ninja
|
293 |
|
294 | local compiler=$1
|
295 | local variant=$2
|
296 | local more_link_flags=$3
|
297 | local out=$4
|
298 | shift 4
|
299 | # rest are inputs
|
300 |
|
301 | setglobal_link_flags $variant
|
302 |
|
303 | setglobal_cxx $compiler
|
304 |
|
305 | local prefix=''
|
306 | if test -n "${TIME_TSV_OUT:-}"; then
|
307 | prefix="benchmarks/time_.py --tsv --out $TIME_TSV_OUT --append --rusage --field link --field $out --"
|
308 | fi
|
309 |
|
310 | if test -n "${OILS_CXX_VERBOSE:-}"; then
|
311 | echo "__ $prefix $cxx -o $out $@ $link_flags" >&2
|
312 | fi
|
313 | # IMPORTANT: Flags like -ltcmalloc have to come AFTER objects! Weird but
|
314 | # true.
|
315 | $prefix "$cxx" -o "$out" "$@" $link_flags $more_link_flags
|
316 | }
|
317 |
|
318 | compile_and_link() {
|
319 | ### This function is no longer used; use 'compile_one' and 'link'
|
320 |
|
321 | local compiler=$1
|
322 | local variant=$2
|
323 | local more_cxx_flags=$3
|
324 | local out=$4
|
325 | shift 4
|
326 |
|
327 | setglobal_compile_flags "$variant" "$more_cxx_flags" "" # no dotd
|
328 |
|
329 | setglobal_link_flags $variant
|
330 |
|
331 | setglobal_cxx $compiler
|
332 |
|
333 | if test -n "${OILS_CXX_VERBOSE:-}"; then
|
334 | echo "__ $cxx -o $out $flags $@ $link_flags" >&2
|
335 | fi
|
336 |
|
337 | "$cxx" -o "$out" $flags "$@" $link_flags
|
338 | }
|
339 |
|
340 | strip_() {
|
341 | ### Invoked by ninja
|
342 |
|
343 | local in=$1
|
344 | local stripped=$2
|
345 | local symbols=${3:-}
|
346 |
|
347 | strip -o $stripped $in
|
348 |
|
349 | if test -n "$symbols"; then
|
350 | objcopy --only-keep-debug $in $symbols
|
351 | objcopy --add-gnu-debuglink=$symbols $stripped
|
352 | fi
|
353 | }
|
354 |
|
355 | symlink() {
|
356 | local dir=$1
|
357 | local in=$2
|
358 | local out=$3
|
359 |
|
360 | cd $dir
|
361 | ln -s -f -v $in $out
|
362 | }
|
363 |
|
364 | # test/cpp-unit.sh sources this
|
365 | if test $(basename $0) = 'ninja-rules-cpp.sh'; then
|
366 | "$@"
|
367 | fi
|