Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

postgresql: replace pg_config with custom script #388807

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions pkgs/development/tools/rust/cargo-pgrx/buildPgrxExtension.nix
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ let
preBuildAndTest = ''
export PGRX_HOME="$(mktemp -d)"
export PGDATA="$PGRX_HOME/data-${pgrxPostgresMajor}/"
cargo-pgrx pgrx init "--pg${pgrxPostgresMajor}" ${lib.getDev postgresql}/bin/pg_config
cargo-pgrx pgrx init "--pg${pgrxPostgresMajor}" ${postgresql.pg_config}/bin/pg_config
# unix sockets work in sandbox, too.
export PGHOST="$(mktemp -d)"
Expand Down Expand Up @@ -140,7 +140,7 @@ let
PGRX_BUILD_FLAGS="--frozen -j $NIX_BUILD_CORES ${builtins.concatStringsSep " " cargoBuildFlags}" \
${lib.optionalString stdenv.hostPlatform.isDarwin ''RUSTFLAGS="''${RUSTFLAGS:+''${RUSTFLAGS} }-Clink-args=-Wl,-undefined,dynamic_lookup"''} \
cargo pgrx package \
--pg-config ${lib.getDev postgresql}/bin/pg_config \
--pg-config ${postgresql.pg_config}/bin/pg_config \
${maybeDebugFlag} \
--features "${builtins.concatStringsSep " " buildFeatures}" \
--out-dir "$out"
Expand Down
2 changes: 1 addition & 1 deletion pkgs/servers/sql/postgresql/buildPostgresqlExtension.nix
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ let

strictDeps = true;
buildInputs = [ postgresql ] ++ prevAttrs.buildInputs or [ ];
nativeBuildInputs = [ postgresql ] ++ prevAttrs.nativeBuildInputs or [ ];
nativeBuildInputs = [ postgresql.pg_config ] ++ prevAttrs.nativeBuildInputs or [ ];

