Skip to content

Commit

Permalink
postgresql: improve fake pg_config in default output
Browse files Browse the repository at this point in the history
This fixes some build systems which look up the location of pg_config
via the location of the postgres binary itself, e.g. timescaledb,
instead of calling pg_config which is on PATH.

Since the -dev output is correctly placed before the default output of
postgresql in PATH, we can rely on that and call "pg_config" from the
default output's fake script. Only do that, when the one on PATH is
actually a different file, though, to prevent infinite loops.

Resolves #341408
  • Loading branch information
wolfgangwalther committed Sep 19, 2024
1 parent eb709dd commit 0c47767
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 9 deletions.
19 changes: 10 additions & 9 deletions pkgs/servers/sql/postgresql/generic.nix
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ let
, glibc, zlib, readline, openssl, icu, lz4, zstd, systemdLibs, libossp_uuid
, pkg-config, libxml2, tzdata, libkrb5, substituteAll, darwin
, linux-pam
, removeReferencesTo

, removeReferencesTo, writeShellApplication

# This is important to obtain a version of `libpq` that does not depend on systemd.
, systemdSupport ? lib.meta.availableOn stdenv.hostPlatform systemdLibs && !stdenv.hostPlatform.isStatic
Expand Down Expand Up @@ -54,6 +55,11 @@ let
})
else
stdenv;

pg_config = writeShellApplication {
name = "pg_config";
text = builtins.readFile ./pg_config.sh;
};
in stdenv'.mkDerivation (finalAttrs: {
inherit version;
pname = pname + lib.optionalString jitSupport "-jit";
Expand Down Expand Up @@ -201,15 +207,10 @@ let
moveToOutput "lib/pgxs" "$dev"
# Pretend pg_config is located in $out/bin to return correct paths, but
# actually have it in -dev to avoid pulling in all other outputs.
# actually have it in -dev to avoid pulling in all other outputs. See the
# pg_config.sh script's comments for details.
moveToOutput "bin/pg_config" "$dev"
# To prevent a "pg_config: could not find own program executable" error, we fake
# pg_config in the default output.
cat << EOF > "$out/bin/pg_config" && chmod +x "$out/bin/pg_config"
#!${stdenv'.shell}
echo The real pg_config can be found in the -dev output.
exit 1
EOF
install -c -m 755 "${pg_config}"/bin/pg_config "$out/bin/pg_config"
wrapProgram "$dev/bin/pg_config" --argv0 "$out/bin/pg_config"
# postgres exposes external symbols get_pkginclude_path and similar. Those
Expand Down
35 changes: 35 additions & 0 deletions pkgs/servers/sql/postgresql/pg_config.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# The real pg_config needs to be in the same path as the "postgres" binary
# to return proper paths. However, we want it in the -dev output to prevent
# cyclic references and to prevent blowing up the runtime closure. Thus, we
# have wrapped -dev/bin/pg_config to fake its argv0 to be in the default
# output. Unfortunately, pg_config tries to be smart and tries to find itself -
# which will then fail with:
# pg_config: could not find own program executable
# To counter this, we're creating *this* fake pg_config script and put it into
# the default output. The real pg_config is happy.
# Some extensions, e.g. timescaledb, use the reverse logic and look for pg_config
# in the same path as the "postgres" binary to support multi-version-installs.
# Thus, they will end up calling this script during build, even though the real
# pg_config would be available on PATH, provided by nativeBuildInputs. To help
# this case, we're redirecting the call to pg_config to the one found in PATH,
# iff we can be convinced that it belongs to our -dev output.

# Avoid infinite recursion
if [[ ! -v PG_CONFIG_CALLED ]]; then
# compares "path of *this* script" with "path, which pg_config on PATH believes it is in"
if [[ "$(readlink -f -- "$0")" == "$(PG_CONFIG_CALLED=1 pg_config --bindir)/pg_config" ]]; then
# The pg_config in PATH returns the same bindir that we're actually called from.
# This means that the pg_config in PATH is the one from "our" -dev output.
# This happens when the -dev output has been put in native build
# inputs and allows us to call the real pg_config without referencing
# the -dev output itself.
exec pg_config "$@"
fi
fi

# This will happen in one of these cases:
# - *this* script is the first on PATH
# - np pg_config on PATH
# - some other pg_config on PATH, not from our -dev output
echo The real pg_config can be found in the -dev output.
exit 1

0 comments on commit 0c47767

Please sign in to comment.