at master 6.4 kB view raw
1# PostgreSQL's build system for extensions (PGXS) makes the following assumptions: 2# - All extensions will be installed in the same prefix as PostgreSQL itself. 3# - pg_config is able to return the correct paths for bindir/libdir/datadir etc. 4# 5# Both of those assumptions break with nix. Since each extension is a separate 6# derivation, we need to put all its files into a different folder. At the same 7# time, pg_config only points to the PostgreSQL derivation's paths. 8# 9# When building extensions, the paths provided by pg_config are used for two 10# purposes: 11# - To find postgres libs and headers and reference those paths via -L and -I flags. 12# - To determine the correct install directory. 13# 14# The PGXS Makefiles also support an environment variable DESTDIR, which is added as 15# a prefix to all install locations. This is primarily used for temporary installs 16# while running the test suite. Since pg_config returns absolute paths to /nix/store 17# for us, using DESTDIR will result in install locations of the form: 18# $DESTIDR/nix/store/<postgresql-output>/... 19# 20# In multiple iterations, the following approaches have been tried to work around all 21# of this: 22# 1. For a long time, all extensions in nixpkgs just overwrote the installPhase 23# and moved the respective files to the correct location manually. This approach 24# is not maintainable, because whenever upstream adds a new file, we'd have to 25# make sure the file is correctly installed as well. Additionally, it makes adding 26# a new extension harder than it should be. 27# 28# 2. A wrapper around pg_config could just replace the returned paths with paths to 29# $out of currently building derivation, i.e. the extension. This works for install- 30# ation, but breaks for any of the libs and headers the extension needs from postgres 31# itself. 32# 33# 3. A variation of 2., but make the pg_config wrapper only return the changed paths 34# during the installPahse. During configure and build, it would return the regular 35# paths to the PostgreSQL derivation. This works better, but not for every case. 36# Some extensions try to be smarter and search for the "postgres" binary to deduce 37# the necessary paths from that. Those would still need special handling. 38# 39# 4. Use the fact that DESTDIR is prepended to every installation directory - and only 40# there, to run a replacement of all Makefiles in postgres' lib/pgxs/ folder and 41# all Makefiles in the extension's source. "$DESTDIR/$bindir" can be replaced with 42# "$out/bin" etc. - thus mapping the installPhase directly into the right output. 43# This works beautifully - for the majority of cases. But it doesn't work for 44# some extensions that use CMake. And it doesn't work for some extensions that use 45# custom variables instead of the default "bindir" and friends. 46# 47# 5. Just set DESTDIR to the extensions's output and then clean up afterward. This will 48# result in paths like this: 49# /nix/store/<extension-output>/nix/store/<postgresql-output>/... 50# Directly after the installPhase, we'll move the files in the right folder. 51# This seems to work consistently across all extensions we have in nixpkgs right now. 52# Of course, it would break down for any extension that doesn't support DESTDIR - 53# but that just means PGXS is not used either, so that's OK. 54# 55# This last approach is the one we're taking in this file. To make sure the removal of the 56# nested nix/store happens immediately after the installPhase, before any other postInstall 57# hooks run, this needs to be run in an override of `mkDerivation` and not in a setup hook. 58 59{ 60 lib, 61 stdenv, 62 postgresql, 63 nix-update-script, 64}: 65 66lib.extendMkDerivation { 67 constructDrv = stdenv.mkDerivation; 68 69 excludeDrvArgNames = [ 70 "enableUpdateScript" 71 ]; 72 73 extendDrvArgs = 74 finalAttrs: 75 { 76 enableUpdateScript ? true, 77 ... 78 }@prevAttrs: 79 { 80 passthru = 81 prevAttrs.passthru or { } 82 // lib.optionalAttrs enableUpdateScript { 83 updateScript = 84 prevAttrs.passthru.updateScript or (nix-update-script ( 85 lib.optionalAttrs (lib.hasInfix "unstable" prevAttrs.version) { 86 extraArgs = [ "--version=branch" ]; 87 } 88 )); 89 }; 90 91 strictDeps = true; 92 buildInputs = [ postgresql ] ++ prevAttrs.buildInputs or [ ]; 93 nativeBuildInputs = [ postgresql.pg_config ] ++ prevAttrs.nativeBuildInputs or [ ]; 94 95 installFlags = [ 96 "DESTDIR=${placeholder "out"}" 97 ] 98 ++ prevAttrs.installFlags or [ ]; 99 100 postInstall = '' 101 # DESTDIR + pg_config install the files into 102 # /nix/store/<extension>/nix/store/<postgresql>/... 103 # We'll now remove the /nix/store/<postgresql> part: 104 if [[ -d "$out${postgresql}" ]]; then 105 cp -alt "$out" "$out${postgresql}"/* 106 rm -r "$out${postgresql}" 107 fi 108 109 if [[ -d "$out${postgresql.dev}" ]]; then 110 mkdir -p "''${dev:-$out}" 111 cp -alt "''${dev:-$out}" "$out${postgresql.dev}"/* 112 rm -r "$out${postgresql.dev}" 113 fi 114 115 if [[ -d "$out${postgresql.lib}" ]]; then 116 mkdir -p "''${lib:-$out}" 117 cp -alt "''${lib:-$out}" "$out${postgresql.lib}"/* 118 rm -r "$out${postgresql.lib}" 119 fi 120 121 if [[ -d "$out${postgresql.doc}" ]]; then 122 mkdir -p "''${doc:-$out}" 123 cp -alt "''${doc:-$out}" "$out${postgresql.doc}"/* 124 rm -r "$out${postgresql.doc}" 125 fi 126 127 if [[ -d "$out${postgresql.man}" ]]; then 128 mkdir -p "''${man:-$out}" 129 cp -alt "''${man:-$out}" "$out${postgresql.man}"/* 130 rm -r "$out${postgresql.man}" 131 fi 132 133 # In some cases (postgis) parts of the install script 134 # actually work "OK", before we add DESTDIR, so some 135 # files end up in 136 # /nix/store/<extension>/nix/store/<extension>/... 137 if [[ -d "$out$out" ]]; then 138 cp -alt "$out" "$out$out"/* 139 rm -r "$out$out" 140 fi 141 142 if [[ -d "$out/nix/store" ]]; then 143 if ! rmdir "$out/nix/store" "$out/nix"; then 144 find "$out/nix" 145 nixErrorLog 'Found left-overs in $out/nix/store, make sure to move them into $out properly.' 146 exit 1 147 fi 148 fi 149 '' 150 + prevAttrs.postInstall or ""; 151 }; 152}