installFlags = [
"DESTDIR=${placeholder "out"}"
Expand Down
2 changes: 2 additions & 0 deletions pkgs/servers/sql/postgresql/ext/postgis.nix
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ buildPostgresqlExtension (finalAttrs: {
dontDisableStatic = true;

nativeCheckInputs = [
postgresql
postgresqlTestHook
cunit
libxslt
Expand All @@ -90,6 +91,7 @@ buildPostgresqlExtension (finalAttrs: {
'';

configureFlags = [
"--with-pgconfig=${postgresql.pg_config}/bin/pg_config"
"--with-gdalconfig=${gdal}/bin/gdal-config"
"--with-jsondir=${json_c.dev}"
"--disable-extension-upgrades-install"
Expand Down
17 changes: 7 additions & 10 deletions pkgs/servers/sql/postgresql/generic.nix
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ let

# passthru
buildEnv,
buildPackages,
newScope,
nixosTests,
postgresqlTestHook,
Expand Down Expand Up @@ -125,8 +126,6 @@ let
)
else
stdenv;

pg_config = writeShellScriptBin "pg_config" (builtins.readFile ./pg_config.sh);
in
stdenv'.mkDerivation (finalAttrs: {
inherit version;
Expand Down Expand Up @@ -323,21 +322,17 @@ let

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
cat ${./pg_config.env.mk} >> src/common/Makefile
'';

postInstall =
''
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"
rm "$out/bin/pg_config"
make -C src/common pg_config.env
install -D src/common/pg_config.env "$dev/nix-support/pg_config.env"
# postgres exposes external symbols get_pkginclude_path and similar. Those
# can't be stripped away by --gc-sections/LTO, because they could theoretically
Expand Down Expand Up @@ -466,6 +461,8 @@ let
postgresql = this;
};

pg_config = buildPackages.callPackage ./pg_config.nix { inherit (finalAttrs) finalPackage; };
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should make it work nicely for cross-compilation, @rhelmot. I tried a very simple extension in nix-build -A pkgsCross.x86_64-freebsd.postgresql.pkgs.pgtap, which built fine. It's a SQL-only extension, which essentially only depends on pg_config, so builds fine without your follow ups.

(had to cherry pick the --with-uuid=bsd change, ofc)

Currently, this extension fails to build on master, because pg_config can't be executed.


tests =
{
postgresql = nixosTests.postgresql.postgresql.passthru.override finalAttrs.finalPackage;
Expand Down
14 changes: 11 additions & 3 deletions pkgs/servers/sql/postgresql/libpq.nix
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

# passthru / meta
postgresql,
buildPackages,

# GSSAPI
gssSupport ? with stdenv.hostPlatform; !isWindows && !isStatic,
Expand Down Expand Up @@ -105,16 +106,19 @@ stdenv.mkDerivation (finalAttrs: {
./patches/socketdir-in-run-13+.patch
];

postPatch = ''
cat ${./pg_config.env.mk} >> src/common/Makefile
'';

installPhase = ''
runHook preInstall
make -C src/bin/pg_config install
make -C src/common install
make -C src/common install pg_config.env
make -C src/include install
make -C src/interfaces/libpq install
make -C src/port install
moveToOutput bin/pg_config "$dev"
install -D src/common/pg_config.env "$dev/nix-support/pg_config.env"
moveToOutput "lib/*.a" "$dev"
rm -rfv $out/share
Expand All @@ -135,6 +139,10 @@ stdenv.mkDerivation (finalAttrs: {

doCheck = false;

passthru.pg_config = buildPackages.callPackage ./pg_config.nix {
inherit (finalAttrs) finalPackage;
};

meta = {
inherit (postgresql.meta)
homepage
Expand Down
13 changes: 13 additions & 0 deletions pkgs/servers/sql/postgresql/pg_config.env.mk
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Everything that pg_config normally returns is put into pg_config.env, so
# that we can read it from our own pg_config script later on.
pg_config.env: $(top_builddir)/src/port/pg_config_paths.h | $(top_builddir)/src/include/pg_config.h
echo "CC=\"$(CC)\"" >$@
echo "CPPFLAGS=\"$(STD_CPPFLAGS)\"" >>$@
echo "CFLAGS=\"$(CFLAGS)\"" >>$@
echo "CFLAGS_SL=\"$(CFLAGS_SL)\"" >>$@
echo "LDFLAGS=\"$(STD_LDFLAGS)\"" >>$@
echo "LDFLAGS_EX=\"$(LDFLAGS_EX)\"" >>$@
echo "LDFLAGS_SL=\"$(LDFLAGS_SL)\"" >>$@
echo "LIBS=\"$(LIBS)\"" >>$@
cat $(top_builddir)/src/port/pg_config_paths.h $(top_builddir)/src/include/pg_config.h \
| sed -nE 's/^#define ([^ ]+) ("?)(.*)\2$$/\1="\3"/p' >>$@
18 changes: 18 additions & 0 deletions pkgs/servers/sql/postgresql/pg_config.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
lib,
replaceVarsWith,
runtimeShell,
# PostgreSQL package
finalPackage,
}:

replaceVarsWith {
name = "pg_config";
src = ./pg_config.sh;
dir = "bin";
isExecutable = true;
replacements = {
inherit runtimeShell;
postgresql-dev = lib.getDev finalPackage;
};
}
151 changes: 118 additions & 33 deletions pkgs/servers/sql/postgresql/pg_config.sh
Original file line number Diff line number Diff line change
@@ -1,37 +1,122 @@
#!@runtimeShell@
set -euo pipefail

# 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
# This replacement script for the pg_config binary is based on the original pg_config
# shell script, which was removed from PostgreSQL's codebase in 2004:
# https://github.com/postgres/postgres/commit/cc07f8cfe73f56fce1ddda4ea25d7b0b6c4f0ae9
#
# The main reason for removal was the ability to relocate an existing installation, which
# is exactly the one feature that we are trying to work around in nixpkgs.
# Going back to a shell script is much better for cross compiling.
#
# This file is a combination of the following two files:
# https://github.com/postgres/postgres/blob/7510ac6203bc8e3c56eae95466feaeebfc1b4f31/src/bin/pg_config/pg_config.sh
# https://github.com/postgres/postgres/blob/master/src/bin/pg_config/pg_config.c

source @postgresql-dev@/nix-support/pg_config.env

help="
pg_config provides information about the installed version of PostgreSQL.
Usage:
pg_config [OPTION]...
Options:
--bindir show location of user executables
--docdir show location of documentation files
--htmldir show location of HTML documentation files
--includedir show location of C header files of the client
interfaces
--pkgincludedir show location of other C header files
--includedir-server show location of C header files for the server
--libdir show location of object code libraries
--pkglibdir show location of dynamically loadable modules
--localedir show location of locale support files
--mandir show location of manual pages
--sharedir show location of architecture-independent support files
--sysconfdir show location of system-wide configuration files
--pgxs show location of extension makefile
--configure show options given to \"configure\" script when
PostgreSQL was built
--cc show CC value used when PostgreSQL was built
--cppflags show CPPFLAGS value used when PostgreSQL was built
--cflags show CFLAGS value used when PostgreSQL was built
--cflags_sl show CFLAGS_SL value used when PostgreSQL was built
--ldflags show LDFLAGS value used when PostgreSQL was built
--ldflags_ex show LDFLAGS_EX value used when PostgreSQL was built
--ldflags_sl show LDFLAGS_SL value used when PostgreSQL was built
--libs show LIBS value used when PostgreSQL was built
--version show the PostgreSQL version
-?, --help show this help, then exit
With no arguments, all known items are shown.
Report bugs to <${PACKAGE_BUGREPORT}>.
${PACKAGE_NAME} home page: <${PACKAGE_URL}>"

show=()

for opt; do
case "$opt" in
--bindir) show+=("$PGBINDIR") ;;
--docdir) show+=("$DOCDIR") ;;
--htmldir) show+=("$HTMLDIR") ;;
--includedir) show+=("$INCLUDEDIR") ;;
--pkgincludedir) show+=("$PKGINCLUDEDIR") ;;
--includedir-server) show+=("$INCLUDEDIRSERVER") ;;
--libdir) show+=("$LIBDIR") ;;
--pkglibdir) show+=("$PKGLIBDIR") ;;
--localedir) show+=("$LOCALEDIR") ;;
--mandir) show+=("$MANDIR") ;;
--sharedir) show+=("$PGSHAREDIR") ;;
--sysconfdir) show+=("$SYSCONFDIR") ;;
--pgxs) show+=("@postgresql-dev@/lib/pgxs/src/makefiles/pgxs.mk") ;;
--configure) show+=("$CONFIGURE_ARGS") ;;
--cc) show+=("$CC") ;;
--cppflags) show+=("$CPPFLAGS") ;;
--cflags) show+=("$CFLAGS") ;;
--cflags_sl) show+=("$CFLAGS_SL") ;;
--ldflags) show+=("$LDFLAGS") ;;
--ldflags_ex) show+=("$LDFLAGS_EX") ;;
--ldflags_sl) show+=("$LDFLAGS_SL") ;;
--libs) show+=("$LIBS") ;;
--version) show+=("PostgreSQL $PG_VERSION") ;;
--help|-\?) echo "$help"
exit 0 ;;
*) >&2 echo "pg_config: invalid argument: $opt"
>&2 echo "Try \"pg_config --help\" for more information."
exit 1 ;;
esac
done

