
1 changed files with 181 additions and 0 deletions
@ -0,0 +1,181 @@ |
|||||
|
#!/usr/bin/env bash |
||||
|
set -eu -o pipefail |
||||
|
|
||||
|
os= |
||||
|
case $(uname -s | awk '{print tolower($0)}') in |
||||
|
linux*) os=linux;; |
||||
|
darwin*) os=mac;; |
||||
|
cygwin*) os=cygwin;; |
||||
|
*bsd*) os=bsd;; |
||||
|
*) os=unknown;; |
||||
|
esac |
||||
|
|
||||
|
|
||||
|
print_usage() { |
||||
|
cat <<EOF |
||||
|
Usage: tool [options] <command> [<args>] |
||||
|
Options: |
||||
|
-v Print important commands as they're executed. |
||||
|
-c <name> Use a specific compiler binary instead. |
||||
|
Default: \$CC, or cc |
||||
|
-h Print this message and exit. |
||||
|
EOF |
||||
|
} |
||||
|
|
||||
|
compiler_exe="${CC:-cc}" |
||||
|
|
||||
|
verbose=0 |
||||
|
|
||||
|
while getopts c:hv- opt_val; do |
||||
|
case "$opt_val" in |
||||
|
c) compiler_exe="$OPTARG";; |
||||
|
v) verbose=1;; |
||||
|
h) print_usage; exit 0;; |
||||
|
\?) print_usage >&2; exit 1;; |
||||
|
*) break;; |
||||
|
esac |
||||
|
done |
||||
|
|
||||
|
warn() { |
||||
|
echo "Warning: $*" >&2 |
||||
|
} |
||||
|
fatal() { |
||||
|
echo "Error: $*" >&2 |
||||
|
exit 1 |
||||
|
} |
||||
|
script_error() { |
||||
|
echo "Script error: $*" >&2 |
||||
|
exit 1 |
||||
|
} |
||||
|
|
||||
|
verbose_echo() { |
||||
|
if [[ $verbose = 1 ]]; then |
||||
|
echo "$@" |
||||
|
fi |
||||
|
"$@" |
||||
|
} |
||||
|
|
||||
|
if [[ ($os == bsd) || ($os == unknown) ]]; then |
||||
|
warn "Build script not tested on this platform" |
||||
|
fi |
||||
|
|
||||
|
# This is not perfect by any means |
||||
|
cc_id= |
||||
|
compiler_vers= |
||||
|
if ${compiler_exe} --version | grep -q ^clang 2> /dev/null; then |
||||
|
cc_id=clang |
||||
|
compiler_vers=$(${compiler_exe} -dumpversion) |
||||
|
# Only gcc has -dumpfullversion |
||||
|
elif compiler_vers=$(${compiler_exe} -dumpfullversion 2> /dev/null); then |
||||
|
cc_id=gcc |
||||
|
fi |
||||
|
|
||||
|
if [[ -z $cc_id ]]; then |
||||
|
warn "Failed to detect compiler type" |
||||
|
fi |
||||
|
if [[ -z $compiler_vers ]]; then |
||||
|
warn "Failed to detect compiler version" |
||||
|
fi |
||||
|
|
||||
|
add() { |
||||
|
if [[ -z "${1:-}" ]]; then |
||||
|
script_error "At least one argument required for array add" |
||||
|
fi |
||||
|
local array_name |
||||
|
array_name=${1} |
||||
|
shift |
||||
|
eval "$array_name+=($(printf "'%s' " "$@"))" |
||||
|
} |
||||
|
|
||||
|
try_make_dir() { |
||||
|
if ! [[ -e "$1" ]]; then |
||||
|
verbose_echo mkdir "$1" |
||||
|
elif ! [[ -d "$1" ]]; then |
||||
|
fatal "File $1 already exists but is not a directory" |
||||
|
fi |
||||
|
} |
||||
|
|
||||
|
out_exe=orca |
||||
|
build_dir=build |
||||
|
source_files=() |
||||
|
add source_files field.c mark.c bank.c sim.c |
||||
|
|
||||
|
# safety flags: -D_FORTIFY_SOURCE=2 -fstack-protector-strong -fpie -Wl,-pie |
||||
|
#local tui_flags=() |
||||
|
#add tui_flags -D_XOPEN_SOURCE_EXTENDED=1 |
||||
|
|
||||
|
build_target() { |
||||
|
local build_subdir |
||||
|
local compiler_flags=() |
||||
|
local libraries=() |
||||
|
add compiler_flags -std=c99 -pipe -Wall -Wpedantic -Wextra -Wconversion -Werror=implicit-function-declaration -Werror=implicit-int -Werror=incompatible-pointer-types -Werror=int-conversion |
||||
|
case "$1" in |
||||
|
debug) |
||||
|
build_subdir=debug |
||||
|
add compiler_flags -DDEBUG -ggdb -fsanitize=address -fsanitize=undefined |
||||
|
if [[ $os = mac ]]; then |
||||
|
# mac clang does not have -Og |
||||
|
add compiler_flags -O1 |
||||
|
# tui in the future |
||||
|
# add libraries -lncurses |
||||
|
else |
||||
|
add compiler_flags -Og -feliminate-unused-debug-symbols |
||||
|
# needed if address is already specified? doesn't work on mac clang, at |
||||
|
# least |
||||
|
# add compiler_flags -fsanitize=leak |
||||
|
# add libraries -lncursesw |
||||
|
fi |
||||
|
;; |
||||
|
release) |
||||
|
build_subdir=release |
||||
|
add compiler_flags -DNDEBUG -O2 -g0 |
||||
|
if [[ $os = mac ]]; then |
||||
|
# todo some stripping option |
||||
|
true |
||||
|
else |
||||
|
# -flto is good on both clang and gcc on Linux |
||||
|
add compiler_flags -flto -s |
||||
|
fi |
||||
|
;; |
||||
|
*) fatal "Unknown build target \"$1\"";; |
||||
|
esac |
||||
|
add source_files cli_main.c |
||||
|
try_make_dir "$build_dir" |
||||
|
try_make_dir "$build_dir/$build_subdir" |
||||
|
verbose_echo "${compiler_exe}" "${compiler_flags[@]}" -o "$build_dir/$build_subdir/$out_exe" "${source_files[@]}" "${libraries[@]}" |
||||
|
} |
||||
|
|
||||
|
shift $((OPTIND - 1)) |
||||
|
|
||||
|
if [[ -z "${1:-}" ]]; then |
||||
|
echo "Error: Command required" >&2 |
||||
|
print_usage >&2 |
||||
|
exit 1 |
||||
|
fi |
||||
|
|
||||
|
case "$1" in |
||||
|
info) |
||||
|
echo "OS: $os" |
||||
|
echo "Compiler name: $compiler_exe" |
||||
|
echo "Compiler type: $cc_id" |
||||
|
echo "Compiler version: $compiler_vers" |
||||
|
exit 0 |
||||
|
;; |
||||
|
build) |
||||
|
if [[ "$#" -gt 2 ]]; then |
||||
|
fatal "Too many arguments for 'build'" |
||||
|
fi |
||||
|
if [ "$#" -lt 1 ]; then |
||||
|
fatal "Argument required for build target" |
||||
|
exit 1 |
||||
|
fi |
||||
|
build_target "$2" |
||||
|
;; |
||||
|
clean) |
||||
|
if [[ -d "$build_dir" ]]; then |
||||
|
verbose_echo rm -rf "$build_dir" |
||||
|
fi |
||||
|
;; |
||||
|
*) echo "Unrecognized command $1"; exit 1;; |
||||
|
esac |
||||
|
|
Loading…
Reference in new issue