Files
openwrt/scripts/cache-run.sh
T
John Crispin c6a1bf5966 build: reuse the output of slow compression steps
On a rebuild, the initrd and the initramfs kernel image usually have
the same content as before, but xz and lzma compress them again on
every build. For the OpenWrt One this takes about 6 s of the build.

Add scripts/cache-run.sh. It runs a command that creates one file from
another, and stores the output together with a hash of the input, the
command line and the tool. If they are the same in the next run, it
copies the stored output instead. The commands are deterministic, so
the result is identical.

On a hit the script compares the stored output with the file that is
already there and copies only when the two differ. The output then keeps
its timestamp, so a later step that compares timestamps does not treat it
as new work.

Use it for the initrd compression and for Build/lzma. bzip2 and lzop
stay as they are: bzip2 writes to stdout, and lzop stores the mtime of
its input. xz and gzip now keep the cpio, as the other tools do, so a
cache hit leaves the same files behind as a normal run.

The slot name follows the path of the output below $(KDIR), because two
targets in different directories can share a basename. cache-run.sh holds
a lock over the slot and swaps the stored output in with a rename, so two
image recipes on one slot never read a half written pair.

Signed-off-by: John Crispin <john@phrozen.org>
2026-09-22 18:18:58 +02:00

56 lines
1.5 KiB
Bash
Executable File

#!/bin/sh
# SPDX-License-Identifier: GPL-2.0-only
#
# Usage: cache-run.sh <slot> <input> <output> <command> [<arg>...]
#
# Run a command that creates <output> from <input>. If the content of the
# input, the command line and the command binary are the same as in the
# last run for <slot>, copy the stored output instead of running the
# command again. Only use it for deterministic commands, such as the
# compression of kernel and initramfs images, which are slow and get the
# same input on most rebuilds.
[ $# -ge 4 ] || {
echo "Usage: $0 <slot> <input> <output> <command> [<arg>...]" >&2
exit 1
}
[ -n "$MKHASH" ] || {
echo "$0: MKHASH is not set" >&2
exit 1
}
slot="$1"
input="$2"
output="$3"
shift 3
[ -f "$input" ] || {
echo "$0: $input does not exist" >&2
exit 1
}
tool="$(command -v "$1")" || {
echo "$0: $1 not found" >&2
exit 1
}
input_hash="$("$MKHASH" sha256 "$input")" || exit 1
tool_hash="$("$MKHASH" sha256 "$tool")" || exit 1
key="$(printf '%s\n' "$input_hash" "$tool_hash" "$@" | "$MKHASH" sha256)" || exit 1
mkdir -p "$(dirname "$slot")" || exit 1
# Two image recipes can hold the same slot at the same time. Hold a lock over
# the whole slot, so that a reader never sees a half written pair.
exec 9>"$slot.lock" || exit 1
flock 9 || exit 1
if [ -f "$slot.data" ] && [ "$(cat "$slot.key" 2>/dev/null)" = "$key" ]; then
cmp -s "$slot.data" "$output" && exit 0
exec cp "$slot.data" "$output"
fi
rm -f "$slot.key"
"$@" || exit
cp "$output" "$slot.data.new" && mv -f "$slot.data.new" "$slot.data" &&
echo "$key" > "$slot.key"