if [ ${#show[@]} -gt 0 ]; then
printf '%s\n' "${show[@]}"
exit 0
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
# no arguments -> print everything
cat <<EOF
BINDIR = $PGBINDIR
DOCDIR = $DOCDIR
HTMLDIR = $HTMLDIR
INCLUDEDIR = $INCLUDEDIR
PKGINCLUDEDIR = $PKGINCLUDEDIR
INCLUDEDIR-SERVER = $INCLUDEDIRSERVER
LIBDIR = $LIBDIR
PKGLIBDIR = $PKGLIBDIR
LOCALEDIR = $LOCALEDIR
MANDIR = $MANDIR
SHAREDIR = $PGSHAREDIR
SYSCONFDIR = $SYSCONFDIR
PGXS = @postgresql-dev@/lib/pgxs/src/makefiles/pgxs.mk
CONFIGURE = $CONFIGURE_ARGS
CC = $CC
CPPFLAGS = $CPPFLAGS
CFLAGS = $CFLAGS
CFLAGS_SL = $CFLAGS_SL
LDFLAGS = $LDFLAGS
LDFLAGS_EX = $LDFLAGS_EX
LDFLAGS_SL = $LDFLAGS_SL
LIBS = $LIBS
VERSION = PostgreSQL $PG_VERSION
EOF