diff --git a/nix/cargo-pgrx/buildPgrxExtension.nix b/nix/cargo-pgrx/buildPgrxExtension.nix index adfee55ec..16e47ced8 100644 --- a/nix/cargo-pgrx/buildPgrxExtension.nix +++ b/nix/cargo-pgrx/buildPgrxExtension.nix @@ -160,7 +160,6 @@ let cargo-pgrx pgrx stop all mv $out/${postgresql}/* $out - mv $out/${postgresql.lib}/* $out rm -rf $out/nix ${maybeLeaveBuildAndTestSubdir} diff --git a/nix/ext/tests/wrappers.nix b/nix/ext/tests/wrappers.nix index 54cc63944..ceae1b647 100644 --- a/nix/ext/tests/wrappers.nix +++ b/nix/ext/tests/wrappers.nix @@ -13,7 +13,6 @@ let name = "postgresql-${majorVersion}-${pname}"; paths = [ postgresql - postgresql.lib (installedExtension majorVersion) ]; passthru = { @@ -21,17 +20,11 @@ let lib = pkg; withPackages = _: pkg; }; - nativeBuildInputs = [ pkgs.makeWrapper ]; pathsToLink = [ "/" "/bin" "/lib" ]; - postBuild = '' - wrapProgram $out/bin/postgres --set NIX_PGLIBDIR $out/lib - wrapProgram $out/bin/pg_ctl --set NIX_PGLIBDIR $out/lib - wrapProgram $out/bin/pg_upgrade --set NIX_PGLIBDIR $out/lib - ''; }; in pkg; diff --git a/nix/postgresql/generic.nix b/nix/postgresql/generic.nix index 7cdf79ea5..788a6e50f 100644 --- a/nix/postgresql/generic.nix +++ b/nix/postgresql/generic.nix @@ -16,8 +16,8 @@ let icu, lz4, zstd, - systemd, - libossp_uuid, + systemdLibs, + libuuid, pkg-config, libxml2, tzdata, @@ -25,6 +25,8 @@ let replaceVars, darwin, linux-pam, + removeReferencesTo, + writeShellApplication, #orioledb specific perl, bison, @@ -34,9 +36,7 @@ let docbook_xsl_ns, libxslt, - # This is important to obtain a version of `libpq` that does not depend on systemd. - systemdSupport ? lib.meta.availableOn stdenv.hostPlatform systemd && !stdenv.hostPlatform.isStatic, - enableSystemd ? null, + systemdSupport ? lib.meta.availableOn stdenv.hostPlatform systemdLibs, gssSupport ? with stdenv.hostPlatform; !isWindows && !isStatic, # for postgresql.pkgs @@ -55,8 +55,8 @@ let # JIT jitSupport, nukeReferences, - patchelf, llvmPackages, + overrideCC, # PL/Python pythonSupport ? false, @@ -72,17 +72,27 @@ let lz4Enabled = atLeast "14"; zstdEnabled = atLeast "15"; - systemdSupport' = - if enableSystemd == null then - systemdSupport - else - (lib.warn "postgresql: argument enableSystemd is deprecated, please use systemdSupport instead." enableSystemd); + dlSuffix = if olderThan "16" then ".so" else stdenv.hostPlatform.extensions.sharedLibrary; isOrioleDB = (builtins.match "[0-9][0-9]_.*" version) != null; pname = "postgresql"; - stdenv' = if jitSupport then llvmPackages.stdenv else stdenv; + stdenv' = + if jitSupport && !stdenv.cc.isClang then + overrideCC llvmPackages.stdenv ( + llvmPackages.stdenv.cc.override { + # LLVM bintools are not used by default, but are needed to make -flto work below. + bintools = llvmPackages.bintools; + } + ) + else + stdenv; + + pg_config = writeShellApplication { + name = "pg_config"; + text = builtins.readFile ./pg_config.sh; + }; in stdenv'.mkDerivation (finalAttrs: { inherit version; @@ -100,31 +110,62 @@ let inherit hash; }; + __structuredAttrs = true; + hardeningEnable = lib.optionals (!stdenv'.cc.isClang) [ "pie" ]; outputs = [ "out" + "dev" + "doc" "lib" ]; - setOutputFlags = false; # $out retains configureFlags :-/ + outputChecks.out = { + disallowedReferences = [ + "dev" + "doc" + ]; + disallowedRequisites = + [ + stdenv'.cc + ] + ++ (map lib.getDev (builtins.filter (drv: drv ? "dev") finalAttrs.buildInputs)) + ++ lib.optionals jitSupport [ + llvmPackages.llvm.out + ]; + }; + outputChecks.lib = { + disallowedReferences = [ + "out" + "dev" + ]; + disallowedRequisites = + [ + stdenv'.cc + ] + ++ (map lib.getDev (builtins.filter (drv: drv ? "dev") finalAttrs.buildInputs)) + ++ lib.optionals jitSupport [ + llvmPackages.llvm.out + ]; + }; buildInputs = [ zlib readline openssl - (libxml2.override { python = python3; }) + (libxml2.override { enableHttp = true; }) icu + libuuid ] ++ lib.optionals (olderThan "13") [ libxcrypt ] ++ lib.optionals jitSupport [ llvmPackages.llvm ] ++ lib.optionals lz4Enabled [ lz4 ] ++ lib.optionals zstdEnabled [ zstd ] - ++ lib.optionals systemdSupport' [ systemd ] + ++ lib.optionals systemdSupport [ systemdLibs ] ++ lib.optionals pythonSupport [ python3 ] ++ lib.optionals gssSupport [ libkrb5 ] - ++ lib.optionals stdenv'.isLinux [ linux-pam ] - ++ lib.optionals (!stdenv'.isDarwin) [ libossp_uuid ] + ++ lib.optionals stdenv'.hostPlatform.isLinux [ linux-pam ] ++ lib.optionals (isOrioleDB || (lib.versionAtLeast version "17")) [ perl bison @@ -139,11 +180,11 @@ let [ makeWrapper pkg-config + removeReferencesTo ] ++ lib.optionals jitSupport [ llvmPackages.llvm.dev nukeReferences - patchelf ]; enableParallelBuilding = true; @@ -152,9 +193,17 @@ let buildFlags = [ "world-bin" ]; - # Makes cross-compiling work when xml2-config can't be executed on the host. - # Fixed upstream in https://github.com/postgres/postgres/commit/0bc8cebdb889368abdf224aeac8bc197fe4c9ae6 - env.NIX_CFLAGS_COMPILE = lib.optionalString (olderThan "13") "-I${libxml2.dev}/include/libxml2"; + # libpgcommon.a and libpgport.a contain all paths returned by pg_config and are linked + # into all binaries. However, almost no binaries actually use those paths. The following + # flags will remove unused sections from all shared libraries and binaries - including + # those paths. This avoids a lot of circular dependency problems with different outputs, + # and allows splitting them cleanly. + env.CFLAGS = + "-fdata-sections -ffunction-sections" + + (if stdenv'.cc.isClang then " -flto" else " -fmerge-constants -Wl,--gc-sections") + # Makes cross-compiling work when xml2-config can't be executed on the host. + # Fixed upstream in https://github.com/postgres/postgres/commit/0bc8cebdb889368abdf224aeac8bc197fe4c9ae6 + + lib.optionalString (olderThan "13") " -I${libxml2.dev}/include/libxml2"; configureFlags = [ @@ -162,18 +211,22 @@ let "--with-libxml" "--with-icu" "--sysconfdir=/etc" - "--libdir=$(lib)/lib" "--with-system-tzdata=${tzdata}/share/zoneinfo" "--enable-debug" - (lib.optionalString systemdSupport' "--with-systemd") - (if stdenv'.isDarwin then "--with-uuid=e2fs" else "--with-ossp-uuid") + (lib.optionalString systemdSupport "--with-systemd") + "--with-uuid=e2fs" ] ++ lib.optionals lz4Enabled [ "--with-lz4" ] ++ lib.optionals zstdEnabled [ "--with-zstd" ] ++ lib.optionals gssSupport [ "--with-gssapi" ] ++ lib.optionals pythonSupport [ "--with-python" ] ++ lib.optionals jitSupport [ "--with-llvm" ] - ++ lib.optionals stdenv'.isLinux [ "--with-pam" ]; + ++ lib.optionals stdenv'.hostPlatform.isLinux [ "--with-pam" ] + # This could be removed once the upstream issue is resolved: + # https://postgr.es/m/flat/427c7c25-e8e1-4fc5-a1fb-01ceff185e5b%40technowledgy.de + ++ lib.optionals (stdenv'.hostPlatform.isDarwin && atLeast "16") [ + "LDFLAGS_EX_BE=-Wl,-export_dynamic" + ]; patches = [ @@ -183,9 +236,14 @@ let else ./patches/relative-to-symlinks.patch ) + ( + if atLeast "15" then + ./patches/empty-pg-config-view-15+.patch + else + ./patches/empty-pg-config-view.patch + ) ./patches/less-is-more.patch ./patches/paths-for-split-outputs.patch - ./patches/specify_pkglibdir_at_runtime.patch ./patches/paths-with-postgresql-suffix.patch (replaceVars ./patches/locale-binary-path.patch { @@ -210,37 +268,45 @@ let # Using fetchurl instead of fetchpatch on purpose: https://github.com/NixOS/nixpkgs/issues/240141 map fetchurl (lib.attrValues muslPatches) ) - ++ lib.optionals stdenv'.isLinux [ + ++ lib.optionals stdenv'.hostPlatform.isLinux [ (if atLeast "13" then ./patches/socketdir-in-run-13+.patch else ./patches/socketdir-in-run.patch) + ] + ++ lib.optionals (stdenv'.hostPlatform.isDarwin && olderThan "16") [ + ./patches/export-dynamic-darwin-15-.patch ]; installTargets = [ "install-world-bin" ]; - postPatch = - '' - # Hardcode the path to pgxs so pg_config returns the path in $out - substituteInPlace "src/common/config_info.c" --subst-var out - '' - + lib.optionalString jitSupport '' - # Force lookup of jit stuff in $out instead of $lib - substituteInPlace src/backend/jit/jit.c --replace pkglib_path \"$out/lib\" - substituteInPlace src/backend/jit/llvm/llvmjit.c --replace pkglib_path \"$out/lib\" - substituteInPlace src/backend/jit/llvm/llvmjit_inline.cpp --replace pkglib_path \"$out/lib\" - ''; + postPatch = '' + substituteInPlace "src/Makefile.global.in" --subst-var out + # Hardcode the path to pgxs so pg_config returns the path in $dev + substituteInPlace "src/common/config_info.c" --subst-var dev + ''; postInstall = '' - moveToOutput "lib/pgxs" "$out" # looks strange, but not deleting it - moveToOutput "lib/libpgcommon*.a" "$out" - moveToOutput "lib/libpgport*.a" "$out" - moveToOutput "lib/libecpg*" "$out" - - # Prevent a retained dependency on gcc-wrapper. - substituteInPlace "$out/lib/pgxs/src/Makefile.global" --replace ${stdenv'.cc}/bin/ld ld + moveToOutput "bin/ecpg" "$dev" + 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. See the + # pg_config.sh script's comments for details. + moveToOutput "bin/pg_config" "$dev" + 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 + # can't be stripped away by --gc-sections/LTO, because they could theoretically + # be used by dynamically loaded modules / extensions. To avoid circular dependencies, + # references to -dev, -doc and -man are removed here. References to -lib must be kept, + # because there is a realistic use-case for extensions to locate the /lib directory to + # load other shared modules. + remove-references-to -t "$dev" -t "$doc" "$out/bin/postgres" + remove-references-to -t "$dev" -t "$doc" "$out/bin/pg_rewind" if [ -z "''${dontDisableStatic:-}" ]; then # Remove static libraries in case dynamic are available. - for i in $out/lib/*.a $lib/lib/*.a; do + for i in $lib/lib/*.a; do name="$(basename "$i")" ext="${stdenv'.hostPlatform.extensions.sharedLibrary}" if [ -e "$lib/lib/''${name%.a}$ext" ] || [ -e "''${i%.a}$ext" ]; then @@ -248,46 +314,26 @@ let fi done fi + # The remaining static libraries are libpgcommon.a, libpgport.a and related. + # Those are only used when building e.g. extensions, so go to $dev. + moveToOutput "lib/*.a" "$dev" '' + lib.optionalString jitSupport '' - # Move the bitcode and libllvmjit.so library out of $lib; otherwise, every client that - # depends on libpq.so will also have libLLVM.so in its closure too, bloating it - moveToOutput "lib/bitcode" "$out" - moveToOutput "lib/llvmjit*" "$out" - - # In the case of JIT support, prevent a retained dependency on clang-wrapper - substituteInPlace "$out/lib/pgxs/src/Makefile.global" --replace ${stdenv'.cc}/bin/clang clang - nuke-refs $out/lib/llvmjit_types.bc $(find $out/lib/bitcode -type f) - - # Stop out depending on the default output of llvm - substituteInPlace $out/lib/pgxs/src/Makefile.global \ - --replace ${llvmPackages.llvm.out}/bin "" \ - --replace '$(LLVM_BINPATH)/' "" - - # Stop out depending on the -dev output of llvm - substituteInPlace $out/lib/pgxs/src/Makefile.global \ - --replace ${llvmPackages.llvm.dev}/bin/llvm-config llvm-config \ - --replace -I${llvmPackages.llvm.dev}/include "" - - ${lib.optionalString (!stdenv'.isDarwin) '' - # Stop lib depending on the -dev output of llvm - rpath=$(patchelf --print-rpath $out/lib/llvmjit.so) - nuke-refs -e $out $out/lib/llvmjit.so - # Restore the correct rpath - patchelf $out/lib/llvmjit.so --set-rpath "$rpath" - ''} + # In the case of JIT support, prevent useless dependencies on header files + find "$out/lib" -iname '*.bc' -type f -exec nuke-refs '{}' + + + # Stop lib depending on the -dev output of llvm + remove-references-to -t ${llvmPackages.llvm.dev} "$out/lib/llvmjit${dlSuffix}" ''; - postFixup = lib.optionalString (!stdenv'.isDarwin && stdenv'.hostPlatform.libc == "glibc") '' + postFixup = lib.optionalString stdenv'.hostPlatform.isGnu '' # initdb needs access to "locale" command from glibc. wrapProgram $out/bin/initdb --prefix PATH ":" ${glibc.bin}/bin ''; - doCheck = !stdenv'.isDarwin; + doCheck = !stdenv'.hostPlatform.isDarwin; # autodetection doesn't seem to able to find this, but it's there. - checkTarget = "check"; - - disallowedReferences = [ stdenv'.cc ]; + checkTarget = "check-world"; passthru = let @@ -295,13 +341,13 @@ let jitToggle = this.override { jitSupport = !jitSupport; }; in { + inherit dlSuffix; + psqlSchema = lib.versions.major version; withJIT = if jitSupport then this else jitToggle; withoutJIT = if jitSupport then jitToggle else this; - dlSuffix = if olderThan "16" then ".so" else stdenv.hostPlatform.extensions.sharedLibrary; - pkgs = let scope = { @@ -318,7 +364,7 @@ let import ./ext newSelf newSuper; withPackages = postgresqlWithPackages { - inherit makeWrapper buildEnv; + inherit buildEnv; postgresql = this; } this.pkgs; @@ -372,17 +418,13 @@ let # resulting LLVM IR isn't platform-independent this doesn't give you much. # In fact, I tried to test the result in a VM-test, but as soon as JIT was used to optimize # a query, postgres would coredump with `Illegal instruction`. - broken = - (jitSupport && stdenv.hostPlatform != stdenv.buildPlatform) - # Allmost all tests fail FATAL errors for v12 and v13 - || (jitSupport && stdenv.hostPlatform.isMusl && olderThan "14"); + broken = jitSupport && !stdenv.hostPlatform.canExecute stdenv.buildPlatform; }; }); postgresqlWithPackages = { postgresql, - makeWrapper, buildEnv, }: pkgs: f: @@ -390,29 +432,13 @@ let name = "postgresql-and-plugins-${postgresql.version}"; paths = f pkgs ++ [ postgresql - postgresql.lib #TODO RM postgresql.man # in case user installs this into environment ]; - nativeBuildInputs = [ makeWrapper ]; - # We include /bin to ensure the $out/bin directory is created, which is - # needed because we'll be removing the files from that directory in postBuild - # below. See #22653 pathsToLink = [ "/" - "/bin" ]; - # Note: the duplication of executables is about 4MB size. - # So a nicer solution was patching postgresql to allow setting the - # libdir explicitly. - postBuild = '' - mkdir -p $out/bin - rm $out/bin/{pg_config,postgres,pg_ctl} - cp --target-directory=$out/bin ${postgresql}/bin/{postgres,pg_config,pg_ctl} - wrapProgram $out/bin/postgres --set NIX_PGLIBDIR $out/lib - ''; - passthru.version = postgresql.version; passthru.psqlSchema = postgresql.psqlSchema; }; diff --git a/nix/postgresql/patches/empty-pg-config-view-15+.patch b/nix/postgresql/patches/empty-pg-config-view-15+.patch new file mode 100644 index 000000000..c83e6964c --- /dev/null +++ b/nix/postgresql/patches/empty-pg-config-view-15+.patch @@ -0,0 +1,54 @@ +Empty the pg_config system information view. This view keeps references to +several -dev outputs, which we want to avoid to keep closure size down. + +The alternative to this patch would be to nuke references across the board, +but this will also affect the output of the pg_config utility. By emptying +the view only, we keep the pg_config binary intact. It resides in the -dev +output, so it's fine to have all those references there. + +--- +--- a/src/backend/utils/misc/pg_config.c ++++ b/src/backend/utils/misc/pg_config.c +@@ -32,20 +32,5 @@ pg_config(PG_FUNCTION_ARGS) + /* initialize our tuplestore */ + InitMaterializedSRF(fcinfo, 0); + +- configdata = get_configdata(my_exec_path, &configdata_len); +- for (i = 0; i < configdata_len; i++) +- { +- Datum values[2]; +- bool nulls[2]; +- +- memset(values, 0, sizeof(values)); +- memset(nulls, 0, sizeof(nulls)); +- +- values[0] = CStringGetTextDatum(configdata[i].name); +- values[1] = CStringGetTextDatum(configdata[i].setting); +- +- tuplestore_putvalues(rsinfo->setResult, rsinfo->setDesc, values, nulls); +- } +- + return (Datum) 0; + } +--- a/src/test/regress/expected/sysviews.out ++++ b/src/test/regress/expected/sysviews.out +@@ -29,7 +29,7 @@ select name, ident, parent, level, total_bytes >= free_bytes + (1 row) + + -- At introduction, pg_config had 23 entries; it may grow +-select count(*) > 20 as ok from pg_config; ++select count(*) = 0 as ok from pg_config; + ok + ---- + t +--- a/src/test/regress/sql/sysviews.sql ++++ b/src/test/regress/sql/sysviews.sql +@@ -18,7 +18,7 @@ select name, ident, parent, level, total_bytes >= free_bytes + from pg_backend_memory_contexts where level = 0; + + -- At introduction, pg_config had 23 entries; it may grow +-select count(*) > 20 as ok from pg_config; ++select count(*) = 0 as ok from pg_config; + + -- We expect no cursors in this test; see also portals.sql + select count(*) = 0 as ok from pg_cursors; diff --git a/nix/postgresql/patches/empty-pg-config-view.patch b/nix/postgresql/patches/empty-pg-config-view.patch new file mode 100644 index 000000000..98e4b8151 --- /dev/null +++ b/nix/postgresql/patches/empty-pg-config-view.patch @@ -0,0 +1,50 @@ +Empty the pg_config system information view. This view keeps references to +several -dev outputs, which we want to avoid to keep closure size down. + +The alternative to this patch would be to nuke references across the board, +but this will also affect the output of the pg_config utility. By emptying +the view only, we keep the pg_config binary intact. It resides in the -dev +output, so it's fine to have all those references there. + +--- +--- a/src/backend/utils/misc/pg_config.c ++++ b/src/backend/utils/misc/pg_config.c +@@ -69,16 +69,6 @@ pg_config(PG_FUNCTION_ARGS) + /* initialize our tuplestore */ + tupstore = tuplestore_begin_heap(true, false, work_mem); + +- configdata = get_configdata(my_exec_path, &configdata_len); +- for (i = 0; i < configdata_len; i++) +- { +- values[0] = configdata[i].name; +- values[1] = configdata[i].setting; +- +- tuple = BuildTupleFromCStrings(attinmeta, values); +- tuplestore_puttuple(tupstore, tuple); +- } +- + /* + * no longer need the tuple descriptor reference created by + * TupleDescGetAttInMetadata() +--- a/src/test/regress/expected/sysviews.out ++++ b/src/test/regress/expected/sysviews.out +@@ -20,7 +20,7 @@ select count(*) >= 0 as ok from pg_available_extensions; + (1 row) + + -- At introduction, pg_config had 23 entries; it may grow +-select count(*) > 20 as ok from pg_config; ++select count(*) = 0 as ok from pg_config; + ok + ---- + t +--- a/src/test/regress/sql/sysviews.sql ++++ b/src/test/regress/sql/sysviews.sql +@@ -13,7 +13,7 @@ select count(*) >= 0 as ok from pg_available_extension_versions; + select count(*) >= 0 as ok from pg_available_extensions; + + -- At introduction, pg_config had 23 entries; it may grow +-select count(*) > 20 as ok from pg_config; ++select count(*) = 0 as ok from pg_config; + + -- We expect no cursors in this test; see also portals.sql + select count(*) = 0 as ok from pg_cursors; diff --git a/nix/postgresql/patches/export-dynamic-darwin-15-.patch b/nix/postgresql/patches/export-dynamic-darwin-15-.patch new file mode 100644 index 000000000..fa0f4be4d --- /dev/null +++ b/nix/postgresql/patches/export-dynamic-darwin-15-.patch @@ -0,0 +1,13 @@ +See https://postgr.es/m/eb249761-56e2-4e42-a2c5-b9ae18c1ca1f%40technowledgy.de +--- +--- a/src/makefiles/Makefile.darwin ++++ b/src/makefiles/Makefile.darwin +@@ -5,6 +5,8 @@ DLSUFFIX = .so + # env var name to use in place of LD_LIBRARY_PATH + ld_library_path_var = DYLD_LIBRARY_PATH + ++export_dynamic = -Wl,-export_dynamic ++ + ifdef PGXS + BE_DLLLIBS = -bundle_loader $(bindir)/postgres + else diff --git a/nix/postgresql/patches/paths-for-split-outputs.patch b/nix/postgresql/patches/paths-for-split-outputs.patch index 2134f7e81..46164bba2 100644 --- a/nix/postgresql/patches/paths-for-split-outputs.patch +++ b/nix/postgresql/patches/paths-for-split-outputs.patch @@ -4,8 +4,19 @@ i++; configdata[i].name = pstrdup("PGXS"); -+ strlcpy(path, "@out@/lib", sizeof(path)); ++ strlcpy(path, "@dev@/lib", sizeof(path)); - get_pkglib_path(my_exec_path, path); strlcat(path, "/pgxs/src/makefiles/pgxs.mk", sizeof(path)); cleanup_path(path); configdata[i].setting = pstrdup(path); +--- a/src/Makefile.global.in ++++ b/src/Makefile.global.in +@@ -116,7 +116,7 @@ endif + + libdir := @libdir@ + +-pkglibdir = $(libdir) ++pkglibdir = @out@/lib + ifeq "$(findstring pgsql, $(pkglibdir))" "" + ifeq "$(findstring postgres, $(pkglibdir))" "" + override pkglibdir := $(pkglibdir)/postgresql diff --git a/nix/postgresql/patches/specify_pkglibdir_at_runtime.patch b/nix/postgresql/patches/specify_pkglibdir_at_runtime.patch deleted file mode 100644 index b94fc9efc..000000000 --- a/nix/postgresql/patches/specify_pkglibdir_at_runtime.patch +++ /dev/null @@ -1,28 +0,0 @@ ---- a/src/port/path.c -+++ b/src/port/path.c -@@ -714,7 +714,11 @@ - void - get_lib_path(const char *my_exec_path, char *ret_path) - { -- make_relative_path(ret_path, LIBDIR, PGBINDIR, my_exec_path); -+ char const * const nix_pglibdir = getenv("NIX_PGLIBDIR"); -+ if(nix_pglibdir == NULL) -+ make_relative_path(ret_path, LIBDIR, PGBINDIR, my_exec_path); -+ else -+ make_relative_path(ret_path, nix_pglibdir, PGBINDIR, my_exec_path); - } - - /* -@@ -723,7 +727,11 @@ - void - get_pkglib_path(const char *my_exec_path, char *ret_path) - { -- make_relative_path(ret_path, PKGLIBDIR, PGBINDIR, my_exec_path); -+ char const * const nix_pglibdir = getenv("NIX_PGLIBDIR"); -+ if(nix_pglibdir == NULL) -+ make_relative_path(ret_path, PKGLIBDIR, PGBINDIR, my_exec_path); -+ else -+ make_relative_path(ret_path, nix_pglibdir, PGBINDIR, my_exec_path); - } - - /* diff --git a/nix/postgresql/pg_config.sh b/nix/postgresql/pg_config.sh new file mode 100644 index 000000000..9538b213f --- /dev/null +++ b/nix/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