| 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
|