Use custom install command in Makefile to speed up incremental builds (#2458)

Fixes #1873: previously any run of `make` caused the `postgres-v15-headers`
target to build. It copied a bunch of headers via `install -C`. Unfortunately,
some origins were symlinks in the `./pg_install/build` directory pointing
inside `./vendor/postgres-v15` (e.g. `pg_config_os.h` pointing to `linux.h`).

GNU coreutils' `install` ignores the `-C` key for non-regular files and
always overwrites the destination if the origin is a symlink. That in turn
made Cargo rebuild the `postgres_ffi` crate and all its dependencies because
it thinks that Postgres headers changed, even if they did not. That was slow.

Now we use a custom script that wraps the `install` program. It handles one
specific case and makes sure individual headers are never copied if their
content did not change. Hence, `postgres_ffi` is not rebuilt unless there were
some changes to the C code.

One may still have slow incremental single-threaded builds because Postgres
Makefiles spawn about 2800 sub-makes even if no files have been changed.
A no-op build takes "only" 3-4 seconds on my machine now when run with `-j30`,
and 20 seconds when run with `-j1`.
This commit is contained in:
Egor Suvorov
2022-09-16 17:44:02 +02:00
committed by GitHub
parent 9c35a09452
commit 65a5010e25
2 changed files with 25 additions and 1 deletions

View File

@@ -38,7 +38,7 @@ endif
# headers, the mtime of the headers are not changed when there have # headers, the mtime of the headers are not changed when there have
# been no changes to the files. Changing the mtime triggers an # been no changes to the files. Changing the mtime triggers an
# unnecessary rebuild of 'postgres_ffi'. # unnecessary rebuild of 'postgres_ffi'.
PG_CONFIGURE_OPTS += INSTALL='install -C' PG_CONFIGURE_OPTS += INSTALL='$(ROOT_PROJECT_DIR)/scripts/ninstall.sh -C'
# Choose whether we should be silent or verbose # Choose whether we should be silent or verbose
CARGO_BUILD_FLAGS += --$(if $(filter s,$(MAKEFLAGS)),quiet,verbose) CARGO_BUILD_FLAGS += --$(if $(filter s,$(MAKEFLAGS)),quiet,verbose)

24
scripts/ninstall.sh Executable file
View File

@@ -0,0 +1,24 @@
#!/bin/bash
set -euo pipefail
# GNU coreutil's `install -C` always overrides the destination if the source
# is not a regular file, which is the case with lots of headers symlinked into
# the build directory by `./configure`. That causes Rust's Cargo to think that
# Postgres headers have been updated after `make` call even if no files have been
# touched. That causes long recompilation of `postgres_ffi` and all dependent
# packages. To counter that, we handle a special case here: do not copy the file
# if its content did not change. We only handle a single case where `install`
# installs a single file with a specific set of arguments, the rest does not
# matter in our configuration.
#
# Such behavior may be incorrect if e.g. permissions have changed, but it should
# not happen during normal Neon development that often, and rebuild should help.
#
# See https://github.com/neondatabase/neon/issues/1873
if [ "$#" == "5" ]; then
if [ "$1" == "-C" ] && [ "$2" == "-m" ] && [ "$3" == "644" ]; then
if [ -e "$5" ] && diff -q "$4" "$5" >/dev/null 2>&1; then
exit 0
fi
fi
fi
install "$@"