1let
2
3 generic =
4 # dependencies
5 { stdenv, lib, fetchurl, fetchpatch, makeWrapper
6 , glibc, zlib, readline, openssl, icu, lz4, zstd, systemd, libossp_uuid
7 , pkg-config, libxml2, tzdata, libkrb5, substituteAll, darwin
8 , linux-pam
9
10 # This is important to obtain a version of `libpq` that does not depend on systemd.
11 , systemdSupport ? lib.meta.availableOn stdenv.hostPlatform systemd && !stdenv.hostPlatform.isStatic
12 , enableSystemd ? null
13 , gssSupport ? with stdenv.hostPlatform; !isWindows && !isStatic
14
15 # for postgresql.pkgs
16 , self, newScope, buildEnv
17
18 # source specification
19 , version, hash, muslPatches ? {}
20
21 # for tests
22 , testers, nixosTests
23
24 # JIT
25 , jitSupport
26 , nukeReferences, patchelf, llvmPackages
27
28 # PL/Python
29 , pythonSupport ? false
30 , python3
31
32 # detection of crypt fails when using llvm stdenv, so we add it manually
33 # for <13 (where it got removed: https://github.com/postgres/postgres/commit/c45643d618e35ec2fe91438df15abd4f3c0d85ca)
34 , libxcrypt
35 } @args:
36 let
37 atLeast = lib.versionAtLeast version;
38 olderThan = lib.versionOlder version;
39 lz4Enabled = atLeast "14";
40 zstdEnabled = atLeast "15";
41
42 systemdSupport' = if enableSystemd == null then systemdSupport else (lib.warn "postgresql: argument enableSystemd is deprecated, please use systemdSupport instead." enableSystemd);
43
44 pname = "postgresql";
45
46 stdenv' = if jitSupport then llvmPackages.stdenv else stdenv;
47 in stdenv'.mkDerivation (finalAttrs: {
48 inherit version;
49 pname = pname + lib.optionalString jitSupport "-jit";
50
51 src = fetchurl {
52 url = "mirror://postgresql/source/v${version}/${pname}-${version}.tar.bz2";
53 inherit hash;
54 };
55
56 hardeningEnable = lib.optionals (!stdenv'.cc.isClang) [ "pie" ];
57
58 outputs = [ "out" "lib" "doc" "man" ];
59 setOutputFlags = false; # $out retains configureFlags :-/
60
61 buildInputs = [
62 zlib
63 readline
64 openssl
65 libxml2
66 icu
67 ]
68 ++ lib.optionals (olderThan "13") [ libxcrypt ]
69 ++ lib.optionals jitSupport [ llvmPackages.llvm ]
70 ++ lib.optionals lz4Enabled [ lz4 ]
71 ++ lib.optionals zstdEnabled [ zstd ]
72 ++ lib.optionals systemdSupport' [ systemd ]
73 ++ lib.optionals pythonSupport [ python3 ]
74 ++ lib.optionals gssSupport [ libkrb5 ]
75 ++ lib.optionals stdenv'.isLinux [ linux-pam ]
76 ++ lib.optionals (!stdenv'.isDarwin) [ libossp_uuid ];
77
78 nativeBuildInputs = [
79 makeWrapper
80 pkg-config
81 ]
82 ++ lib.optionals jitSupport [ llvmPackages.llvm.dev nukeReferences patchelf ];
83
84 enableParallelBuilding = true;
85
86 separateDebugInfo = true;
87
88 buildFlags = [ "world" ];
89
90 # Makes cross-compiling work when xml2-config can't be executed on the host.
91 # Fixed upstream in https://github.com/postgres/postgres/commit/0bc8cebdb889368abdf224aeac8bc197fe4c9ae6
92 env.NIX_CFLAGS_COMPILE = lib.optionalString (olderThan "13") "-I${libxml2.dev}/include/libxml2";
93
94 configureFlags = [
95 "--with-openssl"
96 "--with-libxml"
97 "--with-icu"
98 "--sysconfdir=/etc"
99 "--libdir=$(lib)/lib"
100 "--with-system-tzdata=${tzdata}/share/zoneinfo"
101 "--enable-debug"
102 (lib.optionalString systemdSupport' "--with-systemd")
103 (if stdenv'.isDarwin then "--with-uuid=e2fs" else "--with-ossp-uuid")
104 ] ++ lib.optionals lz4Enabled [ "--with-lz4" ]
105 ++ lib.optionals zstdEnabled [ "--with-zstd" ]
106 ++ lib.optionals gssSupport [ "--with-gssapi" ]
107 ++ lib.optionals pythonSupport [ "--with-python" ]
108 ++ lib.optionals jitSupport [ "--with-llvm" ]
109 ++ lib.optionals stdenv'.isLinux [ "--with-pam" ];
110
111 patches = [
112 (if atLeast "16" then ./patches/relative-to-symlinks-16+.patch else ./patches/relative-to-symlinks.patch)
113 ./patches/less-is-more.patch
114 ./patches/paths-for-split-outputs.patch
115 ./patches/specify_pkglibdir_at_runtime.patch
116 ./patches/paths-with-postgresql-suffix.patch
117
118 (substituteAll {
119 src = ./patches/locale-binary-path.patch;
120 locale = "${if stdenv.isDarwin then darwin.adv_cmds else lib.getBin stdenv.cc.libc}/bin/locale";
121 })
122
123 (
124 if atLeast "16" then
125 fetchpatch {
126 name = "libxml2-2.13-compat.patch";
127 # This one is for 16 branch upstream.
128 url = "https://github.com/postgres/postgres/commit/f85c91a1867b45742bb28e4578ca2b4a0976383f.diff";
129 hash = "sha256-4YcXfo98uVuCu+ybVw3bM4x8Y0I1xfjdjBZOlhyF21w=";
130 }
131 else
132 fetchpatch {
133 name = "libxml2-2.13-compat.patch";
134 # This one is for 15 branch upstream, but it also applies well to all our older branches.
135 url = "https://github.com/postgres/postgres/commit/f68d6aabb7e2c803818185b49a3d356bdb2b2974.diff";
136 hash = "sha256-Nelb0mbjx0Xq9UJuVv7cs3ifCtUPP7UZraPMPGb2wyQ=";
137 }
138 )
139 ] ++ lib.optionals stdenv'.hostPlatform.isMusl (
140 # Using fetchurl instead of fetchpatch on purpose: https://github.com/NixOS/nixpkgs/issues/240141
141 map fetchurl (lib.attrValues muslPatches)
142 ) ++ lib.optionals stdenv'.isLinux [
143 (if atLeast "13" then ./patches/socketdir-in-run-13+.patch else ./patches/socketdir-in-run.patch)
144 ];
145
146 installTargets = [ "install-world" ];
147
148 postPatch = ''
149 # Hardcode the path to pgxs so pg_config returns the path in $out
150 substituteInPlace "src/common/config_info.c" --subst-var out
151 '' + lib.optionalString jitSupport ''
152 # Force lookup of jit stuff in $out instead of $lib
153 substituteInPlace src/backend/jit/jit.c --replace pkglib_path \"$out/lib\"
154 substituteInPlace src/backend/jit/llvm/llvmjit.c --replace pkglib_path \"$out/lib\"
155 substituteInPlace src/backend/jit/llvm/llvmjit_inline.cpp --replace pkglib_path \"$out/lib\"
156 '';
157
158 postInstall =
159 ''
160 moveToOutput "lib/pgxs" "$out" # looks strange, but not deleting it
161 moveToOutput "lib/libpgcommon*.a" "$out"
162 moveToOutput "lib/libpgport*.a" "$out"
163 moveToOutput "lib/libecpg*" "$out"
164
165 # Prevent a retained dependency on gcc-wrapper.
166 substituteInPlace "$out/lib/pgxs/src/Makefile.global" --replace ${stdenv'.cc}/bin/ld ld
167
168 if [ -z "''${dontDisableStatic:-}" ]; then
169 # Remove static libraries in case dynamic are available.
170 for i in $out/lib/*.a $lib/lib/*.a; do
171 name="$(basename "$i")"
172 ext="${stdenv'.hostPlatform.extensions.sharedLibrary}"
173 if [ -e "$lib/lib/''${name%.a}$ext" ] || [ -e "''${i%.a}$ext" ]; then
174 rm "$i"
175 fi
176 done
177 fi
178 '' + lib.optionalString jitSupport ''
179 # Move the bitcode and libllvmjit.so library out of $lib; otherwise, every client that
180 # depends on libpq.so will also have libLLVM.so in its closure too, bloating it
181 moveToOutput "lib/bitcode" "$out"
182 moveToOutput "lib/llvmjit*" "$out"
183
184 # In the case of JIT support, prevent a retained dependency on clang-wrapper
185 substituteInPlace "$out/lib/pgxs/src/Makefile.global" --replace ${stdenv'.cc}/bin/clang clang
186 nuke-refs $out/lib/llvmjit_types.bc $(find $out/lib/bitcode -type f)
187
188 # Stop out depending on the default output of llvm
189 substituteInPlace $out/lib/pgxs/src/Makefile.global \
190 --replace ${llvmPackages.llvm.out}/bin "" \
191 --replace '$(LLVM_BINPATH)/' ""
192
193 # Stop out depending on the -dev output of llvm
194 substituteInPlace $out/lib/pgxs/src/Makefile.global \
195 --replace ${llvmPackages.llvm.dev}/bin/llvm-config llvm-config \
196 --replace -I${llvmPackages.llvm.dev}/include ""
197
198 ${lib.optionalString (!stdenv'.isDarwin) ''
199 # Stop lib depending on the -dev output of llvm
200 rpath=$(patchelf --print-rpath $out/lib/llvmjit.so)
201 nuke-refs -e $out $out/lib/llvmjit.so
202 # Restore the correct rpath
203 patchelf $out/lib/llvmjit.so --set-rpath "$rpath"
204 ''}
205 '';
206
207 postFixup = lib.optionalString (!stdenv'.isDarwin && stdenv'.hostPlatform.libc == "glibc")
208 ''
209 # initdb needs access to "locale" command from glibc.
210 wrapProgram $out/bin/initdb --prefix PATH ":" ${glibc.bin}/bin
211 '';
212
213 doCheck = !stdenv'.isDarwin;
214 # autodetection doesn't seem to able to find this, but it's there.
215 checkTarget = "check";
216
217 disallowedReferences = [ stdenv'.cc ];
218
219 passthru = let
220 this = self.callPackage generic args;
221 jitToggle = this.override {
222 jitSupport = !jitSupport;
223 };
224 in
225 {
226 psqlSchema = lib.versions.major version;
227
228 withJIT = if jitSupport then this else jitToggle;
229 withoutJIT = if jitSupport then jitToggle else this;
230
231 dlSuffix = if olderThan "16" then ".so" else stdenv.hostPlatform.extensions.sharedLibrary;
232
233 pkgs = let
234 scope = {
235 inherit jitSupport;
236 inherit (llvmPackages) llvm;
237 postgresql = this;
238 stdenv = stdenv';
239 };
240 newSelf = self // scope;
241 newSuper = { callPackage = newScope (scope // this.pkgs); };
242 in import ./ext newSelf newSuper;
243
244 withPackages = postgresqlWithPackages {
245 inherit makeWrapper buildEnv;
246 postgresql = this;
247 }
248 this.pkgs;
249
250 tests = {
251 postgresql-wal-receiver = import ../../../../nixos/tests/postgresql-wal-receiver.nix {
252 inherit (stdenv) system;
253 pkgs = self;
254 package = this;
255 };
256 pkg-config = testers.testMetaPkgConfig finalAttrs.finalPackage;
257 } // lib.optionalAttrs jitSupport {
258 postgresql-jit = import ../../../../nixos/tests/postgresql-jit.nix {
259 inherit (stdenv) system;
260 pkgs = self;
261 package = this;
262 };
263 };
264 };
265
266 meta = with lib; {
267 homepage = "https://www.postgresql.org";
268 description = "Powerful, open source object-relational database system";
269 license = licenses.postgresql;
270 changelog = "https://www.postgresql.org/docs/release/${finalAttrs.version}/";
271 maintainers = with maintainers; [ thoughtpolice danbst globin ivan ma27 wolfgangwalther ];
272 pkgConfigModules = [ "libecpg" "libecpg_compat" "libpgtypes" "libpq" ];
273 platforms = platforms.unix;
274
275 # JIT support doesn't work with cross-compilation. It is attempted to build LLVM-bytecode
276 # (`%.bc` is the corresponding `make(1)`-rule) for each sub-directory in `backend/` for
277 # the JIT apparently, but with a $(CLANG) that can produce binaries for the build, not the
278 # host-platform.
279 #
280 # I managed to get a cross-build with JIT support working with
281 # `depsBuildBuild = [ llvmPackages.clang ] ++ buildInputs`, but considering that the
282 # resulting LLVM IR isn't platform-independent this doesn't give you much.
283 # In fact, I tried to test the result in a VM-test, but as soon as JIT was used to optimize
284 # a query, postgres would coredump with `Illegal instruction`.
285 broken = (jitSupport && stdenv.hostPlatform != stdenv.buildPlatform)
286 # Allmost all tests fail FATAL errors for v12 and v13
287 || (jitSupport && stdenv.hostPlatform.isMusl && olderThan "14");
288 };
289 });
290
291 postgresqlWithPackages = { postgresql, makeWrapper, buildEnv }: pkgs: f: buildEnv {
292 name = "postgresql-and-plugins-${postgresql.version}";
293 paths = f pkgs ++ [
294 postgresql
295 postgresql.lib
296 postgresql.man # in case user installs this into environment
297 ];
298 nativeBuildInputs = [ makeWrapper ];
299
300
301 # We include /bin to ensure the $out/bin directory is created, which is
302 # needed because we'll be removing the files from that directory in postBuild
303 # below. See #22653
304 pathsToLink = ["/" "/bin"];
305
306 # Note: the duplication of executables is about 4MB size.
307 # So a nicer solution was patching postgresql to allow setting the
308 # libdir explicitly.
309 postBuild = ''
310 mkdir -p $out/bin
311 rm $out/bin/{pg_config,postgres,pg_ctl}
312 cp --target-directory=$out/bin ${postgresql}/bin/{postgres,pg_config,pg_ctl}
313 wrapProgram $out/bin/postgres --set NIX_PGLIBDIR $out/lib
314 '';
315
316 passthru.version = postgresql.version;
317 passthru.psqlSchema = postgresql.psqlSchema;
318 };
319
320in
321# passed by <major>.nix
322versionArgs:
323# passed by default.nix
324{ self, ... } @defaultArgs:
325self.callPackage generic (defaultArgs // versionArgs)