#!/usr/bin/env bash # # USAGE # [targets='...'] [mpw_feature=0|1 ...] [CFLAGS='...'] [LDFLAGS='...'] ./build [cc arguments ...] # # By default, you should only need to run ./build # # You can customize the targets that are built using targets='...'. Use targets='all' to build all targets. # By default, we only build the 'mpw' target. # See targets_all for all possible targets as well as the features they support and require. # # Several features can be enabled or disabled using feature flags. # See the Features section for an overview of the features, their default setting, their meaning and their dependencies. # You will need to have each of the feature's dependencies installed for the build to succeed with that feature enabled. # # Finally, the C compiler can be tuned using CFLAGS, LDFLAGS and compiler arguments passed to the script. # # BUGS # masterpassword@lyndir.com # # AUTHOR # Maarten Billemont # cd "${BASH_SOURCE%/*}" shopt -s extglob set -e ### CONFIGURATION # Targets to build. targets_all=( mpw # C CLI version of Master Password (needs: mpw_sodium, optional: mpw_color, mpw_json). mpw-bench # C CLI Master Password benchmark utility (needs: mpw_sodium). mpw-tests # C Master Password algorithm test suite (needs: mpw_sodium, mpw_xml). ) targets_default='mpw' # Override with: targets='...' ./build # Features. mpw_sodium=${mpw_sodium:-1} # Implement crypto functions with sodium (depends on libsodium). mpw_json=${mpw_json:-1} # Support JSON-based user configuration format (depends on libjson-c). mpw_color=${mpw_color:-1} # Colorized identicon (depends on libncurses). mpw_xml=${mpw_xml:-1} # XML parsing (depends on libxml2). # Default build flags. cflags=( -O3 $CFLAGS ) ldflags=( $LDFLAGS ) # Version. if { mpw_version=$(git describe --match '*-cli*' --long --dirty) || mpw_version=$(/dev/null; then cflags+=( -D"MP_VERSION=$mpw_version" ) fi echo 2>&1 "Current mpw source version ${mpw_version:-}..." ### TARGET: MPW mpw() { # dependencies use_mpw_sodium required use_mpw_color optional use_mpw_json optional # target cflags=( "${cflags[@]}" # library paths -I"lib/include" # mpw paths -I"core" -I"cli" ) ldflags=( "${ldflags[@]}" ) # build cc "${cflags[@]}" "$@" "core/base64.c" "core/aes.c" "core/mpw-algorithm.c" "core/mpw-types.c" "core/mpw-util.c" "core/mpw-marshal-util.c" "core/mpw-marshal.c" "cli/mpw-cli-util.c" \ "${ldflags[@]}" "cli/mpw-cli.c" -o "mpw" echo "done! You can now run ./mpw-cli-tests, ./install or use ./$_" } ### TARGET: MPW-BENCH mpw-bench() { # dependencies use_mpw_sodium required # target cflags=( "${cflags[@]}" # library paths -I"lib/include" # mpw paths -I"core" -I"cli" ) ldflags=( "${ldflags[@]}" ) # build cc "${cflags[@]}" "$@" "core/base64.c" "core/aes.c" "core/mpw-algorithm.c" "core/mpw-types.c" "core/mpw-util.c" \ "${ldflags[@]}" "cli/mpw-bench.c" -o "mpw-bench" echo "done! You can now use ./$_" } ### TARGET: MPW-TESTS mpw-tests() { # dependencies use_mpw_sodium required use_mpw_xml required # target cflags=( "${cflags[@]}" # library paths -I"lib/include" # mpw paths -I"core" -I"cli" ) ldflags=( "${ldflags[@]}" ) # build cc "${cflags[@]}" "$@" "core/base64.c" "core/aes.c" "core/mpw-algorithm.c" "core/mpw-types.c" "core/mpw-util.c" "cli/mpw-tests-util.c" \ "${ldflags[@]}" "cli/mpw-tests.c" -o "mpw-tests" echo "done! You can now use ./$_" } ### TOOLS haslib() { cc -x c "${ldflags[@]}" -l"$1" -o /dev/null - <<< 'int main() { return 0; }' &>/dev/null } cc() { if hash llvm-gcc 2>/dev/null; then llvm-gcc "$@" elif hash gcc 2>/dev/null; then gcc -std=c11 "$@" elif hash clang 2>/dev/null; then clang "$@" else echo >&2 "Need a compiler. Please install GCC or LLVM." exit 1 fi } ### DEPENDENCIES use() { local option=$1 requisite=$2 lib=$3; shift 3 local enabled=${!option} if (( enabled )); then if haslib "$lib"; then for lib in "$lib" "$@"; do haslib "$lib" && ldflags+=( -l"$lib" ) done echo >&2 "INFO: Enabled $option (lib$lib)." return 0 elif [[ $requisite == required ]]; then echo >&2 "ERROR: $option was enabled but is missing $lib library. Please install this library before continuing." exit 1 else echo >&2 "WARNING: $option was enabled but is missing $lib library. Will continue with $option disabled!" return 1 fi elif [[ $requisite == required ]]; then echo >&2 "ERROR: $option was required but is not enabled. Please enable the option or remove this target before continuing." exit 1 else echo >&2 "INFO: $option is supported but not enabled." return 1 fi } use_mpw_sodium() { local requisite=$1 use mpw_sodium "$requisite" sodium && cflags+=( -D"MPW_SODIUM=1" ) ||: } use_mpw_color() { local requisite=$1 use mpw_color "$requisite" curses tinfo && cflags+=( -D"MPW_COLOR=1" ) ||: } use_mpw_json() { local requisite=$1 use mpw_json "$requisite" json-c && cflags+=( -D"MPW_JSON=1" ) ||: } use_mpw_xml() { local requisite=$1 use mpw_xml "$requisite" xml2 && cflags+=( -D"MPW_XML=1" -I"/usr/include/libxml2" -I"/usr/local/include/libxml2" ) ||: } ### BUILD TARGETS for target in "${targets_all[@]}"; do if [[ ${targets:-$targets_default} == 'all' || " ${targets:-$targets_default} " = *" $target "* ]]; then echo echo "Building target: $target..." ( "$target" "$@" ) fi done