1let
2
3 generic =
4 # dependencies
5 { stdenv, lib, fetchurl, makeWrapper
6 , glibc, zlib, readline, openssl, icu, lz4, zstd, systemd, libossp_uuid
7 , pkg-config, libxml2, tzdata, libkrb5
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 ./patches/disable-resolve_symlinks.patch
102 ./patches/less-is-more.patch
103 ./patches/hardcode-pgxs-path.patch
104 ./patches/specify_pkglibdir_at_runtime.patch
105 ./patches/findstring.patch
106 ] ++ lib.optionals stdenv'.isLinux [
107 (if atLeast "13" then ./patches/socketdir-in-run-13.patch else ./patches/socketdir-in-run.patch)
108 ];
109
110 installTargets = [ "install-world" ];
111
112 LC_ALL = "C";
113
114 postPatch = ''
115 # Hardcode the path to pgxs so pg_config returns the path in $out
116 substituteInPlace "src/common/config_info.c" --replace HARDCODED_PGXS_PATH "$out/lib"
117 '' + lib.optionalString jitSupport ''
118 # Force lookup of jit stuff in $out instead of $lib
119 substituteInPlace src/backend/jit/jit.c --replace pkglib_path \"$out/lib\"
120 substituteInPlace src/backend/jit/llvm/llvmjit.c --replace pkglib_path \"$out/lib\"
121 substituteInPlace src/backend/jit/llvm/llvmjit_inline.cpp --replace pkglib_path \"$out/lib\"
122 '';
123
124 postInstall =
125 ''
126 moveToOutput "lib/pgxs" "$out" # looks strange, but not deleting it
127 moveToOutput "lib/libpgcommon*.a" "$out"
128 moveToOutput "lib/libpgport*.a" "$out"
129 moveToOutput "lib/libecpg*" "$out"
130
131 # Prevent a retained dependency on gcc-wrapper.
132 substituteInPlace "$out/lib/pgxs/src/Makefile.global" --replace ${stdenv'.cc}/bin/ld ld
133
134 if [ -z "''${dontDisableStatic:-}" ]; then
135 # Remove static libraries in case dynamic are available.
136 for i in $out/lib/*.a $lib/lib/*.a; do
137 name="$(basename "$i")"
138 ext="${stdenv'.hostPlatform.extensions.sharedLibrary}"
139 if [ -e "$lib/lib/''${name%.a}$ext" ] || [ -e "''${i%.a}$ext" ]; then
140 rm "$i"
141 fi
142 done
143 fi
144 '' + lib.optionalString jitSupport ''
145 # Move the bitcode and libllvmjit.so library out of $lib; otherwise, every client that
146 # depends on libpq.so will also have libLLVM.so in its closure too, bloating it
147 moveToOutput "lib/bitcode" "$out"
148 moveToOutput "lib/llvmjit*" "$out"
149
150 # In the case of JIT support, prevent a retained dependency on clang-wrapper
151 substituteInPlace "$out/lib/pgxs/src/Makefile.global" --replace ${self.llvmPackages.stdenv.cc}/bin/clang clang
152 nuke-refs $out/lib/llvmjit_types.bc $(find $out/lib/bitcode -type f)
153
154 # Stop out depending on the default output of llvm
155 substituteInPlace $out/lib/pgxs/src/Makefile.global \
156 --replace ${self.llvmPackages.llvm.out}/bin "" \
157 --replace '$(LLVM_BINPATH)/' ""
158
159 # Stop out depending on the -dev output of llvm
160 substituteInPlace $out/lib/pgxs/src/Makefile.global \
161 --replace ${self.llvmPackages.llvm.dev}/bin/llvm-config llvm-config \
162 --replace -I${self.llvmPackages.llvm.dev}/include ""
163
164 ${lib.optionalString (!stdenv'.isDarwin) ''
165 # Stop lib depending on the -dev output of llvm
166 rpath=$(patchelf --print-rpath $out/lib/llvmjit.so)
167 nuke-refs -e $out $out/lib/llvmjit.so
168 # Restore the correct rpath
169 patchelf $out/lib/llvmjit.so --set-rpath "$rpath"
170 ''}
171 '';
172
173 postFixup = lib.optionalString (!stdenv'.isDarwin && stdenv'.hostPlatform.libc == "glibc")
174 ''
175 # initdb needs access to "locale" command from glibc.
176 wrapProgram $out/bin/initdb --prefix PATH ":" ${glibc.bin}/bin
177 '';
178
179 doCheck = !stdenv'.isDarwin;
180 # autodetection doesn't seem to able to find this, but it's there.
181 checkTarget = "check";
182
183 preCheck =
184 # On musl, comment skip the following tests, because they break due to
185 # ! 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)
186 # See also here:
187 # https://git.alpinelinux.org/aports/tree/main/postgresql/disable-broken-tests.patch?id=6d7d32c12e073a57a9e5946e55f4c1fbb68bd442
188 if stdenv'.hostPlatform.isMusl then ''
189 substituteInPlace src/test/regress/parallel_schedule \
190 --replace "subscription" "" \
191 --replace "object_address" ""
192 '' else null;
193
194 doInstallCheck = false; # needs a running daemon?
195
196 disallowedReferences = [ stdenv'.cc ];
197
198 passthru = let
199 jitToggle = this.override {
200 jitSupport = !jitSupport;
201 this = jitToggle;
202 };
203 in
204 {
205 inherit readline psqlSchema jitSupport;
206
207 withJIT = if jitSupport then this else jitToggle;
208 withoutJIT = if jitSupport then jitToggle else this;
209
210 pkgs = let
211 scope = {
212 postgresql = this;
213 stdenv = stdenv';
214 buildPgxExtension = buildPgxExtension.override {
215 stdenv = stdenv';
216 rustPlatform = makeRustPlatform {
217 stdenv = stdenv';
218 inherit rustc cargo;
219 };
220 };
221 };
222 newSelf = self // scope;
223 newSuper = { callPackage = newScope (scope // this.pkgs); };
224 in import ./packages.nix newSelf newSuper;
225
226 withPackages = postgresqlWithPackages {
227 inherit makeWrapper buildEnv;
228 postgresql = this;
229 }
230 this.pkgs;
231
232 tests = {
233 postgresql = nixosTests.postgresql-wal-receiver.${thisAttr};
234 } // lib.optionalAttrs jitSupport {
235 postgresql-jit = nixosTests.postgresql-jit.${thisAttr};
236 };
237 } // lib.optionalAttrs jitSupport {
238 inherit (llvmPackages) llvm;
239 };
240
241 meta = with lib; {
242 homepage = "https://www.postgresql.org";
243 description = "A powerful, open source object-relational database system";
244 license = licenses.postgresql;
245 maintainers = with maintainers; [ thoughtpolice danbst globin marsam ivan ma27 ];
246 platforms = platforms.unix;
247
248 # JIT support doesn't work with cross-compilation. It is attempted to build LLVM-bytecode
249 # (`%.bc` is the corresponding `make(1)`-rule) for each sub-directory in `backend/` for
250 # the JIT apparently, but with a $(CLANG) that can produce binaries for the build, not the
251 # host-platform.
252 #
253 # I managed to get a cross-build with JIT support working with
254 # `depsBuildBuild = [ llvmPackages.clang ] ++ buildInputs`, but considering that the
255 # resulting LLVM IR isn't platform-independent this doesn't give you much.
256 # In fact, I tried to test the result in a VM-test, but as soon as JIT was used to optimize
257 # a query, postgres would coredump with `Illegal instruction`.
258 broken = jitSupport && (stdenv.hostPlatform != stdenv.buildPlatform);
259 };
260 };
261
262 postgresqlWithPackages = { postgresql, makeWrapper, buildEnv }: pkgs: f: buildEnv {
263 name = "postgresql-and-plugins-${postgresql.version}";
264 paths = f pkgs ++ [
265 postgresql
266 postgresql.lib
267 postgresql.man # in case user installs this into environment
268 ];
269 nativeBuildInputs = [ makeWrapper ];
270
271
272 # We include /bin to ensure the $out/bin directory is created, which is
273 # needed because we'll be removing the files from that directory in postBuild
274 # below. See #22653
275 pathsToLink = ["/" "/bin"];
276
277 # Note: the duplication of executables is about 4MB size.
278 # So a nicer solution was patching postgresql to allow setting the
279 # libdir explicitly.
280 postBuild = ''
281 mkdir -p $out/bin
282 rm $out/bin/{pg_config,postgres,pg_ctl}
283 cp --target-directory=$out/bin ${postgresql}/bin/{postgres,pg_config,pg_ctl}
284 wrapProgram $out/bin/postgres --set NIX_PGLIBDIR $out/lib
285 '';
286
287 passthru.version = postgresql.version;
288 passthru.psqlSchema = postgresql.psqlSchema;
289 };
290
291 mkPackages = self: {
292 postgresql_11 = self.callPackage generic {
293 version = "11.20";
294 psqlSchema = "11.1"; # should be 11, but changing it is invasive
295 hash = "sha256-PXyIgvZKfphTSgRCV9/uerrXelt9oSUI2F1yK5i1rM4=";
296 this = self.postgresql_11;
297 thisAttr = "postgresql_11";
298 inherit self;
299 };
300
301 postgresql_12 = self.callPackage generic {
302 version = "12.15";
303 psqlSchema = "12";
304 hash = "sha256-u1IG4oZMHEV5k4uW6mCW0VXyKr8tLMKqV1cePEyxKzY=";
305 this = self.postgresql_12;
306 thisAttr = "postgresql_12";
307 inherit self;
308 };
309
310 postgresql_13 = self.callPackage generic {
311 version = "13.11";
312 psqlSchema = "13";
313 hash = "sha256-SZL/ZHIDVmtnDU5U3FMXSZomhWyTV20OqVG99r7lC/s=";
314 this = self.postgresql_13;
315 thisAttr = "postgresql_13";
316 inherit self;
317 };
318
319 postgresql_14 = self.callPackage generic {
320 version = "14.8";
321 psqlSchema = "14";
322 hash = "sha256-OdOPADBzftA4Nd6+7+47N9M1RizkmV4kl7w41iHr5Fo=";
323 this = self.postgresql_14;
324 thisAttr = "postgresql_14";
325 inherit self;
326 };
327
328 postgresql_15 = self.callPackage generic {
329 version = "15.3";
330 psqlSchema = "15";
331 hash = "sha256-/8fUiR8A/79cP06rf7vO2EYLjA7mPFpRZxM7nmWZ2TI=";
332 this = self.postgresql_15;
333 thisAttr = "postgresql_15";
334 inherit self;
335 };
336 };
337
338in self:
339 let packages = mkPackages self; in
340 packages
341 // self.lib.mapAttrs'
342 (attrName: postgres: self.lib.nameValuePair "${attrName}_jit" (postgres.override rec {
343 jitSupport = true;
344 thisAttr = "${attrName}_jit";
345 this = self.${thisAttr};
346 }))
347 packages