1#!/bin/sh -e
2
3# Copyright(c) 2019 Intel Corporation
4# SPDX-License-Identifier: BSD-2-Clause-Patent
5
6if printf '%s' "$0" | grep -q '\.sh'; then
7    IN_SCRIPT=true
8fi
9
10print_message() {
11    if [ "$1" = "stdout" ] || [ "$1" = "-" ]; then
12        shift
13        printf '%b\n' "${@:-Unknown Message}" | sed 's/^[ \t]*//'
14    else
15        printf '%b\n' "${@:-Unknown Message}" | sed 's/^[ \t]*//' >&2
16    fi
17}
18
19die() {
20    print_message "${@:-Unknown error}"
21    if ${IN_SCRIPT:-false}; then
22        print_message "The script will now exit."
23        exit 1
24    fi
25}
26
27cd_safe() {
28    if (cd "$1"); then
29        cd "$1"
30    else
31        _dir="$1"
32        shift
33        die "${@:-Failed cd to $_dir.}"
34    fi
35}
36
37${IN_SCRIPT:-false} && cd_safe "$(cd "$(dirname "$0")" > /dev/null 2>&1 && pwd -P)"
38
39echo_help() {
40    cat << EOF
41Usage: $0 [OPTION] ... -- [OPTIONS FOR CMAKE]
42-a, --all, all          Builds release and debug
43    --cc, cc=*          Set C compiler [$CC]
44    --clean, clean      Remove build and Bin folders
45    --debug, debug      Build debug
46    --shared, shared    Build shared libs
47-x, --static, static    Build static libs
48-i, --install, install  Install build [Default release]
49-j, --jobs, jobs=*      Set the amount of jobs cmake will do when building
50-p, --prefix, prefix=*  Set installation prefix
51    --release, release  Build release
52Example usage:
53    build.sh -xi debug -- -G"Ninja"
54    build.sh all cc=clang static release install
55EOF
56}
57
58build() (
59    build_type="Release"
60    while [ -n "$*" ]; do
61        case "$(printf %s "$1" | tr '[:upper:]' '[:lower:]')" in
62        release) build_type="Release" && shift ;;
63        debug) build_type="Debug" && shift ;;
64        *) break ;;
65        esac
66    done
67
68    mkdir -p "$build_type" > /dev/null 2>&1
69    cd_safe "$build_type"
70
71    for file in *; do
72        rm -rf "$file"
73    done
74
75    cmake ../../.. -DCMAKE_BUILD_TYPE="$build_type" $CMAKE_EXTRA_FLAGS "$@"
76
77    # Compile the Library
78    if [ -f Makefile ]; then
79        make -j "${jobs:-4}"
80    elif cmake --build 2>&1 | grep -q -- '-j'; then
81        cmake --build . --config "$build_type" -j "${jobs:-4}"
82    else
83        cmake --build . --config "$build_type"
84    fi
85)
86
87check_executable() (
88    print_exec=false
89    while true; do
90        case "$1" in
91        -p) print_exec=true && shift ;;
92        *) break ;;
93        esac
94    done
95    [ -n "$1" ] && command_to_check="$1" || return 1
96    shift
97    if test -e "$command_to_check"; then
98        $print_exec && printf '%s\n' "$command_to_check"
99        return 0
100    fi
101    for d in "$@" $(printf '%s ' "$PATH" | tr ':' ' '); do
102        if [ -e "$d/$command_to_check" ]; then
103            $print_exec && printf '%s\n' "$d/$command_to_check"
104            return 0
105        fi
106    done
107    return 127
108)
109
110install_build() (
111    build_type="Release"
112    sudo=
113    while [ -n "$*" ]; do
114        case $(printf %s "$1" | tr '[:upper:]' '[:lower:]') in
115        release) build_type="Release" && shift ;;
116        debug) build_type="Debug" && shift ;;
117        *) break ;;
118        esac
119    done
120    check_executable sudo && sudo -v > /dev/null 2>&1 && sudo=sudo
121    { [ -d "$build_type" ] && cd_safe "$build_type"; } ||
122        die "Unable to find the build folder. Did the build command run?"
123    $sudo cmake --build . --target install --config "$build_type" ||
124        die "Unable to run install"
125)
126
127if [ -z "$CC" ] && [ "$(uname -a | cut -c1-5)" != "MINGW" ]; then
128    if check_executable icc /opt/intel/bin; then
129        CC=$(check_executable -p icc /opt/intel/bin)
130    elif check_executable gcc; then
131        CC=$(check_executable -p gcc)
132    elif check_executable clang; then
133        CC=$(check_executable -p clang)
134    elif check_executable cc; then
135        CC=$(check_executable -p cc)
136    else
137        die "No suitable c compiler found in path" \
138            "Please either install one or set it via cc=*"
139    fi
140    export CC
141fi
142
143if [ -z "$jobs" ]; then
144    jobs=$(getconf _NPROCESSORS_ONLN) ||
145        jobs=$(nproc) ||
146        jobs=$(sysctl -n hw.ncpu) ||
147        jobs=2
148fi
149
150build_release=false
151build_debug=false
152build_install=false
153
154parse_options() {
155    while true; do
156        [ -z "$1" ] && break
157        case $(printf %s "$1" | tr '[:upper:]' '[:lower:]') in
158        help) echo_help && exit ;;
159        all) build_debug=true build_release=true && shift ;;
160        cc=*)
161            if check_executable "${1#*=}"; then
162                CC="$(check_executable -p "${1#*=}")"
163                export CC
164            fi
165            shift
166            ;;
167        clean)
168            for d in *; do
169                [ -d "$d" ] && rm -rf "$d"
170            done
171            for d in ../../Bin/*; do
172                [ -d "$d" ] && rm -rf "$d"
173            done
174            shift && ${IN_SCRIPT:-false} && exit
175            ;;
176        debug) build_debug=true && shift ;;
177        build_shared)
178            CMAKE_EXTRA_FLAGS="-DBUILD_SHARED_LIBS=ON ${CMAKE_EXTRA_FLAGS}"
179            shift
180            ;;
181        build_static)
182            CMAKE_EXTRA_FLAGS="-DBUILD_SHARED_LIBS=OFF ${CMAKE_EXTRA_FLAGS}"
183            shift
184            ;;
185        install) build_install=true && shift ;;
186        jobs=*) jobs=${1#*=} && shift ;;
187        prefix=*)
188            CMAKE_EXTRA_FLAGS="-DCMAKE_INSTALL_PREFIX=${1#*=} ${CMAKE_EXTRA_FLAGS}"
189            shift
190            ;;
191        release) build_release=true && shift ;;
192        verbose)
193            CMAKE_EXTRA_FLAGS="-DCMAKE_VERBOSE_MAKEFILE=1 ${CMAKE_EXTRA_FLAGS}"
194            shift
195            ;;
196        *) print_message "Unknown option: $1" && shift ;;
197        esac
198    done
199}
200
201if [ -z "$*" ]; then
202    build_release=true
203    build_debug=true
204else
205    while [ -n "$*" ]; do
206        # Handle --* based args
207        if [ "$(echo "$1" | cut -c1-2)" = "--" ]; then
208            # Stop on "--", pass the rest to cmake
209            [ -z "$(echo "$1" | cut -c3-)" ] && shift && break
210            case "$(echo "$1" | cut -c3- | tr '[:upper:]' '[:lower:]')" in
211            help) parse_options help && shift ;;
212            all) parse_options debug release && shift ;;
213            cc) parse_options cc="$2" && shift 2 ;;
214            clean) parse_options clean && shift ;;
215            debug) parse_options debug && shift ;;
216            install) parse_options install && shift ;;
217            jobs) parse_options jobs="$2" && shift 2 ;;
218            prefix) parse_options prefix="$2" && shift 2 ;;
219            release) parse_options release && shift ;;
220            shared) parse_options build_shared && shift ;;
221            static) parse_options build_static && shift ;;
222            verbose) parse_options verbose && shift ;;
223            *) die "Error, unknown option: $1" ;;
224            esac
225        # Handle -* based args
226        elif [ "$(echo "$1" | cut -c1)" = "-" ]; then
227            i=2
228            match="$1"
229            shift
230            while [ $i -ne $((${#match} + 1)) ]; do
231                case "$(printf %s "$match" | cut -c$i | tr '[:upper:]' '[:lower:]')" in
232                h) parse_options help ;;
233                a) parse_options all && i=$((i + 1)) ;;
234                i) parse_options install && i=$((i + 1)) ;;
235                j) parse_options jobs="$1" && shift && i=$((i + 1)) ;;
236                p) parse_options prefix="$1" && shift && i=$((i + 1)) ;;
237                x) parse_options build_static && i=$((i + 1)) ;;
238                v) parse_options verbose && i=$((i + 1)) ;;
239                *) die "Error, unknown option: -$(echo "$match" | cut -c$i | tr '[:upper:]' '[:lower:]')" ;;
240                esac
241            done
242        # Handle single word args
243        else
244            case "$(echo "$1" | tr '[:upper:]' '[:lower:]')" in
245            all) parse_options release debug && shift ;;
246            cc=*) parse_options cc="${1#*=}" && shift ;;
247            clean) parse_options clean && shift ;;
248            debug) parse_options debug && shift ;;
249            help) parse_options help && shift ;;
250            install) parse_options install && shift ;;
251            jobs=*) parse_options jobs="${1#*=}" && shift ;;
252            prefix=*) parse_options prefix="${1#*=}" && shift ;;
253            shared) parse_options build_shared && shift ;;
254            static) parse_options build_static && shift ;;
255            release) parse_options release && shift ;;
256            verbose) parse_options verbose && shift ;;
257            end) exit ;;
258            *) die "Error, unknown option: $1" ;;
259            esac
260        fi
261    done
262fi
263
264if [ "${PATH#*\/usr\/local\/bin}" = "$PATH" ]; then
265    PATH="$PATH:/usr/local/bin"
266fi
267
268if $build_debug && $build_release; then
269    build release "$@"
270    build debug "$@"
271elif $build_debug; then
272    build debug "$@"
273else
274    build release "$@"
275fi
276
277if $build_install; then
278    if $build_release; then
279        install_build release
280    elif $build_debug; then
281        install_build debug
282    else
283        build release "$@"
284        install_build release
285    fi
286fi
287