From 0c477676412564bd2d5dadc37cf245fe4259f4d9 Mon Sep 17 00:00:00 2001 From: Wolfgang Walther Date: Thu, 12 Sep 2024 19:15:29 +0200 Subject: [PATCH] postgresql: improve fake pg_config in default output 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 --- pkgs/servers/sql/postgresql/generic.nix | 19 +++++++------ pkgs/servers/sql/postgresql/pg_config.sh | 35 ++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 9 deletions(-) create mode 100644 pkgs/servers/sql/postgresql/pg_config.sh diff --git a/pkgs/servers/sql/postgresql/generic.nix b/pkgs/servers/sql/postgresql/generic.nix index de9dc49a09e1c..ce922e807667d 100644 --- a/pkgs/servers/sql/postgresql/generic.nix +++ b/pkgs/servers/sql/postgresql/generic.nix @@ -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 @@ -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"; @@ -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 diff --git a/pkgs/servers/sql/postgresql/pg_config.sh b/pkgs/servers/sql/postgresql/pg_config.sh new file mode 100644 index 0000000000000..9538b213fb97a --- /dev/null +++ b/pkgs/servers/sql/postgresql/pg_config.sh @@ -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