Skip to content

Instantly share code, notes, and snippets.

@ISSOtm
Created February 8, 2023 10:01
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ISSOtm/ba4b7a9c6ba7ecce5d6fc7db82a2ba79 to your computer and use it in GitHub Desktop.
Save ISSOtm/ba4b7a9c6ba7ecce5d6fc7db82a2ba79 to your computer and use it in GitHub Desktop.
Fragment of a `./configure.sh` I wrote that generates a `build.ninja`
#!/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