#!/usr/bin/env bash write_command_file() { local file="$1" shift printf '%q\n' "$@" > "$file" } command_matches() { local file="$1" shift local tmp tmp="$(mktemp)" write_command_file "$tmp" "$@" if [[ -f "$file" ]] && cmp -s "$tmp" "$file"; then rm -f "$tmp" return 0 fi rm -f "$tmp" return 1 } depfile_newer_than() { local depfile="$1" local output="$2" [[ -f "$depfile" ]] || return 0 local deps deps="$(tr '\\\n' ' ' < "$depfile" | sed -e 's/^[^:]*://')" local dep for dep in $deps; do if [[ -f "$dep" && "$dep" -nt "$output" ]]; then return 0 fi done return 1 } object_needs_rebuild() { local obj="$1" local depfile="$2" local cmdfile="$3" shift 3 [[ -f "$obj" ]] || return 0 command_matches "$cmdfile" "$@" || return 0 depfile_newer_than "$depfile" "$obj" && return 0 return 1 } link_needs_rebuild() { local output="$1" local cmdfile="$2" shift 2 [[ -f "$output" ]] || return 0 command_matches "$cmdfile" "$@" || return 0 local arg for arg in "$@"; do if [[ -f "$arg" && "$arg" -nt "$output" ]]; then return 0 fi done return 1 } source_object_path() { local source="$1" local root_dir="$2" local obj_dir="$3" local relative="${source#"$root_dir"/}" if [[ "$relative" == "$source" ]]; then relative="$(basename "$source")" fi relative="${relative//\//__}" printf '%s/%s.o' "$obj_dir" "${relative%.*}" } compile_wasm_object() { local target="$1" local source="$2" local obj="$3" local build_dir="$4" shift 4 local stdout_log="$build_dir/$target.stdout.log" local stderr_log="$build_dir/$target.stderr.log" local depfile="$obj.d" local cmdfile="$obj.cmd" local cmd=(emcc "$@" -MMD -MP -MF "$depfile" -c "$source" -o "$obj") mkdir -p "$(dirname "$obj")" if ! object_needs_rebuild "$obj" "$depfile" "$cmdfile" "${cmd[@]}"; then printf 'up to date: %s\n' "$source" >> "$stdout_log" return 0 fi printf 'compile: %s\n' "$source" >> "$stdout_log" if "${cmd[@]}" >> "$stdout_log" 2>> "$stderr_log"; then write_command_file "$cmdfile" "${cmd[@]}" return 0 fi return 1 } link_wasm_module() { local target="$1" local output="$2" local build_dir="$3" shift 3 local stdout_log="$build_dir/$target.stdout.log" local stderr_log="$build_dir/$target.stderr.log" local cmdfile="$build_dir/$(basename "$output").cmd" local wasm_output="${output%.js}.wasm" local cmd=(emcc "$@" -o "$output") if [[ -f "$output" && ! -f "$wasm_output" ]]; then printf 'missing paired wasm output: %s\n' "$wasm_output" >> "$stdout_log" rm -f "$output" fi if ! link_needs_rebuild "$output" "$cmdfile" "${cmd[@]}"; then printf 'up to date: %s\n' "$output" >> "$stdout_log" return 0 fi printf 'link: %s\n' "$output" >> "$stdout_log" if "${cmd[@]}" >> "$stdout_log" 2>> "$stderr_log"; then write_command_file "$cmdfile" "${cmd[@]}" return 0 fi return 1 }