Created
February 8, 2023 10:01
-
-
Save ISSOtm/ba4b7a9c6ba7ecce5d6fc7db82a2ba79 to your computer and use it in GitHub Desktop.
Fragment of a `./configure.sh` I wrote that generates a `build.ninja`
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# shellcheck disable=SC2016 # Dollar signs in single quotes are destined to Ninja, not Bash. | |
# Safety belt, even if not perfect. Combined with Shellcheck, we should be okay. | |
set -euo pipefail | |
cd "$(dirname "$0")" # Go to the script's directory. | |
BUILD_DIR="build" | |
CFLAGS="-D_GNU_SOURCE -pthread $(pkg-config --cflags sdl2)" | |
INC_PATHS=( | |
src/evdev/include/ | |
) | |
LDFLAGS="-Wl,-z,defs $(pkg-config --libs-L-only sdl2)" | |
LDLIBS="$(pkg-config --libs-l-only sdl2)" | |
SOURCE_ID_LIST_C="$BUILD_DIR/src_id_list.c" | |
SRCS=( | |
src/main.c | |
src/stuff.c | |
src/evdev/evdev.c | |
"$SOURCE_ID_LIST_C" | |
) | |
readonly BUILD_DIR CFLAGS INC_PATHS LDFLAGS LDLIBS SOURCE_ID_LIST_C SRCS | |
# Configuration time! | |
declare -A OBJS | |
for src in "${SRCS[@]}"; do | |
OBJS[$src]="$BUILD_DIR/$(basename "$src" .c).o" | |
done | |
typeset -r OBJS | |
gen_src_id_list() { | |
printf 'char const * src_id_list[] = {\n' | |
for src in "${SRCS[@]}"; do | |
printf '\t"%s",\n' "${src//\"/\\\"}" | |
done | |
printf '};\n' | |
} | |
gen_src_id_list >"$SOURCE_ID_LIST_C" | |
# File generation functions. | |
new_file() { | |
# We will write to a temp file, which we will then move atomically. | |
# This will avoid problems if several processes try to write to the file at the same time. | |
TMP_FILE=$(mktemp -p "$BUILD_DIR") | |
FINAL_FILE="$1" | |
# shellcheck disable=SC2064 # `@Q` ensures the expansion is reusable as input. | |
trap "rm -f ${TMP_FILE@Q}" EXIT | |
} | |
file_done() { | |
# Atomically overwrite the original file. | |
mv "$TMP_FILE" "$FINAL_FILE" | |
trap - EXIT # Reset the deletion trap. | |
} | |
print() { | |
# shellcheck disable=SC2059 # The first argument is intentionally a format. | |
printf "$@" >> "$TMP_FILE" | |
} | |
println() { | |
print "$1\n" "${@:2}" | |
} | |
empty_line() { | |
println '' | |
} | |
# `build.ninja` generation functions. | |
new_file build.ninja | |
variable() { # variable <name> <value> | |
println "%s = %s" "$1" "$2" | |
} | |
# The command will be interpreted by the shell, | |
# so variables should be expanded with `${var@Q}` rather than `$var`. | |
rule() { # rule <name> <cmd> [<descr> [<variables>...]] | |
println "rule %s" "$1" | |
println " command = %s" "$2" | |
if [[ $# -ge 3 ]]; then | |
println " description = %s" "$3" | |
for var in "${@:4}"; do | |
println " $var" | |
done | |
fi | |
} | |
# Paths passed to this function should have their spaces escaped (`$ `); | |
# variables that will be used in the command should follow the same precautions as for `rule`. | |
build() { # build <products> <rule name> <inputs> [<variables...] | |
println "build %s: %s %s" "$1" "$2" "$3" | |
for var in "${@:4}"; do | |
if [ -n "${var/ }" ]; then | |
println " %s" "$var" | |
fi | |
done | |
} | |
# 1.2 required for `ninja_required_version`. | |
# 1.3 required for `deps =`. | |
# 1.7 required for implicit outputs. | |
println 'ninja_required_version = 1.7' | |
empty_line | |
println '# Special variable for Ninja' | |
variable builddir "${BUILD_DIR/ /\$ }" | |
empty_line | |
rule configure './$in' 'Re-configuring...' | |
println ' generator = true' | |
build "build.ninja ${SOURCE_ID_LIST_C/ /\$ } \$builddir/compile_commands.json" configure configure.sh | |
empty_line | |
empty_line | |
# Variable definitions. | |
variable cc "$CC" | |
variable ar "$AR" | |
empty_line | |
INC_FLAGS=() | |
for path in "${INC_PATHS[@]}"; do | |
INC_FLAGS+=(\$$'\n'\"-I"$path"\") | |
done | |
variable cflags "$CFLAGS ${INC_FLAGS[*]}" | |
empty_line | |
variable ldflags "$LDFLAGS" | |
empty_line | |
variable ldlibs "$LDLIBS" | |
empty_line | |
empty_line | |
# Rules. | |
rule cc '$cc $cflags -c $in -o "$out" -MD -MP -MF "$out.d"' 'CC $in' 'depfile = $out.d' 'deps = gcc' | |
empty_line | |
rule link '$cc $cflags $ldflags $in -o "$out" $ldlibs' 'LINK $out' | |
empty_line | |
rule staticlib '$ar rcs "$out" $in' 'STATIC LIB $out' | |
empty_line | |
empty_line | |
# Builds. | |
build all phony "\$builddir/${NOM_APP/ /\$ }" | |
build "\$builddir/${NOM_APP/ /\$ }" link "${OBJS[*]/ /\$ }" | |
for src in "${SRCS[@]}"; do | |
build "${OBJS[$src]}" cc "$src" "cflags = \$cflags -DFILE_NAME=${src@Q}" | |
done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment