1#!/bin/bash
2
3# Build script intended for use in Travis CI and Github workflow
4
5echo "Using bash version $BASH_VERSION"
6set -exo pipefail
7
8num_jobs=3
9
10# We might need binaries installed via pip, so ensure that our personal bin dir is on the PATH
11export PATH=$HOME/.local/bin:$PATH
12
13if [ -n "$TEST_STAGE" ]
14then
15    build-scripts/lint-json.sh
16    make -j "$num_jobs" style-json
17
18    tools/dialogue_validator.py data/json/npcs/* data/json/npcs/*/* data/json/npcs/*/*/*
19
20    tools/json_tools/generic_guns_validator.py
21
22    # Also build chkjson (even though we're not using it), to catch any
23    # compile errors there
24    make -j "$num_jobs" chkjson
25# Skip the rest of the run if this change is pure json and this job doesn't test any extra mods
26elif [ -n "$JUST_JSON" -a -z "$MODS" ]
27then
28    echo "Early exit on just-json change"
29    exit 0
30fi
31
32ccache --zero-stats
33# Increase cache size because debug builds generate large object files
34ccache -M 5G
35ccache --show-stats
36
37function run_test
38{
39    set -eo pipefail
40    test_exit_code=0 sed_exit_code=0 exit_code=0
41    $WINE $1 --min-duration 0.2 --use-colour yes --rng-seed time $EXTRA_TEST_OPTS "$2" 2>&1 | sed -E 's/^(::(warning|error|debug)[^:]*::)?/\1'"$3"'/' || test_exit_code="${PIPESTATUS[0]}" sed_exit_code="${PIPESTATUS[1]}"
42    if [ "$test_exit_code" -ne "0" ]
43    then
44        echo "$3test exited with code $test_exit_code"
45        exit_code=1
46    fi
47    if [ "$sed_exit_code" -ne "0" ]
48    then
49        echo "$3sed exited with code $sed_exit_code"
50        exit_code=1
51    fi
52    return $exit_code
53}
54export -f run_test
55
56if [ "$CMAKE" = "1" ]
57then
58    bin_path="./"
59    if [ "$RELEASE" = "1" ]
60    then
61        build_type=MinSizeRel
62        bin_path="build/tests/"
63    else
64        build_type=Debug
65    fi
66
67    cmake_extra_opts=()
68
69    if [ "$CATA_CLANG_TIDY" = "plugin" ]
70    then
71        cmake_extra_opts+=("-DCATA_CLANG_TIDY_PLUGIN=ON")
72        # Need to specify the particular LLVM / Clang versions to use, lest it
73        # use the llvm-7 that comes by default on the Travis Xenial image.
74        cmake_extra_opts+=("-DLLVM_DIR=/usr/lib/llvm-8/lib/cmake/llvm")
75        cmake_extra_opts+=("-DClang_DIR=/usr/lib/llvm-8/lib/cmake/clang")
76    fi
77
78    if [ "$COMPILER" = "clang++-8" -a -n "$GITHUB_WORKFLOW" -a -n "$CATA_CLANG_TIDY" ]
79    then
80        # This is a hacky workaround for the fact that the custom clang-tidy we are
81        # using is built for Travis CI, so it's not using the correct include directories
82        # for GitHub workflows.
83        cmake_extra_opts+=("-DCMAKE_CXX_FLAGS=-isystem /usr/include/clang/8.0.0/include")
84    fi
85
86    mkdir build
87    cd build
88    cmake \
89        -DBACKTRACE=ON \
90        ${COMPILER:+-DCMAKE_CXX_COMPILER=$COMPILER} \
91        -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
92        -DCMAKE_BUILD_TYPE="$build_type" \
93        -DTILES=${TILES:-0} \
94        -DSOUND=${SOUND:-0} \
95        "${cmake_extra_opts[@]}" \
96        ..
97    if [ -n "$CATA_CLANG_TIDY" ]
98    then
99        if [ "$CATA_CLANG_TIDY" = "plugin" ]
100        then
101            make -j$num_jobs CataAnalyzerPlugin
102            export PATH=$PWD/tools/clang-tidy-plugin/clang-tidy-plugin-support/bin:$PATH
103            if ! which FileCheck
104            then
105                ls -l tools/clang-tidy-plugin/clang-tidy-plugin-support/bin
106                ls -l /usr/bin
107                echo "Missing FileCheck"
108                exit 1
109            fi
110            CATA_CLANG_TIDY=clang-tidy
111            lit -v tools/clang-tidy-plugin/test
112        fi
113
114        "$CATA_CLANG_TIDY" --version
115
116        # Show compiler C++ header search path
117        ${COMPILER:-clang++} -v -x c++ /dev/null -c
118        # And the same for clang-tidy
119        "$CATA_CLANG_TIDY" ../src/version.cpp -- -v
120
121        # Run clang-tidy analysis instead of regular build & test
122        # We could use CMake to create compile_commands.json, but that's super
123        # slow, so use compiledb <https://github.com/nickdiego/compiledb>
124        # instead.
125        compiledb -n make
126
127        cd ..
128        ln -s build/compile_commands.json
129
130        # We want to first analyze all files that changed in this PR, then as
131        # many others as possible, in a random order.
132        set +x
133        all_cpp_files="$( \
134            grep '"file": "' build/compile_commands.json | \
135            sed "s+.*$PWD/++;s+\"$++")"
136        changed_cpp_files="$( \
137            ./build-scripts/files_changed | grep -F "$all_cpp_files" || true )"
138        if [ -n "$changed_cpp_files" ]
139        then
140            remaining_cpp_files="$( \
141                echo "$all_cpp_files" | grep -v -F "$changed_cpp_files" || true )"
142        else
143            remaining_cpp_files="$all_cpp_files"
144        fi
145
146        function analyze_files_in_random_order
147        {
148            if [ -n "$1" ]
149            then
150                echo "$1" | shuf | \
151                    xargs -P "$num_jobs" -n 1 ./build-scripts/clang-tidy-wrapper.sh -quiet
152            else
153                echo "No files to analyze"
154            fi
155        }
156
157        echo "Analyzing changed files"
158        analyze_files_in_random_order "$changed_cpp_files"
159
160        echo "Analyzing remaining files"
161        analyze_files_in_random_order "$remaining_cpp_files"
162        set -x
163    else
164        # Regular build
165        make -j$num_jobs
166        cd ..
167        # Run regular tests
168        [ -f "${bin_path}cata_test" ] && parallel --verbose --linebuffer "run_test $(printf %q "${bin_path}")'/cata_test' {} '('{}')=> '" ::: "crafting_skill_gain" "[slow] ~crafting_skill_gain" "~[slow] ~[.]"
169        [ -f "${bin_path}cata_test-tiles" ] && parallel --verbose --linebuffer "run_test $(printf %q "${bin_path}")'/cata_test-tiles' {} '('{}')=> '" ::: "crafting_skill_gain" "[slow] ~crafting_skill_gain" "~[slow] ~[.]"
170    fi
171elif [ "$NATIVE" == "android" ]
172then
173    export USE_CCACHE=1
174    export NDK_CCACHE="$(which ccache)"
175
176    # Tweak the ccache compiler analysis.  We're using the compiler from the
177    # Android NDK which has an unpredictable mtime, so we need to hash the
178    # content rather than the size+mtime (which is ccache's default behavior).
179    export CCACHE_COMPILERCHECK=content
180
181    cd android
182    # Specify dumb terminal to suppress gradle's constant output of time spent building, which
183    # fills the log with nonsense.
184    TERM=dumb ./gradlew assembleExperimentalRelease -Pj=$num_jobs -Plocalize=false -Pabi_arm_32=false -Pabi_arm_64=true -Pdeps=/home/travis/build/CleverRaven/Cataclysm-DDA/android/app/deps.zip
185else
186    make -j "$num_jobs" RELEASE=1 CCACHE=1 CROSS="$CROSS_COMPILATION" LINTJSON=0
187
188    export ASAN_OPTIONS=detect_odr_violation=1
189    export UBSAN_OPTIONS=print_stacktrace=1
190    parallel --verbose --linebuffer "run_test './tests/cata_test' {} '('{}')=> '" ::: "crafting_skill_gain" "[slow] ~crafting_skill_gain" "~[slow] ~[.]"
191    if [ -n "$MODS" ]
192    then
193        parallel --verbose --linebuffer "run_test './tests/cata_test --user-dir=modded '$(printf %q "${MODS}") {} 'Mods-('{}')=> '" ::: "crafting_skill_gain" "[slow] ~crafting_skill_gain" "~[slow] ~[.]"
194    fi
195
196    if [ -n "$TEST_STAGE" ]
197    then
198        # Run the tests one more time, without actually running any tests, just to verify that all
199        # the mod data can be successfully loaded
200
201        mods="$(./build-scripts/get_all_mods.py)"
202        run_test './tests/cata_test --user-dir=all_modded --mods='"${mods}" '~*' ''
203    fi
204fi
205ccache --show-stats
206# Shrink the ccache back down to 2GB in preperation for pushing to shared storage.
207ccache -M 2G
208ccache -c
209
210# vim:tw=0
211