1let
2
3 generic =
4 # dependencies
5 { stdenv, lib, fetchurl, makeWrapper, fetchpatch
6 , glibc, zlib, readline, openssl, icu, lz4, zstd, systemd, libossp_uuid
7 , pkg-config, libxml2, tzdata, libkrb5, substituteAll, darwin
8
9 # This is important to obtain a version of `libpq` that does not depend on systemd.
10 , enableSystemd ? lib.meta.availableOn stdenv.hostPlatform systemd && !stdenv.hostPlatform.isStatic
11 , gssSupport ? with stdenv.hostPlatform; !isWindows && !isStatic
12
13 # for postgresql.pkgs
14 , this, self, newScope, buildEnv
15
16 # source specification
17 , version, hash, psqlSchema
18
19 # for tests
20 , nixosTests, thisAttr
21
22 # JIT
23 , jitSupport ? false
24 , nukeReferences, patchelf, llvmPackages
25 , makeRustPlatform, buildPgxExtension, cargo, rustc
26
27 # detection of crypt fails when using llvm stdenv, so we add it manually
28 # for <13 (where it got removed: https://github.com/postgres/postgres/commit/c45643d618e35ec2fe91438df15abd4f3c0d85ca)
29 , libxcrypt
30 }:
31 let
32 atLeast = lib.versionAtLeast version;
33 olderThan = lib.versionOlder version;
34 lz4Enabled = atLeast "14";
35 zstdEnabled = atLeast "15";
36
37 stdenv' = if jitSupport then llvmPackages.stdenv else stdenv;
38 in stdenv'.mkDerivation rec {
39 pname = "postgresql";
40 inherit version;
41
42 src = fetchurl {
43 url = "mirror://postgresql/source/v${version}/${pname}-${version}.tar.bz2";
44 inherit hash;
45 };
46
47 hardeningEnable = lib.optionals (!stdenv'.cc.isClang) [ "pie" ];
48
49 outputs = [ "out" "lib" "doc" "man" ];
50 setOutputFlags = false; # $out retains configureFlags :-/
51
52 buildInputs = [
53 zlib
54 readline
55 openssl
56 libxml2
57 icu
58 ]
59 ++ lib.optionals (olderThan "13") [ libxcrypt ]
60 ++ lib.optionals jitSupport [ llvmPackages.llvm ]
61 ++ lib.optionals lz4Enabled [ lz4 ]
62 ++ lib.optionals zstdEnabled [ zstd ]
63 ++ lib.optionals enableSystemd [ systemd ]
64 ++ lib.optionals gssSupport [ libkrb5 ]
65 ++ lib.optionals (!stdenv'.isDarwin) [ libossp_uuid ];
66
67 nativeBuildInputs = [
68 makeWrapper
69 pkg-config
70 ]
71 ++ lib.optionals jitSupport [ llvmPackages.llvm.dev nukeReferences patchelf ];
72
73 enableParallelBuilding = !stdenv'.isDarwin;
74
75 separateDebugInfo = true;
76
77 buildFlags = [ "world" ];
78
79 env.NIX_CFLAGS_COMPILE = "-I${libxml2.dev}/include/libxml2";
80
81 # Otherwise it retains a reference to compiler and fails; see #44767. TODO: better.
82 preConfigure = "CC=${stdenv'.cc.targetPrefix}cc";
83
84 configureFlags = [
85 "--with-openssl"
86 "--with-libxml"
87 "--with-icu"
88 "--sysconfdir=/etc"
89 "--libdir=$(lib)/lib"
90 "--with-system-tzdata=${tzdata}/share/zoneinfo"
91 "--enable-debug"
92 (lib.optionalString enableSystemd "--with-systemd")
93 (if stdenv'.isDarwin then "--with-uuid=e2fs" else "--with-ossp-uuid")
94 ] ++ lib.optionals lz4Enabled [ "--with-lz4" ]
95 ++ lib.optionals zstdEnabled [ "--with-zstd" ]
96 ++ lib.optionals gssSupport [ "--with-gssapi" ]
97 ++ lib.optionals stdenv'.hostPlatform.isRiscV [ "--disable-spinlocks" ]
98 ++ lib.optionals jitSupport [ "--with-llvm" ];
99
100 patches = [
101 (if atLeast "16" then ./patches/disable-normalize_exec_path.patch
102 else ./patches/disable-resolve_symlinks.patch)
103 ./patches/less-is-more.patch
104 ./patches/hardcode-pgxs-path.patch
105 ./patches/specify_pkglibdir_at_runtime.patch
106 ./patches/findstring.patch
107
108 (substituteAll {
109 src = ./locale-binary-path.patch;
110 locale = "${if stdenv.isDarwin then darwin.adv_cmds else lib.getBin stdenv.cc.libc}/bin/locale";
111 })
112
113 ] ++ lib.optionals (stdenv'.hostPlatform.isMusl && atLeast "12") [
114 (fetchpatch {
115 url = "https://git.alpinelinux.org/aports/plain/main/postgresql14/icu-collations-hack.patch?id=56999e6d0265ceff5c5239f85fdd33e146f06cb7";
116 hash = "sha256-Yb6lMBDqeVP/BLMyIr5rmR6OkaVzo68cV/+cL2LOe/M=";
117 })
118 ] ++ lib.optionals (stdenv'.hostPlatform.isMusl && atLeast "13") [
119 (if olderThan "14" then
120 fetchpatch {
121 url = "https://git.alpinelinux.org/aports/plain/main/postgresql13/disable-test-collate.icu.utf8.patch?id=69faa146ec9fff3b981511068f17f9e629d4688b";
122 hash = "sha256-IOOx7/laDYhTz1Q1r6H1FSZBsHCgD4lHvia+/os7CCo=";
123 }
124 else
125 fetchpatch {
126 url = "https://git.alpinelinux.org/aports/plain/main/postgresql14/disable-test-collate.icu.utf8.patch?id=56999e6d0265ceff5c5239f85fdd33e146f06cb7";
127 hash = "sha256-pnl+wM3/IUyq5iJzk+h278MDA9R0GQXQX8d4wJcB2z4=";
128 })
129 ] ++ lib.optionals stdenv'.isLinux [
130 (if atLeast "13" then ./patches/socketdir-in-run-13.patch else ./patches/socketdir-in-run.patch)
131 ];
132
133 installTargets = [ "install-world" ];
134
135 LC_ALL = "C";
136
137 postPatch = ''
138 # Hardcode the path to pgxs so pg_config returns the path in $out
139 substituteInPlace "src/common/config_info.c" --replace HARDCODED_PGXS_PATH "$out/lib"
140 '' + lib.optionalString jitSupport ''
141 # Force lookup of jit stuff in $out instead of $lib
142 substituteInPlace src/backend/jit/jit.c --replace pkglib_path \"$out/lib\"
143 substituteInPlace src/backend/jit/llvm/llvmjit.c --replace pkglib_path \"$out/lib\"
144 substituteInPlace src/backend/jit/llvm/llvmjit_inline.cpp --replace pkglib_path \"$out/lib\"
145 '';
146
147 postInstall =
148 ''
149 moveToOutput "lib/pgxs" "$out" # looks strange, but not deleting it
150 moveToOutput "lib/libpgcommon*.a" "$out"
151 moveToOutput "lib/libpgport*.a" "$out"
152 moveToOutput "lib/libecpg*" "$out"
153
154 # Prevent a retained dependency on gcc-wrapper.
155 substituteInPlace "$out/lib/pgxs/src/Makefile.global" --replace ${stdenv'.cc}/bin/ld ld
156
157 if [ -z "''${dontDisableStatic:-}" ]; then
158 # Remove static libraries in case dynamic are available.
159 for i in $out/lib/*.a $lib/lib/*.a; do
160 name="$(basename "$i")"
161 ext="${stdenv'.hostPlatform.extensions.sharedLibrary}"
162 if [ -e "$lib/lib/''${name%.a}$ext" ] || [ -e "''${i%.a}$ext" ]; then
163 rm "$i"
164 fi
165 done
166 fi
167 '' + lib.optionalString jitSupport ''
168 # Move the bitcode and libllvmjit.so library out of $lib; otherwise, every client that
169 # depends on libpq.so will also have libLLVM.so in its closure too, bloating it
170 moveToOutput "lib/bitcode" "$out"
171 moveToOutput "lib/llvmjit*" "$out"
172
173 # In the case of JIT support, prevent a retained dependency on clang-wrapper
174 substituteInPlace "$out/lib/pgxs/src/Makefile.global" --replace ${self.llvmPackages.stdenv.cc}/bin/clang clang
175 nuke-refs $out/lib/llvmjit_types.bc $(find $out/lib/bitcode -type f)
176
177 # Stop out depending on the default output of llvm
178 substituteInPlace $out/lib/pgxs/src/Makefile.global \
179 --replace ${self.llvmPackages.llvm.out}/bin "" \
180 --replace '$(LLVM_BINPATH)/' ""
181
182 # Stop out depending on the -dev output of llvm
183 substituteInPlace $out/lib/pgxs/src/Makefile.global \
184 --replace ${self.llvmPackages.llvm.dev}/bin/llvm-config llvm-config \
185 --replace -I${self.llvmPackages.llvm.dev}/include ""
186
187 ${lib.optionalString (!stdenv'.isDarwin) ''
188 # Stop lib depending on the -dev output of llvm
189 rpath=$(patchelf --print-rpath $out/lib/llvmjit.so)
190 nuke-refs -e $out $out/lib/llvmjit.so
191 # Restore the correct rpath
192 patchelf $out/lib/llvmjit.so --set-rpath "$rpath"
193 ''}
194 '';
195
196 postFixup = lib.optionalString (!stdenv'.isDarwin && stdenv'.hostPlatform.libc == "glibc")
197 ''
198 # initdb needs access to "locale" command from glibc.
199 wrapProgram $out/bin/initdb --prefix PATH ":" ${glibc.bin}/bin
200 '';
201
202 doCheck = !stdenv'.isDarwin;
203 # autodetection doesn't seem to able to find this, but it's there.
204 checkTarget = "check";
205
206 preCheck =
207 # On musl, comment skip the following tests, because they break due to
208 # ! ERROR: could not load library "/build/postgresql-11.5/tmp_install/nix/store/...-postgresql-11.5-lib/lib/libpqwalreceiver.so": Error loading shared library libpq.so.5: No such file or directory (needed by /build/postgresql-11.5/tmp_install/nix/store/...-postgresql-11.5-lib/lib/libpqwalreceiver.so)
209 # See also here:
210 # https://git.alpinelinux.org/aports/tree/main/postgresql/disable-broken-tests.patch?id=6d7d32c12e073a57a9e5946e55f4c1fbb68bd442
211 if stdenv'.hostPlatform.isMusl then ''
212 substituteInPlace src/test/regress/parallel_schedule \
213 --replace "subscription" "" \
214 --replace "object_address" ""
215 '' else null;
216
217 doInstallCheck = false; # needs a running daemon?
218
219 disallowedReferences = [ stdenv'.cc ];
220
221 passthru = let
222 jitToggle = this.override {
223 jitSupport = !jitSupport;
224 this = jitToggle;
225 };
226 in
227 {
228 inherit readline psqlSchema jitSupport;
229
230 withJIT = if jitSupport then this else jitToggle;
231 withoutJIT = if jitSupport then jitToggle else this;
232
233 pkgs = let
234 scope = {
235 postgresql = this;
236 stdenv = stdenv';
237 buildPgxExtension = buildPgxExtension.override {
238 stdenv = stdenv';
239 rustPlatform = makeRustPlatform {
240 stdenv = stdenv';
241 inherit rustc cargo;
242 };
243 };
244 };
245 newSelf = self // scope;
246 newSuper = { callPackage = newScope (scope // this.pkgs); };
247 in import ./packages.nix newSelf newSuper;
248
249 withPackages = postgresqlWithPackages {
250 inherit makeWrapper buildEnv;
251 postgresql = this;
252 }
253 this.pkgs;
254
255 tests = {
256 postgresql = nixosTests.postgresql-wal-receiver.${thisAttr};
257 } // lib.optionalAttrs jitSupport {
258 postgresql-jit = nixosTests.postgresql-jit.${thisAttr};
259 };
260 } // lib.optionalAttrs jitSupport {
261 inherit (llvmPackages) llvm;
262 };
263
264 meta = with lib; {
265 homepage = "https://www.postgresql.org";
266 description = "A powerful, open source object-relational database system";
267 license = licenses.postgresql;
268 maintainers = with maintainers; [ thoughtpolice danbst globin marsam ivan ma27 ];
269 platforms = platforms.unix;
270
271 # JIT support doesn't work with cross-compilation. It is attempted to build LLVM-bytecode
272 # (`%.bc` is the corresponding `make(1)`-rule) for each sub-directory in `backend/` for
273 # the JIT apparently, but with a $(CLANG) that can produce binaries for the build, not the
274 # host-platform.
275 #
276 # I managed to get a cross-build with JIT support working with
277 # `depsBuildBuild = [ llvmPackages.clang ] ++ buildInputs`, but considering that the
278 # resulting LLVM IR isn't platform-independent this doesn't give you much.
279 # In fact, I tried to test the result in a VM-test, but as soon as JIT was used to optimize
280 # a query, postgres would coredump with `Illegal instruction`.
281 broken = jitSupport && (stdenv.hostPlatform != stdenv.buildPlatform);
282 };
283 };
284
285 postgresqlWithPackages = { postgresql, makeWrapper, buildEnv }: pkgs: f: buildEnv {
286 name = "postgresql-and-plugins-${postgresql.version}";
287 paths = f pkgs ++ [
288 postgresql
289 postgresql.lib
290 postgresql.man # in case user installs this into environment
291 ];
292 nativeBuildInputs = [ makeWrapper ];
293
294
295 # We include /bin to ensure the $out/bin directory is created, which is
296 # needed because we'll be removing the files from that directory in postBuild
297 # below. See #22653
298 pathsToLink = ["/" "/bin"];
299
300 # Note: the duplication of executables is about 4MB size.
301 # So a nicer solution was patching postgresql to allow setting the
302 # libdir explicitly.
303 postBuild = ''
304 mkdir -p $out/bin
305 rm $out/bin/{pg_config,postgres,pg_ctl}
306 cp --target-directory=$out/bin ${postgresql}/bin/{postgres,pg_config,pg_ctl}
307 wrapProgram $out/bin/postgres --set NIX_PGLIBDIR $out/lib
308 '';
309
310 passthru.version = postgresql.version;
311 passthru.psqlSchema = postgresql.psqlSchema;
312 };
313
314 mkPackages = self: {
315 # TODO: remove ahead of 23.11 branchoff
316 # "PostgreSQL 11 will stop receiving fixes on November 9, 2023"
317 postgresql_11 = self.callPackage generic {
318 version = "11.21";
319 psqlSchema = "11.1"; # should be 11, but changing it is invasive
320 hash = "sha256-B7CDdHHV3XeyUWazRxjzuhCBa2rWHmkeb8VHzz/P+FA=";
321 this = self.postgresql_11;
322 thisAttr = "postgresql_11";
323 inherit self;
324 };
325
326 postgresql_12 = self.callPackage generic {
327 version = "12.16";
328 psqlSchema = "12";
329 hash = "sha256-xfH/96D5Ph7DdGQXsFlCkOzmF7SZXtlbjVJ68LoOOPM=";
330 this = self.postgresql_12;
331 thisAttr = "postgresql_12";
332 inherit self;
333 };
334
335 postgresql_13 = self.callPackage generic {
336 version = "13.12";
337 psqlSchema = "13";
338 hash = "sha256-DaHtzuNRS3vHum268MAEmeisFZBmjoeJxQJTpiSfIYs=";
339 this = self.postgresql_13;
340 thisAttr = "postgresql_13";
341 inherit self;
342 };
343
344 postgresql_14 = self.callPackage generic {
345 version = "14.9";
346 psqlSchema = "14";
347 hash = "sha256-sf47qbGn86ljfdFlbf2tKIkBYHP9TTXxO1AUPLu2qO8=";
348 this = self.postgresql_14;
349 thisAttr = "postgresql_14";
350 inherit self;
351 };
352
353 postgresql_15 = self.callPackage generic {
354 version = "15.4";
355 psqlSchema = "15";
356 hash = "sha256-uuxaS9xENzNmU7bLXZ7Ym+W9XAxYuU4L7O4KmZ5jyPk=";
357 this = self.postgresql_15;
358 thisAttr = "postgresql_15";
359 inherit self;
360 };
361
362 postgresql_16 = self.callPackage generic {
363 version = "16.0";
364 psqlSchema = "16";
365 hash = "sha256-356CPrIjMEROHUjlLMZRNaZSpv2zzjJePwhUkzn1G5k=";
366 this = self.postgresql_16;
367 thisAttr = "postgresql_16";
368 inherit self;
369 };
370 };
371
372in self:
373 let packages = mkPackages self; in
374 packages
375 // self.lib.mapAttrs'
376 (attrName: postgres: self.lib.nameValuePair "${attrName}_jit" (postgres.override rec {
377 jitSupport = true;
378 thisAttr = "${attrName}_jit";
379 this = self.${thisAttr};
380 }))
381 packages